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