1 /* 2 * Copyright (C) 2012-2014 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.Manifest.permission.BLUETOOTH_PRIVILEGED; 21 import static android.Manifest.permission.BLUETOOTH_SCAN; 22 import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; 23 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; 24 import static android.bluetooth.BluetoothUtils.RemoteExceptionIgnoringConsumer; 25 26 import static com.android.modules.utils.build.SdkLevel.isAtLeastV; 27 28 import static java.util.Objects.requireNonNullElseGet; 29 30 import android.annotation.NonNull; 31 import android.annotation.RequiresPermission; 32 import android.annotation.SuppressLint; 33 import android.app.Activity; 34 import android.app.admin.SecurityLog; 35 import android.bluetooth.BluetoothAdapter; 36 import android.bluetooth.BluetoothAssignedNumbers; 37 import android.bluetooth.BluetoothClass; 38 import android.bluetooth.BluetoothDevice; 39 import android.bluetooth.BluetoothDevice.AddressType; 40 import android.bluetooth.BluetoothHeadset; 41 import android.bluetooth.BluetoothManager; 42 import android.bluetooth.BluetoothProfile; 43 import android.bluetooth.BluetoothProtoEnums; 44 import android.bluetooth.BluetoothSinkAudioPolicy; 45 import android.bluetooth.BluetoothUtils; 46 import android.bluetooth.IBluetoothConnectionCallback; 47 import android.content.AttributionSource; 48 import android.content.Intent; 49 import android.content.pm.Attribution; 50 import android.net.MacAddress; 51 import android.os.Build; 52 import android.os.Handler; 53 import android.os.Looper; 54 import android.os.Message; 55 import android.os.ParcelUuid; 56 import android.os.SystemProperties; 57 import android.util.Log; 58 59 import com.android.bluetooth.BluetoothStatsLog; 60 import com.android.bluetooth.R; 61 import com.android.bluetooth.Utils; 62 import com.android.bluetooth.bas.BatteryService; 63 import com.android.bluetooth.flags.Flags; 64 import com.android.bluetooth.hfp.HeadsetHalConstants; 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.modules.utils.build.SdkLevel; 67 68 import java.nio.charset.StandardCharsets; 69 import java.util.ArrayDeque; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.Collections; 73 import java.util.HashMap; 74 import java.util.HashSet; 75 import java.util.LinkedHashMap; 76 import java.util.List; 77 import java.util.Map; 78 import java.util.Set; 79 import java.util.function.Predicate; 80 81 /** Remote device manager. This class is currently mostly used for HF and AG remote devices. */ 82 public class RemoteDevices { 83 private static final String TAG = 84 Utils.TAG_PREFIX_BLUETOOTH + RemoteDevices.class.getSimpleName(); 85 86 // Maximum number of device properties to remember 87 private static final int MAX_DEVICE_QUEUE_SIZE = 200; 88 89 private final BluetoothAdapter mAdapter; 90 private AdapterService mAdapterService; 91 private final ArrayList<BluetoothDevice> mSdpTracker; 92 private final Object mObject = new Object(); 93 94 private static final int UUID_INTENT_DELAY = 6000; 95 private static final int MESSAGE_UUID_INTENT = 1; 96 private static final int MESSAGE_UUID_STATUS_SUCCESS = 0; 97 private static final int MESSAGE_UUID_STATUS_TIMEOUT = 1; 98 private static final String LOG_SOURCE_DIS = "DIS"; 99 100 private final HashMap<String, DeviceProperties> mDevices; 101 private final HashMap<String, String> mDualDevicesMap; 102 private final ArrayDeque<String> mDeviceQueue; 103 104 /** 105 * Bluetooth HFP v1.8 specifies the Battery Charge indicator of AG can take values from {@code 106 * 0} to {@code 5}, but it does not specify how to map the values back to percentages. The 107 * following mapping is used: - Level 0: 0% - Level 1: midpoint of 1-25% - Level 2: midpoint of 108 * 26-50% - Level 3: midpoint of 51-75% - Level 4: midpoint of 76-99% - Level 5: 100% 109 */ 110 private static final int HFP_BATTERY_CHARGE_INDICATOR_0 = 0; 111 112 private static final int HFP_BATTERY_CHARGE_INDICATOR_1 = 13; 113 private static final int HFP_BATTERY_CHARGE_INDICATOR_2 = 38; 114 private static final int HFP_BATTERY_CHARGE_INDICATOR_3 = 63; 115 private static final int HFP_BATTERY_CHARGE_INDICATOR_4 = 88; 116 private static final int HFP_BATTERY_CHARGE_INDICATOR_5 = 100; 117 118 private final Handler mHandler; 119 private final Handler mMainHandler; 120 121 private class RemoteDevicesHandler extends Handler { 122 123 /** 124 * Handler must be created from an explicit looper to avoid threading ambiguity 125 * 126 * @param looper The looper that this handler should be executed on 127 */ RemoteDevicesHandler(Looper looper)128 RemoteDevicesHandler(Looper looper) { 129 super(looper); 130 } 131 132 @Override handleMessage(Message msg)133 public void handleMessage(Message msg) { 134 switch (msg.what) { 135 case MESSAGE_UUID_INTENT: 136 BluetoothDevice device = (BluetoothDevice) msg.obj; 137 if (device != null) { 138 boolean success = (msg.arg1 == MESSAGE_UUID_STATUS_SUCCESS); 139 debugLog("MESSAGE_UUID_INTENT: " + device); 140 // SDP Sending delayed SDP UUID intent 141 MetricsLogger.getInstance() 142 .cacheCount(BluetoothProtoEnums.SDP_SENDING_DELAYED_UUID, 1); 143 DeviceProperties prop = getDeviceProperties(device); 144 sendUuidIntent(device, prop, success); 145 } else { 146 // SDP Not sending delayed SDP UUID intent b/c device is not there 147 MetricsLogger.getInstance() 148 .cacheCount(BluetoothProtoEnums.SDP_NOT_SENDING_DELAYED_UUID, 1); 149 } 150 break; 151 } 152 } 153 } 154 155 /** 156 * Predicate that tests if the given {@link BluetoothDevice} is well-known to be used for 157 * physical location. 158 */ 159 private final Predicate<BluetoothDevice> mLocationDenylistPredicate = 160 (device) -> { 161 final MacAddress parsedAddress = MacAddress.fromString(device.getAddress()); 162 if (mAdapterService.getLocationDenylistMac().test(parsedAddress.toByteArray())) { 163 Log.v(TAG, "Skipping device matching denylist: " + device); 164 return true; 165 } 166 final String name = Utils.getName(device); 167 if (mAdapterService.getLocationDenylistName().test(name)) { 168 Log.v(TAG, "Skipping name matching denylist: " + name); 169 return true; 170 } 171 return false; 172 }; 173 RemoteDevices(AdapterService service, Looper looper)174 RemoteDevices(AdapterService service, Looper looper) { 175 mAdapter = service.getSystemService(BluetoothManager.class).getAdapter(); 176 mAdapterService = service; 177 mSdpTracker = new ArrayList<>(); 178 mDevices = new HashMap<>(); 179 mDualDevicesMap = new HashMap<>(); 180 mDeviceQueue = new ArrayDeque<>(); 181 mHandler = new RemoteDevicesHandler(looper); 182 mMainHandler = new Handler(Looper.getMainLooper()); 183 } 184 185 /** 186 * Reset should be called when the state of this object needs to be cleared RemoteDevices is 187 * still usable after reset 188 */ 189 @RequiresPermission(BLUETOOTH_CONNECT) reset()190 void reset() { 191 mSdpTracker.clear(); 192 193 // Unregister Handler and stop all queued messages. 194 mMainHandler.removeCallbacksAndMessages(null); 195 196 synchronized (mDevices) { 197 debugLog("reset(): Broadcasting ACL_DISCONNECTED"); 198 199 mDevices.forEach( 200 (address, deviceProperties) -> { 201 BluetoothDevice bluetoothDevice = deviceProperties.getDevice(); 202 203 debugLog( 204 "reset(): address=" 205 + BluetoothUtils.toAnonymizedAddress(address) 206 + ", connected=" 207 + bluetoothDevice.isConnected()); 208 209 if (bluetoothDevice.isConnected()) { 210 int transport = 211 deviceProperties.getConnectionHandle( 212 BluetoothDevice.TRANSPORT_BREDR) 213 != BluetoothDevice.ERROR 214 ? BluetoothDevice.TRANSPORT_BREDR 215 : BluetoothDevice.TRANSPORT_LE; 216 mAdapterService.notifyAclDisconnected(bluetoothDevice, transport); 217 Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 218 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice); 219 intent.addFlags( 220 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 221 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 222 mAdapterService.sendBroadcast(intent, BLUETOOTH_CONNECT); 223 } 224 }); 225 mDevices.clear(); 226 } 227 228 mDualDevicesMap.clear(); 229 mDeviceQueue.clear(); 230 } 231 232 @Override clone()233 public Object clone() throws CloneNotSupportedException { 234 throw new CloneNotSupportedException(); 235 } 236 getDeviceProperties(BluetoothDevice device)237 DeviceProperties getDeviceProperties(BluetoothDevice device) { 238 if (device == null) { 239 return null; 240 } 241 242 synchronized (mDevices) { 243 String address = mDualDevicesMap.get(device.getAddress()); 244 // If the device is not in the dual map, use its original address 245 if (address == null || mDevices.get(address) == null) { 246 address = device.getAddress(); 247 } 248 return mDevices.get(address); 249 } 250 } 251 getBondState(BluetoothDevice device)252 int getBondState(BluetoothDevice device) { 253 DeviceProperties deviceProp = getDeviceProperties(device); 254 if (deviceProp == null) { 255 return BluetoothDevice.BOND_NONE; 256 } 257 return deviceProp.getBondState(); 258 } 259 getName(BluetoothDevice device)260 String getName(BluetoothDevice device) { 261 DeviceProperties deviceProp = getDeviceProperties(device); 262 if (deviceProp == null) { 263 return null; 264 } 265 return deviceProp.getName(); 266 } 267 getType(BluetoothDevice device)268 int getType(BluetoothDevice device) { 269 DeviceProperties deviceProp = getDeviceProperties(device); 270 if (deviceProp == null) { 271 return BluetoothDevice.DEVICE_TYPE_UNKNOWN; 272 } 273 return deviceProp.getDeviceType(); 274 } 275 getUuids(BluetoothDevice device)276 public ParcelUuid[] getUuids(BluetoothDevice device) { 277 DeviceProperties deviceProp = getDeviceProperties(device); 278 if (deviceProp == null) { 279 return null; 280 } 281 return deviceProp.getUuids(); 282 } 283 getBluetoothClass(BluetoothDevice device)284 public int getBluetoothClass(BluetoothDevice device) { 285 DeviceProperties deviceProp = getDeviceProperties(device); 286 if (deviceProp == null) { 287 return 0; 288 } 289 return deviceProp.getBluetoothClass(); 290 } 291 getDevice(byte[] address)292 BluetoothDevice getDevice(byte[] address) { 293 String addressString = Utils.getAddressStringFromByte(address); 294 String deviceAddress = mDualDevicesMap.get(addressString); 295 // If the device is not in the dual map, use its original address 296 if (deviceAddress == null || mDevices.get(deviceAddress) == null) { 297 deviceAddress = addressString; 298 } 299 300 DeviceProperties prop = mDevices.get(deviceAddress); 301 if (prop != null) { 302 return prop.getDevice(); 303 } 304 return null; 305 } 306 307 @VisibleForTesting addDeviceProperties(byte[] address)308 DeviceProperties addDeviceProperties(byte[] address) { 309 synchronized (mDevices) { 310 String key = Utils.getAddressStringFromByte(address); 311 if (Flags.fixAddDeviceProperties() && mDevices.containsKey(key)) { 312 debugLog("Properties for device " + key + " are already added"); 313 return mDevices.get(key); 314 } 315 316 DeviceProperties prop = new DeviceProperties(); 317 prop.setDevice(mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address))); 318 prop.setAddress(address); 319 320 DeviceProperties pv = mDevices.put(key, prop); 321 322 if (pv == null) { 323 mDeviceQueue.offer(key); 324 if (mDeviceQueue.size() > MAX_DEVICE_QUEUE_SIZE) { 325 String deleteKey = mDeviceQueue.poll(); 326 for (BluetoothDevice device : mAdapterService.getBondedDevices()) { 327 if (device.getAddress().equals(deleteKey)) { 328 return prop; 329 } 330 } 331 debugLog("Removing device " + deleteKey + " from property map"); 332 mDevices.remove(deleteKey); 333 } 334 } 335 return prop; 336 } 337 } 338 339 class DeviceProperties { 340 private static final int MAX_PACKAGE_NAMES = 4; 341 private String mName; 342 private byte[] mAddress; 343 private String mIdentityAddress; 344 @AddressType private int mIdentityAddressType = BluetoothDevice.ADDRESS_TYPE_UNKNOWN; 345 private boolean mIsConsolidated = false; 346 private int mBluetoothClass = BluetoothClass.Device.Major.UNCATEGORIZED; 347 private int mBredrConnectionHandle = BluetoothDevice.ERROR; 348 private int mLeConnectionHandle = BluetoothDevice.ERROR; 349 private short mRssi; 350 private String mAlias; 351 private BluetoothDevice mDevice; 352 private boolean mIsBondingInitiatedLocally; 353 private int mBatteryLevelFromHfp = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 354 private int mBatteryLevelFromBatteryService = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 355 private boolean mIsCoordinatedSetMember; 356 private int mAshaCapability; 357 private int mAshaTruncatedHiSyncId; 358 private String mModelName; 359 @VisibleForTesting int mBondState; 360 @VisibleForTesting int mDeviceType; 361 @VisibleForTesting ParcelUuid[] mUuidsBrEdr; 362 @VisibleForTesting ParcelUuid[] mUuidsLe; 363 @VisibleForTesting boolean mHfpBatteryIndicator = false; 364 private BluetoothSinkAudioPolicy mAudioPolicy; 365 366 // LRU cache of package names associated to this device 367 private final Set<String> mPackages = 368 Collections.newSetFromMap( 369 new LinkedHashMap<String, Boolean>() { 370 // This is called on every add. Returning true removes the eldest entry. 371 protected boolean removeEldestEntry(Map.Entry<String, Boolean> eldest) { 372 return size() >= MAX_PACKAGE_NAMES; 373 } 374 }); 375 DeviceProperties()376 DeviceProperties() { 377 mBondState = BluetoothDevice.BOND_NONE; 378 } 379 380 /** 381 * @return the mName 382 */ getName()383 String getName() { 384 synchronized (mObject) { 385 return mName; 386 } 387 } 388 389 /** 390 * @param name the mName to set 391 */ setName(String name)392 void setName(String name) { 393 synchronized (mObject) { 394 this.mName = name; 395 } 396 } 397 398 /** 399 * @return the mIdentityAddress 400 */ getIdentityAddress()401 String getIdentityAddress() { 402 synchronized (mObject) { 403 return mIdentityAddress; 404 } 405 } 406 407 /** 408 * @param identityAddress the mIdentityAddress to set 409 */ setIdentityAddress(String identityAddress)410 void setIdentityAddress(String identityAddress) { 411 synchronized (mObject) { 412 this.mIdentityAddress = identityAddress; 413 } 414 } 415 416 /** 417 * @return the mIdentityAddressType 418 */ 419 @AddressType getIdentityAddressType()420 int getIdentityAddressType() { 421 synchronized (mObject) { 422 return mIdentityAddressType; 423 } 424 } 425 426 /** 427 * @param identityAddressType the mIdentityAddressType to set 428 */ setIdentityAddressType(int identityAddressType)429 void setIdentityAddressType(int identityAddressType) { 430 synchronized (mObject) { 431 this.mIdentityAddressType = identityAddressType; 432 } 433 } 434 435 /** 436 * @param identityAddressTypeFromNative the mIdentityAddressType to set after mapping to 437 * Java layer. 438 */ setIdentityAddressTypeFromNative(int identityAddressTypeFromNative)439 void setIdentityAddressTypeFromNative(int identityAddressTypeFromNative) { 440 /* 441 * from system/types/ble_address_with_type.h 442 * 443 * #define BLE_ADDR_PUBLIC 0x00 444 * #define BLE_ADDR_RANDOM 0x01 445 */ 446 int identityAddressType = BluetoothDevice.ADDRESS_TYPE_UNKNOWN; 447 switch (identityAddressTypeFromNative) { 448 case 0x00: 449 identityAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC; 450 break; 451 case 0x01: 452 identityAddressType = BluetoothDevice.ADDRESS_TYPE_RANDOM; 453 break; 454 default: 455 errorLog( 456 "Unexpected identity address type received from native: " 457 + identityAddressTypeFromNative); 458 break; 459 } 460 synchronized (mObject) { 461 this.mIdentityAddressType = identityAddressType; 462 } 463 } 464 465 /** 466 * @return mIsConsolidated 467 */ isConsolidated()468 boolean isConsolidated() { 469 synchronized (mObject) { 470 return mIsConsolidated; 471 } 472 } 473 474 /** 475 * @param isConsolidated the mIsConsolidated to set 476 */ setIsConsolidated(boolean isConsolidated)477 void setIsConsolidated(boolean isConsolidated) { 478 synchronized (mObject) { 479 this.mIsConsolidated = isConsolidated; 480 } 481 } 482 483 /** 484 * @return the mClass 485 */ getBluetoothClass()486 int getBluetoothClass() { 487 synchronized (mObject) { 488 return mBluetoothClass; 489 } 490 } 491 492 /** 493 * @param bluetoothClass the mBluetoothClass to set 494 */ setBluetoothClass(int bluetoothClass)495 void setBluetoothClass(int bluetoothClass) { 496 synchronized (mObject) { 497 this.mBluetoothClass = bluetoothClass; 498 } 499 } 500 501 /** 502 * @param transport the transport on which the connection exists 503 * @return the mConnectionHandle 504 */ getConnectionHandle(int transport)505 int getConnectionHandle(int transport) { 506 synchronized (mObject) { 507 if (transport == BluetoothDevice.TRANSPORT_BREDR) { 508 return mBredrConnectionHandle; 509 } else if (transport == BluetoothDevice.TRANSPORT_LE) { 510 return mLeConnectionHandle; 511 } else { 512 return BluetoothDevice.ERROR; 513 } 514 } 515 } 516 517 /** 518 * @param connectionHandle the connectionHandle to set 519 * @param transport the transport on which to set the handle 520 */ setConnectionHandle(int connectionHandle, int transport)521 void setConnectionHandle(int connectionHandle, int transport) { 522 synchronized (mObject) { 523 if (transport == BluetoothDevice.TRANSPORT_BREDR) { 524 mBredrConnectionHandle = connectionHandle; 525 } else if (transport == BluetoothDevice.TRANSPORT_LE) { 526 mLeConnectionHandle = connectionHandle; 527 } else { 528 errorLog("setConnectionHandle() unexpected transport value " + transport); 529 } 530 } 531 } 532 533 /** 534 * @return the UUIDs on LE and Classic transport 535 */ getUuids()536 ParcelUuid[] getUuids() { 537 synchronized (mObject) { 538 /* When we bond dual mode device, and discover LE and Classic services, stack would 539 * return LE and Classic UUIDs separately, but Java apps expect them merged. 540 */ 541 int combinedUuidsLength = 542 (mUuidsBrEdr != null ? mUuidsBrEdr.length : 0) 543 + (mUuidsLe != null ? mUuidsLe.length : 0); 544 if (!Flags.separateServiceStorage() || combinedUuidsLength == 0) { 545 return mUuidsBrEdr; 546 } 547 548 java.util.LinkedHashSet<ParcelUuid> result = 549 new java.util.LinkedHashSet<ParcelUuid>(); 550 if (mUuidsBrEdr != null) { 551 for (ParcelUuid uuid : mUuidsBrEdr) { 552 result.add(uuid); 553 } 554 } 555 556 if (mUuidsLe != null) { 557 for (ParcelUuid uuid : mUuidsLe) { 558 result.add(uuid); 559 } 560 } 561 562 return result.toArray(new ParcelUuid[result.size()]); 563 } 564 } 565 566 /** 567 * @return just classic transport UUIDS 568 */ getUuidsBrEdr()569 ParcelUuid[] getUuidsBrEdr() { 570 synchronized (mObject) { 571 return mUuidsBrEdr; 572 } 573 } 574 575 /** 576 * @param uuids the mUuidsBrEdr to set 577 */ setUuidsBrEdr(ParcelUuid[] uuids)578 void setUuidsBrEdr(ParcelUuid[] uuids) { 579 synchronized (mObject) { 580 this.mUuidsBrEdr = uuids; 581 } 582 } 583 584 /** 585 * @return the mUuidsLe 586 */ getUuidsLe()587 ParcelUuid[] getUuidsLe() { 588 synchronized (mObject) { 589 return mUuidsLe; 590 } 591 } 592 593 /** 594 * @param uuids the mUuidsLe to set 595 */ setUuidsLe(ParcelUuid[] uuids)596 void setUuidsLe(ParcelUuid[] uuids) { 597 synchronized (mObject) { 598 this.mUuidsLe = uuids; 599 } 600 } 601 602 /** 603 * @return the mAddress 604 */ getAddress()605 byte[] getAddress() { 606 synchronized (mObject) { 607 return mAddress; 608 } 609 } 610 611 /** 612 * @param address the mAddress to set 613 */ setAddress(byte[] address)614 void setAddress(byte[] address) { 615 synchronized (mObject) { 616 this.mAddress = address; 617 } 618 } 619 620 /** 621 * @return the mDevice 622 */ getDevice()623 BluetoothDevice getDevice() { 624 synchronized (mObject) { 625 return mDevice; 626 } 627 } 628 629 /** 630 * @param device the mDevice to set 631 */ setDevice(BluetoothDevice device)632 void setDevice(BluetoothDevice device) { 633 synchronized (mObject) { 634 this.mDevice = device; 635 } 636 } 637 638 /** 639 * @return mRssi 640 */ getRssi()641 short getRssi() { 642 synchronized (mObject) { 643 return mRssi; 644 } 645 } 646 647 /** 648 * @param rssi the mRssi to set 649 */ setRssi(short rssi)650 void setRssi(short rssi) { 651 synchronized (mObject) { 652 this.mRssi = rssi; 653 } 654 } 655 656 /** 657 * @return mDeviceType 658 */ getDeviceType()659 int getDeviceType() { 660 synchronized (mObject) { 661 return mDeviceType; 662 } 663 } 664 665 /** 666 * @param deviceType the mDeviceType to set 667 */ 668 @VisibleForTesting setDeviceType(int deviceType)669 void setDeviceType(int deviceType) { 670 synchronized (mObject) { 671 this.mDeviceType = deviceType; 672 } 673 } 674 675 /** 676 * @return the mAlias 677 */ getAlias()678 String getAlias() { 679 synchronized (mObject) { 680 return mAlias; 681 } 682 } 683 684 /** 685 * @param mAlias the mAlias to set 686 */ setAlias(BluetoothDevice device, String mAlias)687 void setAlias(BluetoothDevice device, String mAlias) { 688 synchronized (mObject) { 689 this.mAlias = mAlias; 690 mAdapterService 691 .getNative() 692 .setDeviceProperty( 693 mAddress, 694 AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, 695 mAlias.getBytes()); 696 Intent intent = new Intent(BluetoothDevice.ACTION_ALIAS_CHANGED); 697 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 698 intent.putExtra(BluetoothDevice.EXTRA_NAME, mAlias); 699 mAdapterService.sendBroadcast( 700 intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 701 } 702 } 703 704 /** 705 * @param newBondState the mBondState to set 706 */ setBondState(int newBondState)707 void setBondState(int newBondState) { 708 synchronized (mObject) { 709 this.mBondState = newBondState; 710 if (newBondState == BluetoothDevice.BOND_NONE) { 711 /* Clearing the Uuids local copy when the device is unpaired. If not cleared, 712 cachedBluetoothDevice issued a connect using the local cached copy of uuids, 713 without waiting for the ACTION_UUID intent. 714 This was resulting in multiple calls to connect().*/ 715 mUuidsBrEdr = null; 716 mUuidsLe = null; 717 mAlias = null; 718 } 719 } 720 } 721 722 /** 723 * @return the mBondState 724 */ getBondState()725 int getBondState() { 726 synchronized (mObject) { 727 return mBondState; 728 } 729 } 730 isBonding()731 boolean isBonding() { 732 return getBondState() == BluetoothDevice.BOND_BONDING; 733 } 734 isBondingOrBonded()735 boolean isBondingOrBonded() { 736 return isBonding() || getBondState() == BluetoothDevice.BOND_BONDED; 737 } 738 739 /** 740 * @param isBondingInitiatedLocally whether bonding is initiated locally 741 */ setBondingInitiatedLocally(boolean isBondingInitiatedLocally)742 void setBondingInitiatedLocally(boolean isBondingInitiatedLocally) { 743 synchronized (mObject) { 744 this.mIsBondingInitiatedLocally = isBondingInitiatedLocally; 745 } 746 } 747 748 /** 749 * @return the isBondingInitiatedLocally 750 */ isBondingInitiatedLocally()751 boolean isBondingInitiatedLocally() { 752 synchronized (mObject) { 753 return mIsBondingInitiatedLocally; 754 } 755 } 756 757 /** 758 * @return mBatteryLevel 759 */ getBatteryLevel()760 int getBatteryLevel() { 761 synchronized (mObject) { 762 if (mBatteryLevelFromBatteryService != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { 763 return mBatteryLevelFromBatteryService; 764 } 765 return mBatteryLevelFromHfp; 766 } 767 } 768 769 /** 770 * @param hfpBatteryIndicator is set to true based on the HF battery indicator support 771 * received from AT+BIND command and set to false in disconnect path. 772 */ setHfpBatteryIndicatorStatus(boolean hfpBatteryIndicator)773 void setHfpBatteryIndicatorStatus(boolean hfpBatteryIndicator) { 774 this.mHfpBatteryIndicator = hfpBatteryIndicator; 775 } 776 777 /** 778 * @return mHfpBatteryIndicator 779 */ isHfpBatteryIndicatorEnabled()780 boolean isHfpBatteryIndicatorEnabled() { 781 return mHfpBatteryIndicator; 782 } 783 setBatteryLevelFromHfp(int batteryLevel)784 void setBatteryLevelFromHfp(int batteryLevel) { 785 synchronized (mObject) { 786 if (mBatteryLevelFromHfp == batteryLevel) { 787 return; 788 } 789 mBatteryLevelFromHfp = batteryLevel; 790 } 791 } 792 setBatteryLevelFromBatteryService(int batteryLevel)793 void setBatteryLevelFromBatteryService(int batteryLevel) { 794 synchronized (mObject) { 795 if (mBatteryLevelFromBatteryService == batteryLevel) { 796 return; 797 } 798 mBatteryLevelFromBatteryService = batteryLevel; 799 } 800 } 801 802 /** 803 * @return the mIsCoordinatedSetMember 804 */ isCoordinatedSetMember()805 boolean isCoordinatedSetMember() { 806 synchronized (mObject) { 807 return mIsCoordinatedSetMember; 808 } 809 } 810 811 /** 812 * @param isCoordinatedSetMember the mIsCoordinatedSetMember to set 813 */ setIsCoordinatedSetMember(boolean isCoordinatedSetMember)814 void setIsCoordinatedSetMember(boolean isCoordinatedSetMember) { 815 if ((mAdapterService.getSupportedProfilesBitMask() 816 & (1 << BluetoothProfile.CSIP_SET_COORDINATOR)) 817 == 0) { 818 debugLog("CSIP is not supported"); 819 return; 820 } 821 synchronized (mObject) { 822 this.mIsCoordinatedSetMember = isCoordinatedSetMember; 823 } 824 } 825 826 /** 827 * @return the mAshaCapability 828 */ getAshaCapability()829 int getAshaCapability() { 830 synchronized (mObject) { 831 return mAshaCapability; 832 } 833 } 834 setAshaCapability(int ashaCapability)835 void setAshaCapability(int ashaCapability) { 836 synchronized (mObject) { 837 this.mAshaCapability = ashaCapability; 838 } 839 } 840 841 /** 842 * @return the mAshaTruncatedHiSyncId 843 */ getAshaTruncatedHiSyncId()844 int getAshaTruncatedHiSyncId() { 845 synchronized (mObject) { 846 return mAshaTruncatedHiSyncId; 847 } 848 } 849 setAshaTruncatedHiSyncId(int ashaTruncatedHiSyncId)850 void setAshaTruncatedHiSyncId(int ashaTruncatedHiSyncId) { 851 synchronized (mObject) { 852 this.mAshaTruncatedHiSyncId = ashaTruncatedHiSyncId; 853 } 854 } 855 setHfAudioPolicyForRemoteAg(BluetoothSinkAudioPolicy policies)856 public void setHfAudioPolicyForRemoteAg(BluetoothSinkAudioPolicy policies) { 857 mAudioPolicy = policies; 858 } 859 getHfAudioPolicyForRemoteAg()860 public BluetoothSinkAudioPolicy getHfAudioPolicyForRemoteAg() { 861 return mAudioPolicy; 862 } 863 setModelName(String modelName)864 public void setModelName(String modelName) { 865 mModelName = modelName; 866 mAdapterService.setMetadata( 867 this.mDevice, 868 BluetoothDevice.METADATA_MODEL_NAME, 869 mModelName.getBytes(StandardCharsets.UTF_8)); 870 } 871 872 /** 873 * @return the mModelName 874 */ getModelName()875 String getModelName() { 876 synchronized (mObject) { 877 return mModelName; 878 } 879 } 880 881 @NonNull getPackages()882 public String[] getPackages() { 883 synchronized (mObject) { 884 return mPackages.toArray(new String[0]); 885 } 886 } 887 addPackage(String packageName)888 public void addPackage(String packageName) { 889 synchronized (mObject) { 890 // Removing the package ensures that the LRU cache order is updated. Adding it back 891 // will make it the newest. 892 mPackages.remove(packageName); 893 mPackages.add(packageName); 894 } 895 } 896 } 897 sendUuidIntent(BluetoothDevice device, DeviceProperties prop, boolean success)898 private void sendUuidIntent(BluetoothDevice device, DeviceProperties prop, boolean success) { 899 // Send uuids within the stack before the broadcast is sent out 900 ParcelUuid[] uuids = prop == null ? null : prop.getUuids(); 901 902 if (!Flags.preventDuplicateUuidIntent() || success) { 903 mAdapterService.sendUuidsInternal(device, uuids); 904 } 905 906 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 907 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 908 intent.putExtra(BluetoothDevice.EXTRA_UUID, uuids); 909 mAdapterService.sendBroadcast( 910 intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 911 912 // SDP Sent UUID Intent here 913 MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_SENT_UUID, 1); 914 915 // Remove the outstanding UUID request 916 if (Flags.preventDuplicateUuidIntent()) { 917 // Handler.removeMessages() compares the object pointer so we cannot use the device 918 // directly. So we have to extract original BluetoothDevice object from mSdpTracker. 919 int index = mSdpTracker.indexOf(device); 920 if (index >= 0) { 921 BluetoothDevice originalDevice = mSdpTracker.get(index); 922 if (originalDevice != null) { 923 mHandler.removeMessages(MESSAGE_UUID_INTENT, originalDevice); 924 } 925 } 926 } 927 mSdpTracker.remove(device); 928 } 929 930 /** 931 * When bonding is initiated to remote device that we have never seen, i.e Out Of Band pairing, 932 * we must add device first before setting it's properties. This is a helper method for doing 933 * that. 934 */ setBondingInitiatedLocally(byte[] address)935 void setBondingInitiatedLocally(byte[] address) { 936 DeviceProperties properties; 937 938 BluetoothDevice device = getDevice(address); 939 if (device == null) { 940 properties = addDeviceProperties(address); 941 } else { 942 properties = getDeviceProperties(device); 943 } 944 945 properties.setBondingInitiatedLocally(true); 946 } 947 updateBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas)948 void updateBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas) { 949 if (device == null || batteryLevel < 0 || batteryLevel > 100) { 950 warnLog( 951 "Invalid parameters device=" 952 + String.valueOf(device == null) 953 + ", batteryLevel=" 954 + String.valueOf(batteryLevel)); 955 return; 956 } 957 DeviceProperties deviceProperties = getDeviceProperties(device); 958 if (deviceProperties == null) { 959 deviceProperties = addDeviceProperties(Utils.getByteAddress(device)); 960 } 961 int prevBatteryLevel = deviceProperties.getBatteryLevel(); 962 if (isBas) { 963 deviceProperties.setBatteryLevelFromBatteryService(batteryLevel); 964 } else { 965 deviceProperties.setBatteryLevelFromHfp(batteryLevel); 966 } 967 int newBatteryLevel = deviceProperties.getBatteryLevel(); 968 if (prevBatteryLevel == newBatteryLevel) { 969 debugLog( 970 "Same battery level for device " 971 + device 972 + " received " 973 + String.valueOf(batteryLevel) 974 + "%"); 975 return; 976 } 977 sendBatteryLevelChangedBroadcast(device, newBatteryLevel); 978 Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); 979 } 980 resetBatteryLevel(BluetoothDevice device, boolean isBas)981 void resetBatteryLevel(BluetoothDevice device, boolean isBas) { 982 if (device == null) { 983 warnLog("Device is null"); 984 return; 985 } 986 DeviceProperties deviceProperties = getDeviceProperties(device); 987 if (deviceProperties == null) { 988 return; 989 } 990 int prevBatteryLevel = deviceProperties.getBatteryLevel(); 991 if (isBas) { 992 deviceProperties.setBatteryLevelFromBatteryService( 993 BluetoothDevice.BATTERY_LEVEL_UNKNOWN); 994 } else { 995 deviceProperties.setBatteryLevelFromHfp(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); 996 } 997 998 if (Flags.enableBatteryLevelUpdateOnlyThroughHfIndicator()) { 999 deviceProperties.setHfpBatteryIndicatorStatus(false); 1000 } 1001 int newBatteryLevel = deviceProperties.getBatteryLevel(); 1002 if (prevBatteryLevel == newBatteryLevel) { 1003 debugLog("Battery level was not changed due to reset, device=" + device); 1004 return; 1005 } 1006 sendBatteryLevelChangedBroadcast(device, newBatteryLevel); 1007 Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); 1008 } 1009 sendBatteryLevelChangedBroadcast(BluetoothDevice device, int batteryLevel)1010 private void sendBatteryLevelChangedBroadcast(BluetoothDevice device, int batteryLevel) { 1011 Intent intent = new Intent(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED); 1012 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1013 intent.putExtra(BluetoothDevice.EXTRA_BATTERY_LEVEL, batteryLevel); 1014 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1015 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1016 mAdapterService.sendBroadcast( 1017 intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1018 } 1019 1020 /** 1021 * Converts HFP's Battery Charge indicator values of {@code 0 -- 5} to an integer percentage. 1022 */ 1023 @VisibleForTesting batteryChargeIndicatorToPercentage(int indicator)1024 static int batteryChargeIndicatorToPercentage(int indicator) { 1025 int percent; 1026 switch (indicator) { 1027 case 5: 1028 percent = HFP_BATTERY_CHARGE_INDICATOR_5; 1029 break; 1030 case 4: 1031 percent = HFP_BATTERY_CHARGE_INDICATOR_4; 1032 break; 1033 case 3: 1034 percent = HFP_BATTERY_CHARGE_INDICATOR_3; 1035 break; 1036 case 2: 1037 percent = HFP_BATTERY_CHARGE_INDICATOR_2; 1038 break; 1039 case 1: 1040 percent = HFP_BATTERY_CHARGE_INDICATOR_1; 1041 break; 1042 case 0: 1043 percent = HFP_BATTERY_CHARGE_INDICATOR_0; 1044 break; 1045 default: 1046 percent = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1047 } 1048 Log.d(TAG, "Battery charge indicator: " + indicator + "; converted to: " + percent + "%"); 1049 return percent; 1050 } 1051 areUuidsEqual(ParcelUuid[] uuids1, ParcelUuid[] uuids2)1052 private static boolean areUuidsEqual(ParcelUuid[] uuids1, ParcelUuid[] uuids2) { 1053 final int length1 = uuids1 == null ? 0 : uuids1.length; 1054 final int length2 = uuids2 == null ? 0 : uuids2.length; 1055 if (length1 != length2) { 1056 return false; 1057 } 1058 Set<ParcelUuid> set = new HashSet<>(); 1059 for (int i = 0; i < length1; ++i) { 1060 set.add(uuids1[i]); 1061 } 1062 for (int i = 0; i < length2; ++i) { 1063 set.remove(uuids2[i]); 1064 } 1065 return set.isEmpty(); 1066 } 1067 devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values)1068 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 1069 Intent intent; 1070 byte[] val; 1071 int type; 1072 BluetoothDevice bdDevice = getDevice(address); 1073 DeviceProperties deviceProperties; 1074 if (bdDevice == null) { 1075 debugLog("Added new device property, device=" + bdDevice); 1076 deviceProperties = addDeviceProperties(address); 1077 bdDevice = getDevice(address); 1078 } else { 1079 deviceProperties = getDeviceProperties(bdDevice); 1080 } 1081 1082 if (types.length <= 0) { 1083 errorLog("No properties to update"); 1084 return; 1085 } 1086 1087 boolean uuids_updated = false; 1088 1089 for (int j = 0; j < types.length; j++) { 1090 type = types[j]; 1091 val = values[j]; 1092 if (val.length == 0) { 1093 continue; 1094 } 1095 1096 synchronized (mObject) { 1097 debugLog("Update property, device=" + bdDevice + ", type: " + type); 1098 switch (type) { 1099 case AbstractionLayer.BT_PROPERTY_BDNAME: 1100 final String newName = new String(val); 1101 if (newName.equals(deviceProperties.getName())) { 1102 debugLog("Skip name update for " + bdDevice); 1103 break; 1104 } 1105 deviceProperties.setName(newName); 1106 List<String> wordBreakdownList = 1107 MetricsLogger.getInstance().getWordBreakdownList(newName); 1108 if (SdkLevel.isAtLeastU()) { 1109 MetricsLogger.getInstance() 1110 .uploadRestrictedBluetoothDeviceName(wordBreakdownList); 1111 } 1112 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 1113 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 1114 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProperties.getName()); 1115 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1116 mAdapterService.sendBroadcast( 1117 intent, 1118 BLUETOOTH_CONNECT, 1119 Utils.getTempBroadcastOptions().toBundle()); 1120 debugLog("Remote device name is: " + deviceProperties.getName()); 1121 break; 1122 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 1123 deviceProperties.setAlias(bdDevice, new String(val)); 1124 debugLog("Remote device alias is: " + deviceProperties.getAlias()); 1125 break; 1126 case AbstractionLayer.BT_PROPERTY_BDADDR: 1127 deviceProperties.setAddress(val); 1128 debugLog( 1129 "Remote Address is:" + Utils.getRedactedAddressStringFromByte(val)); 1130 break; 1131 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 1132 final int newBluetoothClass = Utils.byteArrayToInt(val); 1133 if (newBluetoothClass == deviceProperties.getBluetoothClass()) { 1134 debugLog( 1135 "Skip class update, device=" 1136 + bdDevice 1137 + ", cod=0x" 1138 + Integer.toHexString(newBluetoothClass)); 1139 break; 1140 } 1141 deviceProperties.setBluetoothClass(newBluetoothClass); 1142 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 1143 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 1144 intent.putExtra( 1145 BluetoothDevice.EXTRA_CLASS, 1146 new BluetoothClass(deviceProperties.getBluetoothClass())); 1147 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1148 mAdapterService.sendBroadcast( 1149 intent, 1150 BLUETOOTH_CONNECT, 1151 Utils.getTempBroadcastOptions().toBundle()); 1152 debugLog( 1153 "Remote class update, device=" 1154 + bdDevice 1155 + ", cod=0x" 1156 + Integer.toHexString(newBluetoothClass)); 1157 break; 1158 case AbstractionLayer.BT_PROPERTY_UUIDS: 1159 case AbstractionLayer.BT_PROPERTY_UUIDS_LE: 1160 if (type == AbstractionLayer.BT_PROPERTY_UUIDS) { 1161 final ParcelUuid[] newUuids = Utils.byteArrayToUuid(val); 1162 if (areUuidsEqual(newUuids, deviceProperties.getUuidsBrEdr())) { 1163 // SDP Skip adding UUIDs to property cache if equal 1164 debugLog("Skip uuids update for " + bdDevice.getAddress()); 1165 MetricsLogger.getInstance() 1166 .cacheCount(BluetoothProtoEnums.SDP_UUIDS_EQUAL_SKIP, 1); 1167 break; 1168 } 1169 deviceProperties.setUuidsBrEdr(newUuids); 1170 } else if (type == AbstractionLayer.BT_PROPERTY_UUIDS_LE) { 1171 final ParcelUuid[] newUuidsLe = Utils.byteArrayToUuid(val); 1172 if (areUuidsEqual(newUuidsLe, deviceProperties.getUuidsLe())) { 1173 // SDP Skip adding UUIDs to property cache if equal 1174 debugLog("Skip LE uuids update for " + bdDevice.getAddress()); 1175 MetricsLogger.getInstance() 1176 .cacheCount(BluetoothProtoEnums.SDP_UUIDS_EQUAL_SKIP, 1); 1177 break; 1178 } 1179 deviceProperties.setUuidsLe(newUuidsLe); 1180 } 1181 uuids_updated = true; 1182 break; 1183 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 1184 if (deviceProperties.isConsolidated()) { 1185 break; 1186 } 1187 // The device type from hal layer, defined in bluetooth.h, 1188 // matches the type defined in BluetoothDevice.java 1189 deviceProperties.setDeviceType(Utils.byteArrayToInt(val)); 1190 break; 1191 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 1192 // RSSI from hal is in one byte 1193 deviceProperties.setRssi(val[0]); 1194 break; 1195 case AbstractionLayer.BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER: 1196 deviceProperties.setIsCoordinatedSetMember(val[0] != 0); 1197 break; 1198 case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_CAPABILITY: 1199 deviceProperties.setAshaCapability(val[0]); 1200 break; 1201 case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID: 1202 deviceProperties.setAshaTruncatedHiSyncId(val[0]); 1203 break; 1204 case AbstractionLayer.BT_PROPERTY_REMOTE_MODEL_NUM: 1205 final String modelName = new String(val); 1206 debugLog("Remote device model name: " + modelName); 1207 deviceProperties.setModelName(modelName); 1208 BluetoothStatsLog.write( 1209 BluetoothStatsLog.BLUETOOTH_DEVICE_INFO_REPORTED, 1210 mAdapterService.obfuscateAddress(bdDevice), 1211 BluetoothProtoEnums.DEVICE_INFO_INTERNAL, 1212 LOG_SOURCE_DIS, 1213 null, 1214 modelName, 1215 null, 1216 null, 1217 mAdapterService.getMetricId(bdDevice), 1218 bdDevice.getAddressType(), 1219 0, 1220 0, 1221 0); 1222 break; 1223 } 1224 } 1225 } 1226 1227 if (!uuids_updated) { 1228 return; 1229 } 1230 1231 /* uuids_updated == true 1232 * We might have received LE and BREDR UUIDS separately, ensure that UUID intent is sent 1233 * just once */ 1234 1235 if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) { 1236 // SDP Adding UUIDs to property cache and sending intent 1237 MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_ADD_UUID_WITH_INTENT, 1); 1238 mAdapterService.deviceUuidUpdated(bdDevice); 1239 sendUuidIntent(bdDevice, deviceProperties, true); 1240 } else if (mAdapterService.getState() == BluetoothAdapter.STATE_BLE_ON) { 1241 // SDP Adding UUIDs to property cache but with no intent 1242 MetricsLogger.getInstance() 1243 .cacheCount(BluetoothProtoEnums.SDP_ADD_UUID_WITH_NO_INTENT, 1); 1244 mAdapterService.deviceUuidUpdated(bdDevice); 1245 } else { 1246 // SDP Silently dropping UUIDs and with no intent 1247 MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_DROP_UUID, 1); 1248 } 1249 } 1250 deviceFoundCallback(byte[] address)1251 void deviceFoundCallback(byte[] address) { 1252 // The device properties are already registered - we can send the intent 1253 // now 1254 BluetoothDevice device = getDevice(address); 1255 DeviceProperties deviceProp = getDeviceProperties(device); 1256 if (deviceProp == null) { 1257 errorLog("deviceFoundCallback: Device Properties is null for Device:" + device); 1258 return; 1259 } 1260 boolean restrict_device_found = 1261 SystemProperties.getBoolean("bluetooth.restrict_discovered_device.enabled", false); 1262 if (restrict_device_found && (deviceProp.mName == null || deviceProp.mName.isEmpty())) { 1263 warnLog("deviceFoundCallback: Device name is null or empty: " + device); 1264 return; 1265 } 1266 1267 infoLog("deviceFoundCallback: Remote Address is:" + device); 1268 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 1269 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1270 intent.putExtra( 1271 BluetoothDevice.EXTRA_CLASS, new BluetoothClass(deviceProp.getBluetoothClass())); 1272 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.getRssi()); 1273 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.getName()); 1274 intent.putExtra( 1275 BluetoothDevice.EXTRA_IS_COORDINATED_SET_MEMBER, 1276 deviceProp.isCoordinatedSetMember()); 1277 1278 final List<DiscoveringPackage> packages = mAdapterService.getDiscoveringPackages(); 1279 synchronized (packages) { 1280 for (DiscoveringPackage pkg : packages) { 1281 if (pkg.hasDisavowedLocation()) { 1282 if (mLocationDenylistPredicate.test(device)) { 1283 continue; 1284 } 1285 } 1286 1287 intent.setPackage(pkg.packageName()); 1288 1289 if (pkg.permission() != null) { 1290 mAdapterService.sendBroadcastMultiplePermissions( 1291 intent, 1292 new String[] {BLUETOOTH_SCAN, pkg.permission()}, 1293 Utils.getTempBroadcastOptions()); 1294 } else { 1295 mAdapterService.sendBroadcastMultiplePermissions( 1296 intent, new String[] {BLUETOOTH_SCAN}, Utils.getTempBroadcastOptions()); 1297 } 1298 } 1299 } 1300 } 1301 addressConsolidateCallback(byte[] mainAddress, byte[] secondaryAddress)1302 void addressConsolidateCallback(byte[] mainAddress, byte[] secondaryAddress) { 1303 DeviceProperties deviceProperties; 1304 BluetoothDevice device = getDevice(mainAddress); 1305 if (device == null) { 1306 deviceProperties = addDeviceProperties(mainAddress); 1307 device = deviceProperties.getDevice(); 1308 } else { 1309 deviceProperties = getDeviceProperties(device); 1310 } 1311 Log.d( 1312 TAG, 1313 "addressConsolidateCallback device: " 1314 + device 1315 + ", secondaryAddress:" 1316 + Utils.getRedactedAddressStringFromByte(secondaryAddress)); 1317 1318 deviceProperties.setIsConsolidated(true); 1319 deviceProperties.setDeviceType(BluetoothDevice.DEVICE_TYPE_DUAL); 1320 deviceProperties.setIdentityAddress(Utils.getAddressStringFromByte(secondaryAddress)); 1321 mDualDevicesMap.put( 1322 deviceProperties.getIdentityAddress(), Utils.getAddressStringFromByte(mainAddress)); 1323 } 1324 1325 /** 1326 * Callback to associate an LE-only device's RPA with its identity address and identity address 1327 * type 1328 * 1329 * @param mainAddress the device's RPA 1330 * @param secondaryAddress the device's identity address 1331 * @param identityAddressTypeFromNative the device's identity address type from native 1332 */ leAddressAssociateCallback( byte[] mainAddress, byte[] secondaryAddress, int identityAddressTypeFromNative)1333 void leAddressAssociateCallback( 1334 byte[] mainAddress, byte[] secondaryAddress, int identityAddressTypeFromNative) { 1335 DeviceProperties deviceProperties; 1336 BluetoothDevice device = getDevice(mainAddress); 1337 if (device == null) { 1338 deviceProperties = addDeviceProperties(mainAddress); 1339 device = deviceProperties.getDevice(); 1340 } else { 1341 deviceProperties = getDeviceProperties(device); 1342 } 1343 Log.d( 1344 TAG, 1345 "leAddressAssociateCallback device: " 1346 + device 1347 + ", secondaryAddress:" 1348 + Utils.getRedactedAddressStringFromByte(secondaryAddress) 1349 + ", identityAddressTypeFromNative=" 1350 + identityAddressTypeFromNative); 1351 1352 deviceProperties.setIdentityAddress(Utils.getAddressStringFromByte(secondaryAddress)); 1353 deviceProperties.setIdentityAddressTypeFromNative(identityAddressTypeFromNative); 1354 } 1355 aclStateChangeCallback( int status, byte[] address, int newState, int transportLinkType, int hciReason, int handle)1356 void aclStateChangeCallback( 1357 int status, 1358 byte[] address, 1359 int newState, 1360 int transportLinkType, 1361 int hciReason, 1362 int handle) { 1363 if (status != AbstractionLayer.BT_STATUS_SUCCESS) { 1364 debugLog("aclStateChangeCallback status is " + status + ", skipping"); 1365 return; 1366 } 1367 1368 final BluetoothDevice device = 1369 requireNonNullElseGet( 1370 getDevice(address), 1371 () -> { 1372 Log.w( 1373 TAG, 1374 "aclStateChangeCallback: device is NULL" 1375 + ("address=" 1376 + Utils.getRedactedAddressStringFromByte( 1377 address)) 1378 + (" newState=" + newState)); 1379 return addDeviceProperties(address).getDevice(); 1380 }); 1381 1382 DeviceProperties deviceProperties = getDeviceProperties(device); 1383 1384 int state = mAdapterService.getState(); 1385 1386 Intent intent = null; 1387 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 1388 deviceProperties.setConnectionHandle(handle, transportLinkType); 1389 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { 1390 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 1391 intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, transportLinkType); 1392 } else if (state == BluetoothAdapter.STATE_BLE_ON 1393 || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { 1394 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); 1395 } 1396 BatteryService batteryService = BatteryService.getBatteryService(); 1397 if (batteryService != null && transportLinkType == BluetoothDevice.TRANSPORT_LE) { 1398 batteryService.connectIfPossible(device); 1399 } 1400 mAdapterService.updatePhonePolicyOnAclConnect(device); 1401 SecurityLog.writeEvent( 1402 SecurityLog.TAG_BLUETOOTH_CONNECTION, 1403 Utils.getLoggableAddress(device), /* success */ 1404 1, /* reason */ 1405 ""); 1406 debugLog( 1407 "aclStateChangeCallback: Adapter State: " 1408 + BluetoothAdapter.nameForState(state) 1409 + " Connected: " 1410 + device); 1411 } else { 1412 deviceProperties.setConnectionHandle(BluetoothDevice.ERROR, transportLinkType); 1413 if (getBondState(device) == BluetoothDevice.BOND_BONDING) { 1414 // Send PAIRING_CANCEL intent to dismiss any dialog requesting bonding. 1415 sendPairingCancelIntent(device); 1416 } else if (getBondState(device) == BluetoothDevice.BOND_NONE) { 1417 removeAddressMapping(Utils.getAddressStringFromByte(address)); 1418 } 1419 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { 1420 mAdapterService.notifyAclDisconnected(device, transportLinkType); 1421 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 1422 intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, transportLinkType); 1423 } else if (state == BluetoothAdapter.STATE_BLE_ON 1424 || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 1425 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); 1426 } 1427 // Reset battery level on complete disconnection 1428 if (mAdapterService.getConnectionState(device) == 0) { 1429 BatteryService batteryService = BatteryService.getBatteryService(); 1430 if (batteryService != null 1431 && batteryService.getConnectionState(device) != STATE_DISCONNECTED 1432 && transportLinkType == BluetoothDevice.TRANSPORT_LE) { 1433 batteryService.disconnect(device); 1434 } 1435 resetBatteryLevel(device, /* isBas= */ true); 1436 } 1437 1438 if (mAdapterService.isAllProfilesUnknown(device)) { 1439 DeviceProperties deviceProp = getDeviceProperties(device); 1440 if (deviceProp != null) { 1441 deviceProp.setBondingInitiatedLocally(false); 1442 } 1443 } 1444 SecurityLog.writeEvent( 1445 SecurityLog.TAG_BLUETOOTH_DISCONNECTION, 1446 Utils.getLoggableAddress(device), 1447 BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonToString( 1448 AdapterService.hciToAndroidDisconnectReason(hciReason))); 1449 debugLog( 1450 "aclStateChangeCallback: Adapter State: " 1451 + BluetoothAdapter.nameForState(state) 1452 + " Disconnected: " 1453 + device 1454 + " transportLinkType: " 1455 + transportLinkType 1456 + " hciReason: " 1457 + hciReason); 1458 } 1459 1460 int connectionState = 1461 newState == AbstractionLayer.BT_ACL_STATE_CONNECTED 1462 ? BluetoothAdapter.STATE_CONNECTED 1463 : BluetoothAdapter.STATE_DISCONNECTED; 1464 int metricId = mAdapterService.getMetricId(device); 1465 BluetoothStatsLog.write( 1466 BluetoothStatsLog.BLUETOOTH_ACL_CONNECTION_STATE_CHANGED, 1467 mAdapterService.obfuscateAddress(device), 1468 connectionState, 1469 metricId, 1470 transportLinkType); 1471 1472 BluetoothStatsLog.write( 1473 BluetoothStatsLog.BLUETOOTH_CLASS_OF_DEVICE_REPORTED, 1474 mAdapterService.obfuscateAddress(device), 1475 getBluetoothClass(device), 1476 metricId); 1477 1478 byte[] remoteDeviceInfoBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(device); 1479 1480 BluetoothStatsLog.write( 1481 BluetoothStatsLog.REMOTE_DEVICE_INFORMATION_WITH_METRIC_ID, 1482 metricId, 1483 remoteDeviceInfoBytes); 1484 1485 if (intent == null) { 1486 Log.e(TAG, "aclStateChangeCallback intent is null. BondState: " + getBondState(device)); 1487 return; 1488 } 1489 1490 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device) 1491 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) 1492 .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1493 mAdapterService.sendBroadcast( 1494 intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1495 1496 RemoteExceptionIgnoringConsumer<IBluetoothConnectionCallback> connectionChangeConsumer; 1497 if (connectionState == BluetoothAdapter.STATE_CONNECTED) { 1498 connectionChangeConsumer = cb -> cb.onDeviceConnected(device); 1499 } else { 1500 final int disconnectReason; 1501 if (hciReason == 0x16 /* HCI_ERR_CONN_CAUSE_LOCAL_HOST */ 1502 && mAdapterService.getDatabase().getKeyMissingCount(device) > 0) { 1503 // Native stack disconnects the link on detecting the bond loss. Native GATT would 1504 // return HCI_ERR_CONN_CAUSE_LOCAL_HOST in such case, but the apps should see 1505 // HCI_ERR_AUTH_FAILURE. 1506 Log.d( 1507 TAG, 1508 "aclStateChangeCallback() - disconnected due to bond loss for device=" 1509 + device); 1510 disconnectReason = 0x05; /* HCI_ERR_AUTH_FAILURE */ 1511 } else { 1512 disconnectReason = hciReason; 1513 } 1514 connectionChangeConsumer = 1515 cb -> 1516 cb.onDeviceDisconnected( 1517 device, 1518 AdapterService.hciToAndroidDisconnectReason(disconnectReason)); 1519 } 1520 1521 mAdapterService.aclStateChangeBroadcastCallback(connectionChangeConsumer); 1522 } 1523 sendPairingCancelIntent(BluetoothDevice device)1524 private void sendPairingCancelIntent(BluetoothDevice device) { 1525 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 1526 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1527 intent.setPackage( 1528 SystemProperties.get( 1529 Utils.PAIRING_UI_PROPERTY, 1530 mAdapterService.getString(R.string.pairing_ui_package))); 1531 1532 Log.i(TAG, "sendPairingCancelIntent: device=" + device); 1533 mAdapterService.sendBroadcast( 1534 intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1535 } 1536 removeAddressMapping(String address)1537 private void removeAddressMapping(String address) { 1538 DeviceProperties deviceProperties = mDevices.get(address); 1539 if (deviceProperties != null) { 1540 String pseudoAddress = mDualDevicesMap.get(address); 1541 if (pseudoAddress != null) { 1542 deviceProperties = mDevices.get(pseudoAddress); 1543 } 1544 } 1545 1546 if (deviceProperties != null) { 1547 int leConnectionHandle = 1548 deviceProperties.getConnectionHandle(BluetoothDevice.TRANSPORT_LE); 1549 int bredrConnectionHandle = 1550 deviceProperties.getConnectionHandle(BluetoothDevice.TRANSPORT_BREDR); 1551 if (leConnectionHandle != BluetoothDevice.ERROR 1552 || bredrConnectionHandle != BluetoothDevice.ERROR) { 1553 // Device still connected, wait for disconnection to remove the properties 1554 return; 1555 } 1556 } 1557 1558 synchronized (mDevices) { 1559 mDevices.remove(address); 1560 mDeviceQueue.remove(address); // Remove from LRU cache 1561 1562 // Remove from dual mode device mappings 1563 mDualDevicesMap.values().remove(address); 1564 mDualDevicesMap.remove(address); 1565 } 1566 } 1567 onBondStateChange(BluetoothDevice device, int newState)1568 void onBondStateChange(BluetoothDevice device, int newState) { 1569 String address = device.getAddress(); 1570 1571 if (newState == BluetoothDevice.BOND_NONE) { 1572 removeAddressMapping(address); 1573 } 1574 } 1575 1576 // TODO: remove when key_missing_public flag is deleted 1577 @SuppressLint("AndroidFrameworkRequiresPermission") keyMissingCallback(byte[] address)1578 void keyMissingCallback(byte[] address) { 1579 BluetoothDevice bluetoothDevice = getDevice(address); 1580 if (bluetoothDevice == null) { 1581 errorLog( 1582 "keyMissingCallback: device is NULL, address=" 1583 + Utils.getRedactedAddressStringFromByte(address)); 1584 return; 1585 } 1586 Log.i(TAG, "keyMissingCallback device: " + bluetoothDevice); 1587 1588 if (getBondState(bluetoothDevice) == BluetoothDevice.BOND_BONDED) { 1589 Intent intent = 1590 new Intent(BluetoothDevice.ACTION_KEY_MISSING) 1591 .putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice) 1592 .addFlags( 1593 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1594 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1595 1596 // Log transition to key missing state, if the key missing count is 0 which indicates 1597 // that the device is bonded until now. 1598 if (mAdapterService.getDatabase().getKeyMissingCount(bluetoothDevice) == 0) { 1599 MetricsLogger.getInstance() 1600 .logBluetoothEvent( 1601 bluetoothDevice, 1602 BluetoothStatsLog 1603 .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__TRANSITION, 1604 BluetoothStatsLog 1605 .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__BOND_BONDED_TO_ACTION_KEY_MISSING, 1606 0); 1607 } 1608 1609 // Bond loss detected, add to the count. 1610 mAdapterService.getDatabase().updateKeyMissingCount(bluetoothDevice, true); 1611 1612 // Some apps are not able to handle the key missing broadcast, so we need to remove 1613 // the bond to prevent them from misbehaving. 1614 // TODO (b/402854328): Remove when the misbehaving apps are updated 1615 if (bondLossIopFixNeeded(bluetoothDevice)) { 1616 DeviceProperties deviceProperties = getDeviceProperties(bluetoothDevice); 1617 if (deviceProperties == null) { 1618 return; 1619 } 1620 String[] packages = deviceProperties.getPackages(); 1621 if (packages.length == 0) { 1622 return; 1623 } 1624 1625 Log.w( 1626 TAG, 1627 "Removing " 1628 + bluetoothDevice 1629 + " on behalf of: " 1630 + Arrays.toString(packages)); 1631 bluetoothDevice.removeBond(); 1632 } 1633 1634 if (Flags.keyMissingPublic()) { 1635 mAdapterService.sendOrderedBroadcast( 1636 intent, 1637 BLUETOOTH_CONNECT, 1638 Utils.getTempBroadcastOptions().toBundle(), 1639 null /* resultReceiver */, 1640 null /* scheduler */, 1641 Activity.RESULT_OK /* initialCode */, 1642 null /* initialData */, 1643 null /* initialExtras */); 1644 return; 1645 } 1646 1647 if (isAtLeastV() 1648 && Flags.keyMissingAsOrderedBroadcast() 1649 && android.os.Flags.orderedBroadcastMultiplePermissions()) { 1650 mAdapterService.sendOrderedBroadcastMultiplePermissions( 1651 intent, 1652 new String[] {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 1653 null /* receiverAppOp */, 1654 null /* resultReceiver */, 1655 null /* scheduler */, 1656 Activity.RESULT_OK /* initialCode */, 1657 null /* initialData */, 1658 null /* initialExtras */, 1659 Utils.getTempBroadcastOptions().toBundle()); 1660 } else { 1661 mAdapterService.sendBroadcastMultiplePermissions( 1662 intent, 1663 new String[] {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 1664 Utils.getTempBroadcastOptions()); 1665 } 1666 } 1667 } 1668 encryptionChangeCallback( byte[] address, int status, boolean encryptionEnable, int transport, boolean secureConnection, int keySize)1669 void encryptionChangeCallback( 1670 byte[] address, 1671 int status, 1672 boolean encryptionEnable, 1673 int transport, 1674 boolean secureConnection, 1675 int keySize) { 1676 BluetoothDevice bluetoothDevice = getDevice(address); 1677 if (bluetoothDevice == null) { 1678 errorLog( 1679 "encryptionChangeCallback: device is NULL, address=" 1680 + Utils.getRedactedAddressStringFromByte(address)); 1681 return; 1682 } 1683 Log.d( 1684 TAG, 1685 "encryptionChangeCallback device: " 1686 + bluetoothDevice 1687 + ", status: " 1688 + status 1689 + ", enabled: " 1690 + encryptionEnable 1691 + ", transport: " 1692 + transport 1693 + ", secureConnection: " 1694 + secureConnection 1695 + ", keySize: " 1696 + keySize); 1697 1698 int algorithm = BluetoothDevice.ENCRYPTION_ALGORITHM_NONE; 1699 if (encryptionEnable) { 1700 if (secureConnection || transport == BluetoothDevice.TRANSPORT_LE) { 1701 /* LE link or Classic Secure Connections */ 1702 algorithm = BluetoothDevice.ENCRYPTION_ALGORITHM_AES; 1703 } else { 1704 /* Classic link using non-secure connections mode */ 1705 algorithm = BluetoothDevice.ENCRYPTION_ALGORITHM_E0; 1706 } 1707 1708 // Log transition to encryption change state (bonded), if the key missing count is > 0 1709 // which indicates that the device is in key missing state. 1710 if (mAdapterService.getDatabase().getKeyMissingCount(bluetoothDevice) > 0) { 1711 MetricsLogger.getInstance() 1712 .logBluetoothEvent( 1713 bluetoothDevice, 1714 BluetoothStatsLog 1715 .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__TRANSITION, 1716 BluetoothStatsLog 1717 .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__ACTION_KEY_MISSING_TO_ENCRYPTION_CHANGE, 1718 0); 1719 1720 // Successful bond detected, reset the count. 1721 mAdapterService.getDatabase().updateKeyMissingCount(bluetoothDevice, false); 1722 } 1723 } 1724 1725 Intent intent = 1726 new Intent(BluetoothDevice.ACTION_ENCRYPTION_CHANGE) 1727 .putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice) 1728 .putExtra(BluetoothDevice.EXTRA_TRANSPORT, transport) 1729 .putExtra(BluetoothDevice.EXTRA_ENCRYPTION_STATUS, status) 1730 .putExtra(BluetoothDevice.EXTRA_ENCRYPTION_ENABLED, encryptionEnable) 1731 .putExtra(BluetoothDevice.EXTRA_KEY_SIZE, keySize) 1732 .putExtra(BluetoothDevice.EXTRA_ENCRYPTION_ALGORITHM, algorithm); 1733 1734 if (com.android.bluetooth.flags.Flags.encryptionChangeBroadcast()) { 1735 mAdapterService.sendBroadcast(intent, BLUETOOTH_CONNECT); 1736 } 1737 } 1738 fetchUuids(BluetoothDevice device, int transport)1739 void fetchUuids(BluetoothDevice device, int transport) { 1740 if (mSdpTracker.contains(device)) { 1741 debugLog( 1742 "Skip fetch UUIDs are they are already cached peer:" 1743 + device 1744 + " transport:" 1745 + transport); 1746 MetricsLogger.getInstance() 1747 .cacheCount(BluetoothProtoEnums.SDP_FETCH_UUID_SKIP_ALREADY_CACHED, 1); 1748 return; 1749 } 1750 1751 // If no UUIDs are cached and the device is bonding, wait for SDP after the device is bonded 1752 DeviceProperties deviceProperties = getDeviceProperties(device); 1753 if (deviceProperties != null 1754 && deviceProperties.isBonding() 1755 && getDeviceProperties(device).getUuids() == null) { 1756 debugLog("Skip fetch UUIDs due to bonding peer:" + device + " transport:" + transport); 1757 MetricsLogger.getInstance() 1758 .cacheCount(BluetoothProtoEnums.SDP_FETCH_UUID_SKIP_ALREADY_BONDED, 1); 1759 return; 1760 } 1761 1762 mSdpTracker.add(device); 1763 1764 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 1765 message.obj = device; 1766 message.arg1 = MESSAGE_UUID_STATUS_TIMEOUT; 1767 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 1768 1769 // Uses cached UUIDs if we are bonding. If not, we fetch the UUIDs with SDP. 1770 if (deviceProperties == null || !deviceProperties.isBonding()) { 1771 debugLog( 1772 "Invoking core stack to spin up SDP cycle peer:" 1773 + device 1774 + " transport:" 1775 + transport); 1776 mAdapterService 1777 .getNative() 1778 .getRemoteServices(Utils.getBytesFromAddress(device.getAddress()), transport); 1779 MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_INVOKE_SDP_CYCLE, 1); 1780 } 1781 } 1782 updateUuids(BluetoothDevice device)1783 void updateUuids(BluetoothDevice device) { 1784 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 1785 message.obj = device; 1786 message.arg1 = MESSAGE_UUID_STATUS_SUCCESS; 1787 mHandler.sendMessage(message); 1788 } 1789 1790 /** Handles headset connection state change event */ handleHeadsetConnectionStateChanged( BluetoothDevice device, int fromState, int toState)1791 public void handleHeadsetConnectionStateChanged( 1792 BluetoothDevice device, int fromState, int toState) { 1793 mMainHandler.post(() -> onHeadsetConnectionStateChanged(device, fromState, toState)); 1794 } 1795 1796 @VisibleForTesting onHeadsetConnectionStateChanged(BluetoothDevice device, int fromState, int toState)1797 void onHeadsetConnectionStateChanged(BluetoothDevice device, int fromState, int toState) { 1798 if (device == null) { 1799 Log.e(TAG, "onHeadsetConnectionStateChanged() remote device is null"); 1800 return; 1801 } 1802 if (toState == STATE_DISCONNECTED && !hasBatteryService(device)) { 1803 resetBatteryLevel(device, /* isBas= */ false); 1804 } 1805 } 1806 1807 /** Handle Indicator status events from Hands-free. */ handleHfIndicatorStatus( BluetoothDevice device, int indicatorId, boolean indicatorStatus)1808 public void handleHfIndicatorStatus( 1809 BluetoothDevice device, int indicatorId, boolean indicatorStatus) { 1810 mMainHandler.post(() -> onHfIndicatorStatus(device, indicatorId, indicatorStatus)); 1811 } 1812 1813 @VisibleForTesting onHfIndicatorStatus(BluetoothDevice device, int indicatorId, boolean indicatorStatus)1814 void onHfIndicatorStatus(BluetoothDevice device, int indicatorId, boolean indicatorStatus) { 1815 if (device == null) { 1816 Log.e(TAG, "onHfIndicatorStatus() remote device is null"); 1817 return; 1818 } 1819 if (indicatorId == HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS) { 1820 getDeviceProperties(device).setHfpBatteryIndicatorStatus(indicatorStatus); 1821 } 1822 } 1823 1824 /** Handle indication events from Hands-free. */ handleHfIndicatorValueChanged( BluetoothDevice device, int indicatorId, int indicatorValue)1825 public void handleHfIndicatorValueChanged( 1826 BluetoothDevice device, int indicatorId, int indicatorValue) { 1827 mMainHandler.post(() -> onHfIndicatorValueChanged(device, indicatorId, indicatorValue)); 1828 } 1829 1830 @VisibleForTesting onHfIndicatorValueChanged(BluetoothDevice device, int indicatorId, int indicatorValue)1831 void onHfIndicatorValueChanged(BluetoothDevice device, int indicatorId, int indicatorValue) { 1832 if (device == null) { 1833 Log.e(TAG, "onHfIndicatorValueChanged() remote device is null"); 1834 return; 1835 } 1836 if (indicatorId == HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS) { 1837 updateBatteryLevel(device, indicatorValue, /* isBas= */ false); 1838 } 1839 } 1840 1841 /** Handles Headset specific Bluetooth events */ handleVendorSpecificHeadsetEvent( BluetoothDevice device, String cmd, int companyId, int cmdType, Object[] args)1842 public void handleVendorSpecificHeadsetEvent( 1843 BluetoothDevice device, String cmd, int companyId, int cmdType, Object[] args) { 1844 mMainHandler.post( 1845 () -> onVendorSpecificHeadsetEvent(device, cmd, companyId, cmdType, args)); 1846 } 1847 1848 @VisibleForTesting onVendorSpecificHeadsetEvent( BluetoothDevice device, String cmd, int companyId, int cmdType, Object[] args)1849 void onVendorSpecificHeadsetEvent( 1850 BluetoothDevice device, String cmd, int companyId, int cmdType, Object[] args) { 1851 if (device == null) { 1852 Log.e(TAG, "onVendorSpecificHeadsetEvent() remote device is null"); 1853 return; 1854 } 1855 if (companyId != BluetoothAssignedNumbers.PLANTRONICS 1856 && companyId != BluetoothAssignedNumbers.APPLE) { 1857 Log.i( 1858 TAG, 1859 "onVendorSpecificHeadsetEvent() filtered out non-PLANTRONICS and non-APPLE " 1860 + "vendor commands"); 1861 return; 1862 } 1863 if (cmd == null) { 1864 Log.e(TAG, "onVendorSpecificHeadsetEvent() command is null"); 1865 return; 1866 } 1867 // Only process set command 1868 if (cmdType != BluetoothHeadset.AT_CMD_TYPE_SET) { 1869 debugLog("onVendorSpecificHeadsetEvent() only SET command is processed"); 1870 return; 1871 } 1872 if (args == null) { 1873 Log.e(TAG, "onVendorSpecificHeadsetEvent() arguments are null"); 1874 return; 1875 } 1876 1877 if (Flags.enableBatteryLevelUpdateOnlyThroughHfIndicator()) { 1878 DeviceProperties deviceProperties = getDeviceProperties(device); 1879 if ((deviceProperties.isHfpBatteryIndicatorEnabled()) 1880 && ((BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT.equals(cmd)) 1881 || (BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV.equals( 1882 cmd)))) { 1883 infoLog( 1884 "Ignoring Battery Level update through vendor specific command as" 1885 + "HfpBatteryIndicator support is enabled."); 1886 return; 1887 } 1888 } 1889 1890 int batteryPercent = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1891 switch (cmd) { 1892 case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT: 1893 batteryPercent = getBatteryLevelFromXEventVsc(args); 1894 break; 1895 case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV: 1896 batteryPercent = getBatteryLevelFromAppleBatteryVsc(args); 1897 break; 1898 } 1899 if (batteryPercent != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { 1900 updateBatteryLevel(device, batteryPercent, /* isBas= */ false); 1901 infoLog( 1902 "Updated device " 1903 + device 1904 + " battery level to " 1905 + String.valueOf(batteryPercent) 1906 + "%"); 1907 } 1908 } 1909 1910 /** 1911 * Parse AT+IPHONEACCEV=[NumberOfIndicators],[IndicatorType],[IndicatorValue] vendor specific 1912 * event 1913 * 1914 * @param args Array of arguments on the right side of assignment 1915 * @return Battery level in percents, [0-100], {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} 1916 * when there is an error parsing the arguments 1917 */ 1918 @VisibleForTesting getBatteryLevelFromAppleBatteryVsc(Object[] args)1919 static int getBatteryLevelFromAppleBatteryVsc(Object[] args) { 1920 if (args.length == 0) { 1921 Log.w(TAG, "getBatteryLevelFromAppleBatteryVsc() empty arguments"); 1922 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1923 } 1924 int numKvPair; 1925 if (args[0] instanceof Integer) { 1926 numKvPair = (Integer) args[0]; 1927 } else { 1928 Log.w(TAG, "getBatteryLevelFromAppleBatteryVsc() error parsing number of arguments"); 1929 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1930 } 1931 if (args.length != (numKvPair * 2 + 1)) { 1932 Log.w(TAG, "getBatteryLevelFromAppleBatteryVsc() number of arguments does not match"); 1933 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1934 } 1935 int indicatorType; 1936 int indicatorValue = -1; 1937 for (int i = 0; i < numKvPair; ++i) { 1938 Object indicatorTypeObj = args[2 * i + 1]; 1939 if (indicatorTypeObj instanceof Integer) { 1940 indicatorType = (Integer) indicatorTypeObj; 1941 } else { 1942 Log.w(TAG, "getBatteryLevelFromAppleBatteryVsc() error parsing indicator type"); 1943 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1944 } 1945 if (indicatorType 1946 != BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV_BATTERY_LEVEL) { 1947 continue; 1948 } 1949 Object indicatorValueObj = args[2 * i + 2]; 1950 if (indicatorValueObj instanceof Integer) { 1951 indicatorValue = (Integer) indicatorValueObj; 1952 } else { 1953 Log.w(TAG, "getBatteryLevelFromAppleBatteryVsc() error parsing indicator value"); 1954 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1955 } 1956 break; 1957 } 1958 return (indicatorValue < 0 || indicatorValue > 9) 1959 ? BluetoothDevice.BATTERY_LEVEL_UNKNOWN 1960 : (indicatorValue + 1) * 10; 1961 } 1962 1963 /** 1964 * Parse AT+XEVENT=BATTERY,[Level],[NumberOfLevel],[MinutesOfTalk],[IsCharging] vendor specific 1965 * event 1966 * 1967 * @param args Array of arguments on the right side of SET command 1968 * @return Battery level in percents, [0-100], {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} 1969 * when there is an error parsing the arguments 1970 */ 1971 @VisibleForTesting getBatteryLevelFromXEventVsc(Object[] args)1972 static int getBatteryLevelFromXEventVsc(Object[] args) { 1973 if (args.length == 0) { 1974 Log.w(TAG, "getBatteryLevelFromXEventVsc() empty arguments"); 1975 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1976 } 1977 Object eventNameObj = args[0]; 1978 if (!(eventNameObj instanceof String)) { 1979 Log.w(TAG, "getBatteryLevelFromXEventVsc() error parsing event name"); 1980 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1981 } 1982 String eventName = (String) eventNameObj; 1983 if (!eventName.equals( 1984 BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT_BATTERY_LEVEL)) { 1985 infoLog("getBatteryLevelFromXEventVsc() skip none BATTERY event: " + eventName); 1986 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1987 } 1988 if (args.length != 5) { 1989 Log.w( 1990 TAG, 1991 "getBatteryLevelFromXEventVsc() wrong battery level event length: " 1992 + String.valueOf(args.length)); 1993 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1994 } 1995 if (!(args[1] instanceof Integer) || !(args[2] instanceof Integer)) { 1996 Log.w(TAG, "getBatteryLevelFromXEventVsc() error parsing event values"); 1997 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 1998 } 1999 int batteryLevel = (Integer) args[1]; 2000 int numberOfLevels = (Integer) args[2]; 2001 if (batteryLevel < 0 || numberOfLevels <= 1 || batteryLevel > numberOfLevels) { 2002 Log.w( 2003 TAG, 2004 "getBatteryLevelFromXEventVsc() wrong event value, batteryLevel=" 2005 + String.valueOf(batteryLevel) 2006 + ", numberOfLevels=" 2007 + String.valueOf(numberOfLevels)); 2008 return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 2009 } 2010 return batteryLevel * 100 / (numberOfLevels - 1); 2011 } 2012 2013 @VisibleForTesting hasBatteryService(BluetoothDevice device)2014 boolean hasBatteryService(BluetoothDevice device) { 2015 BatteryService batteryService = BatteryService.getBatteryService(); 2016 return batteryService != null 2017 && batteryService.getConnectionState(device) == STATE_CONNECTED; 2018 } 2019 2020 /** Handles headset client connection state change event. */ handleHeadsetClientConnectionStateChanged( BluetoothDevice device, int fromState, int toState)2021 public void handleHeadsetClientConnectionStateChanged( 2022 BluetoothDevice device, int fromState, int toState) { 2023 mMainHandler.post(() -> onHeadsetClientConnectionStateChanged(device, fromState, toState)); 2024 } 2025 2026 @VisibleForTesting onHeadsetClientConnectionStateChanged(BluetoothDevice device, int fromState, int toState)2027 void onHeadsetClientConnectionStateChanged(BluetoothDevice device, int fromState, int toState) { 2028 if (device == null) { 2029 Log.e(TAG, "onHeadsetClientConnectionStateChanged() remote device is null"); 2030 return; 2031 } 2032 if (toState == STATE_DISCONNECTED && !hasBatteryService(device)) { 2033 resetBatteryLevel(device, /* isBas= */ false); 2034 } 2035 } 2036 2037 /** Handle battery level changes indication events from Audio Gateway. */ handleAgBatteryLevelChanged(BluetoothDevice device, int batteryLevel)2038 public void handleAgBatteryLevelChanged(BluetoothDevice device, int batteryLevel) { 2039 mMainHandler.post(() -> onAgBatteryLevelChanged(device, batteryLevel)); 2040 } 2041 2042 @VisibleForTesting onAgBatteryLevelChanged(BluetoothDevice device, int batteryLevel)2043 void onAgBatteryLevelChanged(BluetoothDevice device, int batteryLevel) { 2044 if (device == null) { 2045 Log.e(TAG, "onAgBatteryLevelChanged() remote device is null"); 2046 return; 2047 } 2048 updateBatteryLevel( 2049 device, batteryChargeIndicatorToPercentage(batteryLevel), /* isBas= */ false); 2050 } 2051 2052 private static final String[] BOND_LOSS_IOP_PACKAGES = { 2053 "com.sjm.crmd.patientApp_Android", "com.abbott.crm.ngq.patient", 2054 }; 2055 2056 private static final Set<String> BOND_LOSS_IOP_DEVICE_NAMES = Set.of("CM", "DM"); 2057 2058 // TODO (b/402854328): Remove when the misbehaving apps are updated bondLossIopFixNeeded(BluetoothDevice device)2059 public boolean bondLossIopFixNeeded(BluetoothDevice device) { 2060 DeviceProperties deviceProperties = getDeviceProperties(device); 2061 if (deviceProperties == null) { 2062 return false; 2063 } 2064 2065 String deviceName = deviceProperties.getName(); 2066 if (deviceName == null) { 2067 return false; 2068 } 2069 2070 String[] packages = deviceProperties.getPackages(); 2071 if (packages.length == 0) { 2072 return false; 2073 } 2074 2075 if (!BOND_LOSS_IOP_DEVICE_NAMES.contains(deviceName)) { 2076 return false; 2077 } 2078 2079 for (String iopFixPackage : BOND_LOSS_IOP_PACKAGES) { 2080 for (String packageName : packages) { 2081 if (packageName.contains(iopFixPackage) 2082 && !Utils.checkCallerTargetSdk( 2083 mAdapterService, packageName, Build.VERSION_CODES.BAKLAVA)) { 2084 Log.w( 2085 TAG, 2086 "bondLossIopFixNeeded(): " 2087 + " IOP fix needed for " 2088 + device 2089 + " name: " 2090 + deviceName 2091 + " package: " 2092 + packageName); 2093 return true; 2094 } 2095 } 2096 } 2097 2098 return false; 2099 } 2100 errorLog(String msg)2101 private static void errorLog(String msg) { 2102 Log.e(TAG, msg); 2103 } 2104 debugLog(String msg)2105 private static void debugLog(String msg) { 2106 Log.d(TAG, msg); 2107 } 2108 infoLog(String msg)2109 private static void infoLog(String msg) { 2110 Log.i(TAG, msg); 2111 } 2112 warnLog(String msg)2113 private static void warnLog(String msg) { 2114 Log.w(TAG, msg); 2115 } 2116 } 2117