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