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.hfp.HeadsetService; 42 import com.android.bluetooth.hfpclient.HeadsetClientService; 43 import com.android.bluetooth.hid.HidHostService; 44 import com.android.bluetooth.pbapclient.PbapClientService; 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.util.State; 47 import com.android.internal.util.StateMachine; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.HashSet; 52 import java.util.Objects; 53 import java.util.Optional; 54 import java.util.Set; 55 56 /** 57 * This state machine handles Bluetooth Adapter State. 58 * States: 59 * {@link StableState} : No device is in bonding / unbonding state. 60 * {@link PendingCommandState} : Some device is in bonding / unbonding state. 61 * TODO(BT) This class can be removed and this logic moved to the stack. 62 */ 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 93 @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>(); 94 BondStateMachine(AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)95 private BondStateMachine(AdapterService service, AdapterProperties prop, 96 RemoteDevices remoteDevices) { 97 super("BondStateMachine:"); 98 addState(mStableState); 99 addState(mPendingCommandState); 100 mRemoteDevices = remoteDevices; 101 mAdapterService = service; 102 mAdapterProperties = prop; 103 mAdapter = BluetoothAdapter.getDefaultAdapter(); 104 setInitialState(mStableState); 105 } 106 make(AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)107 public static BondStateMachine make(AdapterService service, AdapterProperties prop, 108 RemoteDevices remoteDevices) { 109 Log.d(TAG, "make"); 110 BondStateMachine bsm = new BondStateMachine(service, prop, remoteDevices); 111 bsm.start(); 112 return bsm; 113 } 114 doQuit()115 public synchronized void doQuit() { 116 quitNow(); 117 } 118 cleanup()119 private void cleanup() { 120 mAdapterService = null; 121 mRemoteDevices = null; 122 mAdapterProperties = null; 123 } 124 125 @Override onQuitting()126 protected void onQuitting() { 127 cleanup(); 128 } 129 130 private class StableState extends State { 131 @Override enter()132 public void enter() { 133 infoLog("StableState(): Entering Off State"); 134 } 135 136 @Override processMessage(Message msg)137 public synchronized boolean processMessage(Message msg) { 138 139 BluetoothDevice dev = (BluetoothDevice) msg.obj; 140 141 switch (msg.what) { 142 143 case CREATE_BOND: 144 OobData p192Data = (msg.getData() != null) 145 ? msg.getData().getParcelable(OOBDATAP192) : null; 146 OobData p256Data = (msg.getData() != null) 147 ? msg.getData().getParcelable(OOBDATAP256) : null; 148 createBond(dev, msg.arg1, p192Data, p256Data, true); 149 break; 150 case REMOVE_BOND: 151 removeBond(dev, true); 152 break; 153 case BONDING_STATE_CHANGE: 154 int newState = msg.arg1; 155 /* if incoming pairing, transition to pending state */ 156 if (newState == BluetoothDevice.BOND_BONDING) { 157 deferMessage(msg); 158 transitionTo(mPendingCommandState); 159 } else if (newState == BluetoothDevice.BOND_NONE) { 160 /* if the link key was deleted by the stack */ 161 sendIntent(dev, newState, 0, false); 162 } else { 163 Log.e(TAG, "In stable state, received invalid newState: " 164 + state2str(newState)); 165 } 166 break; 167 case BONDED_INTENT_DELAY: 168 if (mPendingBondedDevices.contains(dev)) { 169 sendIntent(dev, BluetoothDevice.BOND_BONDED, 0, true); 170 } 171 break; 172 case UUID_UPDATE: 173 if (mPendingBondedDevices.contains(dev)) { 174 sendIntent(dev, BluetoothDevice.BOND_BONDED, 0, false); 175 } 176 break; 177 case CANCEL_BOND: 178 default: 179 Log.e(TAG, "Received unhandled state: " + msg.what); 180 return false; 181 } 182 return true; 183 } 184 } 185 186 private class PendingCommandState extends State { 187 private final ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>(); 188 189 @Override enter()190 public void enter() { 191 infoLog("Entering PendingCommandState State"); 192 } 193 194 @Override processMessage(Message msg)195 public synchronized boolean processMessage(Message msg) { 196 BluetoothDevice dev = (BluetoothDevice) msg.obj; 197 198 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 199 boolean result = false; 200 if ((mDevices.contains(dev) || mPendingBondedDevices.contains(dev)) 201 && msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE 202 && msg.what != SSP_REQUEST && msg.what != PIN_REQUEST) { 203 deferMessage(msg); 204 return true; 205 } 206 207 switch (msg.what) { 208 case CREATE_BOND: 209 OobData p192Data = (msg.getData() != null) 210 ? msg.getData().getParcelable(OOBDATAP192) : null; 211 OobData p256Data = (msg.getData() != null) 212 ? msg.getData().getParcelable(OOBDATAP256) : null; 213 result = createBond(dev, msg.arg1, p192Data, p256Data, false); 214 break; 215 case REMOVE_BOND: 216 result = removeBond(dev, false); 217 break; 218 case CANCEL_BOND: 219 result = cancelBond(dev); 220 break; 221 case BONDING_STATE_CHANGE: 222 int newState = msg.arg1; 223 int reason = getUnbondReasonFromHALCode(msg.arg2); 224 // Bond is explicitly removed if we are in pending command state 225 if (newState == BluetoothDevice.BOND_NONE 226 && reason == BluetoothDevice.BOND_SUCCESS) { 227 reason = BluetoothDevice.UNBOND_REASON_REMOVED; 228 } 229 sendIntent(dev, newState, reason, false); 230 if (newState != BluetoothDevice.BOND_BONDING) { 231 // This is either none/bonded, remove and transition, and also set 232 // result=false to avoid adding the device to mDevices. 233 mDevices.remove(dev); 234 result = false; 235 if (mDevices.isEmpty()) { 236 transitionTo(mStableState); 237 } 238 if (newState == BluetoothDevice.BOND_NONE) { 239 mAdapterService.setPhonebookAccessPermission(dev, 240 BluetoothDevice.ACCESS_UNKNOWN); 241 mAdapterService.setMessageAccessPermission(dev, 242 BluetoothDevice.ACCESS_UNKNOWN); 243 mAdapterService.setSimAccessPermission(dev, 244 BluetoothDevice.ACCESS_UNKNOWN); 245 // Set the profile Priorities to undefined 246 clearProfilePriority(dev); 247 } 248 } else if (!mDevices.contains(dev)) { 249 result = true; 250 } 251 break; 252 case SSP_REQUEST: 253 int passkey = msg.arg1; 254 int variant = msg.arg2; 255 boolean displayPasskey = 256 (msg.getData() != null) 257 ? msg.getData().getByte(DISPLAY_PASSKEY) == 1 /* 1 == true */ 258 : false; 259 sendDisplayPinIntent( 260 devProp.getAddress(), 261 displayPasskey ? Optional.of(passkey) : Optional.empty(), 262 variant); 263 break; 264 case PIN_REQUEST: 265 BluetoothClass btClass = dev.getBluetoothClass(); 266 int btDeviceClass = btClass.getDeviceClass(); 267 if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || btDeviceClass 268 == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { 269 // Its a keyboard. Follow the HID spec recommendation of creating the 270 // passkey and displaying it to the user. If the keyboard doesn't follow 271 // the spec recommendation, check if the keyboard has a fixed PIN zero 272 // and pair. 273 //TODO: Maintain list of devices that have fixed pin 274 // Generate a variable 6-digit PIN in range of 100000-999999 275 // This is not truly random but good enough. 276 int pin = 100000 + (int) Math.floor((Math.random() * (999999 - 100000))); 277 sendDisplayPinIntent( 278 devProp.getAddress(), 279 Optional.of(pin), 280 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); 281 break; 282 } 283 284 if (msg.arg2 == 1) { // Minimum 16 digit pin required here 285 sendDisplayPinIntent( 286 devProp.getAddress(), 287 Optional.empty(), 288 BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS); 289 } else { 290 // In PIN_REQUEST, there is no passkey to display.So do not send the 291 // EXTRA_PAIRING_KEY type in the intent 292 sendDisplayPinIntent( 293 devProp.getAddress(), 294 Optional.empty(), 295 BluetoothDevice.PAIRING_VARIANT_PIN); 296 } 297 break; 298 default: 299 Log.e(TAG, "Received unhandled event:" + msg.what); 300 return false; 301 } 302 if (result) { 303 mDevices.add(dev); 304 } 305 return true; 306 } 307 } 308 309 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) cancelBond(BluetoothDevice dev)310 private boolean cancelBond(BluetoothDevice dev) { 311 if (dev.getBondState() == BluetoothDevice.BOND_BONDING) { 312 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 313 if (!mAdapterService.cancelBondNative(addr)) { 314 Log.e(TAG, "Unexpected error while cancelling bond:"); 315 } else { 316 return true; 317 } 318 } 319 return false; 320 } 321 removeBond(BluetoothDevice dev, boolean transition)322 private boolean removeBond(BluetoothDevice dev, boolean transition) { 323 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 324 if (devProp != null && devProp.getBondState() == BluetoothDevice.BOND_BONDED) { 325 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 326 if (!mAdapterService.removeBondNative(addr)) { 327 Log.e(TAG, "Unexpected error while removing bond:"); 328 } else { 329 if (transition) { 330 transitionTo(mPendingCommandState); 331 } 332 return true; 333 } 334 } 335 return false; 336 } 337 338 @RequiresPermission(allOf = { 339 android.Manifest.permission.BLUETOOTH_CONNECT, 340 android.Manifest.permission.INTERACT_ACROSS_USERS, 341 }) createBond(BluetoothDevice dev, int transport, OobData remoteP192Data, OobData remoteP256Data, boolean transition)342 private boolean createBond(BluetoothDevice dev, int transport, OobData remoteP192Data, 343 OobData remoteP256Data, boolean transition) { 344 if (dev.getBondState() == BluetoothDevice.BOND_NONE) { 345 infoLog("Bond address is:" + dev); 346 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 347 int addrType = dev.getAddressType(); 348 boolean result; 349 // If we have some data 350 if (remoteP192Data != null || remoteP256Data != null) { 351 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 352 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 353 BluetoothDevice.BOND_BONDING, 354 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_START_PAIRING_OOB, 355 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN, mAdapterService.getMetricId(dev)); 356 result = mAdapterService.createBondOutOfBandNative(addr, transport, 357 remoteP192Data, remoteP256Data); 358 } else { 359 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 360 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 361 BluetoothDevice.BOND_BONDING, 362 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_START_PAIRING, 363 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN, mAdapterService.getMetricId(dev)); 364 result = mAdapterService.createBondNative(addr, addrType, transport); 365 } 366 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED, 367 mAdapterService.getMetricId(dev), dev.getName()); 368 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 369 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 370 BluetoothDevice.BOND_BONDING, 371 remoteP192Data == null && remoteP256Data == null 372 ? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN 373 : BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED, 374 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN); 375 376 if (!result) { 377 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 378 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 379 BluetoothDevice.BOND_NONE, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN, 380 BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS); 381 // Using UNBOND_REASON_REMOVED for legacy reason 382 sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED, 383 false); 384 return false; 385 } else if (transition) { 386 transitionTo(mPendingCommandState); 387 } 388 return true; 389 } 390 return false; 391 } 392 sendDisplayPinIntent(byte[] address, Optional<Integer> maybePin, int variant)393 private void sendDisplayPinIntent(byte[] address, Optional<Integer> maybePin, int variant) { 394 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 395 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address)); 396 maybePin.ifPresent(pin -> intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin)); 397 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 398 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 399 // Workaround for Android Auto until pre-accepting pairing requests is added. 400 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 401 Utils.sendOrderedBroadcast(mAdapterService, intent, BLUETOOTH_CONNECT, 402 Utils.getTempAllowlistBroadcastOptions(), null/* resultReceiver */, 403 null/* scheduler */, Activity.RESULT_OK/* initialCode */, null/* initialData */, 404 null/* initialExtras */); 405 } 406 407 @VisibleForTesting 408 @RequiresPermission(allOf = { 409 android.Manifest.permission.BLUETOOTH_CONNECT, 410 android.Manifest.permission.INTERACT_ACROSS_USERS, 411 }) sendIntent(BluetoothDevice device, int newState, int reason, boolean isTriggerFromDelayMessage)412 void sendIntent(BluetoothDevice device, int newState, int reason, 413 boolean isTriggerFromDelayMessage) { 414 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); 415 int oldState = BluetoothDevice.BOND_NONE; 416 if (newState != BluetoothDevice.BOND_NONE 417 && newState != BluetoothDevice.BOND_BONDING 418 && newState != BluetoothDevice.BOND_BONDED) { 419 infoLog("Invalid bond state " + newState); 420 return; 421 } 422 if (devProp != null) { 423 oldState = devProp.getBondState(); 424 } 425 if (isTriggerFromDelayMessage && (oldState != BluetoothDevice.BOND_BONDED 426 || newState != BluetoothDevice.BOND_BONDED 427 || !mPendingBondedDevices.contains(device))) { 428 infoLog("Invalid state when doing delay send bonded intent, oldState: " + oldState 429 + ", newState: " + newState + ", in PendingBondedDevices list? " 430 + mPendingBondedDevices.contains(device)); 431 return; 432 } 433 if (mPendingBondedDevices.contains(device)) { 434 mPendingBondedDevices.remove(device); 435 if (oldState == BluetoothDevice.BOND_BONDED) { 436 if (newState == BluetoothDevice.BOND_BONDING) { 437 mAdapterProperties.onBondStateChanged(device, newState); 438 } 439 oldState = BluetoothDevice.BOND_BONDING; 440 } else { 441 // Should not enter here. 442 throw new IllegalArgumentException("Invalid old state " + oldState); 443 } 444 } 445 if (oldState == newState) { 446 return; 447 } 448 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 449 mAdapterService.obfuscateAddress(device), 0, device.getType(), 450 newState, BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_BOND_STATE_INTENT_SENT, reason, 451 mAdapterService.getMetricId(device)); 452 BluetoothClass deviceClass = device.getBluetoothClass(); 453 int classOfDevice = deviceClass == null ? 0 : deviceClass.getClassOfDevice(); 454 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_CLASS_OF_DEVICE_REPORTED, 455 mAdapterService.obfuscateAddress(device), classOfDevice, 456 mAdapterService.getMetricId(device)); 457 mAdapterProperties.onBondStateChanged(device, newState); 458 459 if (!isTriggerFromDelayMessage && newState == BluetoothDevice.BOND_BONDED 460 && devProp != null && devProp.getUuids() == null) { 461 infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent"); 462 if (!mPendingBondedDevices.contains(device)) { 463 mPendingBondedDevices.add(device); 464 Message msg = obtainMessage(BONDED_INTENT_DELAY); 465 msg.obj = device; 466 sendMessageDelayed(msg, sPendingUuidUpdateTimeoutMillis); 467 } 468 if (oldState == BluetoothDevice.BOND_NONE) { 469 // Broadcast NONE->BONDING for NONE->BONDED case. 470 newState = BluetoothDevice.BOND_BONDING; 471 } else { 472 return; 473 } 474 } 475 476 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 477 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 478 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); 479 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 480 if (newState == BluetoothDevice.BOND_NONE) { 481 intent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON, reason); 482 } 483 mAdapterService.onBondStateChanged(device, newState); 484 mAdapterService.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT, 485 Utils.getTempAllowlistBroadcastOptions()); 486 infoLog("Bond State Change Intent:" + device + " " + state2str(oldState) + " => " 487 + state2str(newState)); 488 } 489 bondStateChangeCallback(int status, byte[] address, int newState, int hciReason)490 void bondStateChangeCallback(int status, byte[] address, int newState, int hciReason) { 491 BluetoothDevice device = mRemoteDevices.getDevice(address); 492 493 if (device == null) { 494 infoLog("No record of the device:" + device); 495 // This device will be added as part of the BONDING_STATE_CHANGE intent processing 496 // in sendIntent above 497 device = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 498 } 499 500 infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device + " newState: " 501 + newState + " hciReason: " + hciReason); 502 503 Message msg = obtainMessage(BONDING_STATE_CHANGE); 504 msg.obj = device; 505 506 if (newState == BOND_STATE_BONDED) { 507 msg.arg1 = BluetoothDevice.BOND_BONDED; 508 } else if (newState == BOND_STATE_BONDING) { 509 msg.arg1 = BluetoothDevice.BOND_BONDING; 510 } else { 511 msg.arg1 = BluetoothDevice.BOND_NONE; 512 } 513 msg.arg2 = status; 514 515 sendMessage(msg); 516 } 517 518 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey)519 void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey) { 520 //TODO(BT): Get wakelock and update name and cod 521 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 522 if (bdDevice == null) { 523 mRemoteDevices.addDeviceProperties(address); 524 } 525 infoLog("sspRequestCallback: " + Arrays.toString(address) 526 + " name: " + Arrays.toString(name) 527 + " cod: " + cod 528 + " pairingVariant " + pairingVariant 529 + " passkey: " + (Build.isDebuggable() ? passkey : "******")); 530 int variant; 531 boolean displayPasskey = false; 532 switch (pairingVariant) { 533 534 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION: 535 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 536 displayPasskey = true; 537 break; 538 539 case AbstractionLayer.BT_SSP_VARIANT_CONSENT: 540 variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; 541 break; 542 543 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY: 544 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 545 break; 546 547 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION: 548 variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; 549 displayPasskey = true; 550 break; 551 552 default: 553 errorLog("SSP Pairing variant not present"); 554 return; 555 } 556 BluetoothDevice device = mRemoteDevices.getDevice(address); 557 if (device == null) { 558 warnLog("Device is not known for:" + Utils.getRedactedAddressStringFromByte(address)); 559 mRemoteDevices.addDeviceProperties(address); 560 device = Objects.requireNonNull(mRemoteDevices.getDevice(address)); 561 } 562 563 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 564 mAdapterService.obfuscateAddress(device), 0, device.getType(), 565 BluetoothDevice.BOND_BONDING, 566 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_SSP_REQUESTED, 0); 567 568 Message msg = obtainMessage(SSP_REQUEST); 569 msg.obj = device; 570 if (displayPasskey) { 571 msg.arg1 = passkey; 572 Bundle bundle = new Bundle(); 573 bundle.putByte(BondStateMachine.DISPLAY_PASSKEY, (byte) 1 /* true */); 574 msg.setData(bundle); 575 } 576 msg.arg2 = variant; 577 sendMessage(msg); 578 } 579 580 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits)581 void pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits) { 582 //TODO(BT): Get wakelock and update name and cod 583 584 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 585 if (bdDevice == null) { 586 mRemoteDevices.addDeviceProperties(address); 587 bdDevice = Objects.requireNonNull(mRemoteDevices.getDevice(address)); 588 } 589 590 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 591 mAdapterService.obfuscateAddress(bdDevice), 0, bdDevice.getType(), 592 BluetoothDevice.BOND_BONDING, 593 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_PIN_REQUESTED, 0); 594 595 infoLog("pinRequestCallback: " + bdDevice 596 + " name:" + Utils.getName(bdDevice) + " cod:" + new BluetoothClass(cod)); 597 598 Message msg = obtainMessage(PIN_REQUEST); 599 msg.obj = bdDevice; 600 msg.arg2 = min16Digits ? 1 : 0; // Use arg2 to pass the min16Digit boolean 601 602 sendMessage(msg); 603 } 604 605 /* 606 * Check whether has the specific message in message queue 607 */ 608 @VisibleForTesting hasMessage(int what)609 public boolean hasMessage(int what) { 610 return hasMessages(what); 611 } 612 613 /* 614 * Remove the specific message from message queue 615 */ 616 @VisibleForTesting removeMessage(int what)617 public void removeMessage(int what) { 618 removeMessages(what); 619 } 620 621 @RequiresPermission(allOf = { 622 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 623 android.Manifest.permission.MODIFY_PHONE_STATE, 624 }) clearProfilePriority(BluetoothDevice device)625 private void clearProfilePriority(BluetoothDevice device) { 626 HidHostService hidService = HidHostService.getHidHostService(); 627 A2dpService a2dpService = A2dpService.getA2dpService(); 628 HeadsetService headsetService = HeadsetService.getHeadsetService(); 629 HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService(); 630 A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService(); 631 PbapClientService pbapClientService = PbapClientService.getPbapClientService(); 632 633 if (hidService != null) { 634 hidService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 635 } 636 if (a2dpService != null) { 637 a2dpService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 638 } 639 if (headsetService != null) { 640 headsetService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 641 } 642 if (headsetClientService != null) { 643 headsetClientService.setConnectionPolicy(device, 644 BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 645 } 646 if (a2dpSinkService != null) { 647 a2dpSinkService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 648 } 649 if (pbapClientService != null) { 650 pbapClientService.setConnectionPolicy(device, 651 BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 652 } 653 } 654 state2str(int state)655 private String state2str(int state) { 656 if (state == BluetoothDevice.BOND_NONE) { 657 return "BOND_NONE"; 658 } else if (state == BluetoothDevice.BOND_BONDING) { 659 return "BOND_BONDING"; 660 } else if (state == BluetoothDevice.BOND_BONDED) { 661 return "BOND_BONDED"; 662 } else return "UNKNOWN(" + state + ")"; 663 } 664 infoLog(String msg)665 private void infoLog(String msg) { 666 Log.i(TAG, msg); 667 } 668 errorLog(String msg)669 private void errorLog(String msg) { 670 Log.e(TAG, msg); 671 } 672 warnLog(String msg)673 private void warnLog(String msg) { 674 Log.w(TAG, msg); 675 } 676 getUnbondReasonFromHALCode(int reason)677 private int getUnbondReasonFromHALCode(int reason) { 678 if (reason == AbstractionLayer.BT_STATUS_SUCCESS) { 679 return BluetoothDevice.BOND_SUCCESS; 680 } else if (reason == AbstractionLayer.BT_STATUS_RMT_DEV_DOWN) { 681 return BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN; 682 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_FAILURE) { 683 return BluetoothDevice.UNBOND_REASON_AUTH_FAILED; 684 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_REJECTED) { 685 return BluetoothDevice.UNBOND_REASON_AUTH_REJECTED; 686 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_TIMEOUT) { 687 return BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT; 688 } 689 690 /* default */ 691 return BluetoothDevice.UNBOND_REASON_REMOVED; 692 } 693 } 694