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