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