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