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