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