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