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