BluetoothManagerService.java revision e957a8a0b4100d001f79c866e7904d2426ac8da0
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
17package com.android.server;
18
19import android.Manifest;
20import android.app.ActivityManager;
21import android.bluetooth.BluetoothAdapter;
22import android.bluetooth.BluetoothProfile;
23import android.bluetooth.IBluetooth;
24import android.bluetooth.IBluetoothCallback;
25import android.bluetooth.IBluetoothGatt;
26import android.bluetooth.IBluetoothHeadset;
27import android.bluetooth.IBluetoothManager;
28import android.bluetooth.IBluetoothManagerCallback;
29import android.bluetooth.IBluetoothProfileServiceConnection;
30import android.bluetooth.IBluetoothStateChangeCallback;
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.ContentResolver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.ServiceConnection;
38import android.content.pm.PackageManager;
39import android.content.pm.UserInfo;
40import android.database.ContentObserver;
41import android.os.Binder;
42import android.os.Handler;
43import android.os.IBinder;
44import android.os.Looper;
45import android.os.Message;
46import android.os.Process;
47import android.os.RemoteCallbackList;
48import android.os.RemoteException;
49import android.os.SystemClock;
50import android.os.UserHandle;
51import android.os.UserManager;
52import android.provider.Settings;
53import android.provider.Settings.SettingNotFoundException;
54import android.util.Slog;
55import java.util.concurrent.locks.ReentrantReadWriteLock;
56
57import java.io.FileDescriptor;
58import java.io.PrintWriter;
59import java.util.HashMap;
60import java.util.Map;
61
62class BluetoothManagerService extends IBluetoothManager.Stub {
63    private static final String TAG = "BluetoothManagerService";
64    private static final boolean DBG = false;
65
66    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
67    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
68    private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
69    private static final String EXTRA_ACTION="action";
70    private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
71    private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
72    private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
73    private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
74    private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
75    //Maximum msec to wait for service restart
76    private static final int SERVICE_RESTART_TIME_MS = 200;
77    //Maximum msec to wait for restart due to error
78    private static final int ERROR_RESTART_TIME_MS = 3000;
79    //Maximum msec to delay MESSAGE_USER_SWITCHED
80    private static final int USER_SWITCHED_TIME_MS = 200;
81    // Delay for the addProxy function in msec
82    private static final int ADD_PROXY_DELAY_MS = 100;
83
84    private static final int MESSAGE_ENABLE = 1;
85    private static final int MESSAGE_DISABLE = 2;
86    private static final int MESSAGE_REGISTER_ADAPTER = 20;
87    private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
88    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
89    private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
90    private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
91    private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
92    private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
93    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
94    private static final int MESSAGE_TIMEOUT_BIND = 100;
95    private static final int MESSAGE_TIMEOUT_UNBIND = 101;
96    private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
97    private static final int MESSAGE_USER_SWITCHED = 300;
98    private static final int MESSAGE_USER_UNLOCKED = 301;
99    private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
100    private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
101    private static final int MAX_SAVE_RETRIES = 3;
102    private static final int MAX_ERROR_RESTART_RETRIES = 6;
103
104    // Bluetooth persisted setting is off
105    private static final int BLUETOOTH_OFF=0;
106    // Bluetooth persisted setting is on
107    // and Airplane mode won't affect Bluetooth state at start up
108    private static final int BLUETOOTH_ON_BLUETOOTH=1;
109    // Bluetooth persisted setting is on
110    // but Airplane mode will affect Bluetooth state at start up
111    // and Airplane mode will have higher priority.
112    private static final int BLUETOOTH_ON_AIRPLANE=2;
113
114    private static final int SERVICE_IBLUETOOTH = 1;
115    private static final int SERVICE_IBLUETOOTHGATT = 2;
116
117    private final Context mContext;
118    private static int mBleAppCount = 0;
119
120    // Locks are not provided for mName and mAddress.
121    // They are accessed in handler or broadcast receiver, same thread context.
122    private String mAddress;
123    private String mName;
124    private final ContentResolver mContentResolver;
125    private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
126    private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
127    private IBinder mBluetoothBinder;
128    private IBluetooth mBluetooth;
129    private IBluetoothGatt mBluetoothGatt;
130    private final ReentrantReadWriteLock mBluetoothLock =
131        new ReentrantReadWriteLock();
132    private boolean mBinding;
133    private boolean mUnbinding;
134    // used inside handler thread
135    private boolean mQuietEnable = false;
136    // configuarion from external IBinder call which is used to
137    // synchronize with broadcast receiver.
138    private boolean mQuietEnableExternal;
139    // configuarion from external IBinder call which is used to
140    // synchronize with broadcast receiver.
141    private boolean mEnableExternal;
142    // used inside handler thread
143    private boolean mEnable;
144    private int mState;
145    private final BluetoothHandler mHandler;
146    private int mErrorRecoveryRetryCounter;
147    private final int mSystemUiUid;
148
149    // Save a ProfileServiceConnections object for each of the bound
150    // bluetooth profile services
151    private final Map <Integer, ProfileServiceConnections> mProfileServices =
152            new HashMap <Integer, ProfileServiceConnections>();
153
154    private void registerForAirplaneMode(IntentFilter filter) {
155        final ContentResolver resolver = mContext.getContentResolver();
156        final String airplaneModeRadios = Settings.Global.getString(resolver,
157                Settings.Global.AIRPLANE_MODE_RADIOS);
158        final String toggleableRadios = Settings.Global.getString(resolver,
159                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
160        boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
161                airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
162        if (mIsAirplaneSensitive) {
163            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
164        }
165    }
166
167    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
168        @Override
169        public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
170            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
171            mHandler.sendMessage(msg);
172        }
173    };
174
175    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
176        @Override
177        public void onReceive(Context context, Intent intent) {
178            String action = intent.getAction();
179            if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
180                String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
181                if (DBG) Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
182                if (newName != null) {
183                    storeNameAndAddress(newName, null);
184                }
185            } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
186                synchronized(mReceiver) {
187                    if (isBluetoothPersistedStateOn()) {
188                        if (isAirplaneModeOn()) {
189                            persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
190                        } else {
191                            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
192                        }
193                    }
194
195                    int st = BluetoothAdapter.STATE_OFF;
196                    try {
197                        mBluetoothLock.readLock().lock();
198                        if (mBluetooth != null) {
199                            st = mBluetooth.getState();
200                        }
201                    } catch (RemoteException e) {
202                        Slog.e(TAG, "Unable to call getState", e);
203                    } finally {
204                        mBluetoothLock.readLock().unlock();
205                    }
206                    Slog.d(TAG, "state" + st);
207
208                    if (isAirplaneModeOn()) {
209                        // Clear registered LE apps to force shut-off
210                        synchronized (this) {
211                            mBleAppCount = 0;
212                            mBleApps.clear();
213                        }
214                        if (st == BluetoothAdapter.STATE_BLE_ON) {
215                            //if state is BLE_ON make sure you trigger disableBLE part
216                            try {
217                                mBluetoothLock.readLock().lock();
218                                if (mBluetooth != null) {
219                                    mBluetooth.onBrEdrDown();
220                                    mEnableExternal = false;
221                                }
222                            } catch (RemoteException e) {
223                                Slog.e(TAG,"Unable to call onBrEdrDown", e);
224                            } finally {
225                                mBluetoothLock.readLock().lock();
226                            }
227                        } else if (st == BluetoothAdapter.STATE_ON){
228                            // disable without persisting the setting
229                            Slog.d(TAG, "Calling disable");
230                            sendDisableMsg();
231                        }
232                    } else if (mEnableExternal) {
233                        // enable without persisting the setting
234                        Slog.d(TAG, "Calling enable");
235                        sendEnableMsg(mQuietEnableExternal);
236                    }
237                }
238            }
239        }
240    };
241
242    BluetoothManagerService(Context context) {
243        mHandler = new BluetoothHandler(IoThread.get().getLooper());
244
245        mContext = context;
246        mBluetooth = null;
247        mBluetoothBinder = null;
248        mBluetoothGatt = null;
249        mBinding = false;
250        mUnbinding = false;
251        mEnable = false;
252        mState = BluetoothAdapter.STATE_OFF;
253        mQuietEnableExternal = false;
254        mEnableExternal = false;
255        mAddress = null;
256        mName = null;
257        mErrorRecoveryRetryCounter = 0;
258        mContentResolver = context.getContentResolver();
259        // Observe BLE scan only mode settings change.
260        registerForBleScanModeChange();
261        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
262        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
263        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
264        registerForAirplaneMode(filter);
265        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
266        mContext.registerReceiver(mReceiver, filter);
267        loadStoredNameAndAddress();
268        if (isBluetoothPersistedStateOn()) {
269            mEnableExternal = true;
270        }
271
272        int sysUiUid = -1;
273        try {
274            sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
275                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
276        } catch (PackageManager.NameNotFoundException e) {
277            // Some platforms, such as wearables do not have a system ui.
278            Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
279        }
280        mSystemUiUid = sysUiUid;
281    }
282
283    /**
284     *  Returns true if airplane mode is currently on
285     */
286    private final boolean isAirplaneModeOn() {
287        return Settings.Global.getInt(mContext.getContentResolver(),
288                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
289    }
290
291    /**
292     *  Returns true if the Bluetooth saved state is "on"
293     */
294    private final boolean isBluetoothPersistedStateOn() {
295        return Settings.Global.getInt(mContentResolver,
296                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
297    }
298
299    /**
300     *  Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
301     */
302    private final boolean isBluetoothPersistedStateOnBluetooth() {
303        return Settings.Global.getInt(mContentResolver,
304                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
305    }
306
307    /**
308     *  Save the Bluetooth on/off state
309     *
310     */
311    private void persistBluetoothSetting(int value) {
312        Settings.Global.putInt(mContext.getContentResolver(),
313                               Settings.Global.BLUETOOTH_ON,
314                               value);
315    }
316
317    /**
318     * Returns true if the Bluetooth Adapter's name and address is
319     * locally cached
320     * @return
321     */
322    private boolean isNameAndAddressSet() {
323        return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
324    }
325
326    /**
327     * Retrieve the Bluetooth Adapter's name and address and save it in
328     * in the local cache
329     */
330    private void loadStoredNameAndAddress() {
331        if (DBG) Slog.d(TAG, "Loading stored name and address");
332        if (mContext.getResources().getBoolean
333            (com.android.internal.R.bool.config_bluetooth_address_validation) &&
334             Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
335            // if the valid flag is not set, don't load the address and name
336            if (DBG) Slog.d(TAG, "invalid bluetooth name and address stored");
337            return;
338        }
339        mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
340        mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
341        if (DBG) Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
342    }
343
344    /**
345     * Save the Bluetooth name and address in the persistent store.
346     * Only non-null values will be saved.
347     * @param name
348     * @param address
349     */
350    private void storeNameAndAddress(String name, String address) {
351        if (name != null) {
352            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
353            mName = name;
354            if (DBG) Slog.d(TAG,"Stored Bluetooth name: " +
355                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
356        }
357
358        if (address != null) {
359            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
360            mAddress=address;
361            if (DBG)  Slog.d(TAG,"Stored Bluetoothaddress: " +
362                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
363        }
364
365        if ((name != null) && (address != null)) {
366            Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
367        }
368    }
369
370    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
371        if (callback == null) {
372            Slog.w(TAG, "Callback is null in registerAdapter");
373            return null;
374        }
375        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
376        msg.obj = callback;
377        mHandler.sendMessage(msg);
378
379        return mBluetooth;
380    }
381
382    public void unregisterAdapter(IBluetoothManagerCallback callback) {
383        if (callback == null) {
384            Slog.w(TAG, "Callback is null in unregisterAdapter");
385            return;
386        }
387        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
388                                                "Need BLUETOOTH permission");
389        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
390        msg.obj = callback;
391        mHandler.sendMessage(msg);
392    }
393
394    public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
395        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
396                                                "Need BLUETOOTH permission");
397        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
398        msg.obj = callback;
399        mHandler.sendMessage(msg);
400    }
401
402    public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
403        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
404                                                "Need BLUETOOTH permission");
405        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
406        msg.obj = callback;
407        mHandler.sendMessage(msg);
408    }
409
410    public boolean isEnabled() {
411        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
412            (!checkIfCallerIsForegroundUser())) {
413            Slog.w(TAG,"isEnabled(): not allowed for non-active and non system user");
414            return false;
415        }
416
417        try {
418            mBluetoothLock.readLock().lock();
419            if (mBluetooth != null) return mBluetooth.isEnabled();
420        } catch (RemoteException e) {
421            Slog.e(TAG, "isEnabled()", e);
422        } finally {
423            mBluetoothLock.readLock().unlock();
424        }
425        return false;
426    }
427
428    class ClientDeathRecipient implements IBinder.DeathRecipient {
429        public void binderDied() {
430            if (DBG) Slog.d(TAG, "Binder is dead -  unregister Ble App");
431            if (mBleAppCount > 0) --mBleAppCount;
432
433            if (mBleAppCount == 0) {
434                if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
435                try {
436                    mBluetoothLock.readLock().lock();
437                    if (mBluetooth != null) {
438                        mBluetooth.onBrEdrDown();
439                    }
440                } catch (RemoteException e) {
441                     Slog.e(TAG,"Unable to call onBrEdrDown", e);
442                } finally {
443                    mBluetoothLock.readLock().unlock();
444                }
445            }
446        }
447    }
448
449    /** Internal death rec list */
450    Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
451
452    @Override
453    public boolean isBleScanAlwaysAvailable() {
454        try {
455            return (Settings.Global.getInt(mContentResolver,
456                    Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
457        } catch (SettingNotFoundException e) {
458        }
459        return false;
460    }
461
462    // Monitor change of BLE scan only mode settings.
463    private void registerForBleScanModeChange() {
464        ContentObserver contentObserver = new ContentObserver(null) {
465            @Override
466            public void onChange(boolean selfChange) {
467                if (!isBleScanAlwaysAvailable()) {
468                    disableBleScanMode();
469                    clearBleApps();
470                    try {
471                        mBluetoothLock.readLock().lock();
472                        if (mBluetooth != null) mBluetooth.onBrEdrDown();
473                    } catch (RemoteException e) {
474                        Slog.e(TAG, "error when disabling bluetooth", e);
475                    } finally {
476                        mBluetoothLock.readLock().unlock();
477                    }
478                }
479            }
480        };
481
482        mContentResolver.registerContentObserver(
483                Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE),
484                false, contentObserver);
485    }
486
487    // Disable ble scan only mode.
488    private void disableBleScanMode() {
489        try {
490            mBluetoothLock.writeLock().lock();
491            if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
492                if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable");
493                mEnable = false;
494            }
495        } catch (RemoteException e) {
496            Slog.e(TAG, "getState()", e);
497        } finally {
498            mBluetoothLock.writeLock().unlock();
499        }
500    }
501
502    public int updateBleAppCount(IBinder token, boolean enable) {
503        if (enable) {
504            ClientDeathRecipient r = mBleApps.get(token);
505            if (r == null) {
506                ClientDeathRecipient deathRec = new ClientDeathRecipient();
507                try {
508                    token.linkToDeath(deathRec, 0);
509                } catch (RemoteException ex) {
510                    throw new IllegalArgumentException("Wake lock is already dead.");
511                }
512                mBleApps.put(token, deathRec);
513                synchronized (this) {
514                    ++mBleAppCount;
515                }
516                if (DBG) Slog.d(TAG, "Registered for death Notification");
517            }
518
519        } else  {
520            ClientDeathRecipient r = mBleApps.get(token);
521            if (r != null) {
522                // Unregister death recipient as the app goes away.
523                token.unlinkToDeath(r, 0);
524                mBleApps.remove(token);
525                synchronized (this) {
526                    if (mBleAppCount > 0) --mBleAppCount;
527                }
528                if (DBG) Slog.d(TAG, "Unregistered for death Notification");
529            }
530        }
531        if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount);
532        if (mBleAppCount == 0 && mEnable) {
533            disableBleScanMode();
534        }
535        return mBleAppCount;
536    }
537
538    // Clear all apps using BLE scan only mode.
539    private void clearBleApps() {
540        synchronized (this) {
541            mBleApps.clear();
542            mBleAppCount = 0;
543        }
544    }
545
546    /** @hide*/
547    public boolean isBleAppPresent() {
548        if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
549        return (mBleAppCount > 0);
550    }
551
552    /**
553     * Action taken when GattService is turned off
554     */
555    private void onBluetoothGattServiceUp() {
556        if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up");
557        try {
558            mBluetoothLock.readLock().lock();
559            if (isBleAppPresent() == false && mBluetooth != null
560                  && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
561                mBluetooth.onLeServiceUp();
562
563                // waive WRITE_SECURE_SETTINGS permission check
564                long callingIdentity = Binder.clearCallingIdentity();
565                persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
566                Binder.restoreCallingIdentity(callingIdentity);
567            }
568        } catch (RemoteException e) {
569            Slog.e(TAG,"Unable to call onServiceUp", e);
570        } finally {
571            mBluetoothLock.readLock().unlock();
572        }
573    }
574
575    /**
576     * Inform BluetoothAdapter instances that BREDR part is down
577     * and turn off all service and stack if no LE app needs it
578     */
579    private void sendBrEdrDownCallback() {
580        if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks");
581
582        if (mBluetooth == null) {
583            Slog.w(TAG, "Bluetooth handle is null");
584            return;
585        }
586
587        if (isBleAppPresent() == false) {
588            try {
589                mBluetoothLock.readLock().lock();
590                if (mBluetooth != null) mBluetooth.onBrEdrDown();
591            } catch (RemoteException e) {
592                Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
593            } finally {
594                mBluetoothLock.readLock().unlock();
595            }
596        } else {
597            // Need to stay at BLE ON. Disconnect all Gatt connections
598            try {
599                mBluetoothGatt.unregAll();
600            } catch (RemoteException e) {
601                Slog.e(TAG, "Unable to disconnect all apps.", e);
602            }
603        }
604    }
605
606    public boolean enableNoAutoConnect()
607    {
608        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
609                                                "Need BLUETOOTH ADMIN permission");
610
611        if (DBG) {
612            Slog.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
613                    " mBinding = " + mBinding);
614        }
615        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
616
617        if (callingAppId != Process.NFC_UID) {
618            throw new SecurityException("no permission to enable Bluetooth quietly");
619        }
620
621        synchronized(mReceiver) {
622            mQuietEnableExternal = true;
623            mEnableExternal = true;
624            sendEnableMsg(true);
625        }
626        return true;
627    }
628
629    public boolean enable() {
630        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
631            (!checkIfCallerIsForegroundUser())) {
632            Slog.w(TAG,"enable(): not allowed for non-active and non system user");
633            return false;
634        }
635
636        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
637                                                "Need BLUETOOTH ADMIN permission");
638        if (DBG) {
639            Slog.d(TAG,"enable():  mBluetooth =" + mBluetooth +
640                    " mBinding = " + mBinding + " mState = " + mState);
641        }
642        // We do not honor ON requests when the adapter is already turned ON or in the process of
643        // turning ON.
644        // As a protective mechanism to make sure that the native stack gets cleaned up properly
645        // before turning it back ON we ignore requests while the bluetooth is turning OFF.
646        // Bug: b/28318203
647        if (mState == BluetoothAdapter.STATE_BLE_TURNING_OFF ||
648            mState == BluetoothAdapter.STATE_TURNING_OFF ||
649            mState == BluetoothAdapter.STATE_ON ||
650            mState == BluetoothAdapter.STATE_BLE_ON ||
651            mState == BluetoothAdapter.STATE_TURNING_ON ||
652            mState == BluetoothAdapter.STATE_BLE_TURNING_ON) {
653            return false;
654        }
655
656        synchronized(mReceiver) {
657            mQuietEnableExternal = false;
658            mEnableExternal = true;
659            // waive WRITE_SECURE_SETTINGS permission check
660            sendEnableMsg(false);
661        }
662        if (DBG) Slog.d(TAG, "enable returning");
663        return true;
664    }
665
666    public boolean disable(boolean persist) {
667        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
668                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
669
670        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
671            (!checkIfCallerIsForegroundUser())) {
672            Slog.w(TAG,"disable(): not allowed for non-active and non system user");
673            return false;
674        }
675
676        if (DBG) {
677            Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth +
678                " mBinding = " + mBinding);
679        }
680
681        synchronized(mReceiver) {
682            if (persist) {
683                // waive WRITE_SECURE_SETTINGS permission check
684                long callingIdentity = Binder.clearCallingIdentity();
685                persistBluetoothSetting(BLUETOOTH_OFF);
686                Binder.restoreCallingIdentity(callingIdentity);
687            }
688            mEnableExternal = false;
689            sendDisableMsg();
690        }
691        return true;
692    }
693
694    public void unbindAndFinish() {
695        if (DBG) {
696            Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
697                " mBinding = " + mBinding);
698        }
699
700        try {
701            mBluetoothLock.writeLock().lock();
702            if (mUnbinding) return;
703            mUnbinding = true;
704            if (mBluetooth != null) {
705                //Unregister callback object
706                try {
707                    mBluetooth.unregisterCallback(mBluetoothCallback);
708                } catch (RemoteException re) {
709                    Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
710                }
711
712                if (DBG) Slog.d(TAG, "Sending unbind request.");
713                mBluetoothBinder = null;
714                mBluetooth = null;
715                //Unbind
716                mContext.unbindService(mConnection);
717                mUnbinding = false;
718                mBinding = false;
719            } else {
720                mUnbinding=false;
721            }
722            mBluetoothGatt = null;
723        } finally {
724            mBluetoothLock.writeLock().unlock();
725        }
726    }
727
728    public IBluetoothGatt getBluetoothGatt() {
729        // sync protection
730        return mBluetoothGatt;
731    }
732
733    @Override
734    public boolean bindBluetoothProfileService(int bluetoothProfile,
735            IBluetoothProfileServiceConnection proxy) {
736        if (!mEnable) {
737            if (DBG) {
738                Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
739                        ", while Bluetooth was disabled");
740            }
741            return false;
742        }
743        synchronized (mProfileServices) {
744            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
745            if (psc == null) {
746                if (DBG) {
747                    Slog.d(TAG, "Creating new ProfileServiceConnections object for"
748                            + " profile: " + bluetoothProfile);
749                }
750
751                if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
752
753                Intent intent = new Intent(IBluetoothHeadset.class.getName());
754                psc = new ProfileServiceConnections(intent);
755                if (!psc.bindService()) return false;
756
757                mProfileServices.put(new Integer(bluetoothProfile), psc);
758            }
759        }
760
761        // Introducing a delay to give the client app time to prepare
762        Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
763        addProxyMsg.arg1 = bluetoothProfile;
764        addProxyMsg.obj = proxy;
765        mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
766        return true;
767    }
768
769    @Override
770    public void unbindBluetoothProfileService(int bluetoothProfile,
771            IBluetoothProfileServiceConnection proxy) {
772        synchronized (mProfileServices) {
773            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
774            if (psc == null) {
775                return;
776            }
777            psc.removeProxy(proxy);
778        }
779    }
780
781    private void unbindAllBluetoothProfileServices() {
782        synchronized (mProfileServices) {
783            for (Integer i : mProfileServices.keySet()) {
784                ProfileServiceConnections psc = mProfileServices.get(i);
785                try {
786                    mContext.unbindService(psc);
787                } catch (IllegalArgumentException e) {
788                    Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
789                }
790                psc.removeAllProxies();
791            }
792            mProfileServices.clear();
793        }
794    }
795
796    /**
797     * Send enable message and set adapter name and address. Called when the boot phase becomes
798     * PHASE_SYSTEM_SERVICES_READY.
799     */
800    public void handleOnBootPhase() {
801        if (DBG) Slog.d(TAG, "Bluetooth boot completed");
802        if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
803            if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
804            sendEnableMsg(mQuietEnableExternal);
805        } else if (!isNameAndAddressSet()) {
806            if (DBG) Slog.d(TAG, "Getting adapter name and address");
807            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
808            mHandler.sendMessage(getMsg);
809        }
810    }
811
812    /**
813     * Called when switching to a different foreground user.
814     */
815    public void handleOnSwitchUser(int userHandle) {
816        if (DBG) Slog.d(TAG, "User " + userHandle + " switched");
817        mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
818    }
819
820    /**
821     * Called when user is unlocked.
822     */
823    public void handleOnUnlockUser(int userHandle) {
824        if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked");
825        mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
826    }
827
828    /**
829     * This class manages the clients connected to a given ProfileService
830     * and maintains the connection with that service.
831     */
832    final private class ProfileServiceConnections implements ServiceConnection,
833            IBinder.DeathRecipient {
834        final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
835                new RemoteCallbackList <IBluetoothProfileServiceConnection>();
836        IBinder mService;
837        ComponentName mClassName;
838        Intent mIntent;
839        boolean mInvokingProxyCallbacks = false;
840
841        ProfileServiceConnections(Intent intent) {
842            mService = null;
843            mClassName = null;
844            mIntent = intent;
845        }
846
847        private boolean bindService() {
848            if (mIntent != null && mService == null &&
849                    doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
850                Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
851                msg.obj = this;
852                mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
853                return true;
854            }
855            Slog.w(TAG, "Unable to bind with intent: " + mIntent);
856            return false;
857        }
858
859        private void addProxy(IBluetoothProfileServiceConnection proxy) {
860            mProxies.register(proxy);
861            if (mService != null) {
862                try{
863                    proxy.onServiceConnected(mClassName, mService);
864                } catch (RemoteException e) {
865                    Slog.e(TAG, "Unable to connect to proxy", e);
866                }
867            } else {
868                if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
869                    Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
870                    msg.obj = this;
871                    mHandler.sendMessage(msg);
872                }
873            }
874        }
875
876        private void removeProxy(IBluetoothProfileServiceConnection proxy) {
877            if (proxy != null) {
878                if (mProxies.unregister(proxy)) {
879                    try {
880                        proxy.onServiceDisconnected(mClassName);
881                    } catch (RemoteException e) {
882                        Slog.e(TAG, "Unable to disconnect proxy", e);
883                    }
884                }
885            } else {
886                Slog.w(TAG, "Trying to remove a null proxy");
887            }
888        }
889
890        private void removeAllProxies() {
891            onServiceDisconnected(mClassName);
892            mProxies.kill();
893        }
894
895        @Override
896        public void onServiceConnected(ComponentName className, IBinder service) {
897            // remove timeout message
898            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
899            mService = service;
900            mClassName = className;
901            try {
902                mService.linkToDeath(this, 0);
903            } catch (RemoteException e) {
904                Slog.e(TAG, "Unable to linkToDeath", e);
905            }
906
907            if (mInvokingProxyCallbacks) {
908                Slog.e(TAG, "Proxy callbacks already in progress.");
909                return;
910            }
911            mInvokingProxyCallbacks = true;
912
913            final int n = mProxies.beginBroadcast();
914            try {
915                for (int i = 0; i < n; i++) {
916                    try {
917                        mProxies.getBroadcastItem(i).onServiceConnected(className, service);
918                    } catch (RemoteException e) {
919                        Slog.e(TAG, "Unable to connect to proxy", e);
920                    }
921                }
922            } finally {
923                mProxies.finishBroadcast();
924                mInvokingProxyCallbacks = false;
925            }
926        }
927
928        @Override
929        public void onServiceDisconnected(ComponentName className) {
930            if (mService == null) return;
931            mService.unlinkToDeath(this, 0);
932            mService = null;
933            mClassName = null;
934
935            if (mInvokingProxyCallbacks) {
936                Slog.e(TAG, "Proxy callbacks already in progress.");
937                return;
938            }
939            mInvokingProxyCallbacks = true;
940
941            final int n = mProxies.beginBroadcast();
942            try {
943                for (int i = 0; i < n; i++) {
944                    try {
945                        mProxies.getBroadcastItem(i).onServiceDisconnected(className);
946                    } catch (RemoteException e) {
947                        Slog.e(TAG, "Unable to disconnect from proxy", e);
948                    }
949                }
950            } finally {
951                mProxies.finishBroadcast();
952                mInvokingProxyCallbacks = false;
953            }
954        }
955
956        @Override
957        public void binderDied() {
958            if (DBG) {
959                Slog.w(TAG, "Profile service for profile: " + mClassName
960                        + " died.");
961            }
962            onServiceDisconnected(mClassName);
963            // Trigger rebind
964            Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
965            msg.obj = this;
966            mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
967        }
968    }
969
970    private void sendBluetoothStateCallback(boolean isUp) {
971        try {
972            int n = mStateChangeCallbacks.beginBroadcast();
973            if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
974            for (int i=0; i <n;i++) {
975                try {
976                    mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
977                } catch (RemoteException e) {
978                    Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
979                }
980            }
981        } finally {
982            mStateChangeCallbacks.finishBroadcast();
983        }
984    }
985
986    /**
987     * Inform BluetoothAdapter instances that Adapter service is up
988     */
989    private void sendBluetoothServiceUpCallback() {
990        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
991        try {
992            int n = mCallbacks.beginBroadcast();
993            Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
994            for (int i=0; i <n;i++) {
995                try {
996                    mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
997                }  catch (RemoteException e) {
998                    Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
999                }
1000            }
1001        } finally {
1002            mCallbacks.finishBroadcast();
1003        }
1004    }
1005    /**
1006     * Inform BluetoothAdapter instances that Adapter service is down
1007     */
1008    private void sendBluetoothServiceDownCallback() {
1009        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
1010        try {
1011            int n = mCallbacks.beginBroadcast();
1012            Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
1013            for (int i=0; i <n;i++) {
1014                try {
1015                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
1016                }  catch (RemoteException e) {
1017                    Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
1018                }
1019            }
1020        } finally {
1021            mCallbacks.finishBroadcast();
1022        }
1023    }
1024
1025    public String getAddress() {
1026        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1027                "Need BLUETOOTH permission");
1028
1029        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
1030                (!checkIfCallerIsForegroundUser())) {
1031            Slog.w(TAG,"getAddress(): not allowed for non-active and non system user");
1032            return null;
1033        }
1034
1035        if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
1036                != PackageManager.PERMISSION_GRANTED) {
1037            return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
1038        }
1039
1040        try {
1041            mBluetoothLock.readLock().lock();
1042            if (mBluetooth != null) return mBluetooth.getAddress();
1043        } catch (RemoteException e) {
1044            Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e);
1045        } finally {
1046            mBluetoothLock.readLock().unlock();
1047        }
1048
1049        // mAddress is accessed from outside.
1050        // It is alright without a lock. Here, bluetooth is off, no other thread is
1051        // changing mAddress
1052        return mAddress;
1053    }
1054
1055    public String getName() {
1056        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1057                                                "Need BLUETOOTH permission");
1058
1059        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
1060            (!checkIfCallerIsForegroundUser())) {
1061            Slog.w(TAG,"getName(): not allowed for non-active and non system user");
1062            return null;
1063        }
1064
1065        try {
1066            mBluetoothLock.readLock().lock();
1067            if (mBluetooth != null) return mBluetooth.getName();
1068        } catch (RemoteException e) {
1069            Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
1070        } finally {
1071            mBluetoothLock.readLock().unlock();
1072        }
1073
1074        // mName is accessed from outside.
1075        // It alright without a lock. Here, bluetooth is off, no other thread is
1076        // changing mName
1077        return mName;
1078    }
1079
1080    private class BluetoothServiceConnection implements ServiceConnection {
1081        public void onServiceConnected(ComponentName className, IBinder service) {
1082            if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
1083            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
1084            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
1085            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
1086                msg.arg1 = SERVICE_IBLUETOOTH;
1087                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
1088            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
1089                msg.arg1 = SERVICE_IBLUETOOTHGATT;
1090            } else {
1091                Slog.e(TAG, "Unknown service connected: " + className.getClassName());
1092                return;
1093            }
1094            msg.obj = service;
1095            mHandler.sendMessage(msg);
1096        }
1097
1098        public void onServiceDisconnected(ComponentName className) {
1099            // Called if we unexpected disconnected.
1100            if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " +
1101                           className.getClassName());
1102            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
1103            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
1104                msg.arg1 = SERVICE_IBLUETOOTH;
1105            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
1106                msg.arg1 = SERVICE_IBLUETOOTHGATT;
1107            } else {
1108                Slog.e(TAG, "Unknown service disconnected: " + className.getClassName());
1109                return;
1110            }
1111            mHandler.sendMessage(msg);
1112        }
1113    }
1114
1115    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
1116
1117    private class BluetoothHandler extends Handler {
1118        boolean mGetNameAddressOnly = false;
1119
1120        public BluetoothHandler(Looper looper) {
1121            super(looper);
1122        }
1123
1124        @Override
1125        public void handleMessage(Message msg) {
1126            if (DBG) Slog.d (TAG, "Message: " + msg.what);
1127            switch (msg.what) {
1128                case MESSAGE_GET_NAME_AND_ADDRESS:
1129                    if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
1130                    try {
1131                        mBluetoothLock.writeLock().lock();
1132                        if ((mBluetooth == null) && (!mBinding)) {
1133                            if (DBG) Slog.d(TAG, "Binding to service to get name and address");
1134                            mGetNameAddressOnly = true;
1135                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1136                            mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
1137                            Intent i = new Intent(IBluetooth.class.getName());
1138                            if (!doBind(i, mConnection,
1139                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1140                                UserHandle.CURRENT)) {
1141                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1142                            } else {
1143                                mBinding = true;
1144                            }
1145                        } else if (mBluetooth != null) {
1146                            try {
1147                                storeNameAndAddress(mBluetooth.getName(),
1148                                                    mBluetooth.getAddress());
1149                            } catch (RemoteException re) {
1150                                Slog.e(TAG, "Unable to grab names", re);
1151                            }
1152                            if (mGetNameAddressOnly && !mEnable) {
1153                                unbindAndFinish();
1154                            }
1155                            mGetNameAddressOnly = false;
1156                        }
1157                    } finally {
1158                        mBluetoothLock.writeLock().unlock();
1159                    }
1160                    break;
1161
1162                case MESSAGE_ENABLE:
1163                    if (DBG) {
1164                        Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
1165                    }
1166                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1167                    mEnable = true;
1168                    handleEnable(msg.arg1 == 1);
1169                    break;
1170
1171                case MESSAGE_DISABLE:
1172                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1173                    if (mEnable && mBluetooth != null) {
1174                        waitForOnOff(true, false);
1175                        mEnable = false;
1176                        handleDisable();
1177                        waitForOnOff(false, false);
1178                    } else {
1179                        mEnable = false;
1180                        handleDisable();
1181                    }
1182                    break;
1183
1184                case MESSAGE_REGISTER_ADAPTER:
1185                {
1186                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1187                    boolean added = mCallbacks.register(callback);
1188                    Slog.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
1189                }
1190                    break;
1191                case MESSAGE_UNREGISTER_ADAPTER:
1192                {
1193                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1194                    boolean removed = mCallbacks.unregister(callback);
1195                    Slog.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
1196                    break;
1197                }
1198                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1199                {
1200                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1201                    if (callback != null) {
1202                        mStateChangeCallbacks.register(callback);
1203                    }
1204                    break;
1205                }
1206                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1207                {
1208                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1209                    if (callback != null) {
1210                        mStateChangeCallbacks.unregister(callback);
1211                    }
1212                    break;
1213                }
1214                case MESSAGE_ADD_PROXY_DELAYED:
1215                {
1216                    ProfileServiceConnections psc = mProfileServices.get(
1217                            new Integer(msg.arg1));
1218                    if (psc == null) {
1219                        break;
1220                    }
1221                    IBluetoothProfileServiceConnection proxy =
1222                            (IBluetoothProfileServiceConnection) msg.obj;
1223                    psc.addProxy(proxy);
1224                    break;
1225                }
1226                case MESSAGE_BIND_PROFILE_SERVICE:
1227                {
1228                    ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1229                    removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1230                    if (psc == null) {
1231                        break;
1232                    }
1233                    psc.bindService();
1234                    break;
1235                }
1236                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1237                {
1238                    if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
1239
1240                    IBinder service = (IBinder) msg.obj;
1241                    try {
1242                        mBluetoothLock.writeLock().lock();
1243                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1244                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1245                            onBluetoothGattServiceUp();
1246                            break;
1247                        } // else must be SERVICE_IBLUETOOTH
1248
1249                        //Remove timeout
1250                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1251
1252                        mBinding = false;
1253                        mBluetoothBinder = service;
1254                        mBluetooth = IBluetooth.Stub.asInterface(service);
1255
1256                        if (!isNameAndAddressSet()) {
1257                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1258                            mHandler.sendMessage(getMsg);
1259                            if (mGetNameAddressOnly) return;
1260                        }
1261
1262                        try {
1263                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1264                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1265                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1266                                Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
1267                            }
1268                        } catch (RemoteException e) {
1269                            Slog.e(TAG,"Unable to call configHciSnoopLog", e);
1270                        }
1271
1272                        //Register callback object
1273                        try {
1274                            mBluetooth.registerCallback(mBluetoothCallback);
1275                        } catch (RemoteException re) {
1276                            Slog.e(TAG, "Unable to register BluetoothCallback",re);
1277                        }
1278                        //Inform BluetoothAdapter instances that service is up
1279                        sendBluetoothServiceUpCallback();
1280
1281                        //Do enable request
1282                        try {
1283                            if (mQuietEnable == false) {
1284                                if(!mBluetooth.enable()) {
1285                                    Slog.e(TAG,"IBluetooth.enable() returned false");
1286                                }
1287                            }
1288                            else
1289                            {
1290                                if(!mBluetooth.enableNoAutoConnect()) {
1291                                    Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1292                                }
1293                            }
1294                        } catch (RemoteException e) {
1295                            Slog.e(TAG,"Unable to call enable()",e);
1296                        }
1297                    } finally {
1298                        mBluetoothLock.writeLock().unlock();
1299                    }
1300
1301                    if (!mEnable) {
1302                        waitForOnOff(true, false);
1303                        handleDisable();
1304                        waitForOnOff(false, false);
1305                    }
1306                    break;
1307                }
1308                case MESSAGE_TIMEOUT_BIND: {
1309                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
1310                    mBluetoothLock.writeLock().lock();
1311                    mBinding = false;
1312                    mBluetoothLock.writeLock().unlock();
1313
1314                    break;
1315                }
1316                case MESSAGE_BLUETOOTH_STATE_CHANGE:
1317                {
1318                    int prevState = msg.arg1;
1319                    int newState = msg.arg2;
1320                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
1321                    mState = newState;
1322                    bluetoothStateChangeHandler(prevState, newState);
1323                    // handle error state transition case from TURNING_ON to OFF
1324                    // unbind and rebind bluetooth service and enable bluetooth
1325                    if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
1326                        (newState == BluetoothAdapter.STATE_OFF) &&
1327                        (mBluetooth != null) && mEnable) {
1328                        recoverBluetoothServiceFromError();
1329                    }
1330                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1331                        (newState == BluetoothAdapter.STATE_BLE_ON) &&
1332                        (mBluetooth != null) && mEnable) {
1333                        recoverBluetoothServiceFromError();
1334                    }
1335                    if (newState == BluetoothAdapter.STATE_ON ||
1336                        newState == BluetoothAdapter.STATE_BLE_ON) {
1337                        // bluetooth is working, reset the counter
1338                        if (mErrorRecoveryRetryCounter != 0) {
1339                            Slog.w(TAG, "bluetooth is recovered from error");
1340                            mErrorRecoveryRetryCounter = 0;
1341                        }
1342                    }
1343                    break;
1344                }
1345                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1346                {
1347                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
1348                    try {
1349                        mBluetoothLock.writeLock().lock();
1350                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
1351                            // if service is unbinded already, do nothing and return
1352                            if (mBluetooth == null) break;
1353                            mBluetooth = null;
1354                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1355                            mBluetoothGatt = null;
1356                            break;
1357                        } else {
1358                            Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
1359                            break;
1360                        }
1361                    } finally {
1362                        mBluetoothLock.writeLock().unlock();
1363                    }
1364
1365                    if (mEnable) {
1366                        mEnable = false;
1367                        // Send a Bluetooth Restart message
1368                        Message restartMsg = mHandler.obtainMessage(
1369                            MESSAGE_RESTART_BLUETOOTH_SERVICE);
1370                        mHandler.sendMessageDelayed(restartMsg,
1371                            SERVICE_RESTART_TIME_MS);
1372                    }
1373
1374                    sendBluetoothServiceDownCallback();
1375
1376                    // Send BT state broadcast to update
1377                    // the BT icon correctly
1378                    if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1379                        (mState == BluetoothAdapter.STATE_ON)) {
1380                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1381                                                    BluetoothAdapter.STATE_TURNING_OFF);
1382                        mState = BluetoothAdapter.STATE_TURNING_OFF;
1383                    }
1384                    if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1385                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1386                                                    BluetoothAdapter.STATE_OFF);
1387                    }
1388
1389                    mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1390                    mState = BluetoothAdapter.STATE_OFF;
1391                    break;
1392                }
1393                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1394                {
1395                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1396                        +" Restart IBluetooth service");
1397                    /* Enable without persisting the setting as
1398                     it doesnt change when IBluetooth
1399                     service restarts */
1400                    mEnable = true;
1401                    handleEnable(mQuietEnable);
1402                    break;
1403                }
1404
1405                case MESSAGE_TIMEOUT_UNBIND:
1406                {
1407                    Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
1408                    mBluetoothLock.writeLock().lock();
1409                    mUnbinding = false;
1410                    mBluetoothLock.writeLock().unlock();
1411                    break;
1412                }
1413
1414                case MESSAGE_USER_SWITCHED: {
1415                    if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
1416                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1417
1418                    /* disable and enable BT when detect a user switch */
1419                    if (mEnable && mBluetooth != null) {
1420                        try {
1421                            mBluetoothLock.readLock().lock();
1422                            if (mBluetooth != null) {
1423                                mBluetooth.unregisterCallback(mBluetoothCallback);
1424                            }
1425                        } catch (RemoteException re) {
1426                            Slog.e(TAG, "Unable to unregister", re);
1427                        } finally {
1428                            mBluetoothLock.readLock().unlock();
1429                        }
1430
1431                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1432                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1433                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1434                            mState = BluetoothAdapter.STATE_OFF;
1435                        }
1436                        if (mState == BluetoothAdapter.STATE_OFF) {
1437                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1438                            mState = BluetoothAdapter.STATE_TURNING_ON;
1439                        }
1440
1441                        waitForOnOff(true, false);
1442
1443                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1444                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1445                        }
1446
1447                        unbindAllBluetoothProfileServices();
1448                        // disable
1449                        handleDisable();
1450                        // Pbap service need receive STATE_TURNING_OFF intent to close
1451                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1452                                                    BluetoothAdapter.STATE_TURNING_OFF);
1453
1454                        waitForOnOff(false, true);
1455
1456                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1457                                                    BluetoothAdapter.STATE_OFF);
1458                        sendBluetoothServiceDownCallback();
1459
1460                        try {
1461                            mBluetoothLock.writeLock().lock();
1462                            if (mBluetooth != null) {
1463                                mBluetooth = null;
1464                                // Unbind
1465                                mContext.unbindService(mConnection);
1466                            }
1467                            mBluetoothGatt = null;
1468                        } finally {
1469                            mBluetoothLock.writeLock().unlock();
1470                        }
1471
1472                        SystemClock.sleep(100);
1473
1474                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1475                        mState = BluetoothAdapter.STATE_OFF;
1476                        // enable
1477                        handleEnable(mQuietEnable);
1478                    } else if (mBinding || mBluetooth != null) {
1479                        Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1480                        userMsg.arg2 = 1 + msg.arg2;
1481                        // if user is switched when service is being binding
1482                        // delay sending MESSAGE_USER_SWITCHED
1483                        mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1484                        if (DBG) {
1485                            Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1486                        }
1487                    }
1488                    break;
1489                }
1490                case MESSAGE_USER_UNLOCKED: {
1491                    if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
1492                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1493
1494                    if (mEnable && !mBinding && (mBluetooth == null)) {
1495                        // We should be connected, but we gave up for some
1496                        // reason; maybe the Bluetooth service wasn't encryption
1497                        // aware, so try binding again.
1498                        if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
1499                        handleEnable(mQuietEnable);
1500                    }
1501                }
1502            }
1503        }
1504    }
1505
1506    private void handleEnable(boolean quietMode) {
1507        mQuietEnable = quietMode;
1508
1509        try {
1510            mBluetoothLock.writeLock().lock();
1511            if ((mBluetooth == null) && (!mBinding)) {
1512                //Start bind timeout and bind
1513                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1514                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1515                Intent i = new Intent(IBluetooth.class.getName());
1516                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1517                        UserHandle.CURRENT)) {
1518                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1519                } else {
1520                    mBinding = true;
1521                }
1522            } else if (mBluetooth != null) {
1523                //Enable bluetooth
1524                try {
1525                    if (!mQuietEnable) {
1526                        if(!mBluetooth.enable()) {
1527                            Slog.e(TAG,"IBluetooth.enable() returned false");
1528                        }
1529                    }
1530                    else {
1531                        if(!mBluetooth.enableNoAutoConnect()) {
1532                            Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1533                        }
1534                    }
1535                } catch (RemoteException e) {
1536                    Slog.e(TAG,"Unable to call enable()",e);
1537                }
1538            }
1539        } finally {
1540            mBluetoothLock.writeLock().unlock();
1541        }
1542    }
1543
1544    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1545        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1546        intent.setComponent(comp);
1547        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1548            Slog.e(TAG, "Fail to bind to: " + intent);
1549            return false;
1550        }
1551        return true;
1552    }
1553
1554    private void handleDisable() {
1555        try {
1556            mBluetoothLock.readLock().lock();
1557            if (mBluetooth != null) {
1558                if (DBG) Slog.d(TAG,"Sending off request.");
1559                if (!mBluetooth.disable()) {
1560                    Slog.e(TAG,"IBluetooth.disable() returned false");
1561                }
1562            }
1563        } catch (RemoteException e) {
1564            Slog.e(TAG,"Unable to call disable()",e);
1565        } finally {
1566            mBluetoothLock.readLock().unlock();
1567        }
1568    }
1569
1570    private boolean checkIfCallerIsForegroundUser() {
1571        int foregroundUser;
1572        int callingUser = UserHandle.getCallingUserId();
1573        int callingUid = Binder.getCallingUid();
1574        long callingIdentity = Binder.clearCallingIdentity();
1575        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1576        UserInfo ui = um.getProfileParent(callingUser);
1577        int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
1578        int callingAppId = UserHandle.getAppId(callingUid);
1579        boolean valid = false;
1580        try {
1581            foregroundUser = ActivityManager.getCurrentUser();
1582            valid = (callingUser == foregroundUser) ||
1583                    parentUser == foregroundUser    ||
1584                    callingAppId == Process.NFC_UID ||
1585                    callingAppId == mSystemUiUid;
1586            if (DBG) {
1587                Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1588                    + " callingUser=" + callingUser
1589                    + " parentUser=" + parentUser
1590                    + " foregroundUser=" + foregroundUser);
1591            }
1592        } finally {
1593            Binder.restoreCallingIdentity(callingIdentity);
1594        }
1595        return valid;
1596    }
1597
1598    private void sendBleStateChanged(int prevState, int newState) {
1599        if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1600        // Send broadcast message to everyone else
1601        Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1602        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1603        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1604        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1605        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1606    }
1607
1608    private void bluetoothStateChangeHandler(int prevState, int newState) {
1609        boolean isStandardBroadcast = true;
1610        if (prevState != newState) {
1611            //Notify all proxy objects first of adapter state change
1612            if (newState == BluetoothAdapter.STATE_BLE_ON
1613                   || newState == BluetoothAdapter.STATE_OFF) {
1614                boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1615                   && newState == BluetoothAdapter.STATE_BLE_ON);
1616
1617                if (newState == BluetoothAdapter.STATE_OFF) {
1618                    // If Bluetooth is off, send service down event to proxy objects, and unbind
1619                    if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
1620                    if (canUnbindBluetoothService()) {
1621                        if (DBG) Slog.d(TAG, "Good to unbind!");
1622                        sendBluetoothServiceDownCallback();
1623                        unbindAndFinish();
1624                        sendBleStateChanged(prevState, newState);
1625                        // Don't broadcast as it has already been broadcast before
1626                        isStandardBroadcast = false;
1627                    }
1628
1629                } else if (!intermediate_off) {
1630                    // connect to GattService
1631                    if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
1632                    if (mBluetoothGatt != null) {
1633                        if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
1634                        onBluetoothGattServiceUp();
1635                    } else {
1636                        if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
1637                        if (mContext.getPackageManager().hasSystemFeature(
1638                                                        PackageManager.FEATURE_BLUETOOTH_LE)) {
1639                            Intent i = new Intent(IBluetoothGatt.class.getName());
1640                            doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1641                        }
1642                    }
1643                    sendBleStateChanged(prevState, newState);
1644                    //Don't broadcase this as std intent
1645                    isStandardBroadcast = false;
1646
1647                } else if (intermediate_off){
1648                    if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
1649                    // For LE only mode, broadcast as is
1650                    sendBleStateChanged(prevState, newState);
1651                    sendBluetoothStateCallback(false); // BT is OFF for general users
1652                    // Broadcast as STATE_OFF
1653                    newState = BluetoothAdapter.STATE_OFF;
1654                    sendBrEdrDownCallback();
1655                }
1656            } else if (newState == BluetoothAdapter.STATE_ON) {
1657                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1658                sendBluetoothStateCallback(isUp);
1659                sendBleStateChanged(prevState, newState);
1660
1661            } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
1662                || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1663                sendBleStateChanged(prevState, newState);
1664                isStandardBroadcast = false;
1665
1666            } else if (newState == BluetoothAdapter.STATE_TURNING_ON
1667                || newState == BluetoothAdapter.STATE_TURNING_OFF) {
1668                sendBleStateChanged(prevState, newState);
1669            }
1670
1671            if (isStandardBroadcast) {
1672                if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1673                    // Show prevState of BLE_ON as OFF to standard users
1674                    prevState = BluetoothAdapter.STATE_OFF;
1675                }
1676                Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1677                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1678                intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1679                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1680                mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1681            }
1682        }
1683    }
1684
1685    /**
1686     *  if on is true, wait for state become ON
1687     *  if off is true, wait for state become OFF
1688     *  if both on and off are false, wait for state not ON
1689     */
1690    private boolean waitForOnOff(boolean on, boolean off) {
1691        int i = 0;
1692        while (i < 10) {
1693            try {
1694                mBluetoothLock.readLock().lock();
1695                if (mBluetooth == null) break;
1696                if (on) {
1697                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1698                } else if (off) {
1699                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1700                } else {
1701                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1702                }
1703            } catch (RemoteException e) {
1704                Slog.e(TAG, "getState()", e);
1705                break;
1706            } finally {
1707                mBluetoothLock.readLock().unlock();
1708            }
1709            if (on || off) {
1710                SystemClock.sleep(300);
1711            } else {
1712                SystemClock.sleep(50);
1713            }
1714            i++;
1715        }
1716        Slog.e(TAG,"waitForOnOff time out");
1717        return false;
1718    }
1719
1720    private void sendDisableMsg() {
1721        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1722    }
1723
1724    private void sendEnableMsg(boolean quietMode) {
1725        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1726                             quietMode ? 1 : 0, 0));
1727    }
1728
1729    private boolean canUnbindBluetoothService() {
1730        try {
1731            //Only unbind with mEnable flag not set
1732            //For race condition: disable and enable back-to-back
1733            //Avoid unbind right after enable due to callback from disable
1734            //Only unbind with Bluetooth at OFF state
1735            //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1736            mBluetoothLock.readLock().lock();
1737            if (mEnable || (mBluetooth == null)) return false;
1738            if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1739            return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1740        } catch (RemoteException e) {
1741            Slog.e(TAG, "getState()", e);
1742        } finally {
1743            mBluetoothLock.readLock().unlock();
1744        }
1745        return false;
1746    }
1747
1748    private void recoverBluetoothServiceFromError() {
1749        Slog.e(TAG,"recoverBluetoothServiceFromError");
1750        try {
1751            mBluetoothLock.readLock().lock();
1752            if (mBluetooth != null) {
1753                //Unregister callback object
1754                mBluetooth.unregisterCallback(mBluetoothCallback);
1755            }
1756        } catch (RemoteException re) {
1757            Slog.e(TAG, "Unable to unregister", re);
1758        } finally {
1759            mBluetoothLock.readLock().unlock();
1760        }
1761
1762        SystemClock.sleep(500);
1763
1764        // disable
1765        handleDisable();
1766
1767        waitForOnOff(false, true);
1768
1769        sendBluetoothServiceDownCallback();
1770
1771        try {
1772            mBluetoothLock.writeLock().lock();
1773            if (mBluetooth != null) {
1774                mBluetooth = null;
1775                // Unbind
1776                mContext.unbindService(mConnection);
1777            }
1778            mBluetoothGatt = null;
1779        } finally {
1780            mBluetoothLock.writeLock().unlock();
1781        }
1782
1783        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1784        mState = BluetoothAdapter.STATE_OFF;
1785
1786        mEnable = false;
1787
1788        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1789            // Send a Bluetooth Restart message to reenable bluetooth
1790            Message restartMsg = mHandler.obtainMessage(
1791                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
1792            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1793        } else {
1794            // todo: notify user to power down and power up phone to make bluetooth work.
1795        }
1796    }
1797
1798    @Override
1799    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1800        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1801        String errorMsg = null;
1802        if (mBluetoothBinder == null) {
1803            errorMsg = "Bluetooth Service not connected";
1804        } else {
1805            try {
1806                mBluetoothBinder.dump(fd, args);
1807            } catch (RemoteException re) {
1808                errorMsg = "RemoteException while calling Bluetooth Service";
1809            }
1810        }
1811        if (errorMsg != null) {
1812            // Silently return if we are extracting metrics in Protobuf format
1813            if ((args.length > 0) && args[0].startsWith("--proto"))
1814                return;
1815            writer.println(errorMsg);
1816        }
1817    }
1818}
1819