• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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