1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.hid; 18 19 import android.app.ActivityManager; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothHidDevice; 22 import android.bluetooth.BluetoothHidDeviceAppQosSettings; 23 import android.bluetooth.BluetoothHidDeviceAppSdpSettings; 24 import android.bluetooth.BluetoothProfile; 25 import android.bluetooth.IBluetoothHidDevice; 26 import android.bluetooth.IBluetoothHidDeviceCallback; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.os.Binder; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Message; 33 import android.os.Process; 34 import android.os.RemoteException; 35 import android.util.Log; 36 37 import com.android.bluetooth.BluetoothMetricsProto; 38 import com.android.bluetooth.Utils; 39 import com.android.bluetooth.btservice.AdapterService; 40 import com.android.bluetooth.btservice.MetricsLogger; 41 import com.android.bluetooth.btservice.ProfileService; 42 import com.android.bluetooth.btservice.storage.DatabaseManager; 43 import com.android.internal.annotations.VisibleForTesting; 44 45 import java.nio.ByteBuffer; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.List; 49 import java.util.NoSuchElementException; 50 import java.util.Objects; 51 52 /** @hide */ 53 public class HidDeviceService extends ProfileService { 54 private static final boolean DBG = false; 55 private static final String TAG = HidDeviceService.class.getSimpleName(); 56 57 private static final int MESSAGE_APPLICATION_STATE_CHANGED = 1; 58 private static final int MESSAGE_CONNECT_STATE_CHANGED = 2; 59 private static final int MESSAGE_GET_REPORT = 3; 60 private static final int MESSAGE_SET_REPORT = 4; 61 private static final int MESSAGE_SET_PROTOCOL = 5; 62 private static final int MESSAGE_INTR_DATA = 6; 63 private static final int MESSAGE_VC_UNPLUG = 7; 64 private static final int MESSAGE_IMPORTANCE_CHANGE = 8; 65 66 private static final int FOREGROUND_IMPORTANCE_CUTOFF = 67 ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; 68 69 private static HidDeviceService sHidDeviceService; 70 71 private DatabaseManager mDatabaseManager; 72 private HidDeviceNativeInterface mHidDeviceNativeInterface; 73 74 private boolean mNativeAvailable = false; 75 private BluetoothDevice mHidDevice; 76 private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED; 77 private int mUserUid = 0; 78 private IBluetoothHidDeviceCallback mCallback; 79 private BluetoothHidDeviceDeathRecipient mDeathRcpt; 80 private ActivityManager mActivityManager; 81 82 private HidDeviceServiceHandler mHandler; 83 84 private class HidDeviceServiceHandler extends Handler { 85 @Override handleMessage(Message msg)86 public void handleMessage(Message msg) { 87 if (DBG) { 88 Log.d(TAG, "handleMessage(): msg.what=" + msg.what); 89 } 90 91 switch (msg.what) { 92 case MESSAGE_APPLICATION_STATE_CHANGED: { 93 BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null; 94 boolean success = (msg.arg1 != 0); 95 96 if (success) { 97 Log.d(TAG, "App registered, set device to: " + device); 98 mHidDevice = device; 99 } else { 100 mHidDevice = null; 101 } 102 103 try { 104 if (mCallback != null) { 105 mCallback.onAppStatusChanged(device, success); 106 } else { 107 break; 108 } 109 } catch (RemoteException e) { 110 Log.e(TAG, "e=" + e.toString()); 111 e.printStackTrace(); 112 } 113 114 if (success) { 115 mDeathRcpt = new BluetoothHidDeviceDeathRecipient(HidDeviceService.this); 116 if (mCallback != null) { 117 IBinder binder = mCallback.asBinder(); 118 try { 119 binder.linkToDeath(mDeathRcpt, 0); 120 Log.i(TAG, "IBinder.linkToDeath() ok"); 121 } catch (RemoteException e) { 122 e.printStackTrace(); 123 } 124 } 125 } else if (mDeathRcpt != null) { 126 if (mCallback != null) { 127 IBinder binder = mCallback.asBinder(); 128 try { 129 binder.unlinkToDeath(mDeathRcpt, 0); 130 Log.i(TAG, "IBinder.unlinkToDeath() ok"); 131 } catch (NoSuchElementException e) { 132 e.printStackTrace(); 133 } 134 mDeathRcpt.cleanup(); 135 mDeathRcpt = null; 136 } 137 } 138 139 if (!success) { 140 mCallback = null; 141 } 142 143 break; 144 } 145 146 case MESSAGE_CONNECT_STATE_CHANGED: { 147 BluetoothDevice device = (BluetoothDevice) msg.obj; 148 int halState = msg.arg1; 149 int state = convertHalState(halState); 150 151 if (state != BluetoothHidDevice.STATE_DISCONNECTED) { 152 mHidDevice = device; 153 } 154 155 setAndBroadcastConnectionState(device, state); 156 157 try { 158 if (mCallback != null) { 159 mCallback.onConnectionStateChanged(device, state); 160 } 161 } catch (RemoteException e) { 162 e.printStackTrace(); 163 } 164 break; 165 } 166 167 case MESSAGE_GET_REPORT: 168 byte type = (byte) msg.arg1; 169 byte id = (byte) msg.arg2; 170 int bufferSize = msg.obj == null ? 0 : ((Integer) msg.obj).intValue(); 171 172 try { 173 if (mCallback != null) { 174 mCallback.onGetReport(mHidDevice, type, id, bufferSize); 175 } 176 } catch (RemoteException e) { 177 e.printStackTrace(); 178 } 179 break; 180 181 case MESSAGE_SET_REPORT: { 182 byte reportType = (byte) msg.arg1; 183 byte reportId = (byte) msg.arg2; 184 byte[] data = ((ByteBuffer) msg.obj).array(); 185 186 try { 187 if (mCallback != null) { 188 mCallback.onSetReport(mHidDevice, reportType, reportId, data); 189 } 190 } catch (RemoteException e) { 191 e.printStackTrace(); 192 } 193 break; 194 } 195 196 case MESSAGE_SET_PROTOCOL: 197 byte protocol = (byte) msg.arg1; 198 199 try { 200 if (mCallback != null) { 201 mCallback.onSetProtocol(mHidDevice, protocol); 202 } 203 } catch (RemoteException e) { 204 e.printStackTrace(); 205 } 206 break; 207 208 case MESSAGE_INTR_DATA: 209 byte reportId = (byte) msg.arg1; 210 byte[] data = ((ByteBuffer) msg.obj).array(); 211 212 try { 213 if (mCallback != null) { 214 mCallback.onInterruptData(mHidDevice, reportId, data); 215 } 216 } catch (RemoteException e) { 217 e.printStackTrace(); 218 } 219 break; 220 221 case MESSAGE_VC_UNPLUG: 222 try { 223 if (mCallback != null) { 224 mCallback.onVirtualCableUnplug(mHidDevice); 225 } 226 } catch (RemoteException e) { 227 e.printStackTrace(); 228 } 229 mHidDevice = null; 230 break; 231 232 case MESSAGE_IMPORTANCE_CHANGE: 233 int importance = msg.arg1; 234 int uid = msg.arg2; 235 if (importance > FOREGROUND_IMPORTANCE_CUTOFF 236 && uid >= Process.FIRST_APPLICATION_UID) { 237 unregisterAppUid(uid); 238 } 239 break; 240 } 241 } 242 } 243 244 private static class BluetoothHidDeviceDeathRecipient implements IBinder.DeathRecipient { 245 private HidDeviceService mService; 246 BluetoothHidDeviceDeathRecipient(HidDeviceService service)247 BluetoothHidDeviceDeathRecipient(HidDeviceService service) { 248 mService = service; 249 } 250 251 @Override binderDied()252 public void binderDied() { 253 Log.w(TAG, "Binder died, need to unregister app :("); 254 mService.unregisterApp(); 255 } 256 cleanup()257 public void cleanup() { 258 mService = null; 259 } 260 } 261 262 private ActivityManager.OnUidImportanceListener mUidImportanceListener = 263 new ActivityManager.OnUidImportanceListener() { 264 @Override 265 public void onUidImportance(final int uid, final int importance) { 266 Message message = mHandler.obtainMessage(MESSAGE_IMPORTANCE_CHANGE); 267 message.arg1 = importance; 268 message.arg2 = uid; 269 mHandler.sendMessage(message); 270 } 271 }; 272 273 @VisibleForTesting 274 static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub 275 implements IProfileServiceBinder { 276 277 private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName(); 278 279 private HidDeviceService mService; 280 BluetoothHidDeviceBinder(HidDeviceService service)281 BluetoothHidDeviceBinder(HidDeviceService service) { 282 mService = service; 283 } 284 285 @VisibleForTesting getServiceForTesting()286 HidDeviceService getServiceForTesting() { 287 if (mService != null && mService.isAvailable()) { 288 return mService; 289 } 290 return null; 291 } 292 293 @Override cleanup()294 public void cleanup() { 295 mService = null; 296 } 297 getService()298 private HidDeviceService getService() { 299 if (!Utils.checkCaller()) { 300 Log.w(TAG, "HidDevice call not allowed for non-active user"); 301 return null; 302 } 303 304 if (mService != null && mService.isAvailable()) { 305 return mService; 306 } 307 308 return null; 309 } 310 311 @Override registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)312 public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, 313 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, 314 IBluetoothHidDeviceCallback callback) { 315 if (DBG) { 316 Log.d(TAG, "registerApp()"); 317 } 318 319 HidDeviceService service = getService(); 320 if (service == null) { 321 return false; 322 } 323 324 return service.registerApp(sdp, inQos, outQos, callback); 325 } 326 327 @Override unregisterApp()328 public boolean unregisterApp() { 329 if (DBG) { 330 Log.d(TAG, "unregisterApp()"); 331 } 332 333 HidDeviceService service = getService(); 334 if (service == null) { 335 return false; 336 } 337 338 return service.unregisterApp(); 339 } 340 341 @Override sendReport(BluetoothDevice device, int id, byte[] data)342 public boolean sendReport(BluetoothDevice device, int id, byte[] data) { 343 if (DBG) { 344 Log.d(TAG, "sendReport(): device=" + device + " id=" + id); 345 } 346 347 HidDeviceService service = getService(); 348 if (service == null) { 349 return false; 350 } 351 352 return service.sendReport(device, id, data); 353 } 354 355 @Override replyReport(BluetoothDevice device, byte type, byte id, byte[] data)356 public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { 357 if (DBG) { 358 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); 359 } 360 361 HidDeviceService service = getService(); 362 if (service == null) { 363 return false; 364 } 365 366 return service.replyReport(device, type, id, data); 367 } 368 369 @Override unplug(BluetoothDevice device)370 public boolean unplug(BluetoothDevice device) { 371 if (DBG) { 372 Log.d(TAG, "unplug(): device=" + device); 373 } 374 375 HidDeviceService service = getService(); 376 if (service == null) { 377 return false; 378 } 379 380 return service.unplug(device); 381 } 382 383 @Override connect(BluetoothDevice device)384 public boolean connect(BluetoothDevice device) { 385 if (DBG) { 386 Log.d(TAG, "connect(): device=" + device); 387 } 388 389 HidDeviceService service = getService(); 390 if (service == null) { 391 return false; 392 } 393 394 return service.connect(device); 395 } 396 397 @Override disconnect(BluetoothDevice device)398 public boolean disconnect(BluetoothDevice device) { 399 if (DBG) { 400 Log.d(TAG, "disconnect(): device=" + device); 401 } 402 403 HidDeviceService service = getService(); 404 if (service == null) { 405 return false; 406 } 407 408 return service.disconnect(device); 409 } 410 411 @Override setConnectionPolicy(BluetoothDevice device, int connectionPolicy)412 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 413 if (DBG) { 414 Log.d(TAG, "setConnectionPolicy(): device=" + device + " connectionPolicy=" 415 + connectionPolicy); 416 } 417 418 HidDeviceService service = getService(); 419 if (service == null) { 420 return false; 421 } 422 423 return service.setConnectionPolicy(device, connectionPolicy); 424 } 425 426 @Override reportError(BluetoothDevice device, byte error)427 public boolean reportError(BluetoothDevice device, byte error) { 428 if (DBG) { 429 Log.d(TAG, "reportError(): device=" + device + " error=" + error); 430 } 431 432 HidDeviceService service = getService(); 433 if (service == null) { 434 return false; 435 } 436 437 return service.reportError(device, error); 438 } 439 440 @Override getConnectionState(BluetoothDevice device)441 public int getConnectionState(BluetoothDevice device) { 442 if (DBG) { 443 Log.d(TAG, "getConnectionState(): device=" + device); 444 } 445 446 HidDeviceService service = getService(); 447 if (service == null) { 448 return BluetoothHidDevice.STATE_DISCONNECTED; 449 } 450 451 return service.getConnectionState(device); 452 } 453 454 @Override getConnectedDevices()455 public List<BluetoothDevice> getConnectedDevices() { 456 if (DBG) { 457 Log.d(TAG, "getConnectedDevices()"); 458 } 459 460 return getDevicesMatchingConnectionStates(new int[]{BluetoothProfile.STATE_CONNECTED}); 461 } 462 463 @Override getDevicesMatchingConnectionStates(int[] states)464 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 465 if (DBG) { 466 Log.d(TAG, 467 "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); 468 } 469 470 HidDeviceService service = getService(); 471 if (service == null) { 472 return new ArrayList<BluetoothDevice>(0); 473 } 474 475 return service.getDevicesMatchingConnectionStates(states); 476 } 477 478 @Override getUserAppName()479 public String getUserAppName() { 480 HidDeviceService service = getService(); 481 if (service == null) { 482 return ""; 483 } 484 return service.getUserAppName(); 485 } 486 } 487 488 @Override initBinder()489 protected IProfileServiceBinder initBinder() { 490 return new BluetoothHidDeviceBinder(this); 491 } 492 checkDevice(BluetoothDevice device)493 private boolean checkDevice(BluetoothDevice device) { 494 if (mHidDevice == null || !mHidDevice.equals(device)) { 495 Log.w(TAG, "Unknown device: " + device); 496 return false; 497 } 498 return true; 499 } 500 checkCallingUid()501 private boolean checkCallingUid() { 502 int callingUid = Binder.getCallingUid(); 503 if (callingUid != mUserUid) { 504 Log.w(TAG, "checkCallingUid(): caller UID doesn't match registered user UID"); 505 return false; 506 } 507 return true; 508 } 509 registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)510 synchronized boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, 511 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, 512 IBluetoothHidDeviceCallback callback) { 513 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 514 if (mUserUid != 0) { 515 Log.w(TAG, "registerApp(): failed because another app is registered"); 516 return false; 517 } 518 519 int callingUid = Binder.getCallingUid(); 520 if (DBG) { 521 Log.d(TAG, "registerApp(): calling uid=" + callingUid); 522 } 523 if (callingUid >= Process.FIRST_APPLICATION_UID 524 && mActivityManager.getUidImportance(callingUid) > FOREGROUND_IMPORTANCE_CUTOFF) { 525 Log.w(TAG, "registerApp(): failed because the app is not foreground"); 526 return false; 527 } 528 mUserUid = callingUid; 529 mCallback = callback; 530 531 return mHidDeviceNativeInterface.registerApp( 532 sdp.getName(), 533 sdp.getDescription(), 534 sdp.getProvider(), 535 sdp.getSubclass(), 536 sdp.getDescriptors(), 537 inQos == null 538 ? null 539 : new int[] { 540 inQos.getServiceType(), 541 inQos.getTokenRate(), 542 inQos.getTokenBucketSize(), 543 inQos.getPeakBandwidth(), 544 inQos.getLatency(), 545 inQos.getDelayVariation() 546 }, 547 outQos == null 548 ? null 549 : new int[] { 550 outQos.getServiceType(), 551 outQos.getTokenRate(), 552 outQos.getTokenBucketSize(), 553 outQos.getPeakBandwidth(), 554 outQos.getLatency(), 555 outQos.getDelayVariation() 556 }); 557 } 558 unregisterApp()559 synchronized boolean unregisterApp() { 560 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 561 if (DBG) { 562 Log.d(TAG, "unregisterApp()"); 563 } 564 565 int callingUid = Binder.getCallingUid(); 566 return unregisterAppUid(callingUid); 567 } 568 unregisterAppUid(int uid)569 private synchronized boolean unregisterAppUid(int uid) { 570 if (DBG) { 571 Log.d(TAG, "unregisterAppUid(): uid=" + uid); 572 } 573 574 if (mUserUid != 0 && (uid == mUserUid || uid < Process.FIRST_APPLICATION_UID)) { 575 mUserUid = 0; 576 return mHidDeviceNativeInterface.unregisterApp(); 577 } 578 if (DBG) { 579 Log.d(TAG, "unregisterAppUid(): caller UID doesn't match user UID"); 580 } 581 return false; 582 } 583 sendReport(BluetoothDevice device, int id, byte[] data)584 synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) { 585 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 586 if (DBG) { 587 Log.d(TAG, "sendReport(): device=" + device + " id=" + id); 588 } 589 590 return checkDevice(device) && checkCallingUid() 591 && mHidDeviceNativeInterface.sendReport(id, data); 592 } 593 replyReport(BluetoothDevice device, byte type, byte id, byte[] data)594 synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { 595 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 596 if (DBG) { 597 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); 598 } 599 600 return checkDevice(device) && checkCallingUid() 601 && mHidDeviceNativeInterface.replyReport(type, id, data); 602 } 603 unplug(BluetoothDevice device)604 synchronized boolean unplug(BluetoothDevice device) { 605 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 606 if (DBG) { 607 Log.d(TAG, "unplug(): device=" + device); 608 } 609 610 return checkDevice(device) && checkCallingUid() 611 && mHidDeviceNativeInterface.unplug(); 612 } 613 614 /** 615 * Connects the Hid device profile for the remote bluetooth device 616 * 617 * @param device is the device with which we would like to connect the hid device profile 618 * @return true if the connection is successful, false otherwise 619 */ connect(BluetoothDevice device)620 public synchronized boolean connect(BluetoothDevice device) { 621 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 622 if (DBG) { 623 Log.d(TAG, "connect(): device=" + device); 624 } 625 626 return checkCallingUid() && mHidDeviceNativeInterface.connect(device); 627 } 628 629 /** 630 * Disconnects the hid device profile for the remote bluetooth device 631 * 632 * @param device is the device with which we would like to disconnect the hid device profile 633 * @return true if the disconnection is successful, false otherwise 634 */ disconnect(BluetoothDevice device)635 public synchronized boolean disconnect(BluetoothDevice device) { 636 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 637 if (DBG) { 638 Log.d(TAG, "disconnect(): device=" + device); 639 } 640 641 int callingUid = Binder.getCallingUid(); 642 if (callingUid != mUserUid && callingUid >= Process.FIRST_APPLICATION_UID) { 643 Log.w(TAG, "disconnect(): caller UID doesn't match user UID"); 644 return false; 645 } 646 return checkDevice(device) && mHidDeviceNativeInterface.disconnect(); 647 } 648 649 /** 650 * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} 651 * and disconnects Hid device if connectionPolicy is 652 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}. 653 * 654 * <p> The device should already be paired. 655 * Connection policy can be one of: 656 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 657 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 658 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 659 * 660 * @param device Paired bluetooth device 661 * @param connectionPolicy determines whether hid device should be connected or disconnected 662 * @return true if hid device is connected or disconnected, false otherwise 663 */ setConnectionPolicy(BluetoothDevice device, int connectionPolicy)664 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 665 enforceCallingOrSelfPermission( 666 BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission"); 667 if (DBG) { 668 Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); 669 } 670 671 if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.HID_DEVICE, 672 connectionPolicy)) { 673 return false; 674 } 675 if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { 676 disconnect(device); 677 } 678 return true; 679 } 680 681 /** 682 * Get the connection policy of the profile. 683 * 684 * <p> The connection policy can be any of: 685 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 686 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 687 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 688 * 689 * @param device Bluetooth device 690 * @return connection policy of the device 691 * @hide 692 */ getConnectionPolicy(BluetoothDevice device)693 public int getConnectionPolicy(BluetoothDevice device) { 694 if (device == null) { 695 throw new IllegalArgumentException("Null device"); 696 } 697 enforceCallingOrSelfPermission( 698 BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission"); 699 return mDatabaseManager 700 .getProfileConnectionPolicy(device, BluetoothProfile.HID_DEVICE); 701 } 702 reportError(BluetoothDevice device, byte error)703 synchronized boolean reportError(BluetoothDevice device, byte error) { 704 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 705 if (DBG) { 706 Log.d(TAG, "reportError(): device=" + device + " error=" + error); 707 } 708 709 return checkDevice(device) && checkCallingUid() 710 && mHidDeviceNativeInterface.reportError(error); 711 } 712 getUserAppName()713 synchronized String getUserAppName() { 714 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 715 if (mUserUid < Process.FIRST_APPLICATION_UID) { 716 return ""; 717 } 718 String appName = getPackageManager().getNameForUid(mUserUid); 719 return appName != null ? appName : ""; 720 } 721 722 @Override start()723 protected boolean start() { 724 if (DBG) { 725 Log.d(TAG, "start()"); 726 } 727 728 mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(), 729 "DatabaseManager cannot be null when HidDeviceService starts"); 730 731 mHandler = new HidDeviceServiceHandler(); 732 mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance(); 733 mHidDeviceNativeInterface.init(); 734 mNativeAvailable = true; 735 mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 736 mActivityManager.addOnUidImportanceListener(mUidImportanceListener, 737 FOREGROUND_IMPORTANCE_CUTOFF); 738 setHidDeviceService(this); 739 return true; 740 } 741 742 @Override stop()743 protected boolean stop() { 744 if (DBG) { 745 Log.d(TAG, "stop()"); 746 } 747 748 if (sHidDeviceService == null) { 749 Log.w(TAG, "stop() called before start()"); 750 return true; 751 } 752 753 setHidDeviceService(null); 754 if (mNativeAvailable) { 755 mHidDeviceNativeInterface.cleanup(); 756 mNativeAvailable = false; 757 } 758 mActivityManager.removeOnUidImportanceListener(mUidImportanceListener); 759 return true; 760 } 761 762 @Override onUnbind(Intent intent)763 public boolean onUnbind(Intent intent) { 764 Log.d(TAG, "Need to unregister app"); 765 unregisterApp(); 766 return super.onUnbind(intent); 767 } 768 769 /** 770 * Get the HID Device Service instance 771 * @return HID Device Service instance 772 */ getHidDeviceService()773 public static synchronized HidDeviceService getHidDeviceService() { 774 if (sHidDeviceService == null) { 775 Log.d(TAG, "getHidDeviceService(): service is NULL"); 776 return null; 777 } 778 if (!sHidDeviceService.isAvailable()) { 779 Log.d(TAG, "getHidDeviceService(): service is not available"); 780 return null; 781 } 782 return sHidDeviceService; 783 } 784 setHidDeviceService(HidDeviceService instance)785 private static synchronized void setHidDeviceService(HidDeviceService instance) { 786 if (DBG) { 787 Log.d(TAG, "setHidDeviceService(): set to: " + instance); 788 } 789 sHidDeviceService = instance; 790 } 791 792 /** 793 * Gets the connections state for the hid device profile for the passed in device 794 * 795 * @param device is the device whose conenction state we want to verify 796 * @return current connection state, one of {@link BluetoothProfile#STATE_DISCONNECTED}, 797 * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or 798 * {@link BluetoothProfile#STATE_DISCONNECTING} 799 */ getConnectionState(BluetoothDevice device)800 public int getConnectionState(BluetoothDevice device) { 801 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 802 if (mHidDevice != null && mHidDevice.equals(device)) { 803 return mHidDeviceState; 804 } 805 return BluetoothHidDevice.STATE_DISCONNECTED; 806 } 807 getDevicesMatchingConnectionStates(int[] states)808 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 809 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 810 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 811 812 if (mHidDevice != null) { 813 for (int state : states) { 814 if (state == mHidDeviceState) { 815 inputDevices.add(mHidDevice); 816 break; 817 } 818 } 819 } 820 return inputDevices; 821 } 822 onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered)823 synchronized void onApplicationStateChangedFromNative(BluetoothDevice device, 824 boolean registered) { 825 if (DBG) { 826 Log.d(TAG, "onApplicationStateChanged(): registered=" + registered); 827 } 828 829 Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED); 830 msg.obj = device; 831 msg.arg1 = registered ? 1 : 0; 832 mHandler.sendMessage(msg); 833 } 834 onConnectStateChangedFromNative(BluetoothDevice device, int state)835 synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) { 836 if (DBG) { 837 Log.d(TAG, "onConnectStateChanged(): device=" 838 + device + " state=" + state); 839 } 840 841 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 842 msg.obj = device; 843 msg.arg1 = state; 844 mHandler.sendMessage(msg); 845 } 846 onGetReportFromNative(byte type, byte id, short bufferSize)847 synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) { 848 if (DBG) { 849 Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize); 850 } 851 852 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 853 msg.obj = bufferSize > 0 ? new Integer(bufferSize) : null; 854 msg.arg1 = type; 855 msg.arg2 = id; 856 mHandler.sendMessage(msg); 857 } 858 onSetReportFromNative(byte reportType, byte reportId, byte[] data)859 synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) { 860 if (DBG) { 861 Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId); 862 } 863 864 ByteBuffer bb = ByteBuffer.wrap(data); 865 866 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 867 msg.arg1 = reportType; 868 msg.arg2 = reportId; 869 msg.obj = bb; 870 mHandler.sendMessage(msg); 871 } 872 onSetProtocolFromNative(byte protocol)873 synchronized void onSetProtocolFromNative(byte protocol) { 874 if (DBG) { 875 Log.d(TAG, "onSetProtocol(): protocol=" + protocol); 876 } 877 878 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL); 879 msg.arg1 = protocol; 880 mHandler.sendMessage(msg); 881 } 882 onInterruptDataFromNative(byte reportId, byte[] data)883 synchronized void onInterruptDataFromNative(byte reportId, byte[] data) { 884 if (DBG) { 885 Log.d(TAG, "onInterruptData(): reportId=" + reportId); 886 } 887 888 ByteBuffer bb = ByteBuffer.wrap(data); 889 890 Message msg = mHandler.obtainMessage(MESSAGE_INTR_DATA); 891 msg.arg1 = reportId; 892 msg.obj = bb; 893 mHandler.sendMessage(msg); 894 } 895 onVirtualCableUnplugFromNative()896 synchronized void onVirtualCableUnplugFromNative() { 897 if (DBG) { 898 Log.d(TAG, "onVirtualCableUnplug()"); 899 } 900 901 Message msg = mHandler.obtainMessage(MESSAGE_VC_UNPLUG); 902 mHandler.sendMessage(msg); 903 } 904 setAndBroadcastConnectionState(BluetoothDevice device, int newState)905 private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) { 906 if (DBG) { 907 Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress() 908 + " oldState=" + mHidDeviceState + " newState=" + newState); 909 } 910 911 if (mHidDevice != null && !mHidDevice.equals(device)) { 912 Log.w(TAG, "Connection state changed for unknown device, ignoring"); 913 return; 914 } 915 916 int prevState = mHidDeviceState; 917 mHidDeviceState = newState; 918 919 if (prevState == newState) { 920 Log.w(TAG, "Connection state is unchanged, ignoring"); 921 return; 922 } 923 924 if (newState == BluetoothProfile.STATE_CONNECTED) { 925 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HID_DEVICE); 926 } 927 928 Intent intent = new Intent(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED); 929 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 930 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 931 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 932 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 933 sendBroadcast(intent, BLUETOOTH_PERM); 934 } 935 convertHalState(int halState)936 private static int convertHalState(int halState) { 937 switch (halState) { 938 case HAL_CONN_STATE_CONNECTED: 939 return BluetoothProfile.STATE_CONNECTED; 940 case HAL_CONN_STATE_CONNECTING: 941 return BluetoothProfile.STATE_CONNECTING; 942 case HAL_CONN_STATE_DISCONNECTED: 943 return BluetoothProfile.STATE_DISCONNECTED; 944 case HAL_CONN_STATE_DISCONNECTING: 945 return BluetoothProfile.STATE_DISCONNECTING; 946 default: 947 return BluetoothProfile.STATE_DISCONNECTED; 948 } 949 } 950 951 static final int HAL_CONN_STATE_CONNECTED = 0; 952 static final int HAL_CONN_STATE_CONNECTING = 1; 953 static final int HAL_CONN_STATE_DISCONNECTED = 2; 954 static final int HAL_CONN_STATE_DISCONNECTING = 3; 955 } 956