1 /* 2 * Copyright (C) 2012 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 static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; 22 23 import android.annotation.RequiresPermission; 24 import android.app.ActivityThread; 25 import android.bluetooth.BluetoothDevice; 26 import android.bluetooth.BluetoothHidHost; 27 import android.bluetooth.BluetoothProfile; 28 import android.bluetooth.IBluetoothHidHost; 29 import android.content.Attributable; 30 import android.content.AttributionSource; 31 import android.content.Intent; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.Message; 35 import android.os.UserHandle; 36 import android.util.Log; 37 38 import androidx.annotation.VisibleForTesting; 39 40 import com.android.bluetooth.BluetoothMetricsProto; 41 import com.android.bluetooth.Utils; 42 import com.android.bluetooth.btservice.AdapterService; 43 import com.android.bluetooth.btservice.MetricsLogger; 44 import com.android.bluetooth.btservice.ProfileService; 45 import com.android.bluetooth.btservice.storage.DatabaseManager; 46 47 import java.util.ArrayList; 48 import java.util.Collections; 49 import java.util.HashMap; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.Objects; 53 54 /** 55 * Provides Bluetooth Hid Host profile, as a service in 56 * the Bluetooth application. 57 * @hide 58 */ 59 public class HidHostService extends ProfileService { 60 private static final boolean DBG = false; 61 private static final String TAG = "BluetoothHidHostService"; 62 63 private Map<BluetoothDevice, Integer> mInputDevices; 64 private boolean mNativeAvailable; 65 private static HidHostService sHidHostService; 66 private BluetoothDevice mTargetDevice = null; 67 68 private DatabaseManager mDatabaseManager; 69 70 private static final int MESSAGE_CONNECT = 1; 71 private static final int MESSAGE_DISCONNECT = 2; 72 private static final int MESSAGE_CONNECT_STATE_CHANGED = 3; 73 private static final int MESSAGE_GET_PROTOCOL_MODE = 4; 74 private static final int MESSAGE_VIRTUAL_UNPLUG = 5; 75 private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6; 76 private static final int MESSAGE_SET_PROTOCOL_MODE = 7; 77 private static final int MESSAGE_GET_REPORT = 8; 78 private static final int MESSAGE_ON_GET_REPORT = 9; 79 private static final int MESSAGE_SET_REPORT = 10; 80 private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12; 81 private static final int MESSAGE_ON_HANDSHAKE = 13; 82 private static final int MESSAGE_GET_IDLE_TIME = 14; 83 private static final int MESSAGE_ON_GET_IDLE_TIME = 15; 84 private static final int MESSAGE_SET_IDLE_TIME = 16; 85 86 static { classInitNative()87 classInitNative(); 88 } 89 90 @Override initBinder()91 public IProfileServiceBinder initBinder() { 92 return new BluetoothHidHostBinder(this); 93 } 94 95 @Override start()96 protected boolean start() { 97 mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(), 98 "DatabaseManager cannot be null when HidHostService starts"); 99 100 mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>()); 101 initializeNative(); 102 mNativeAvailable = true; 103 setHidHostService(this); 104 return true; 105 } 106 107 @Override stop()108 protected boolean stop() { 109 if (DBG) { 110 Log.d(TAG, "Stopping Bluetooth HidHostService"); 111 } 112 return true; 113 } 114 115 @Override cleanup()116 protected void cleanup() { 117 if (DBG) Log.d(TAG, "Stopping Bluetooth HidHostService"); 118 if (mNativeAvailable) { 119 cleanupNative(); 120 mNativeAvailable = false; 121 } 122 123 if (mInputDevices != null) { 124 for (BluetoothDevice device : mInputDevices.keySet()) { 125 int inputDeviceState = getConnectionState(device); 126 if (inputDeviceState != BluetoothProfile.STATE_DISCONNECTED) { 127 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 128 } 129 } 130 mInputDevices.clear(); 131 } 132 // TODO(b/72948646): this should be moved to stop() 133 setHidHostService(null); 134 } 135 getHidHostService()136 public static synchronized HidHostService getHidHostService() { 137 if (sHidHostService == null) { 138 Log.w(TAG, "getHidHostService(): service is null"); 139 return null; 140 } 141 if (!sHidHostService.isAvailable()) { 142 Log.w(TAG, "getHidHostService(): service is not available "); 143 return null; 144 } 145 return sHidHostService; 146 } 147 setHidHostService(HidHostService instance)148 private static synchronized void setHidHostService(HidHostService instance) { 149 if (DBG) { 150 Log.d(TAG, "setHidHostService(): set to: " + instance); 151 } 152 sHidHostService = instance; 153 } 154 155 private final Handler mHandler = new Handler() { 156 157 @Override 158 public void handleMessage(Message msg) { 159 if (DBG) Log.v(TAG, "handleMessage(): msg.what=" + msg.what); 160 161 switch (msg.what) { 162 case MESSAGE_CONNECT: { 163 BluetoothDevice device = (BluetoothDevice) msg.obj; 164 Attributable.setAttributionSource(device, 165 ActivityThread.currentAttributionSource()); 166 if (!connectHidNative(Utils.getByteAddress(device))) { 167 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 168 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 169 break; 170 } 171 mTargetDevice = device; 172 } 173 break; 174 case MESSAGE_DISCONNECT: { 175 BluetoothDevice device = (BluetoothDevice) msg.obj; 176 Attributable.setAttributionSource(device, 177 ActivityThread.currentAttributionSource()); 178 if (!disconnectHidNative(Utils.getByteAddress(device))) { 179 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 180 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 181 break; 182 } 183 } 184 break; 185 case MESSAGE_CONNECT_STATE_CHANGED: { 186 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 187 Attributable.setAttributionSource(device, 188 ActivityThread.currentAttributionSource()); 189 int halState = msg.arg1; 190 Integer prevStateInteger = mInputDevices.get(device); 191 int prevState = 192 (prevStateInteger == null) ? BluetoothHidHost.STATE_DISCONNECTED 193 : prevStateInteger; 194 if (DBG) { 195 Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:" + convertHalState( 196 halState) + ", prevState:" + prevState); 197 } 198 if (halState == CONN_STATE_CONNECTED 199 && prevState == BluetoothHidHost.STATE_DISCONNECTED 200 && (!okToConnect(device))) { 201 if (DBG) { 202 Log.d(TAG, "Incoming HID connection rejected"); 203 } 204 virtualUnPlugNative(Utils.getByteAddress(device)); 205 } else { 206 broadcastConnectionState(device, convertHalState(halState)); 207 } 208 if (halState == CONN_STATE_CONNECTED && (mTargetDevice != null 209 && mTargetDevice.equals(device))) { 210 mTargetDevice = null; 211 // local device originated connection to hid device, move out 212 // of quiet mode 213 AdapterService adapterService = AdapterService.getAdapterService(); 214 adapterService.enable(false); 215 } 216 } 217 break; 218 case MESSAGE_GET_PROTOCOL_MODE: { 219 BluetoothDevice device = (BluetoothDevice) msg.obj; 220 Attributable.setAttributionSource(device, 221 ActivityThread.currentAttributionSource()); 222 if (!getProtocolModeNative(Utils.getByteAddress(device))) { 223 Log.e(TAG, "Error: get protocol mode native returns false"); 224 } 225 } 226 break; 227 228 case MESSAGE_ON_GET_PROTOCOL_MODE: { 229 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 230 int protocolMode = msg.arg1; 231 broadcastProtocolMode(device, protocolMode); 232 } 233 break; 234 case MESSAGE_VIRTUAL_UNPLUG: { 235 BluetoothDevice device = (BluetoothDevice) msg.obj; 236 Attributable.setAttributionSource(device, 237 ActivityThread.currentAttributionSource()); 238 if (!virtualUnPlugNative(Utils.getByteAddress(device))) { 239 Log.e(TAG, "Error: virtual unplug native returns false"); 240 } 241 } 242 break; 243 case MESSAGE_SET_PROTOCOL_MODE: { 244 BluetoothDevice device = (BluetoothDevice) msg.obj; 245 Attributable.setAttributionSource(device, 246 ActivityThread.currentAttributionSource()); 247 byte protocolMode = (byte) msg.arg1; 248 Log.d(TAG, "sending set protocol mode(" + protocolMode + ")"); 249 if (!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) { 250 Log.e(TAG, "Error: set protocol mode native returns false"); 251 } 252 } 253 break; 254 case MESSAGE_GET_REPORT: { 255 BluetoothDevice device = (BluetoothDevice) msg.obj; 256 Attributable.setAttributionSource(device, 257 ActivityThread.currentAttributionSource()); 258 Bundle data = msg.getData(); 259 byte reportType = data.getByte(BluetoothHidHost.EXTRA_REPORT_TYPE); 260 byte reportId = data.getByte(BluetoothHidHost.EXTRA_REPORT_ID); 261 int bufferSize = data.getInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE); 262 if (!getReportNative(Utils.getByteAddress(device), reportType, reportId, 263 bufferSize)) { 264 Log.e(TAG, "Error: get report native returns false"); 265 } 266 } 267 break; 268 case MESSAGE_ON_GET_REPORT: { 269 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 270 Bundle data = msg.getData(); 271 byte[] report = data.getByteArray(BluetoothHidHost.EXTRA_REPORT); 272 int bufferSize = data.getInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE); 273 broadcastReport(device, report, bufferSize); 274 } 275 break; 276 case MESSAGE_ON_HANDSHAKE: { 277 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 278 int status = msg.arg1; 279 broadcastHandshake(device, status); 280 } 281 break; 282 case MESSAGE_SET_REPORT: { 283 BluetoothDevice device = (BluetoothDevice) msg.obj; 284 Attributable.setAttributionSource(device, 285 ActivityThread.currentAttributionSource()); 286 Bundle data = msg.getData(); 287 byte reportType = data.getByte(BluetoothHidHost.EXTRA_REPORT_TYPE); 288 String report = data.getString(BluetoothHidHost.EXTRA_REPORT); 289 if (!setReportNative(Utils.getByteAddress(device), reportType, report)) { 290 Log.e(TAG, "Error: set report native returns false"); 291 } 292 } 293 break; 294 case MESSAGE_ON_VIRTUAL_UNPLUG: { 295 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 296 int status = msg.arg1; 297 broadcastVirtualUnplugStatus(device, status); 298 } 299 break; 300 case MESSAGE_GET_IDLE_TIME: { 301 BluetoothDevice device = (BluetoothDevice) msg.obj; 302 Attributable.setAttributionSource(device, 303 ActivityThread.currentAttributionSource()); 304 if (!getIdleTimeNative(Utils.getByteAddress(device))) { 305 Log.e(TAG, "Error: get idle time native returns false"); 306 } 307 } 308 break; 309 case MESSAGE_ON_GET_IDLE_TIME: { 310 BluetoothDevice device = getAnonymousDevice((byte[]) msg.obj); 311 int idleTime = msg.arg1; 312 broadcastIdleTime(device, idleTime); 313 } 314 break; 315 case MESSAGE_SET_IDLE_TIME: { 316 BluetoothDevice device = (BluetoothDevice) msg.obj; 317 Attributable.setAttributionSource(device, 318 ActivityThread.currentAttributionSource()); 319 Bundle data = msg.getData(); 320 byte idleTime = data.getByte(BluetoothHidHost.EXTRA_IDLE_TIME); 321 if (!setIdleTimeNative(Utils.getByteAddress(device), idleTime)) { 322 Log.e(TAG, "Error: get idle time native returns false"); 323 } 324 } 325 break; 326 } 327 } 328 }; 329 330 /** 331 * Handlers for incoming service calls 332 */ 333 private static class BluetoothHidHostBinder extends IBluetoothHidHost.Stub 334 implements IProfileServiceBinder { 335 private HidHostService mService; 336 BluetoothHidHostBinder(HidHostService svc)337 BluetoothHidHostBinder(HidHostService svc) { 338 mService = svc; 339 } 340 341 @Override cleanup()342 public void cleanup() { 343 mService = null; 344 } 345 346 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getService(AttributionSource source)347 private HidHostService getService(AttributionSource source) { 348 if (!Utils.checkCallerIsSystemOrActiveUser(TAG) 349 || !Utils.checkServiceAvailable(mService, TAG) 350 || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) { 351 return null; 352 } 353 return mService; 354 } 355 356 @Override connect(BluetoothDevice device, AttributionSource source)357 public boolean connect(BluetoothDevice device, AttributionSource source) { 358 Attributable.setAttributionSource(device, source); 359 HidHostService service = getService(source); 360 if (service == null) { 361 return false; 362 } 363 enforceBluetoothPrivilegedPermission(service); 364 return service.connect(device); 365 } 366 367 @Override disconnect(BluetoothDevice device, AttributionSource source)368 public boolean disconnect(BluetoothDevice device, AttributionSource source) { 369 Attributable.setAttributionSource(device, source); 370 HidHostService service = getService(source); 371 if (service == null) { 372 return false; 373 } 374 enforceBluetoothPrivilegedPermission(service); 375 return service.disconnect(device); 376 } 377 378 @Override getConnectionState(BluetoothDevice device, AttributionSource source)379 public int getConnectionState(BluetoothDevice device, AttributionSource source) { 380 Attributable.setAttributionSource(device, source); 381 HidHostService service = getService(source); 382 if (service == null) { 383 return BluetoothHidHost.STATE_DISCONNECTED; 384 } 385 return service.getConnectionState(device); 386 } 387 388 @Override getConnectedDevices(AttributionSource source)389 public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { 390 return getDevicesMatchingConnectionStates(new int[] { 391 BluetoothProfile.STATE_CONNECTED 392 }, source); 393 } 394 395 @Override getDevicesMatchingConnectionStates(int[] states, AttributionSource source)396 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states, 397 AttributionSource source) { 398 HidHostService service = getService(source); 399 if (service == null) { 400 return new ArrayList<BluetoothDevice>(0); 401 } 402 return service.getDevicesMatchingConnectionStates(states); 403 } 404 405 @Override setConnectionPolicy(BluetoothDevice device, int connectionPolicy, AttributionSource source)406 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy, 407 AttributionSource source) { 408 Attributable.setAttributionSource(device, source); 409 HidHostService service = getService(source); 410 if (service == null) { 411 return false; 412 } 413 enforceBluetoothPrivilegedPermission(service); 414 return service.setConnectionPolicy(device, connectionPolicy); 415 } 416 417 @Override getConnectionPolicy(BluetoothDevice device, AttributionSource source)418 public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { 419 Attributable.setAttributionSource(device, source); 420 HidHostService service = getService(source); 421 if (service == null) { 422 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 423 } 424 enforceBluetoothPrivilegedPermission(service); 425 return service.getConnectionPolicy(device); 426 } 427 428 /* The following APIs regarding test app for compliance */ 429 @Override getProtocolMode(BluetoothDevice device, AttributionSource source)430 public boolean getProtocolMode(BluetoothDevice device, AttributionSource source) { 431 Attributable.setAttributionSource(device, source); 432 HidHostService service = getService(source); 433 if (service == null) { 434 return false; 435 } 436 return service.getProtocolMode(device); 437 } 438 439 @Override virtualUnplug(BluetoothDevice device, AttributionSource source)440 public boolean virtualUnplug(BluetoothDevice device, AttributionSource source) { 441 Attributable.setAttributionSource(device, source); 442 HidHostService service = getService(source); 443 if (service == null) { 444 return false; 445 } 446 return service.virtualUnplug(device); 447 } 448 449 @Override setProtocolMode(BluetoothDevice device, int protocolMode, AttributionSource source)450 public boolean setProtocolMode(BluetoothDevice device, int protocolMode, 451 AttributionSource source) { 452 Attributable.setAttributionSource(device, source); 453 HidHostService service = getService(source); 454 if (service == null) { 455 return false; 456 } 457 return service.setProtocolMode(device, protocolMode); 458 } 459 460 @Override getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize, AttributionSource source)461 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, 462 int bufferSize, AttributionSource source) { 463 Attributable.setAttributionSource(device, source); 464 HidHostService service = getService(source); 465 if (service == null) { 466 return false; 467 } 468 return service.getReport(device, reportType, reportId, bufferSize); 469 } 470 471 @Override setReport(BluetoothDevice device, byte reportType, String report, AttributionSource source)472 public boolean setReport(BluetoothDevice device, byte reportType, String report, 473 AttributionSource source) { 474 Attributable.setAttributionSource(device, source); 475 HidHostService service = getService(source); 476 if (service == null) { 477 return false; 478 } 479 return service.setReport(device, reportType, report); 480 } 481 482 @Override sendData(BluetoothDevice device, String report, AttributionSource source)483 public boolean sendData(BluetoothDevice device, String report, AttributionSource source) { 484 Attributable.setAttributionSource(device, source); 485 HidHostService service = getService(source); 486 if (service == null) { 487 return false; 488 } 489 return service.sendData(device, report); 490 } 491 492 @Override setIdleTime(BluetoothDevice device, byte idleTime, AttributionSource source)493 public boolean setIdleTime(BluetoothDevice device, byte idleTime, 494 AttributionSource source) { 495 Attributable.setAttributionSource(device, source); 496 HidHostService service = getService(source); 497 if (service == null) { 498 return false; 499 } 500 return service.setIdleTime(device, idleTime); 501 } 502 503 @Override getIdleTime(BluetoothDevice device, AttributionSource source)504 public boolean getIdleTime(BluetoothDevice device, AttributionSource source) { 505 Attributable.setAttributionSource(device, source); 506 HidHostService service = getService(source); 507 if (service == null) { 508 return false; 509 } 510 return service.getIdleTime(device); 511 } 512 } 513 514 ; 515 516 //APIs 517 518 /** 519 * Connects the hid host profile for the passed in device 520 * 521 * @param device is the device with which to connect the hid host profile 522 * @return true if connection request is passed down to mHandler. 523 */ connect(BluetoothDevice device)524 public boolean connect(BluetoothDevice device) { 525 if (DBG) Log.d(TAG, "connect: " + device.getAddress()); 526 if (getConnectionState(device) != BluetoothHidHost.STATE_DISCONNECTED) { 527 Log.e(TAG, "Hid Device not disconnected: " + device); 528 return false; 529 } 530 if (getConnectionPolicy(device) == BluetoothHidHost.CONNECTION_POLICY_FORBIDDEN) { 531 Log.e(TAG, "Hid Device CONNECTION_POLICY_FORBIDDEN: " + device); 532 return false; 533 } 534 535 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device); 536 mHandler.sendMessage(msg); 537 return true; 538 } 539 540 /** 541 * Disconnects the hid host profile from the passed in device 542 * 543 * @param device is the device with which to disconnect the hid host profile 544 * @return true 545 */ disconnect(BluetoothDevice device)546 public boolean disconnect(BluetoothDevice device) { 547 if (DBG) Log.d(TAG, "disconnect: " + device.getAddress()); 548 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT, device); 549 mHandler.sendMessage(msg); 550 return true; 551 } 552 553 /** 554 * Get the current connection state of the profile 555 * 556 * @param device is the remote bluetooth device 557 * @return {@link BluetoothProfile#STATE_DISCONNECTED} if this profile is disconnected, 558 * {@link BluetoothProfile#STATE_CONNECTING} if this profile is being connected, 559 * {@link BluetoothProfile#STATE_CONNECTED} if this profile is connected, or 560 * {@link BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected 561 */ getConnectionState(BluetoothDevice device)562 public int getConnectionState(BluetoothDevice device) { 563 if (DBG) Log.d(TAG, "getConnectionState: " + device.getAddress()); 564 if (mInputDevices.get(device) == null) { 565 return BluetoothHidHost.STATE_DISCONNECTED; 566 } 567 return mInputDevices.get(device); 568 } 569 getDevicesMatchingConnectionStates(int[] states)570 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 571 if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates()"); 572 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 573 574 for (BluetoothDevice device : mInputDevices.keySet()) { 575 int inputDeviceState = getConnectionState(device); 576 for (int state : states) { 577 if (state == inputDeviceState) { 578 inputDevices.add(device); 579 break; 580 } 581 } 582 } 583 return inputDevices; 584 } 585 586 /** 587 * Set connection policy of the profile and connects it if connectionPolicy is 588 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} or disconnects if connectionPolicy is 589 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} 590 * 591 * <p> The device should already be paired. 592 * Connection policy can be one of: 593 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 594 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 595 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 596 * 597 * @param device Paired bluetooth device 598 * @param connectionPolicy is the connection policy to set to for this profile 599 * @return true if connectionPolicy is set, false on error 600 */ setConnectionPolicy(BluetoothDevice device, int connectionPolicy)601 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 602 if (DBG) { 603 Log.d(TAG, "setConnectionPolicy: " + device.getAddress()); 604 } 605 606 if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.HID_HOST, 607 connectionPolicy)) { 608 return false; 609 } 610 if (DBG) { 611 Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); 612 } 613 if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) { 614 connect(device); 615 } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { 616 disconnect(device); 617 } 618 return true; 619 } 620 621 /** 622 * Get the connection policy of the profile. 623 * 624 * <p> The connection policy can be any of: 625 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 626 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 627 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 628 * 629 * @param device Bluetooth device 630 * @return connection policy of the device 631 * @hide 632 */ getConnectionPolicy(BluetoothDevice device)633 public int getConnectionPolicy(BluetoothDevice device) { 634 if (DBG) { 635 Log.d(TAG, "getConnectionPolicy: " + device.getAddress()); 636 } 637 return mDatabaseManager 638 .getProfileConnectionPolicy(device, BluetoothProfile.HID_HOST); 639 } 640 641 /* The following APIs regarding test app for compliance */ getProtocolMode(BluetoothDevice device)642 boolean getProtocolMode(BluetoothDevice device) { 643 if (DBG) { 644 Log.d(TAG, "getProtocolMode: " + device.getAddress()); 645 } 646 int state = this.getConnectionState(device); 647 if (state != BluetoothHidHost.STATE_CONNECTED) { 648 return false; 649 } 650 Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE, device); 651 mHandler.sendMessage(msg); 652 return true; 653 } 654 virtualUnplug(BluetoothDevice device)655 boolean virtualUnplug(BluetoothDevice device) { 656 if (DBG) { 657 Log.d(TAG, "virtualUnplug: " + device.getAddress()); 658 } 659 int state = this.getConnectionState(device); 660 if (state != BluetoothHidHost.STATE_CONNECTED) { 661 return false; 662 } 663 Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG, device); 664 mHandler.sendMessage(msg); 665 return true; 666 } 667 setProtocolMode(BluetoothDevice device, int protocolMode)668 boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 669 if (DBG) { 670 Log.d(TAG, "setProtocolMode: " + device.getAddress()); 671 } 672 int state = this.getConnectionState(device); 673 if (state != BluetoothHidHost.STATE_CONNECTED) { 674 return false; 675 } 676 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE); 677 msg.obj = device; 678 msg.arg1 = protocolMode; 679 mHandler.sendMessage(msg); 680 return true; 681 } 682 getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize)683 boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { 684 if (DBG) { 685 Log.d(TAG, "getReport: " + device.getAddress()); 686 } 687 int state = this.getConnectionState(device); 688 if (state != BluetoothHidHost.STATE_CONNECTED) { 689 return false; 690 } 691 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 692 msg.obj = device; 693 Bundle data = new Bundle(); 694 data.putByte(BluetoothHidHost.EXTRA_REPORT_TYPE, reportType); 695 data.putByte(BluetoothHidHost.EXTRA_REPORT_ID, reportId); 696 data.putInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, bufferSize); 697 msg.setData(data); 698 mHandler.sendMessage(msg); 699 return true; 700 } 701 setReport(BluetoothDevice device, byte reportType, String report)702 boolean setReport(BluetoothDevice device, byte reportType, String report) { 703 if (DBG) { 704 Log.d(TAG, "setReport: " + device.getAddress()); 705 } 706 int state = this.getConnectionState(device); 707 if (state != BluetoothHidHost.STATE_CONNECTED) { 708 return false; 709 } 710 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 711 msg.obj = device; 712 Bundle data = new Bundle(); 713 data.putByte(BluetoothHidHost.EXTRA_REPORT_TYPE, reportType); 714 data.putString(BluetoothHidHost.EXTRA_REPORT, report); 715 msg.setData(data); 716 mHandler.sendMessage(msg); 717 return true; 718 719 } 720 sendData(BluetoothDevice device, String report)721 boolean sendData(BluetoothDevice device, String report) { 722 if (DBG) { 723 Log.d(TAG, "sendData: " + device.getAddress()); 724 } 725 int state = this.getConnectionState(device); 726 if (state != BluetoothHidHost.STATE_CONNECTED) { 727 return false; 728 } 729 730 return sendDataNative(Utils.getByteAddress(device), report); 731 } 732 getIdleTime(BluetoothDevice device)733 boolean getIdleTime(BluetoothDevice device) { 734 if (DBG) Log.d(TAG, "getIdleTime: " + device.getAddress()); 735 int state = this.getConnectionState(device); 736 if (state != BluetoothHidHost.STATE_CONNECTED) { 737 return false; 738 } 739 Message msg = mHandler.obtainMessage(MESSAGE_GET_IDLE_TIME, device); 740 mHandler.sendMessage(msg); 741 return true; 742 } 743 setIdleTime(BluetoothDevice device, byte idleTime)744 boolean setIdleTime(BluetoothDevice device, byte idleTime) { 745 if (DBG) Log.d(TAG, "setIdleTime: " + device.getAddress()); 746 int state = this.getConnectionState(device); 747 if (state != BluetoothHidHost.STATE_CONNECTED) { 748 return false; 749 } 750 Message msg = mHandler.obtainMessage(MESSAGE_SET_IDLE_TIME); 751 msg.obj = device; 752 Bundle data = new Bundle(); 753 data.putByte(BluetoothHidHost.EXTRA_IDLE_TIME, idleTime); 754 msg.setData(data); 755 mHandler.sendMessage(msg); 756 return true; 757 } 758 onGetProtocolMode(byte[] address, int mode)759 private void onGetProtocolMode(byte[] address, int mode) { 760 if (DBG) Log.d(TAG, "onGetProtocolMode()"); 761 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE); 762 msg.obj = address; 763 msg.arg1 = mode; 764 mHandler.sendMessage(msg); 765 } 766 onGetIdleTime(byte[] address, int idleTime)767 private void onGetIdleTime(byte[] address, int idleTime) { 768 if (DBG) Log.d(TAG, "onGetIdleTime()"); 769 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_IDLE_TIME); 770 msg.obj = address; 771 msg.arg1 = idleTime; 772 mHandler.sendMessage(msg); 773 } 774 onGetReport(byte[] address, byte[] report, int rptSize)775 private void onGetReport(byte[] address, byte[] report, int rptSize) { 776 if (DBG) Log.d(TAG, "onGetReport()"); 777 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT); 778 msg.obj = address; 779 Bundle data = new Bundle(); 780 data.putByteArray(BluetoothHidHost.EXTRA_REPORT, report); 781 data.putInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, rptSize); 782 msg.setData(data); 783 mHandler.sendMessage(msg); 784 } 785 onHandshake(byte[] address, int status)786 private void onHandshake(byte[] address, int status) { 787 if (DBG) Log.d(TAG, "onHandshake: status=" + status); 788 Message msg = mHandler.obtainMessage(MESSAGE_ON_HANDSHAKE); 789 msg.obj = address; 790 msg.arg1 = status; 791 mHandler.sendMessage(msg); 792 } 793 onVirtualUnplug(byte[] address, int status)794 private void onVirtualUnplug(byte[] address, int status) { 795 if (DBG) Log.d(TAG, "onVirtualUnplug: status=" + status); 796 Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG); 797 msg.obj = address; 798 msg.arg1 = status; 799 mHandler.sendMessage(msg); 800 } 801 onConnectStateChanged(byte[] address, int state)802 private void onConnectStateChanged(byte[] address, int state) { 803 if (DBG) Log.d(TAG, "onConnectStateChanged: state=" + state); 804 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 805 msg.obj = address; 806 msg.arg1 = state; 807 mHandler.sendMessage(msg); 808 } 809 810 // This method does not check for error conditon (newState == prevState) broadcastConnectionState(BluetoothDevice device, int newState)811 private void broadcastConnectionState(BluetoothDevice device, int newState) { 812 Integer prevStateInteger = mInputDevices.get(device); 813 int prevState = (prevStateInteger == null) ? BluetoothHidHost.STATE_DISCONNECTED 814 : prevStateInteger; 815 if (prevState == newState) { 816 Log.w(TAG, "no state change: " + newState); 817 return; 818 } 819 if (newState == BluetoothProfile.STATE_CONNECTED) { 820 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HID_HOST); 821 } 822 mInputDevices.put(device, newState); 823 824 /* Notifying the connection state change of the profile before sending the intent for 825 connection state change, as it was causing a race condition, with the UI not being 826 updated with the correct connection state. */ 827 Log.d(TAG, "Connection state " + device + ": " + prevState + "->" + newState); 828 Intent intent = new Intent(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED); 829 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 830 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 831 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 832 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 833 sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT, 834 Utils.getTempAllowlistBroadcastOptions()); 835 } 836 broadcastHandshake(BluetoothDevice device, int status)837 private void broadcastHandshake(BluetoothDevice device, int status) { 838 Intent intent = new Intent(BluetoothHidHost.ACTION_HANDSHAKE); 839 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 840 intent.putExtra(BluetoothHidHost.EXTRA_STATUS, status); 841 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 842 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 843 } 844 broadcastProtocolMode(BluetoothDevice device, int protocolMode)845 private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) { 846 Intent intent = new Intent(BluetoothHidHost.ACTION_PROTOCOL_MODE_CHANGED); 847 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 848 intent.putExtra(BluetoothHidHost.EXTRA_PROTOCOL_MODE, protocolMode); 849 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 850 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 851 if (DBG) { 852 Log.d(TAG, "Protocol Mode (" + device + "): " + protocolMode); 853 } 854 } 855 broadcastReport(BluetoothDevice device, byte[] report, int rptSize)856 private void broadcastReport(BluetoothDevice device, byte[] report, int rptSize) { 857 Intent intent = new Intent(BluetoothHidHost.ACTION_REPORT); 858 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 859 intent.putExtra(BluetoothHidHost.EXTRA_REPORT, report); 860 intent.putExtra(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, rptSize); 861 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 862 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 863 } 864 broadcastVirtualUnplugStatus(BluetoothDevice device, int status)865 private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) { 866 Intent intent = new Intent(BluetoothHidHost.ACTION_VIRTUAL_UNPLUG_STATUS); 867 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 868 intent.putExtra(BluetoothHidHost.EXTRA_VIRTUAL_UNPLUG_STATUS, status); 869 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 870 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 871 } 872 broadcastIdleTime(BluetoothDevice device, int idleTime)873 private void broadcastIdleTime(BluetoothDevice device, int idleTime) { 874 Intent intent = new Intent(BluetoothHidHost.ACTION_IDLE_TIME_CHANGED); 875 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 876 intent.putExtra(BluetoothHidHost.EXTRA_IDLE_TIME, idleTime); 877 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 878 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 879 if (DBG) { 880 Log.d(TAG, "Idle time (" + device + "): " + idleTime); 881 } 882 } 883 884 /** 885 * Check whether can connect to a peer device. 886 * The check considers a number of factors during the evaluation. 887 * 888 * @param device the peer device to connect to 889 * @return true if connection is allowed, otherwise false 890 */ 891 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) okToConnect(BluetoothDevice device)892 public boolean okToConnect(BluetoothDevice device) { 893 AdapterService adapterService = AdapterService.getAdapterService(); 894 // Check if adapter service is null. 895 if (adapterService == null) { 896 Log.w(TAG, "okToConnect: adapter service is null"); 897 return false; 898 } 899 // Check if this is an incoming connection in Quiet mode. 900 if (adapterService.isQuietModeEnabled() && mTargetDevice == null) { 901 Log.w(TAG, "okToConnect: return false as quiet mode enabled"); 902 return false; 903 } 904 // Check connection policy and accept or reject the connection. 905 int connectionPolicy = getConnectionPolicy(device); 906 int bondState = adapterService.getBondState(device); 907 // Allow this connection only if the device is bonded. Any attempt to connect while 908 // bonding would potentially lead to an unauthorized connection. 909 if (bondState != BluetoothDevice.BOND_BONDED) { 910 Log.w(TAG, "okToConnect: return false, bondState=" + bondState); 911 return false; 912 } else if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_UNKNOWN 913 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { 914 // Otherwise, reject the connection if connectionPolicy is not valid. 915 Log.w(TAG, "okToConnect: return false, connectionPolicy=" + connectionPolicy); 916 return false; 917 } 918 return true; 919 } 920 convertHalState(int halState)921 private static int convertHalState(int halState) { 922 switch (halState) { 923 case CONN_STATE_CONNECTED: 924 return BluetoothProfile.STATE_CONNECTED; 925 case CONN_STATE_CONNECTING: 926 return BluetoothProfile.STATE_CONNECTING; 927 case CONN_STATE_DISCONNECTED: 928 return BluetoothProfile.STATE_DISCONNECTED; 929 case CONN_STATE_DISCONNECTING: 930 return BluetoothProfile.STATE_DISCONNECTING; 931 default: 932 Log.e(TAG, "bad hid connection state: " + halState); 933 return BluetoothProfile.STATE_DISCONNECTED; 934 } 935 } 936 937 @Override dump(StringBuilder sb)938 public void dump(StringBuilder sb) { 939 super.dump(sb); 940 println(sb, "mTargetDevice: " + mTargetDevice); 941 println(sb, "mInputDevices:"); 942 for (BluetoothDevice device : mInputDevices.keySet()) { 943 println(sb, " " + device + " : " + mInputDevices.get(device)); 944 } 945 } 946 947 // Constants matching Hal header file bt_hh.h 948 // bthh_connection_state_t 949 private static final int CONN_STATE_CONNECTED = 0; 950 private static final int CONN_STATE_CONNECTING = 1; 951 private static final int CONN_STATE_DISCONNECTED = 2; 952 private static final int CONN_STATE_DISCONNECTING = 3; 953 classInitNative()954 private static native void classInitNative(); 955 initializeNative()956 private native void initializeNative(); 957 cleanupNative()958 private native void cleanupNative(); 959 connectHidNative(byte[] btAddress)960 private native boolean connectHidNative(byte[] btAddress); 961 disconnectHidNative(byte[] btAddress)962 private native boolean disconnectHidNative(byte[] btAddress); 963 getProtocolModeNative(byte[] btAddress)964 private native boolean getProtocolModeNative(byte[] btAddress); 965 virtualUnPlugNative(byte[] btAddress)966 private native boolean virtualUnPlugNative(byte[] btAddress); 967 setProtocolModeNative(byte[] btAddress, byte protocolMode)968 private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode); 969 getReportNative(byte[] btAddress, byte reportType, byte reportId, int bufferSize)970 private native boolean getReportNative(byte[] btAddress, byte reportType, byte reportId, 971 int bufferSize); 972 setReportNative(byte[] btAddress, byte reportType, String report)973 private native boolean setReportNative(byte[] btAddress, byte reportType, String report); 974 sendDataNative(byte[] btAddress, String report)975 private native boolean sendDataNative(byte[] btAddress, String report); 976 setIdleTimeNative(byte[] btAddress, byte idleTime)977 private native boolean setIdleTimeNative(byte[] btAddress, byte idleTime); 978 getIdleTimeNative(byte[] btAddress)979 private native boolean getIdleTimeNative(byte[] btAddress); 980 } 981