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.btservice; 18 19 import static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 21 22 import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__BOND_RETRY; 23 import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__FAIL; 24 25 import static java.util.Objects.requireNonNull; 26 27 import android.app.Activity; 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.BluetoothClass; 30 import android.bluetooth.BluetoothDevice; 31 import android.bluetooth.BluetoothProtoEnums; 32 import android.bluetooth.OobData; 33 import android.content.Intent; 34 import android.os.Build; 35 import android.os.Bundle; 36 import android.os.Message; 37 import android.os.UserHandle; 38 import android.util.Log; 39 40 import com.android.bluetooth.BluetoothStatsLog; 41 import com.android.bluetooth.Utils; 42 import com.android.bluetooth.a2dp.A2dpService; 43 import com.android.bluetooth.a2dpsink.A2dpSinkService; 44 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 45 import com.android.bluetooth.csip.CsipSetCoordinatorService; 46 import com.android.bluetooth.hap.HapClientService; 47 import com.android.bluetooth.hfp.HeadsetService; 48 import com.android.bluetooth.hfpclient.HeadsetClientService; 49 import com.android.bluetooth.hid.HidHostService; 50 import com.android.bluetooth.le_audio.LeAudioService; 51 import com.android.bluetooth.pbapclient.PbapClientService; 52 import com.android.bluetooth.vc.VolumeControlService; 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.State; 55 import com.android.internal.util.StateMachine; 56 57 import java.util.ArrayList; 58 import java.util.HashSet; 59 import java.util.Optional; 60 import java.util.Set; 61 62 /** 63 * This state machine handles Bluetooth Adapter State. States: {@link StableState} : No device is in 64 * bonding / unbonding state. {@link PendingCommandState} : Some device is in bonding / unbonding 65 * state. TODO(BT) This class can be removed and this logic moved to the stack. 66 */ 67 final class BondStateMachine extends StateMachine { 68 private static final String TAG = 69 Utils.TAG_PREFIX_BLUETOOTH + BondStateMachine.class.getSimpleName(); 70 71 static final int CREATE_BOND = 1; 72 static final int CANCEL_BOND = 2; 73 static final int REMOVE_BOND = 3; 74 static final int BONDING_STATE_CHANGE = 4; 75 static final int SSP_REQUEST = 5; 76 static final int PIN_REQUEST = 6; 77 static final int UUID_UPDATE = 10; 78 static final int BONDED_INTENT_DELAY = 11; 79 static final int BOND_STATE_NONE = 0; 80 static final int BOND_STATE_BONDING = 1; 81 static final int BOND_STATE_BONDED = 2; 82 83 static int sPendingUuidUpdateTimeoutMillis = 3000; // 3s 84 85 private AdapterService mAdapterService; 86 private AdapterProperties mAdapterProperties; 87 private RemoteDevices mRemoteDevices; 88 private final BluetoothAdapter mAdapter; 89 90 private final PendingCommandState mPendingCommandState = new PendingCommandState(); 91 private final StableState mStableState = new StableState(); 92 93 public static final String OOBDATAP192 = "oobdatap192"; 94 public static final String OOBDATAP256 = "oobdatap256"; 95 public static final String DISPLAY_PASSKEY = "display_passkey"; 96 public static final String DELAY_RETRY_COUNT = "delay_retry_count"; 97 public static final short DELAY_MAX_RETRIES = 30; 98 public static final int BOND_RETRY_DELAY_MS = 500; 99 100 @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>(); 101 BondStateMachine( AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)102 private BondStateMachine( 103 AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices) { 104 super("BondStateMachine:"); 105 addState(mStableState); 106 addState(mPendingCommandState); 107 mRemoteDevices = remoteDevices; 108 mAdapterService = service; 109 mAdapterProperties = prop; 110 mAdapter = BluetoothAdapter.getDefaultAdapter(); 111 setInitialState(mStableState); 112 } 113 make( AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)114 public static BondStateMachine make( 115 AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices) { 116 Log.d(TAG, "make"); 117 BondStateMachine bsm = new BondStateMachine(service, prop, remoteDevices); 118 bsm.start(); 119 return bsm; 120 } 121 doQuit()122 public synchronized void doQuit() { 123 quitNow(); 124 } 125 cleanup()126 private void cleanup() { 127 mAdapterService = null; 128 mRemoteDevices = null; 129 mAdapterProperties = null; 130 } 131 132 @Override onQuitting()133 protected void onQuitting() { 134 cleanup(); 135 } 136 137 private class StableState extends State { 138 @Override enter()139 public void enter() { 140 infoLog("StableState(): Entering Off State"); 141 } 142 143 @Override processMessage(Message msg)144 public synchronized boolean processMessage(Message msg) { 145 146 BluetoothDevice dev = (BluetoothDevice) msg.obj; 147 148 switch (msg.what) { 149 case CREATE_BOND: 150 /* BOND_BONDED event is send after keys are exchanged, but BTIF layer would 151 still use bonding control blocks until service discovery is finished. If 152 next pairing is started while previous still makes service discovery, it 153 would fail. Check the busy status of BTIF instead, and wait with starting 154 the bond. */ 155 if (mAdapterService.getNative().pairingIsBusy()) { 156 short retry_no = 157 (msg.getData() != null) 158 ? msg.getData().getShort(DELAY_RETRY_COUNT) 159 : 0; 160 Log.d( 161 TAG, 162 "Delay CREATE_BOND because native is busy - attempt no " 163 + retry_no); 164 165 if (retry_no < DELAY_MAX_RETRIES) { 166 retry_no++; 167 168 Message new_msg = obtainMessage(); 169 new_msg.copyFrom(msg); 170 171 if (new_msg.getData() == null) { 172 Bundle bundle = new Bundle(); 173 new_msg.setData(bundle); 174 } 175 new_msg.getData().putShort(DELAY_RETRY_COUNT, retry_no); 176 177 sendMessageDelayed(new_msg, BOND_RETRY_DELAY_MS); 178 return true; 179 } else { 180 MetricsLogger.getInstance() 181 .logBluetoothEvent( 182 dev, 183 BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__BOND_RETRY, 184 BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__FAIL, 185 0); 186 Log.w(TAG, "Native was busy - the bond will most likely fail!"); 187 } 188 } 189 190 OobData p192Data = 191 (msg.getData() != null) 192 ? msg.getData().getParcelable(OOBDATAP192) 193 : null; 194 OobData p256Data = 195 (msg.getData() != null) 196 ? msg.getData().getParcelable(OOBDATAP256) 197 : null; 198 createBond(dev, msg.arg1, p192Data, p256Data, true); 199 break; 200 case REMOVE_BOND: 201 removeBond(dev, true); 202 break; 203 case BONDING_STATE_CHANGE: 204 int newState = msg.arg1; 205 /* if incoming pairing, transition to pending state */ 206 if (newState == BluetoothDevice.BOND_BONDING) { 207 deferMessage(msg); 208 transitionTo(mPendingCommandState); 209 } else if (newState == BluetoothDevice.BOND_NONE) { 210 /* if the link key was deleted by the stack */ 211 sendIntent(dev, newState, 0, false); 212 } else { 213 Log.e( 214 TAG, 215 "In stable state, received invalid newState: " 216 + bondStateToString(newState)); 217 } 218 break; 219 case BONDED_INTENT_DELAY: 220 if (mPendingBondedDevices.contains(dev)) { 221 sendIntent(dev, BluetoothDevice.BOND_BONDED, 0, true); 222 } 223 break; 224 case UUID_UPDATE: 225 if (mPendingBondedDevices.contains(dev)) { 226 sendIntent(dev, BluetoothDevice.BOND_BONDED, 0, false); 227 } 228 break; 229 case CANCEL_BOND: 230 default: 231 Log.e(TAG, "Received unhandled state: " + msg.what); 232 return false; 233 } 234 return true; 235 } 236 } 237 238 private class PendingCommandState extends State { 239 private final ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>(); 240 241 @Override enter()242 public void enter() { 243 infoLog("Entering PendingCommandState State"); 244 } 245 246 @Override processMessage(Message msg)247 public synchronized boolean processMessage(Message msg) { 248 BluetoothDevice dev = (BluetoothDevice) msg.obj; 249 250 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 251 boolean result = false; 252 if ((mDevices.contains(dev) || mPendingBondedDevices.contains(dev)) 253 && msg.what != CANCEL_BOND 254 && msg.what != BONDING_STATE_CHANGE 255 && msg.what != SSP_REQUEST 256 && msg.what != PIN_REQUEST) { 257 deferMessage(msg); 258 return true; 259 } 260 261 switch (msg.what) { 262 case CREATE_BOND: 263 OobData p192Data = 264 (msg.getData() != null) 265 ? msg.getData().getParcelable(OOBDATAP192) 266 : null; 267 OobData p256Data = 268 (msg.getData() != null) 269 ? msg.getData().getParcelable(OOBDATAP256) 270 : null; 271 result = createBond(dev, msg.arg1, p192Data, p256Data, false); 272 break; 273 case REMOVE_BOND: 274 result = removeBond(dev, false); 275 break; 276 case CANCEL_BOND: 277 result = cancelBond(dev); 278 break; 279 case BONDING_STATE_CHANGE: 280 int newState = msg.arg1; 281 int reason = getUnbondReasonFromHALCode(msg.arg2); 282 // Bond is explicitly removed if we are in pending command state 283 if (newState == BluetoothDevice.BOND_NONE 284 && reason == BluetoothDevice.BOND_SUCCESS) { 285 reason = BluetoothDevice.UNBOND_REASON_REMOVED; 286 } 287 sendIntent(dev, newState, reason, false); 288 if (newState != BluetoothDevice.BOND_BONDING) { 289 // This is either none/bonded, remove and transition, and also set 290 // result=false to avoid adding the device to mDevices. 291 mDevices.remove(dev); 292 result = false; 293 if (mDevices.isEmpty()) { 294 transitionTo(mStableState); 295 } 296 if (newState == BluetoothDevice.BOND_NONE) { 297 mAdapterService.setPhonebookAccessPermission( 298 dev, BluetoothDevice.ACCESS_UNKNOWN); 299 mAdapterService.setMessageAccessPermission( 300 dev, BluetoothDevice.ACCESS_UNKNOWN); 301 mAdapterService.setSimAccessPermission( 302 dev, BluetoothDevice.ACCESS_UNKNOWN); 303 // Set the profile Priorities to undefined 304 clearProfilePriority(dev); 305 } 306 } else if (!mDevices.contains(dev)) { 307 result = true; 308 } 309 break; 310 case SSP_REQUEST: 311 if (devProp == null) { 312 errorLog("devProp is null, maybe the device is disconnected"); 313 break; 314 } 315 316 int passkey = msg.arg1; 317 int variant = msg.arg2; 318 boolean displayPasskey = 319 (msg.getData() != null) 320 ? msg.getData().getByte(DISPLAY_PASSKEY) == 1 /* 1 == true */ 321 : false; 322 sendDisplayPinIntent( 323 devProp.getAddress(), 324 displayPasskey ? Optional.of(passkey) : Optional.empty(), 325 variant); 326 break; 327 case PIN_REQUEST: 328 if (devProp == null) { 329 errorLog("devProp is null, maybe the device is disconnected"); 330 break; 331 } 332 333 int btDeviceClass = 334 new BluetoothClass(mRemoteDevices.getBluetoothClass(dev)) 335 .getDeviceClass(); 336 if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD 337 || btDeviceClass 338 == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { 339 // Its a keyboard. Follow the HID spec recommendation of creating the 340 // passkey and displaying it to the user. If the keyboard doesn't follow 341 // the spec recommendation, check if the keyboard has a fixed PIN zero 342 // and pair. 343 // TODO: Maintain list of devices that have fixed pin 344 // Generate a variable 6-digit PIN in range of 100000-999999 345 // This is not truly random but good enough. 346 int pin = 100000 + (int) Math.floor((Math.random() * (999999 - 100000))); 347 sendDisplayPinIntent( 348 devProp.getAddress(), 349 Optional.of(pin), 350 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); 351 break; 352 } 353 354 if (msg.arg2 == 1) { // Minimum 16 digit pin required here 355 sendDisplayPinIntent( 356 devProp.getAddress(), 357 Optional.empty(), 358 BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS); 359 } else { 360 // In PIN_REQUEST, there is no passkey to display.So do not send the 361 // EXTRA_PAIRING_KEY type in the intent 362 sendDisplayPinIntent( 363 devProp.getAddress(), 364 Optional.empty(), 365 BluetoothDevice.PAIRING_VARIANT_PIN); 366 } 367 break; 368 default: 369 Log.e(TAG, "Received unhandled event:" + msg.what); 370 return false; 371 } 372 if (result) { 373 mDevices.add(dev); 374 } 375 return true; 376 } 377 } 378 cancelBond(BluetoothDevice dev)379 private boolean cancelBond(BluetoothDevice dev) { 380 if (mRemoteDevices.getBondState(dev) == BluetoothDevice.BOND_BONDING) { 381 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 382 if (!mAdapterService.getNative().cancelBond(addr)) { 383 Log.e(TAG, "Unexpected error while cancelling bond:"); 384 } else { 385 return true; 386 } 387 } 388 return false; 389 } 390 removeBond(BluetoothDevice dev, boolean transition)391 private boolean removeBond(BluetoothDevice dev, boolean transition) { 392 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 393 if (devProp != null && devProp.getBondState() == BluetoothDevice.BOND_BONDED) { 394 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 395 if (!mAdapterService.getNative().removeBond(addr)) { 396 Log.e(TAG, "Unexpected error while removing bond:"); 397 } else { 398 if (transition) { 399 transitionTo(mPendingCommandState); 400 } 401 return true; 402 } 403 } 404 405 Log.w( 406 TAG, 407 dev 408 + " cannot be removed since " 409 + ((devProp == null) 410 ? "properties are empty" 411 : "bond state is " + devProp.getBondState())); 412 return false; 413 } 414 createBond( BluetoothDevice dev, int transport, OobData remoteP192Data, OobData remoteP256Data, boolean transition)415 private boolean createBond( 416 BluetoothDevice dev, 417 int transport, 418 OobData remoteP192Data, 419 OobData remoteP256Data, 420 boolean transition) { 421 if (mRemoteDevices.getBondState(dev) == BluetoothDevice.BOND_NONE) { 422 infoLog("Bond address is:" + dev + ", transport is: " + transport); 423 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 424 int addrType = dev.getAddressType(); 425 boolean result; 426 // If we have some data 427 if (remoteP192Data != null || remoteP256Data != null) { 428 BluetoothStatsLog.write( 429 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 430 mAdapterService.obfuscateAddress(dev), 431 transport, 432 mRemoteDevices.getType(dev), 433 BluetoothDevice.BOND_BONDING, 434 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_START_PAIRING_OOB, 435 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN, 436 mAdapterService.getMetricId(dev)); 437 result = 438 mAdapterService 439 .getNative() 440 .createBondOutOfBand( 441 addr, transport, remoteP192Data, remoteP256Data); 442 } else { 443 BluetoothStatsLog.write( 444 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 445 mAdapterService.obfuscateAddress(dev), 446 transport, 447 mRemoteDevices.getType(dev), 448 BluetoothDevice.BOND_BONDING, 449 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_START_PAIRING, 450 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN, 451 mAdapterService.getMetricId(dev)); 452 result = mAdapterService.getNative().createBond(addr, addrType, transport); 453 } 454 BluetoothStatsLog.write( 455 BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED, 456 mAdapterService.getMetricId(dev), 457 mRemoteDevices.getName(dev)); 458 BluetoothStatsLog.write( 459 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 460 mAdapterService.obfuscateAddress(dev), 461 transport, 462 mRemoteDevices.getType(dev), 463 BluetoothDevice.BOND_BONDING, 464 remoteP192Data == null && remoteP256Data == null 465 ? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN 466 : BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED, 467 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN); 468 469 if (!result) { 470 BluetoothStatsLog.write( 471 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 472 mAdapterService.obfuscateAddress(dev), 473 transport, 474 mRemoteDevices.getType(dev), 475 BluetoothDevice.BOND_NONE, 476 BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN, 477 BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS); 478 // Using UNBOND_REASON_REMOVED for legacy reason 479 sendIntent( 480 dev, 481 BluetoothDevice.BOND_NONE, 482 BluetoothDevice.UNBOND_REASON_REMOVED, 483 false); 484 return false; 485 } else if (transition) { 486 transitionTo(mPendingCommandState); 487 } 488 return true; 489 } 490 return false; 491 } 492 sendDisplayPinIntent(byte[] address, Optional<Integer> maybePin, int variant)493 private void sendDisplayPinIntent(byte[] address, Optional<Integer> maybePin, int variant) { 494 BluetoothDevice device = mRemoteDevices.getDevice(address); 495 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 496 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 497 maybePin.ifPresent(pin -> intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin)); 498 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 499 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 500 // Workaround for Android Auto until pre-accepting pairing requests is added. 501 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 502 Log.i(TAG, "sendDisplayPinIntent: device=" + device + ", variant=" + variant); 503 mAdapterService.sendOrderedBroadcast( 504 intent, 505 BLUETOOTH_CONNECT, 506 Utils.getTempBroadcastOptions().toBundle(), 507 null /* resultReceiver */, 508 null /* scheduler */, 509 Activity.RESULT_OK /* initialCode */, 510 null /* initialData */, 511 null /* initialExtras */); 512 } 513 514 @VisibleForTesting sendIntent( BluetoothDevice device, int newState, int reason, boolean isTriggerFromDelayMessage)515 void sendIntent( 516 BluetoothDevice device, int newState, int reason, boolean isTriggerFromDelayMessage) { 517 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); 518 int oldState = BluetoothDevice.BOND_NONE; 519 if (newState != BluetoothDevice.BOND_NONE 520 && newState != BluetoothDevice.BOND_BONDING 521 && newState != BluetoothDevice.BOND_BONDED) { 522 infoLog("Invalid bond state " + newState); 523 return; 524 } 525 526 mRemoteDevices.onBondStateChange(device, newState); 527 528 if (devProp != null) { 529 oldState = devProp.getBondState(); 530 } 531 if (isTriggerFromDelayMessage 532 && (oldState != BluetoothDevice.BOND_BONDED 533 || newState != BluetoothDevice.BOND_BONDED 534 || !mPendingBondedDevices.contains(device))) { 535 infoLog( 536 "Invalid state when doing delay send bonded intent, oldState: " 537 + oldState 538 + ", newState: " 539 + newState 540 + ", in PendingBondedDevices list? " 541 + mPendingBondedDevices.contains(device)); 542 return; 543 } 544 if (mPendingBondedDevices.contains(device)) { 545 mPendingBondedDevices.remove(device); 546 if (oldState == BluetoothDevice.BOND_BONDED) { 547 if (newState == BluetoothDevice.BOND_BONDING) { 548 mAdapterProperties.onBondStateChanged(device, newState); 549 } 550 oldState = BluetoothDevice.BOND_BONDING; 551 } else { 552 // Should not enter here. 553 throw new IllegalArgumentException("Invalid old state " + oldState); 554 } 555 } 556 if (oldState == newState) { 557 return; 558 } 559 MetricsLogger.getInstance().logBondStateMachineEvent(device, newState); 560 BluetoothStatsLog.write( 561 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 562 mAdapterService.obfuscateAddress(device), 563 0, 564 mRemoteDevices.getType(device), 565 newState, 566 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_BOND_STATE_INTENT_SENT, 567 reason, 568 mAdapterService.getMetricId(device)); 569 int classOfDevice = mRemoteDevices.getBluetoothClass(device); 570 BluetoothStatsLog.write( 571 BluetoothStatsLog.BLUETOOTH_CLASS_OF_DEVICE_REPORTED, 572 mAdapterService.obfuscateAddress(device), 573 classOfDevice, 574 mAdapterService.getMetricId(device)); 575 mAdapterProperties.onBondStateChanged(device, newState); 576 577 if (!isTriggerFromDelayMessage 578 && newState == BluetoothDevice.BOND_BONDED 579 && devProp != null 580 && devProp.getUuids() == null) { 581 infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent"); 582 if (!mPendingBondedDevices.contains(device)) { 583 mPendingBondedDevices.add(device); 584 Message msg = obtainMessage(BONDED_INTENT_DELAY); 585 msg.obj = device; 586 sendMessageDelayed(msg, sPendingUuidUpdateTimeoutMillis); 587 } 588 if (oldState == BluetoothDevice.BOND_NONE) { 589 // Broadcast NONE->BONDING for NONE->BONDED case. 590 newState = BluetoothDevice.BOND_BONDING; 591 } else { 592 return; 593 } 594 } 595 596 mAdapterService.handleBondStateChanged(device, oldState, newState); 597 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 598 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 599 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); 600 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 601 if (newState == BluetoothDevice.BOND_NONE) { 602 intent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON, reason); 603 } 604 mAdapterService.onBondStateChanged(device, newState); 605 mAdapterService.sendBroadcastAsUser( 606 intent, 607 UserHandle.ALL, 608 BLUETOOTH_CONNECT, 609 Utils.getTempBroadcastOptions().toBundle()); 610 infoLog( 611 "Bond State Change Intent:" 612 + device 613 + " " 614 + bondStateToString(oldState) 615 + " => " 616 + bondStateToString(newState)); 617 } 618 bondStateChangeCallback(int status, byte[] address, int newState, int hciReason)619 void bondStateChangeCallback(int status, byte[] address, int newState, int hciReason) { 620 BluetoothDevice device = mRemoteDevices.getDevice(address); 621 622 if (device == null) { 623 infoLog("No record of the device:" + device); 624 // This device will be added as part of the BONDING_STATE_CHANGE intent processing 625 // in sendIntent above 626 device = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 627 } 628 629 infoLog( 630 "bondStateChangeCallback: Status: " 631 + status 632 + " Address: " 633 + device 634 + " newState: " 635 + newState 636 + " hciReason: " 637 + hciReason); 638 639 Message msg = obtainMessage(BONDING_STATE_CHANGE); 640 msg.obj = device; 641 642 if (newState == BOND_STATE_BONDED) { 643 msg.arg1 = BluetoothDevice.BOND_BONDED; 644 } else if (newState == BOND_STATE_BONDING) { 645 msg.arg1 = BluetoothDevice.BOND_BONDING; 646 } else { 647 msg.arg1 = BluetoothDevice.BOND_NONE; 648 } 649 msg.arg2 = status; 650 651 sendMessage(msg); 652 } 653 sspRequestCallback(byte[] address, int pairingVariant, int passkey)654 void sspRequestCallback(byte[] address, int pairingVariant, int passkey) { 655 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 656 if (bdDevice == null) { 657 mRemoteDevices.addDeviceProperties(address); 658 } 659 infoLog( 660 "sspRequestCallback: " 661 + Utils.getRedactedAddressStringFromByte(address) 662 + " pairingVariant " 663 + pairingVariant 664 + " passkey: " 665 + (Build.isDebuggable() ? passkey : "******")); 666 int variant; 667 boolean displayPasskey = false; 668 switch (pairingVariant) { 669 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION: 670 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 671 displayPasskey = true; 672 break; 673 674 case AbstractionLayer.BT_SSP_VARIANT_CONSENT: 675 variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; 676 break; 677 678 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY: 679 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 680 break; 681 682 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION: 683 variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; 684 displayPasskey = true; 685 break; 686 687 default: 688 errorLog("SSP Pairing variant not present"); 689 return; 690 } 691 BluetoothDevice device = mRemoteDevices.getDevice(address); 692 if (device == null) { 693 warnLog("Device is not known for:" + Utils.getRedactedAddressStringFromByte(address)); 694 mRemoteDevices.addDeviceProperties(address); 695 device = requireNonNull(mRemoteDevices.getDevice(address)); 696 } 697 698 BluetoothStatsLog.write( 699 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 700 mAdapterService.obfuscateAddress(device), 701 0, 702 mRemoteDevices.getType(device), 703 BluetoothDevice.BOND_BONDING, 704 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_SSP_REQUESTED, 705 0); 706 707 Message msg = obtainMessage(SSP_REQUEST); 708 msg.obj = device; 709 if (displayPasskey) { 710 msg.arg1 = passkey; 711 Bundle bundle = new Bundle(); 712 bundle.putByte(BondStateMachine.DISPLAY_PASSKEY, (byte) 1 /* true */); 713 msg.setData(bundle); 714 } 715 msg.arg2 = variant; 716 sendMessage(msg); 717 } 718 pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits)719 void pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits) { 720 // TODO(BT): Get wakelock and update name and cod 721 722 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 723 if (bdDevice == null) { 724 mRemoteDevices.addDeviceProperties(address); 725 bdDevice = requireNonNull(mRemoteDevices.getDevice(address)); 726 } 727 728 BluetoothStatsLog.write( 729 BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 730 mAdapterService.obfuscateAddress(bdDevice), 731 0, 732 mRemoteDevices.getType(bdDevice), 733 BluetoothDevice.BOND_BONDING, 734 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_PIN_REQUESTED, 735 0); 736 737 infoLog( 738 "pinRequestCallback: " 739 + bdDevice 740 + " name:" 741 + Utils.getName(bdDevice) 742 + " cod:" 743 + new BluetoothClass(cod)); 744 745 Message msg = obtainMessage(PIN_REQUEST); 746 msg.obj = bdDevice; 747 msg.arg2 = min16Digits ? 1 : 0; // Use arg2 to pass the min16Digit boolean 748 749 sendMessage(msg); 750 } 751 752 /* 753 * Check whether has the specific message in message queue 754 */ 755 @VisibleForTesting hasMessage(int what)756 public boolean hasMessage(int what) { 757 return hasMessages(what); 758 } 759 760 /* 761 * Remove the specific message from message queue 762 */ 763 @VisibleForTesting removeMessage(int what)764 public void removeMessage(int what) { 765 removeMessages(what); 766 } 767 clearProfilePriority(BluetoothDevice device)768 private static void clearProfilePriority(BluetoothDevice device) { 769 HidHostService hidService = HidHostService.getHidHostService(); 770 A2dpService a2dpService = A2dpService.getA2dpService(); 771 HeadsetService headsetService = HeadsetService.getHeadsetService(); 772 HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService(); 773 A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService(); 774 PbapClientService pbapClientService = PbapClientService.getPbapClientService(); 775 LeAudioService leAudioService = LeAudioService.getLeAudioService(); 776 CsipSetCoordinatorService csipSetCoordinatorService = 777 CsipSetCoordinatorService.getCsipSetCoordinatorService(); 778 VolumeControlService volumeControlService = VolumeControlService.getVolumeControlService(); 779 HapClientService hapClientService = HapClientService.getHapClientService(); 780 781 if (hidService != null) { 782 hidService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 783 } 784 if (a2dpService != null) { 785 a2dpService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 786 } 787 if (headsetService != null) { 788 headsetService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 789 } 790 if (headsetClientService != null) { 791 headsetClientService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 792 } 793 if (a2dpSinkService != null) { 794 a2dpSinkService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 795 } 796 if (pbapClientService != null) { 797 pbapClientService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 798 } 799 if (leAudioService != null) { 800 leAudioService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 801 } 802 if (csipSetCoordinatorService != null) { 803 csipSetCoordinatorService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 804 } 805 if (volumeControlService != null) { 806 volumeControlService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 807 } 808 if (hapClientService != null) { 809 hapClientService.setConnectionPolicy(device, CONNECTION_POLICY_UNKNOWN); 810 } 811 } 812 bondStateToString(int state)813 public static String bondStateToString(int state) { 814 if (state == BluetoothDevice.BOND_NONE) { 815 return "BOND_NONE"; 816 } else if (state == BluetoothDevice.BOND_BONDING) { 817 return "BOND_BONDING"; 818 } else if (state == BluetoothDevice.BOND_BONDED) { 819 return "BOND_BONDED"; 820 } else return "UNKNOWN(" + state + ")"; 821 } 822 infoLog(String msg)823 private static void infoLog(String msg) { 824 Log.i(TAG, msg); 825 } 826 errorLog(String msg)827 private static void errorLog(String msg) { 828 Log.e(TAG, msg); 829 } 830 warnLog(String msg)831 private static void warnLog(String msg) { 832 Log.w(TAG, msg); 833 } 834 getUnbondReasonFromHALCode(int reason)835 private static int getUnbondReasonFromHALCode(int reason) { 836 if (reason == AbstractionLayer.BT_STATUS_SUCCESS) { 837 return BluetoothDevice.BOND_SUCCESS; 838 } else if (reason == AbstractionLayer.BT_STATUS_RMT_DEV_DOWN) { 839 return BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN; 840 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_FAILURE) { 841 return BluetoothDevice.UNBOND_REASON_AUTH_FAILED; 842 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_REJECTED) { 843 return BluetoothDevice.UNBOND_REASON_AUTH_REJECTED; 844 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_TIMEOUT) { 845 return BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT; 846 } 847 848 /* default */ 849 return BluetoothDevice.UNBOND_REASON_REMOVED; 850 } 851 } 852