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