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