1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * Copyright (C) 2016-2017 The Linux Foundation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bluetooth.btservice; 19 20 import static android.Manifest.permission.BLUETOOTH_CONNECT; 21 import static android.Manifest.permission.BLUETOOTH_SCAN; 22 23 import android.annotation.NonNull; 24 import android.annotation.RequiresPermission; 25 import android.app.BroadcastOptions; 26 import android.bluetooth.BluetoothA2dp; 27 import android.bluetooth.BluetoothA2dpSink; 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.BluetoothAvrcpController; 30 import android.bluetooth.BluetoothClass; 31 import android.bluetooth.BluetoothDevice; 32 import android.bluetooth.BluetoothHeadset; 33 import android.bluetooth.BluetoothHeadsetClient; 34 import android.bluetooth.BluetoothHearingAid; 35 import android.bluetooth.BluetoothHidDevice; 36 import android.bluetooth.BluetoothHidHost; 37 import android.bluetooth.BluetoothLeAudio; 38 import android.bluetooth.BluetoothMap; 39 import android.bluetooth.BluetoothMapClient; 40 import android.bluetooth.BluetoothPan; 41 import android.bluetooth.BluetoothPbap; 42 import android.bluetooth.BluetoothPbapClient; 43 import android.bluetooth.BluetoothProfile; 44 import android.bluetooth.BluetoothSap; 45 import android.bluetooth.BufferConstraint; 46 import android.bluetooth.BufferConstraints; 47 import android.content.BroadcastReceiver; 48 import android.content.Context; 49 import android.content.Intent; 50 import android.content.IntentFilter; 51 import android.os.Bundle; 52 import android.os.ParcelUuid; 53 import android.os.SystemProperties; 54 import android.os.UserHandle; 55 import android.util.Log; 56 import android.util.Pair; 57 58 import androidx.annotation.VisibleForTesting; 59 60 import com.android.bluetooth.BluetoothStatsLog; 61 import com.android.bluetooth.Utils; 62 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 63 import com.android.bluetooth.flags.Flags; 64 import com.android.modules.utils.build.SdkLevel; 65 66 import com.google.common.collect.EvictingQueue; 67 68 import java.io.FileDescriptor; 69 import java.io.PrintWriter; 70 import java.util.ArrayList; 71 import java.util.HashMap; 72 import java.util.List; 73 import java.util.concurrent.CompletableFuture; 74 import java.util.concurrent.CopyOnWriteArrayList; 75 76 class AdapterProperties { 77 private static final String TAG = "AdapterProperties"; 78 79 private static final String MAX_CONNECTED_AUDIO_DEVICES_PROPERTY = 80 "persist.bluetooth.maxconnectedaudiodevices"; 81 private static final int MAX_CONNECTED_AUDIO_DEVICES_LOWER_BOUND = 1; 82 private static final int MAX_CONNECTED_AUDIO_DEVICES_UPPER_BOUND = 5; 83 private static final String A2DP_OFFLOAD_SUPPORTED_PROPERTY = 84 "ro.bluetooth.a2dp_offload.supported"; 85 private static final String A2DP_OFFLOAD_DISABLED_PROPERTY = 86 "persist.bluetooth.a2dp_offload.disabled"; 87 88 private static final long DEFAULT_DISCOVERY_TIMEOUT_MS = 12800; 89 @VisibleForTesting static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248; 90 private static final int BD_ADDR_LEN = 6; // in bytes 91 private static final int SYSTEM_CONNECTION_LATENCY_METRIC = 65536; 92 93 private volatile String mName; 94 private volatile byte[] mAddress; 95 private volatile BluetoothClass mBluetoothClass; 96 private volatile int mScanMode; 97 private volatile int mDiscoverableTimeout; 98 private volatile ParcelUuid[] mUuids; 99 100 private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices = 101 new CopyOnWriteArrayList<BluetoothDevice>(); 102 103 private static final int SCAN_MODE_CHANGES_MAX_SIZE = 10; 104 private EvictingQueue<String> mScanModeChanges; 105 106 private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting; 107 private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState = 108 new HashMap<>(); 109 110 private final CompletableFuture<List<BufferConstraint>> mBufferConstraintList = 111 new CompletableFuture<>(); 112 113 private volatile int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED; 114 private volatile int mState = BluetoothAdapter.STATE_OFF; 115 private int mMaxConnectedAudioDevices = 1; 116 private boolean mA2dpOffloadEnabled = false; 117 118 private AdapterService mService; 119 private boolean mDiscovering; 120 private long mDiscoveryEndMs; // < Time (ms since epoch) that discovery ended or will end. 121 private RemoteDevices mRemoteDevices; 122 private BluetoothAdapter mAdapter; 123 // TODO - all hw capabilities to be exposed as a class 124 private int mNumOfAdvertisementInstancesSupported; 125 private boolean mRpaOffloadSupported; 126 private int mNumOfOffloadedIrkSupported; 127 private int mNumOfOffloadedScanFilterSupported; 128 private int mOffloadedScanResultStorageBytes; 129 private int mVersSupported; 130 private int mTotNumOfTrackableAdv; 131 private boolean mIsExtendedScanSupported; 132 private boolean mIsDebugLogSupported; 133 private boolean mIsActivityAndEnergyReporting; 134 private boolean mIsLe2MPhySupported; 135 private boolean mIsLeCodedPhySupported; 136 private boolean mIsLeExtendedAdvertisingSupported; 137 private boolean mIsLePeriodicAdvertisingSupported; 138 private int mLeMaximumAdvertisingDataLength; 139 private boolean mIsOffloadedTransportDiscoveryDataScanSupported; 140 141 private int mIsDynamicAudioBufferSizeSupported; 142 private int mDynamicAudioBufferSizeSupportedCodecsGroup1; 143 private int mDynamicAudioBufferSizeSupportedCodecsGroup2; 144 145 private boolean mIsLePeriodicAdvertisingSyncTransferSenderSupported; 146 private boolean mIsLePeriodicAdvertisingSyncTransferRecipientSupported; 147 private boolean mIsLeConnectedIsochronousStreamCentralSupported; 148 private boolean mIsLeIsochronousBroadcasterSupported; 149 private boolean mIsLeChannelSoundingSupported; 150 151 private boolean mReceiverRegistered; 152 153 private final BroadcastReceiver mReceiver = 154 new BroadcastReceiver() { 155 @Override 156 public void onReceive(Context context, Intent intent) { 157 String action = intent.getAction(); 158 if (action == null) { 159 Log.w(TAG, "Received intent with null action"); 160 return; 161 } 162 switch (action) { 163 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 164 logConnectionStateChanges(BluetoothProfile.HEADSET, intent); 165 break; 166 case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: 167 logConnectionStateChanges(BluetoothProfile.A2DP, intent); 168 break; 169 case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED: 170 logConnectionStateChanges(BluetoothProfile.HEADSET_CLIENT, intent); 171 break; 172 case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: 173 logConnectionStateChanges(BluetoothProfile.HEARING_AID, intent); 174 break; 175 case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED: 176 logConnectionStateChanges(BluetoothProfile.A2DP_SINK, intent); 177 break; 178 case BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED: 179 logConnectionStateChanges(BluetoothProfile.HID_DEVICE, intent); 180 break; 181 case BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED: 182 logConnectionStateChanges(BluetoothProfile.HID_HOST, intent); 183 break; 184 case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED: 185 logConnectionStateChanges(BluetoothProfile.AVRCP_CONTROLLER, intent); 186 break; 187 case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED: 188 logConnectionStateChanges(BluetoothProfile.PAN, intent); 189 break; 190 case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED: 191 logConnectionStateChanges(BluetoothProfile.MAP, intent); 192 break; 193 case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED: 194 logConnectionStateChanges(BluetoothProfile.MAP_CLIENT, intent); 195 break; 196 case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED: 197 logConnectionStateChanges(BluetoothProfile.SAP, intent); 198 break; 199 case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED: 200 logConnectionStateChanges(BluetoothProfile.PBAP_CLIENT, intent); 201 break; 202 case BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED: 203 logConnectionStateChanges(BluetoothProfile.PBAP, intent); 204 break; 205 case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED: 206 logConnectionStateChanges(BluetoothProfile.LE_AUDIO, intent); 207 break; 208 default: 209 Log.w(TAG, "Received unknown intent " + intent); 210 break; 211 } 212 } 213 }; 214 215 // Lock for all getters and setters. 216 // If finer grained locking is needer, more locks 217 // can be added here. 218 private final Object mObject = new Object(); 219 AdapterProperties(AdapterService service)220 AdapterProperties(AdapterService service) { 221 mService = service; 222 mAdapter = BluetoothAdapter.getDefaultAdapter(); 223 mScanModeChanges = EvictingQueue.create(SCAN_MODE_CHANGES_MAX_SIZE); 224 invalidateBluetoothCaches(); 225 } 226 init(RemoteDevices remoteDevices)227 public void init(RemoteDevices remoteDevices) { 228 mProfileConnectionState.clear(); 229 mRemoteDevices = remoteDevices; 230 231 // Get default max connected audio devices from config.xml 232 int configDefaultMaxConnectedAudioDevices = 233 mService.getResources() 234 .getInteger( 235 com.android.bluetooth.R.integer 236 .config_bluetooth_max_connected_audio_devices); 237 // Override max connected audio devices if MAX_CONNECTED_AUDIO_DEVICES_PROPERTY is set 238 int propertyOverlayedMaxConnectedAudioDevices = 239 SystemProperties.getInt( 240 MAX_CONNECTED_AUDIO_DEVICES_PROPERTY, 241 configDefaultMaxConnectedAudioDevices); 242 // Make sure the final value of max connected audio devices is within allowed range 243 mMaxConnectedAudioDevices = 244 Math.min( 245 Math.max( 246 propertyOverlayedMaxConnectedAudioDevices, 247 MAX_CONNECTED_AUDIO_DEVICES_LOWER_BOUND), 248 MAX_CONNECTED_AUDIO_DEVICES_UPPER_BOUND); 249 Log.i( 250 TAG, 251 "init(), maxConnectedAudioDevices, default=" 252 + configDefaultMaxConnectedAudioDevices 253 + ", propertyOverlayed=" 254 + propertyOverlayedMaxConnectedAudioDevices 255 + ", finalValue=" 256 + mMaxConnectedAudioDevices); 257 258 mA2dpOffloadEnabled = 259 SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false) 260 && !SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false); 261 262 IntentFilter filter = new IntentFilter(); 263 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 264 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 265 filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); 266 filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); 267 filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 268 filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); 269 filter.addAction(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED); 270 filter.addAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED); 271 filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED); 272 filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 273 filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); 274 filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED); 275 filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); 276 filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED); 277 filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); 278 mService.registerReceiver(mReceiver, filter); 279 mReceiverRegistered = true; 280 invalidateBluetoothCaches(); 281 } 282 cleanup()283 public void cleanup() { 284 mRemoteDevices = null; 285 mProfileConnectionState.clear(); 286 287 if (mReceiverRegistered) { 288 mService.unregisterReceiver(mReceiver); 289 mReceiverRegistered = false; 290 } 291 mService = null; 292 mBondedDevices.clear(); 293 mScanModeChanges.clear(); 294 invalidateBluetoothCaches(); 295 } 296 invalidateGetProfileConnectionStateCache()297 private static void invalidateGetProfileConnectionStateCache() { 298 BluetoothAdapter.invalidateGetProfileConnectionStateCache(); 299 } 300 invalidateIsOffloadedFilteringSupportedCache()301 private static void invalidateIsOffloadedFilteringSupportedCache() { 302 BluetoothAdapter.invalidateIsOffloadedFilteringSupportedCache(); 303 } 304 invalidateBluetoothGetConnectionStateCache()305 private static void invalidateBluetoothGetConnectionStateCache() { 306 BluetoothMap.invalidateBluetoothGetConnectionStateCache(); 307 BluetoothSap.invalidateBluetoothGetConnectionStateCache(); 308 } 309 invalidateGetConnectionStateCache()310 private static void invalidateGetConnectionStateCache() { 311 BluetoothAdapter.invalidateGetAdapterConnectionStateCache(); 312 } 313 invalidateGetBondStateCache()314 private static void invalidateGetBondStateCache() { 315 BluetoothDevice.invalidateBluetoothGetBondStateCache(); 316 } 317 invalidateBluetoothCaches()318 private static void invalidateBluetoothCaches() { 319 invalidateGetProfileConnectionStateCache(); 320 invalidateIsOffloadedFilteringSupportedCache(); 321 invalidateGetConnectionStateCache(); 322 invalidateGetBondStateCache(); 323 invalidateBluetoothGetConnectionStateCache(); 324 } 325 326 @Override clone()327 public Object clone() throws CloneNotSupportedException { 328 throw new CloneNotSupportedException(); 329 } 330 331 /** 332 * @return the mName 333 */ getName()334 String getName() { 335 return mName; 336 } 337 338 /** 339 * Set the local adapter property - name 340 * 341 * @param name the name to set 342 */ setName(String name)343 boolean setName(String name) { 344 synchronized (mObject) { 345 return mService.getNative() 346 .setAdapterProperty( 347 AbstractionLayer.BT_PROPERTY_BDNAME, 348 Utils.truncateStringForUtf8Storage( 349 name, BLUETOOTH_NAME_MAX_LENGTH_BYTES) 350 .getBytes()); 351 } 352 } 353 354 /** 355 * @return the mScanMode 356 */ getScanMode()357 int getScanMode() { 358 return mScanMode; 359 } 360 361 /** 362 * Set the local adapter property - scanMode 363 * 364 * @param scanMode the ScanMode to set, valid values are: { BluetoothAdapter.SCAN_MODE_NONE, 365 * BluetoothAdapter.SCAN_MODE_CONNECTABLE, 366 * BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, } 367 */ setScanMode(int scanMode)368 boolean setScanMode(int scanMode) { 369 addScanChangeLog(scanMode); 370 synchronized (mObject) { 371 return mService.getNative() 372 .setAdapterProperty( 373 AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE, 374 Utils.intToByteArray(AdapterService.convertScanModeToHal(scanMode))); 375 } 376 } 377 addScanChangeLog(int scanMode)378 private void addScanChangeLog(int scanMode) { 379 String time = Utils.getLocalTimeString(); 380 String uidPid = Utils.getUidPidString(); 381 String scanModeString = dumpScanMode(scanMode); 382 383 mScanModeChanges.add(time + " (" + uidPid + ") " + scanModeString); 384 } 385 386 /** 387 * @return the mUuids 388 */ getUuids()389 ParcelUuid[] getUuids() { 390 return mUuids; 391 } 392 393 /** 394 * @return the mAddress 395 */ getAddress()396 byte[] getAddress() { 397 return mAddress; 398 } 399 400 /** 401 * @param connectionState the mConnectionState to set 402 */ setConnectionState(int connectionState)403 void setConnectionState(int connectionState) { 404 mConnectionState = connectionState; 405 invalidateGetConnectionStateCache(); 406 } 407 408 /** 409 * @return the mConnectionState 410 */ getConnectionState()411 int getConnectionState() { 412 return mConnectionState; 413 } 414 415 /** 416 * @param state the mState to set 417 */ setState(int state)418 void setState(int state) { 419 debugLog("Setting state to " + BluetoothAdapter.nameForState(state)); 420 mState = state; 421 } 422 423 /** 424 * @return the mState 425 */ getState()426 int getState() { 427 return mState; 428 } 429 430 /** 431 * @return the mNumOfAdvertisementInstancesSupported 432 */ getNumOfAdvertisementInstancesSupported()433 int getNumOfAdvertisementInstancesSupported() { 434 return mNumOfAdvertisementInstancesSupported; 435 } 436 437 /** 438 * @return the mRpaOffloadSupported 439 */ isRpaOffloadSupported()440 boolean isRpaOffloadSupported() { 441 return mRpaOffloadSupported; 442 } 443 444 /** 445 * @return the mNumOfOffloadedIrkSupported 446 */ getNumOfOffloadedIrkSupported()447 int getNumOfOffloadedIrkSupported() { 448 return mNumOfOffloadedIrkSupported; 449 } 450 451 /** 452 * @return the mNumOfOffloadedScanFilterSupported 453 */ getNumOfOffloadedScanFilterSupported()454 int getNumOfOffloadedScanFilterSupported() { 455 return mNumOfOffloadedScanFilterSupported; 456 } 457 458 /** 459 * @return the mOffloadedScanResultStorageBytes 460 */ getOffloadedScanResultStorage()461 int getOffloadedScanResultStorage() { 462 return mOffloadedScanResultStorageBytes; 463 } 464 465 /** 466 * @return tx/rx/idle activity and energy info 467 */ isActivityAndEnergyReportingSupported()468 boolean isActivityAndEnergyReportingSupported() { 469 return mIsActivityAndEnergyReporting; 470 } 471 472 /** 473 * @return the mIsLe2MPhySupported 474 */ isLe2MPhySupported()475 boolean isLe2MPhySupported() { 476 return mIsLe2MPhySupported; 477 } 478 479 /** 480 * @return the mIsLeCodedPhySupported 481 */ isLeCodedPhySupported()482 boolean isLeCodedPhySupported() { 483 return mIsLeCodedPhySupported; 484 } 485 486 /** 487 * @return the mIsLeExtendedAdvertisingSupported 488 */ isLeExtendedAdvertisingSupported()489 boolean isLeExtendedAdvertisingSupported() { 490 return mIsLeExtendedAdvertisingSupported; 491 } 492 493 /** 494 * @return the mIsLePeriodicAdvertisingSupported 495 */ isLePeriodicAdvertisingSupported()496 boolean isLePeriodicAdvertisingSupported() { 497 return mIsLePeriodicAdvertisingSupported; 498 } 499 500 /** 501 * @return the mIsLePeriodicAdvertisingSyncTransferSenderSupported 502 */ isLePeriodicAdvertisingSyncTransferSenderSupported()503 boolean isLePeriodicAdvertisingSyncTransferSenderSupported() { 504 return mIsLePeriodicAdvertisingSyncTransferSenderSupported; 505 } 506 507 /** 508 * @return the mIsLePeriodicAdvertisingSyncTransferRecipientSupported 509 */ isLePeriodicAdvertisingSyncTransferRecipientSupported()510 boolean isLePeriodicAdvertisingSyncTransferRecipientSupported() { 511 return mIsLePeriodicAdvertisingSyncTransferRecipientSupported; 512 } 513 514 /** 515 * @return the mIsLeConnectedIsochronousStreamCentralSupported 516 */ isLeConnectedIsochronousStreamCentralSupported()517 boolean isLeConnectedIsochronousStreamCentralSupported() { 518 return mIsLeConnectedIsochronousStreamCentralSupported; 519 } 520 521 /** 522 * @return the mIsLeIsochronousBroadcasterSupported 523 */ isLeIsochronousBroadcasterSupported()524 boolean isLeIsochronousBroadcasterSupported() { 525 return mIsLeIsochronousBroadcasterSupported; 526 } 527 528 /** 529 * @return the mIsLeChannelSoundingSupported 530 */ isLeChannelSoundingSupported()531 boolean isLeChannelSoundingSupported() { 532 return mIsLeChannelSoundingSupported; 533 } 534 535 /** 536 * @return the getLeMaximumAdvertisingDataLength 537 */ getLeMaximumAdvertisingDataLength()538 int getLeMaximumAdvertisingDataLength() { 539 return mLeMaximumAdvertisingDataLength; 540 } 541 542 /** 543 * @return total number of trackable advertisements 544 */ getTotalNumOfTrackableAdvertisements()545 int getTotalNumOfTrackableAdvertisements() { 546 return mTotNumOfTrackableAdv; 547 } 548 549 /** 550 * @return the isOffloadedTransportDiscoveryDataScanSupported 551 */ isOffloadedTransportDiscoveryDataScanSupported()552 public boolean isOffloadedTransportDiscoveryDataScanSupported() { 553 return mIsOffloadedTransportDiscoveryDataScanSupported; 554 } 555 556 /** 557 * @return the maximum number of connected audio devices 558 */ getMaxConnectedAudioDevices()559 int getMaxConnectedAudioDevices() { 560 return mMaxConnectedAudioDevices; 561 } 562 563 /** 564 * @return A2DP offload support 565 */ isA2dpOffloadEnabled()566 boolean isA2dpOffloadEnabled() { 567 return mA2dpOffloadEnabled; 568 } 569 570 /** 571 * @return Dynamic Audio Buffer support 572 */ getDynamicBufferSupport()573 int getDynamicBufferSupport() { 574 if (!mA2dpOffloadEnabled) { 575 // TODO: Enable Dynamic Audio Buffer for A2DP software encoding when ready. 576 mIsDynamicAudioBufferSizeSupported = BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; 577 } else { 578 if ((mDynamicAudioBufferSizeSupportedCodecsGroup1 != 0) 579 || (mDynamicAudioBufferSizeSupportedCodecsGroup2 != 0)) { 580 mIsDynamicAudioBufferSizeSupported = 581 BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD; 582 } else { 583 mIsDynamicAudioBufferSizeSupported = BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; 584 } 585 } 586 return mIsDynamicAudioBufferSizeSupported; 587 } 588 589 /** 590 * @return Dynamic Audio Buffer Capability 591 */ getBufferConstraints()592 BufferConstraints getBufferConstraints() { 593 return new BufferConstraints(mBufferConstraintList.join()); 594 } 595 596 /** 597 * Set the dynamic audio buffer size 598 * 599 * @param codec the codecs to set 600 * @param size the size to set 601 */ setBufferLengthMillis(int codec, int size)602 boolean setBufferLengthMillis(int codec, int size) { 603 return mService.getNative().setBufferLengthMillis(codec, size); 604 } 605 606 /** 607 * @return the mBondedDevices 608 */ getBondedDevices()609 BluetoothDevice[] getBondedDevices() { 610 BluetoothDevice[] bondedDeviceList = new BluetoothDevice[0]; 611 try { 612 bondedDeviceList = mBondedDevices.toArray(bondedDeviceList); 613 } catch (ArrayStoreException ee) { 614 Log.e(TAG, "Error retrieving bonded device array"); 615 } 616 infoLog("getBondedDevices: length=" + bondedDeviceList.length); 617 return bondedDeviceList; 618 } 619 620 // This function shall be invoked from BondStateMachine whenever the bond 621 // state changes. 622 @VisibleForTesting onBondStateChanged(BluetoothDevice device, int state)623 void onBondStateChanged(BluetoothDevice device, int state) { 624 if (device == null) { 625 Log.w(TAG, "onBondStateChanged, device is null"); 626 return; 627 } 628 try { 629 byte[] addrByte = Utils.getByteAddress(device); 630 DeviceProperties prop = mRemoteDevices.getDeviceProperties(device); 631 if (prop == null) { 632 prop = mRemoteDevices.addDeviceProperties(addrByte); 633 } 634 device = prop.getDevice(); 635 prop.setBondState(state); 636 637 if (state == BluetoothDevice.BOND_BONDED) { 638 // add if not already in list 639 if (!mBondedDevices.contains(device)) { 640 debugLog("Adding bonded device:" + device); 641 mBondedDevices.add(device); 642 cleanupPrevBondRecordsFor(device); 643 } 644 } else if (state == BluetoothDevice.BOND_NONE) { 645 // remove device from list 646 if (mBondedDevices.remove(device)) { 647 debugLog("Removing bonded device:" + device); 648 } else { 649 debugLog("Failed to remove device: " + device); 650 } 651 } 652 invalidateGetBondStateCache(); 653 } catch (Exception ee) { 654 Log.w(TAG, "onBondStateChanged: Exception ", ee); 655 } 656 } 657 cleanupPrevBondRecordsFor(BluetoothDevice device)658 void cleanupPrevBondRecordsFor(BluetoothDevice device) { 659 String address = device.getAddress(); 660 String identityAddress = 661 Flags.identityAddressNullIfUnknown() 662 ? Utils.getBrEdrAddress(device, mService) 663 : mService.getIdentityAddress(address); 664 int deviceType = mRemoteDevices.getDeviceProperties(device).getDeviceType(); 665 debugLog("cleanupPrevBondRecordsFor: " + device + ", device type: " + deviceType); 666 if (identityAddress == null) { 667 return; 668 } 669 670 if (Flags.cleanupLeOnlyDeviceType() && deviceType != BluetoothDevice.DEVICE_TYPE_LE) { 671 return; 672 } 673 674 for (BluetoothDevice existingDevice : mBondedDevices) { 675 String existingAddress = existingDevice.getAddress(); 676 String existingIdentityAddress = 677 Flags.identityAddressNullIfUnknown() 678 ? Utils.getBrEdrAddress(existingDevice, mService) 679 : mService.getIdentityAddress(existingAddress); 680 int existingDeviceType = 681 mRemoteDevices.getDeviceProperties(existingDevice).getDeviceType(); 682 683 boolean removeExisting = false; 684 if (identityAddress.equals(existingIdentityAddress) 685 && !address.equals(existingAddress)) { 686 if (Flags.cleanupLeOnlyDeviceType()) { 687 // Existing device record should be removed only if the device type is LE-only 688 removeExisting = (existingDeviceType == BluetoothDevice.DEVICE_TYPE_LE); 689 } else { 690 removeExisting = true; 691 } 692 } 693 694 if (removeExisting) { 695 // Found an existing LE-only device with the same identity address but different 696 // pseudo address 697 if (mService.getNative().removeBond(Utils.getBytesFromAddress(existingAddress))) { 698 mBondedDevices.remove(existingDevice); 699 infoLog( 700 "Removing old bond record: " 701 + existingDevice 702 + " for the device: " 703 + device); 704 } else { 705 Log.e( 706 TAG, 707 "Unexpected error while removing old bond record:" 708 + existingDevice 709 + " for the device: " 710 + device); 711 } 712 break; 713 } 714 } 715 } 716 getDiscoverableTimeout()717 int getDiscoverableTimeout() { 718 return mDiscoverableTimeout; 719 } 720 setDiscoverableTimeout(int timeout)721 boolean setDiscoverableTimeout(int timeout) { 722 synchronized (mObject) { 723 return mService.getNative() 724 .setAdapterProperty( 725 AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT, 726 Utils.intToByteArray(timeout)); 727 } 728 } 729 getProfileConnectionState(int profile)730 int getProfileConnectionState(int profile) { 731 synchronized (mObject) { 732 Pair<Integer, Integer> p = mProfileConnectionState.get(profile); 733 if (p != null) { 734 return p.first; 735 } 736 return BluetoothProfile.STATE_DISCONNECTED; 737 } 738 } 739 discoveryEndMillis()740 long discoveryEndMillis() { 741 return mDiscoveryEndMs; 742 } 743 isDiscovering()744 boolean isDiscovering() { 745 return mDiscovering; 746 } 747 748 @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) logConnectionStateChanges(int profile, Intent connIntent)749 private void logConnectionStateChanges(int profile, Intent connIntent) { 750 BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 751 int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 752 int metricId = mService.getMetricId(device); 753 byte[] remoteDeviceInfoBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(device); 754 if (state == BluetoothProfile.STATE_CONNECTING) { 755 BluetoothStatsLog.write( 756 BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED, metricId, device.getName()); 757 BluetoothStatsLog.write( 758 BluetoothStatsLog.REMOTE_DEVICE_INFORMATION_WITH_METRIC_ID, 759 metricId, 760 remoteDeviceInfoBytes); 761 MetricsLogger.getInstance() 762 .logAllowlistedDeviceNameHash(metricId, device.getName(), true); 763 } 764 BluetoothStatsLog.write( 765 BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED, 766 state, 767 0 /* deprecated */, 768 profile, 769 mService.obfuscateAddress(device), 770 metricId, 771 0, 772 -1); 773 } 774 775 @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) updateOnProfileConnectionChanged( BluetoothDevice device, int profile, int newState, int prevState)776 void updateOnProfileConnectionChanged( 777 BluetoothDevice device, int profile, int newState, int prevState) { 778 String logInfo = 779 ("profile=" + BluetoothProfile.getProfileName(profile)) 780 + (" device=" + device) 781 + (" state [" + prevState + " -> " + newState + "]"); 782 Log.d(TAG, "updateOnProfileConnectionChanged: " + logInfo); 783 if (!isNormalStateTransition(prevState, newState)) { 784 Log.w(TAG, "updateOnProfileConnectionChanged: Unexpected transition. " + logInfo); 785 } 786 BluetoothStatsLog.write( 787 BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED, 788 newState, 789 0 /* deprecated */, 790 profile, 791 mService.obfuscateAddress(device), 792 mService.getMetricId(device), 793 0, 794 SYSTEM_CONNECTION_LATENCY_METRIC); 795 if (!validateProfileConnectionState(newState) 796 || !validateProfileConnectionState(prevState)) { 797 // Previously, an invalid state was broadcast anyway, 798 // with the invalid state converted to -1 in the intent. 799 // Better to log an error and not send an intent with 800 // invalid contents or set mAdapterConnectionState to -1. 801 Log.e(TAG, "updateOnProfileConnectionChanged: Invalid transition. " + logInfo); 802 return; 803 } 804 805 synchronized (mObject) { 806 updateProfileConnectionState(profile, newState, prevState); 807 808 if (updateCountersAndCheckForConnectionStateChange(newState, prevState)) { 809 int newAdapterState = convertToAdapterState(newState); 810 int prevAdapterState = convertToAdapterState(prevState); 811 setConnectionState(newAdapterState); 812 813 Intent intent = 814 new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED) 815 .putExtra(BluetoothDevice.EXTRA_DEVICE, device) 816 .putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, newAdapterState) 817 .putExtra( 818 BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, 819 prevAdapterState) 820 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 821 Log.d(TAG, "updateOnProfileConnectionChanged: " + logInfo); 822 mService.sendBroadcastAsUser( 823 intent, 824 UserHandle.ALL, 825 BLUETOOTH_CONNECT, 826 Utils.getTempBroadcastOptions().toBundle()); 827 } 828 } 829 } 830 validateProfileConnectionState(int state)831 private boolean validateProfileConnectionState(int state) { 832 return (state == BluetoothProfile.STATE_DISCONNECTED 833 || state == BluetoothProfile.STATE_CONNECTING 834 || state == BluetoothProfile.STATE_CONNECTED 835 || state == BluetoothProfile.STATE_DISCONNECTING); 836 } 837 convertToAdapterState(int state)838 private static int convertToAdapterState(int state) { 839 switch (state) { 840 case BluetoothProfile.STATE_DISCONNECTED: 841 return BluetoothAdapter.STATE_DISCONNECTED; 842 case BluetoothProfile.STATE_DISCONNECTING: 843 return BluetoothAdapter.STATE_DISCONNECTING; 844 case BluetoothProfile.STATE_CONNECTED: 845 return BluetoothAdapter.STATE_CONNECTED; 846 case BluetoothProfile.STATE_CONNECTING: 847 return BluetoothAdapter.STATE_CONNECTING; 848 } 849 Log.e(TAG, "convertToAdapterState, unknow state " + state); 850 return -1; 851 } 852 isNormalStateTransition(int prevState, int nextState)853 private static boolean isNormalStateTransition(int prevState, int nextState) { 854 switch (prevState) { 855 case BluetoothProfile.STATE_DISCONNECTED: 856 return nextState == BluetoothProfile.STATE_CONNECTING; 857 case BluetoothProfile.STATE_CONNECTED: 858 return nextState == BluetoothProfile.STATE_DISCONNECTING; 859 case BluetoothProfile.STATE_DISCONNECTING: 860 case BluetoothProfile.STATE_CONNECTING: 861 return (nextState == BluetoothProfile.STATE_DISCONNECTED) 862 || (nextState == BluetoothProfile.STATE_CONNECTED); 863 default: 864 return false; 865 } 866 } 867 updateCountersAndCheckForConnectionStateChange(int state, int prevState)868 private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) { 869 switch (prevState) { 870 case BluetoothProfile.STATE_CONNECTING: 871 if (mProfilesConnecting > 0) { 872 mProfilesConnecting--; 873 } else { 874 Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting); 875 throw new IllegalStateException( 876 "Invalid state transition, " + prevState + " -> " + state); 877 } 878 break; 879 880 case BluetoothProfile.STATE_CONNECTED: 881 if (mProfilesConnected > 0) { 882 mProfilesConnected--; 883 } else { 884 Log.e(TAG, "mProfilesConnected " + mProfilesConnected); 885 throw new IllegalStateException( 886 "Invalid state transition, " + prevState + " -> " + state); 887 } 888 break; 889 890 case BluetoothProfile.STATE_DISCONNECTING: 891 if (mProfilesDisconnecting > 0) { 892 mProfilesDisconnecting--; 893 } else { 894 Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting); 895 throw new IllegalStateException( 896 "Invalid state transition, " + prevState + " -> " + state); 897 } 898 break; 899 } 900 901 switch (state) { 902 case BluetoothProfile.STATE_CONNECTING: 903 mProfilesConnecting++; 904 return (mProfilesConnected == 0 && mProfilesConnecting == 1); 905 906 case BluetoothProfile.STATE_CONNECTED: 907 mProfilesConnected++; 908 return (mProfilesConnected == 1); 909 910 case BluetoothProfile.STATE_DISCONNECTING: 911 mProfilesDisconnecting++; 912 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1); 913 914 case BluetoothProfile.STATE_DISCONNECTED: 915 return (mProfilesConnected == 0 && mProfilesConnecting == 0); 916 917 default: 918 return true; 919 } 920 } 921 updateProfileConnectionState(int profile, int newState, int oldState)922 private void updateProfileConnectionState(int profile, int newState, int oldState) { 923 // mProfileConnectionState is a hashmap - 924 // <Integer, Pair<Integer, Integer>> 925 // The key is the profile, the value is a pair. first element 926 // is the state and the second element is the number of devices 927 // in that state. 928 int numDev = 1; 929 int newHashState = newState; 930 boolean update = true; 931 932 // The following conditions are considered in this function: 933 // 1. If there is no record of profile and state - update 934 // 2. If a new device's state is current hash state - increment 935 // number of devices in the state. 936 // 3. If a state change has happened to Connected or Connecting 937 // (if current state is not connected), update. 938 // 4. If numDevices is 1 and that device state is being updated, update 939 // 5. If numDevices is > 1 and one of the devices is changing state, 940 // decrement numDevices but maintain oldState if it is Connected or 941 // Connecting 942 Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile); 943 if (stateNumDev != null) { 944 int currHashState = stateNumDev.first; 945 numDev = stateNumDev.second; 946 947 if (newState == currHashState) { 948 numDev++; 949 } else if (newState == BluetoothProfile.STATE_CONNECTED 950 || (newState == BluetoothProfile.STATE_CONNECTING 951 && currHashState != BluetoothProfile.STATE_CONNECTED)) { 952 numDev = 1; 953 } else if (numDev == 1 && oldState == currHashState) { 954 update = true; 955 } else if (numDev > 1 && oldState == currHashState) { 956 numDev--; 957 958 if (currHashState == BluetoothProfile.STATE_CONNECTED 959 || currHashState == BluetoothProfile.STATE_CONNECTING) { 960 newHashState = currHashState; 961 } 962 } else { 963 update = false; 964 } 965 } 966 967 if (update) { 968 mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState, numDev)); 969 invalidateGetProfileConnectionStateCache(); 970 } 971 } 972 973 @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) adapterPropertyChangedCallback(int[] types, byte[][] values)974 void adapterPropertyChangedCallback(int[] types, byte[][] values) { 975 Intent intent; 976 int type; 977 byte[] val; 978 for (int i = 0; i < types.length; i++) { 979 val = values[i]; 980 type = types[i]; 981 infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length); 982 synchronized (mObject) { 983 switch (type) { 984 case AbstractionLayer.BT_PROPERTY_BDNAME: 985 mName = new String(val); 986 intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 987 intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName); 988 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 989 mService.sendBroadcastAsUser( 990 intent, 991 UserHandle.ALL, 992 BLUETOOTH_CONNECT, 993 Utils.getTempBroadcastOptions().toBundle()); 994 debugLog("Name is: " + mName); 995 break; 996 case AbstractionLayer.BT_PROPERTY_BDADDR: 997 mAddress = val; 998 String address = Utils.getAddressStringFromByte(mAddress); 999 intent = new Intent(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); 1000 intent.putExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS, address); 1001 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1002 mService.sendBroadcastAsUser( 1003 intent, 1004 UserHandle.ALL, 1005 BLUETOOTH_CONNECT, 1006 Utils.getTempBroadcastOptions().toBundle()); 1007 break; 1008 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 1009 if (val == null || val.length != 3) { 1010 debugLog("Invalid BT CoD value from stack."); 1011 return; 1012 } 1013 int bluetoothClass = 1014 ((int) val[0] << 16) + ((int) val[1] << 8) + (int) val[2]; 1015 if (bluetoothClass != 0) { 1016 mBluetoothClass = new BluetoothClass(bluetoothClass); 1017 } 1018 debugLog("BT Class:" + mBluetoothClass); 1019 break; 1020 case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE: 1021 int mode = Utils.byteArrayToInt(val, 0); 1022 mScanMode = AdapterService.convertScanModeFromHal(mode); 1023 intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 1024 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode); 1025 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1026 mService.sendBroadcast( 1027 intent, BLUETOOTH_SCAN, Utils.getTempBroadcastOptions().toBundle()); 1028 debugLog("Scan Mode:" + mScanMode); 1029 break; 1030 case AbstractionLayer.BT_PROPERTY_UUIDS: 1031 mUuids = Utils.byteArrayToUuid(val); 1032 break; 1033 case AbstractionLayer.BT_PROPERTY_ADAPTER_BONDED_DEVICES: 1034 int number = val.length / BD_ADDR_LEN; 1035 byte[] addrByte = new byte[BD_ADDR_LEN]; 1036 for (int j = 0; j < number; j++) { 1037 System.arraycopy(val, j * BD_ADDR_LEN, addrByte, 0, BD_ADDR_LEN); 1038 onBondStateChanged( 1039 mAdapter.getRemoteDevice( 1040 Utils.getAddressStringFromByte(addrByte)), 1041 BluetoothDevice.BOND_BONDED); 1042 } 1043 break; 1044 case AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: 1045 mDiscoverableTimeout = Utils.byteArrayToInt(val, 0); 1046 debugLog("Discoverable Timeout:" + mDiscoverableTimeout); 1047 break; 1048 1049 case AbstractionLayer.BT_PROPERTY_LOCAL_LE_FEATURES: 1050 updateFeatureSupport(val); 1051 mService.updateLeAudioProfileServiceState(); 1052 break; 1053 1054 case AbstractionLayer.BT_PROPERTY_DYNAMIC_AUDIO_BUFFER: 1055 updateDynamicAudioBufferSupport(val); 1056 break; 1057 1058 default: 1059 Log.e(TAG, "Property change not handled in Java land:" + type); 1060 } 1061 } 1062 } 1063 } 1064 updateFeatureSupport(byte[] val)1065 private void updateFeatureSupport(byte[] val) { 1066 mVersSupported = ((0xFF & ((int) val[1])) << 8) + (0xFF & ((int) val[0])); 1067 mNumOfAdvertisementInstancesSupported = (0xFF & ((int) val[3])); 1068 mRpaOffloadSupported = ((0xFF & ((int) val[4])) != 0); 1069 mNumOfOffloadedIrkSupported = (0xFF & ((int) val[5])); 1070 mNumOfOffloadedScanFilterSupported = (0xFF & ((int) val[6])); 1071 mIsActivityAndEnergyReporting = ((0xFF & ((int) val[7])) != 0); 1072 mOffloadedScanResultStorageBytes = ((0xFF & ((int) val[9])) << 8) + (0xFF & ((int) val[8])); 1073 mTotNumOfTrackableAdv = ((0xFF & ((int) val[11])) << 8) + (0xFF & ((int) val[10])); 1074 mIsExtendedScanSupported = ((0xFF & ((int) val[12])) != 0); 1075 mIsDebugLogSupported = ((0xFF & ((int) val[13])) != 0); 1076 mIsLe2MPhySupported = ((0xFF & ((int) val[14])) != 0); 1077 mIsLeCodedPhySupported = ((0xFF & ((int) val[15])) != 0); 1078 mIsLeExtendedAdvertisingSupported = ((0xFF & ((int) val[16])) != 0); 1079 mIsLePeriodicAdvertisingSupported = ((0xFF & ((int) val[17])) != 0); 1080 mLeMaximumAdvertisingDataLength = 1081 (0xFF & ((int) val[18])) + ((0xFF & ((int) val[19])) << 8); 1082 mDynamicAudioBufferSizeSupportedCodecsGroup1 = 1083 ((0xFF & ((int) val[21])) << 8) + (0xFF & ((int) val[20])); 1084 mDynamicAudioBufferSizeSupportedCodecsGroup2 = 1085 ((0xFF & ((int) val[23])) << 8) + (0xFF & ((int) val[22])); 1086 mIsLePeriodicAdvertisingSyncTransferSenderSupported = ((0xFF & ((int) val[24])) != 0); 1087 mIsLeConnectedIsochronousStreamCentralSupported = ((0xFF & ((int) val[25])) != 0); 1088 mIsLeIsochronousBroadcasterSupported = ((0xFF & ((int) val[26])) != 0); 1089 mIsLePeriodicAdvertisingSyncTransferRecipientSupported = ((0xFF & ((int) val[27])) != 0); 1090 mIsOffloadedTransportDiscoveryDataScanSupported = ((0x01 & ((int) val[28])) != 0); 1091 mIsLeChannelSoundingSupported = ((0xFF & ((int) val[30])) != 0); 1092 1093 Log.d( 1094 TAG, 1095 "BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller" 1096 + " mNumOfAdvertisementInstancesSupported = " 1097 + mNumOfAdvertisementInstancesSupported 1098 + " mRpaOffloadSupported = " 1099 + mRpaOffloadSupported 1100 + " mNumOfOffloadedIrkSupported = " 1101 + mNumOfOffloadedIrkSupported 1102 + " mNumOfOffloadedScanFilterSupported = " 1103 + mNumOfOffloadedScanFilterSupported 1104 + " mOffloadedScanResultStorageBytes= " 1105 + mOffloadedScanResultStorageBytes 1106 + " mIsActivityAndEnergyReporting = " 1107 + mIsActivityAndEnergyReporting 1108 + " mVersSupported = " 1109 + mVersSupported 1110 + " mTotNumOfTrackableAdv = " 1111 + mTotNumOfTrackableAdv 1112 + " mIsExtendedScanSupported = " 1113 + mIsExtendedScanSupported 1114 + " mIsDebugLogSupported = " 1115 + mIsDebugLogSupported 1116 + " mIsLe2MPhySupported = " 1117 + mIsLe2MPhySupported 1118 + " mIsLeCodedPhySupported = " 1119 + mIsLeCodedPhySupported 1120 + " mIsLeExtendedAdvertisingSupported = " 1121 + mIsLeExtendedAdvertisingSupported 1122 + " mIsLePeriodicAdvertisingSupported = " 1123 + mIsLePeriodicAdvertisingSupported 1124 + " mLeMaximumAdvertisingDataLength = " 1125 + mLeMaximumAdvertisingDataLength 1126 + " mDynamicAudioBufferSizeSupportedCodecsGroup1 = " 1127 + mDynamicAudioBufferSizeSupportedCodecsGroup1 1128 + " mDynamicAudioBufferSizeSupportedCodecsGroup2 = " 1129 + mDynamicAudioBufferSizeSupportedCodecsGroup2 1130 + " mIsLePeriodicAdvertisingSyncTransferSenderSupported = " 1131 + mIsLePeriodicAdvertisingSyncTransferSenderSupported 1132 + " mIsLeConnectedIsochronousStreamCentralSupported = " 1133 + mIsLeConnectedIsochronousStreamCentralSupported 1134 + " mIsLeIsochronousBroadcasterSupported = " 1135 + mIsLeIsochronousBroadcasterSupported 1136 + " mIsLePeriodicAdvertisingSyncTransferRecipientSupported = " 1137 + mIsLePeriodicAdvertisingSyncTransferRecipientSupported 1138 + " mIsOffloadedTransportDiscoveryDataScanSupported = " 1139 + mIsOffloadedTransportDiscoveryDataScanSupported 1140 + " mIsLeChannelSoundingSupported = " 1141 + mIsLeChannelSoundingSupported); 1142 invalidateIsOffloadedFilteringSupportedCache(); 1143 } 1144 updateDynamicAudioBufferSupport(byte[] val)1145 private void updateDynamicAudioBufferSupport(byte[] val) { 1146 if (mBufferConstraintList.isDone()) { 1147 return; 1148 } 1149 1150 // bufferConstraints is the table indicates the capability of all the codecs 1151 // with buffer time. The raw is codec number, and the column is buffer type. There are 3 1152 // buffer types - default/maximum/minimum. 1153 // The maximum number of raw is BUFFER_CODEC_MAX_NUM(32). 1154 // The maximum number of column is BUFFER_TYPE_MAX(3). 1155 // The array element indicates the buffer time, the size is two octet. 1156 List<BufferConstraint> bufferConstraintList = new ArrayList<BufferConstraint>(); 1157 1158 for (int i = 0; i < BufferConstraints.BUFFER_CODEC_MAX_NUM; i++) { 1159 int defaultBufferTime = 1160 ((0xFF & ((int) val[i * 6 + 1])) << 8) + (0xFF & ((int) val[i * 6])); 1161 int maximumBufferTime = 1162 ((0xFF & ((int) val[i * 6 + 3])) << 8) + (0xFF & ((int) val[i * 6 + 2])); 1163 int minimumBufferTime = 1164 ((0xFF & ((int) val[i * 6 + 5])) << 8) + (0xFF & ((int) val[i * 6 + 4])); 1165 bufferConstraintList.add( 1166 new BufferConstraint(defaultBufferTime, maximumBufferTime, minimumBufferTime)); 1167 } 1168 1169 mBufferConstraintList.complete(bufferConstraintList); 1170 } 1171 onBluetoothReady()1172 void onBluetoothReady() { 1173 debugLog( 1174 "onBluetoothReady, state=" 1175 + BluetoothAdapter.nameForState(getState()) 1176 + ", ScanMode=" 1177 + mScanMode); 1178 1179 synchronized (mObject) { 1180 // Reset adapter and profile connection states 1181 setConnectionState(BluetoothAdapter.STATE_DISCONNECTED); 1182 mProfileConnectionState.clear(); 1183 invalidateGetProfileConnectionStateCache(); 1184 mProfilesConnected = 0; 1185 mProfilesConnecting = 0; 1186 mProfilesDisconnecting = 0; 1187 // adapterPropertyChangedCallback has already been received. Set the scan mode. 1188 setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE); 1189 // This keeps NV up-to date on first-boot after flash. 1190 setDiscoverableTimeout(mDiscoverableTimeout); 1191 } 1192 } 1193 onBleDisable()1194 void onBleDisable() { 1195 // Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state. 1196 debugLog("onBleDisable"); 1197 // Set the scan_mode to NONE (no incoming connections). 1198 setScanMode(BluetoothAdapter.SCAN_MODE_NONE); 1199 } 1200 discoveryStateChangeCallback(int state)1201 void discoveryStateChangeCallback(int state) { 1202 infoLog("Callback:discoveryStateChangeCallback with state:" + state); 1203 synchronized (mObject) { 1204 Intent intent; 1205 if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) { 1206 mDiscovering = false; 1207 mService.clearDiscoveringPackages(); 1208 mDiscoveryEndMs = System.currentTimeMillis(); 1209 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 1210 mService.sendBroadcast( 1211 intent, BLUETOOTH_SCAN, getBroadcastOptionsForDiscoveryFinished()); 1212 } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) { 1213 mDiscovering = true; 1214 mDiscoveryEndMs = System.currentTimeMillis() + DEFAULT_DISCOVERY_TIMEOUT_MS; 1215 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 1216 mService.sendBroadcast( 1217 intent, BLUETOOTH_SCAN, Utils.getTempBroadcastOptions().toBundle()); 1218 } 1219 } 1220 } 1221 1222 /** 1223 * @return broadcast options for ACTION_DISCOVERY_FINISHED broadcast 1224 */ getBroadcastOptionsForDiscoveryFinished()1225 private static @NonNull Bundle getBroadcastOptionsForDiscoveryFinished() { 1226 final BroadcastOptions options = Utils.getTempBroadcastOptions(); 1227 if (SdkLevel.isAtLeastU()) { 1228 options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); 1229 options.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); 1230 } 1231 return options.toBundle(); 1232 } 1233 1234 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) dump(FileDescriptor fd, PrintWriter writer, String[] args)1235 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1236 writer.println(TAG); 1237 writer.println(" " + "Name: " + getName()); 1238 writer.println(" " + "Address: " + Utils.getAddressStringFromByte(mAddress)); 1239 writer.println(" " + "ScanMode: " + dumpScanMode(getScanMode())); 1240 writer.println(" " + "ConnectionState: " + dumpConnectionState(getConnectionState())); 1241 writer.println(" " + "State: " + BluetoothAdapter.nameForState(getState())); 1242 writer.println(" " + "MaxConnectedAudioDevices: " + getMaxConnectedAudioDevices()); 1243 writer.println(" " + "A2dpOffloadEnabled: " + mA2dpOffloadEnabled); 1244 writer.println(" " + "Discovering: " + mDiscovering); 1245 writer.println(" " + "DiscoveryEndMs: " + mDiscoveryEndMs); 1246 1247 writer.println(" " + "Bonded devices:"); 1248 StringBuilder sb = new StringBuilder(); 1249 for (BluetoothDevice device : mBondedDevices) { 1250 String address = device.getAddress(); 1251 BluetoothClass cod = device.getBluetoothClass(); 1252 int codInt = cod != null ? cod.getClassOfDevice() : 0; 1253 String brEdrAddress = 1254 Flags.identityAddressNullIfUnknown() 1255 ? Utils.getBrEdrAddress(device) 1256 : mService.getIdentityAddress(address); 1257 if (brEdrAddress.equals(address)) { 1258 writer.println( 1259 " " 1260 + address 1261 + " [" 1262 + dumpDeviceType(device.getType()) 1263 + "][ 0x" 1264 + String.format("%06X", codInt) 1265 + " ] " 1266 + Utils.getName(device)); 1267 } else { 1268 sb.append( 1269 " " 1270 + address 1271 + " => " 1272 + brEdrAddress 1273 + " [" 1274 + dumpDeviceType(device.getType()) 1275 + "][ 0x" 1276 + String.format("%06X", codInt) 1277 + " ] " 1278 + Utils.getName(device) 1279 + "\n"); 1280 } 1281 } 1282 writer.println(sb.toString()); 1283 1284 writer.println(" " + "Scan Mode Changes:"); 1285 for (String log : mScanModeChanges) { 1286 writer.println(" " + log); 1287 } 1288 } 1289 dumpDeviceType(int deviceType)1290 private String dumpDeviceType(int deviceType) { 1291 switch (deviceType) { 1292 case BluetoothDevice.DEVICE_TYPE_UNKNOWN: 1293 return " ???? "; 1294 case BluetoothDevice.DEVICE_TYPE_CLASSIC: 1295 return "BR/EDR"; 1296 case BluetoothDevice.DEVICE_TYPE_LE: 1297 return " LE "; 1298 case BluetoothDevice.DEVICE_TYPE_DUAL: 1299 return " DUAL "; 1300 default: 1301 return "Invalid device type: " + deviceType; 1302 } 1303 } 1304 dumpConnectionState(int state)1305 private String dumpConnectionState(int state) { 1306 switch (state) { 1307 case BluetoothAdapter.STATE_DISCONNECTED: 1308 return "STATE_DISCONNECTED"; 1309 case BluetoothAdapter.STATE_DISCONNECTING: 1310 return "STATE_DISCONNECTING"; 1311 case BluetoothAdapter.STATE_CONNECTING: 1312 return "STATE_CONNECTING"; 1313 case BluetoothAdapter.STATE_CONNECTED: 1314 return "STATE_CONNECTED"; 1315 default: 1316 return "Unknown Connection State " + state; 1317 } 1318 } 1319 dumpScanMode(int scanMode)1320 private String dumpScanMode(int scanMode) { 1321 switch (scanMode) { 1322 case BluetoothAdapter.SCAN_MODE_NONE: 1323 return "SCAN_MODE_NONE"; 1324 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 1325 return "SCAN_MODE_CONNECTABLE"; 1326 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1327 return "SCAN_MODE_CONNECTABLE_DISCOVERABLE"; 1328 default: 1329 return "Unknown Scan Mode " + scanMode; 1330 } 1331 } 1332 infoLog(String msg)1333 private static void infoLog(String msg) { 1334 Log.i(TAG, msg); 1335 } 1336 debugLog(String msg)1337 private static void debugLog(String msg) { 1338 Log.d(TAG, msg); 1339 } 1340 } 1341