BluetoothManagerService.java revision 414011116777e66bb3364fa86b856aa3574edbfa
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 = true;
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().unlock();
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
643        synchronized(mReceiver) {
644            mQuietEnableExternal = false;
645            mEnableExternal = true;
646            // waive WRITE_SECURE_SETTINGS permission check
647            sendEnableMsg(false);
648        }
649        if (DBG) Slog.d(TAG, "enable returning");
650        return true;
651    }
652
653    public boolean disable(boolean persist) {
654        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
655                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
656
657        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
658            (!checkIfCallerIsForegroundUser())) {
659            Slog.w(TAG,"disable(): not allowed for non-active and non system user");
660            return false;
661        }
662
663        if (DBG) {
664            Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth +
665                " mBinding = " + mBinding);
666        }
667
668        synchronized(mReceiver) {
669            if (persist) {
670                // waive WRITE_SECURE_SETTINGS permission check
671                long callingIdentity = Binder.clearCallingIdentity();
672                persistBluetoothSetting(BLUETOOTH_OFF);
673                Binder.restoreCallingIdentity(callingIdentity);
674            }
675            mEnableExternal = false;
676            sendDisableMsg();
677        }
678        return true;
679    }
680
681    public void unbindAndFinish() {
682        if (DBG) {
683            Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
684                " mBinding = " + mBinding);
685        }
686
687        try {
688            mBluetoothLock.writeLock().lock();
689            if (mUnbinding) return;
690            mUnbinding = true;
691            mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
692            if (mBluetooth != null) {
693                //Unregister callback object
694                try {
695                    mBluetooth.unregisterCallback(mBluetoothCallback);
696                } catch (RemoteException re) {
697                    Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
698                }
699
700                if (DBG) Slog.d(TAG, "Sending unbind request.");
701                mBluetoothBinder = null;
702                mBluetooth = null;
703                //Unbind
704                mContext.unbindService(mConnection);
705                mUnbinding = false;
706                mBinding = false;
707            } else {
708                mUnbinding=false;
709            }
710            mBluetoothGatt = null;
711        } finally {
712            mBluetoothLock.writeLock().unlock();
713        }
714    }
715
716    public IBluetoothGatt getBluetoothGatt() {
717        // sync protection
718        return mBluetoothGatt;
719    }
720
721    @Override
722    public boolean bindBluetoothProfileService(int bluetoothProfile,
723            IBluetoothProfileServiceConnection proxy) {
724        if (!mEnable) {
725            if (DBG) {
726                Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
727                        ", while Bluetooth was disabled");
728            }
729            return false;
730        }
731        synchronized (mProfileServices) {
732            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
733            if (psc == null) {
734                if (DBG) {
735                    Slog.d(TAG, "Creating new ProfileServiceConnections object for"
736                            + " profile: " + bluetoothProfile);
737                }
738
739                if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
740
741                Intent intent = new Intent(IBluetoothHeadset.class.getName());
742                psc = new ProfileServiceConnections(intent);
743                if (!psc.bindService()) return false;
744
745                mProfileServices.put(new Integer(bluetoothProfile), psc);
746            }
747        }
748
749        // Introducing a delay to give the client app time to prepare
750        Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
751        addProxyMsg.arg1 = bluetoothProfile;
752        addProxyMsg.obj = proxy;
753        mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
754        return true;
755    }
756
757    @Override
758    public void unbindBluetoothProfileService(int bluetoothProfile,
759            IBluetoothProfileServiceConnection proxy) {
760        synchronized (mProfileServices) {
761            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
762            if (psc == null) {
763                return;
764            }
765            psc.removeProxy(proxy);
766        }
767    }
768
769    private void unbindAllBluetoothProfileServices() {
770        synchronized (mProfileServices) {
771            for (Integer i : mProfileServices.keySet()) {
772                ProfileServiceConnections psc = mProfileServices.get(i);
773                try {
774                    mContext.unbindService(psc);
775                } catch (IllegalArgumentException e) {
776                    Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
777                }
778                psc.removeAllProxies();
779            }
780            mProfileServices.clear();
781        }
782    }
783
784    /**
785     * Send enable message and set adapter name and address. Called when the boot phase becomes
786     * PHASE_SYSTEM_SERVICES_READY.
787     */
788    public void handleOnBootPhase() {
789        if (DBG) Slog.d(TAG, "Bluetooth boot completed");
790        if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
791            if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
792            sendEnableMsg(mQuietEnableExternal);
793        } else if (!isNameAndAddressSet()) {
794            if (DBG) Slog.d(TAG, "Getting adapter name and address");
795            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
796            mHandler.sendMessage(getMsg);
797        }
798    }
799
800    /**
801     * Called when switching to a different foreground user.
802     */
803    public void handleOnSwitchUser(int userHandle) {
804        if (DBG) Slog.d(TAG, "User " + userHandle + " switched");
805        mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
806    }
807
808    /**
809     * Called when user is unlocked.
810     */
811    public void handleOnUnlockUser(int userHandle) {
812        if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked");
813        mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
814    }
815
816    /**
817     * This class manages the clients connected to a given ProfileService
818     * and maintains the connection with that service.
819     */
820    final private class ProfileServiceConnections implements ServiceConnection,
821            IBinder.DeathRecipient {
822        final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
823                new RemoteCallbackList <IBluetoothProfileServiceConnection>();
824        IBinder mService;
825        ComponentName mClassName;
826        Intent mIntent;
827        boolean mInvokingProxyCallbacks = false;
828
829        ProfileServiceConnections(Intent intent) {
830            mService = null;
831            mClassName = null;
832            mIntent = intent;
833        }
834
835        private boolean bindService() {
836            if (mIntent != null && mService == null &&
837                    doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
838                Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
839                msg.obj = this;
840                mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
841                return true;
842            }
843            Slog.w(TAG, "Unable to bind with intent: " + mIntent);
844            return false;
845        }
846
847        private void addProxy(IBluetoothProfileServiceConnection proxy) {
848            mProxies.register(proxy);
849            if (mService != null) {
850                try{
851                    proxy.onServiceConnected(mClassName, mService);
852                } catch (RemoteException e) {
853                    Slog.e(TAG, "Unable to connect to proxy", e);
854                }
855            } else {
856                if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
857                    Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
858                    msg.obj = this;
859                    mHandler.sendMessage(msg);
860                }
861            }
862        }
863
864        private void removeProxy(IBluetoothProfileServiceConnection proxy) {
865            if (proxy != null) {
866                if (mProxies.unregister(proxy)) {
867                    try {
868                        proxy.onServiceDisconnected(mClassName);
869                    } catch (RemoteException e) {
870                        Slog.e(TAG, "Unable to disconnect proxy", e);
871                    }
872                }
873            } else {
874                Slog.w(TAG, "Trying to remove a null proxy");
875            }
876        }
877
878        private void removeAllProxies() {
879            onServiceDisconnected(mClassName);
880            mProxies.kill();
881        }
882
883        @Override
884        public void onServiceConnected(ComponentName className, IBinder service) {
885            // remove timeout message
886            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
887            mService = service;
888            mClassName = className;
889            try {
890                mService.linkToDeath(this, 0);
891            } catch (RemoteException e) {
892                Slog.e(TAG, "Unable to linkToDeath", e);
893            }
894
895            if (mInvokingProxyCallbacks) {
896                Slog.e(TAG, "Proxy callbacks already in progress.");
897                return;
898            }
899            mInvokingProxyCallbacks = true;
900
901            final int n = mProxies.beginBroadcast();
902            try {
903                for (int i = 0; i < n; i++) {
904                    try {
905                        mProxies.getBroadcastItem(i).onServiceConnected(className, service);
906                    } catch (RemoteException e) {
907                        Slog.e(TAG, "Unable to connect to proxy", e);
908                    }
909                }
910            } finally {
911                mProxies.finishBroadcast();
912                mInvokingProxyCallbacks = false;
913            }
914        }
915
916        @Override
917        public void onServiceDisconnected(ComponentName className) {
918            if (mService == null) return;
919            mService.unlinkToDeath(this, 0);
920            mService = null;
921            mClassName = null;
922
923            if (mInvokingProxyCallbacks) {
924                Slog.e(TAG, "Proxy callbacks already in progress.");
925                return;
926            }
927            mInvokingProxyCallbacks = true;
928
929            final int n = mProxies.beginBroadcast();
930            try {
931                for (int i = 0; i < n; i++) {
932                    try {
933                        mProxies.getBroadcastItem(i).onServiceDisconnected(className);
934                    } catch (RemoteException e) {
935                        Slog.e(TAG, "Unable to disconnect from proxy", e);
936                    }
937                }
938            } finally {
939                mProxies.finishBroadcast();
940                mInvokingProxyCallbacks = false;
941            }
942        }
943
944        @Override
945        public void binderDied() {
946            if (DBG) {
947                Slog.w(TAG, "Profile service for profile: " + mClassName
948                        + " died.");
949            }
950            onServiceDisconnected(mClassName);
951            // Trigger rebind
952            Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
953            msg.obj = this;
954            mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
955        }
956    }
957
958    private void sendBluetoothStateCallback(boolean isUp) {
959        try {
960            int n = mStateChangeCallbacks.beginBroadcast();
961            if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
962            for (int i=0; i <n;i++) {
963                try {
964                    mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
965                } catch (RemoteException e) {
966                    Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
967                }
968            }
969        } finally {
970            mStateChangeCallbacks.finishBroadcast();
971        }
972    }
973
974    /**
975     * Inform BluetoothAdapter instances that Adapter service is up
976     */
977    private void sendBluetoothServiceUpCallback() {
978        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
979        try {
980            int n = mCallbacks.beginBroadcast();
981            Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
982            for (int i=0; i <n;i++) {
983                try {
984                    mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
985                }  catch (RemoteException e) {
986                    Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
987                }
988            }
989        } finally {
990            mCallbacks.finishBroadcast();
991        }
992    }
993    /**
994     * Inform BluetoothAdapter instances that Adapter service is down
995     */
996    private void sendBluetoothServiceDownCallback() {
997        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
998        try {
999            int n = mCallbacks.beginBroadcast();
1000            Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
1001            for (int i=0; i <n;i++) {
1002                try {
1003                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
1004                }  catch (RemoteException e) {
1005                    Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
1006                }
1007            }
1008        } finally {
1009            mCallbacks.finishBroadcast();
1010        }
1011    }
1012
1013    public String getAddress() {
1014        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1015                "Need BLUETOOTH permission");
1016
1017        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
1018                (!checkIfCallerIsForegroundUser())) {
1019            Slog.w(TAG,"getAddress(): not allowed for non-active and non system user");
1020            return null;
1021        }
1022
1023        if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
1024                != PackageManager.PERMISSION_GRANTED) {
1025            return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
1026        }
1027
1028        try {
1029            mBluetoothLock.readLock().lock();
1030            if (mBluetooth != null) return mBluetooth.getAddress();
1031        } catch (RemoteException e) {
1032            Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e);
1033        } finally {
1034            mBluetoothLock.readLock().unlock();
1035        }
1036
1037        // mAddress is accessed from outside.
1038        // It is alright without a lock. Here, bluetooth is off, no other thread is
1039        // changing mAddress
1040        return mAddress;
1041    }
1042
1043    public String getName() {
1044        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1045                                                "Need BLUETOOTH permission");
1046
1047        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
1048            (!checkIfCallerIsForegroundUser())) {
1049            Slog.w(TAG,"getName(): not allowed for non-active and non system user");
1050            return null;
1051        }
1052
1053        try {
1054            mBluetoothLock.readLock().lock();
1055            if (mBluetooth != null) return mBluetooth.getName();
1056        } catch (RemoteException e) {
1057            Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
1058        } finally {
1059            mBluetoothLock.readLock().unlock();
1060        }
1061
1062        // mName is accessed from outside.
1063        // It alright without a lock. Here, bluetooth is off, no other thread is
1064        // changing mName
1065        return mName;
1066    }
1067
1068    private class BluetoothServiceConnection implements ServiceConnection {
1069        public void onServiceConnected(ComponentName className, IBinder service) {
1070            if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
1071            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
1072            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
1073            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
1074                msg.arg1 = SERVICE_IBLUETOOTH;
1075                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
1076            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
1077                msg.arg1 = SERVICE_IBLUETOOTHGATT;
1078            } else {
1079                Slog.e(TAG, "Unknown service connected: " + className.getClassName());
1080                return;
1081            }
1082            msg.obj = service;
1083            mHandler.sendMessage(msg);
1084        }
1085
1086        public void onServiceDisconnected(ComponentName className) {
1087            // Called if we unexpected disconnected.
1088            if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " +
1089                           className.getClassName());
1090            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
1091            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
1092                msg.arg1 = SERVICE_IBLUETOOTH;
1093            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
1094                msg.arg1 = SERVICE_IBLUETOOTHGATT;
1095            } else {
1096                Slog.e(TAG, "Unknown service disconnected: " + className.getClassName());
1097                return;
1098            }
1099            mHandler.sendMessage(msg);
1100        }
1101    }
1102
1103    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
1104
1105    private class BluetoothHandler extends Handler {
1106        boolean mGetNameAddressOnly = false;
1107
1108        public BluetoothHandler(Looper looper) {
1109            super(looper);
1110        }
1111
1112        @Override
1113        public void handleMessage(Message msg) {
1114            if (DBG) Slog.d (TAG, "Message: " + msg.what);
1115            switch (msg.what) {
1116                case MESSAGE_GET_NAME_AND_ADDRESS:
1117                    if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
1118                    try {
1119                        mBluetoothLock.writeLock().lock();
1120                        if ((mBluetooth == null) && (!mBinding)) {
1121                            if (DBG) Slog.d(TAG, "Binding to service to get name and address");
1122                            mGetNameAddressOnly = true;
1123                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1124                            mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
1125                            Intent i = new Intent(IBluetooth.class.getName());
1126                            if (!doBind(i, mConnection,
1127                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1128                                UserHandle.CURRENT)) {
1129                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1130                            } else {
1131                                mBinding = true;
1132                            }
1133                        } else if (mBluetooth != null) {
1134                            try {
1135                                storeNameAndAddress(mBluetooth.getName(),
1136                                                    mBluetooth.getAddress());
1137                            } catch (RemoteException re) {
1138                                Slog.e(TAG, "Unable to grab names", re);
1139                            }
1140                            if (mGetNameAddressOnly && !mEnable) {
1141                                unbindAndFinish();
1142                            }
1143                            mGetNameAddressOnly = false;
1144                        }
1145                    } finally {
1146                        mBluetoothLock.writeLock().unlock();
1147                    }
1148                    break;
1149
1150                case MESSAGE_ENABLE:
1151                    if (DBG) {
1152                        Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
1153                    }
1154                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1155                    mEnable = true;
1156
1157                    // Use service interface to get the exact state
1158                    try {
1159                        mBluetoothLock.readLock().lock();
1160                        if (mBluetooth != null) {
1161                            int state = mBluetooth.getState();
1162                            if (state == BluetoothAdapter.STATE_BLE_ON) {
1163                                Slog.w(TAG, "BT is in BLE_ON State");
1164                                mBluetooth.onLeServiceUp();
1165                                break;
1166                            }
1167                        }
1168                    } catch (RemoteException e) {
1169                        Slog.e(TAG, "", e);
1170                    } finally {
1171                        mBluetoothLock.readLock().unlock();
1172                    }
1173
1174                    mQuietEnable = (msg.arg1 == 1);
1175                    if (mBluetooth == null) {
1176                        handleEnable(mQuietEnable);
1177                    } else {
1178                        //
1179                        // We need to wait until transitioned to STATE_OFF and
1180                        // the previous Bluetooth process has exited. The
1181                        // waiting period has three components:
1182                        // (a) Wait until the local state is STATE_OFF. This
1183                        //     is accomplished by "waitForOnOff(false, true)".
1184                        // (b) Wait until the STATE_OFF state is updated to
1185                        //     all components.
1186                        // (c) Wait until the Bluetooth process exits, and
1187                        //     ActivityManager detects it.
1188                        // The waiting for (b) and (c) is accomplished by
1189                        // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
1190                        // message. On slower devices, that delay needs to be
1191                        // on the order of (2 * SERVICE_RESTART_TIME_MS).
1192                        //
1193                        waitForOnOff(false, true);
1194                        Message restartMsg = mHandler.obtainMessage(
1195                                MESSAGE_RESTART_BLUETOOTH_SERVICE);
1196                        mHandler.sendMessageDelayed(restartMsg,
1197                                2 * SERVICE_RESTART_TIME_MS);
1198                    }
1199                    break;
1200
1201                case MESSAGE_DISABLE:
1202                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1203                    if (mEnable && mBluetooth != null) {
1204                        waitForOnOff(true, false);
1205                        mEnable = false;
1206                        handleDisable();
1207                        waitForOnOff(false, false);
1208                    } else {
1209                        mEnable = false;
1210                        handleDisable();
1211                    }
1212                    break;
1213
1214                case MESSAGE_REGISTER_ADAPTER:
1215                {
1216                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1217                    boolean added = mCallbacks.register(callback);
1218                    Slog.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
1219                }
1220                    break;
1221                case MESSAGE_UNREGISTER_ADAPTER:
1222                {
1223                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1224                    boolean removed = mCallbacks.unregister(callback);
1225                    Slog.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
1226                    break;
1227                }
1228                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1229                {
1230                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1231                    if (callback != null) {
1232                        mStateChangeCallbacks.register(callback);
1233                    }
1234                    break;
1235                }
1236                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1237                {
1238                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1239                    if (callback != null) {
1240                        mStateChangeCallbacks.unregister(callback);
1241                    }
1242                    break;
1243                }
1244                case MESSAGE_ADD_PROXY_DELAYED:
1245                {
1246                    ProfileServiceConnections psc = mProfileServices.get(
1247                            new Integer(msg.arg1));
1248                    if (psc == null) {
1249                        break;
1250                    }
1251                    IBluetoothProfileServiceConnection proxy =
1252                            (IBluetoothProfileServiceConnection) msg.obj;
1253                    psc.addProxy(proxy);
1254                    break;
1255                }
1256                case MESSAGE_BIND_PROFILE_SERVICE:
1257                {
1258                    ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1259                    removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1260                    if (psc == null) {
1261                        break;
1262                    }
1263                    psc.bindService();
1264                    break;
1265                }
1266                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1267                {
1268                    if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
1269
1270                    IBinder service = (IBinder) msg.obj;
1271                    try {
1272                        mBluetoothLock.writeLock().lock();
1273                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1274                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1275                            onBluetoothGattServiceUp();
1276                            break;
1277                        } // else must be SERVICE_IBLUETOOTH
1278
1279                        //Remove timeout
1280                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1281
1282                        mBinding = false;
1283                        mBluetoothBinder = service;
1284                        mBluetooth = IBluetooth.Stub.asInterface(service);
1285
1286                        if (!isNameAndAddressSet()) {
1287                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1288                            mHandler.sendMessage(getMsg);
1289                            if (mGetNameAddressOnly) return;
1290                        }
1291
1292                        try {
1293                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1294                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1295                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1296                                Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
1297                            }
1298                        } catch (RemoteException e) {
1299                            Slog.e(TAG,"Unable to call configHciSnoopLog", e);
1300                        }
1301
1302                        //Register callback object
1303                        try {
1304                            mBluetooth.registerCallback(mBluetoothCallback);
1305                        } catch (RemoteException re) {
1306                            Slog.e(TAG, "Unable to register BluetoothCallback",re);
1307                        }
1308                        //Inform BluetoothAdapter instances that service is up
1309                        sendBluetoothServiceUpCallback();
1310
1311                        //Do enable request
1312                        try {
1313                            if (mQuietEnable == false) {
1314                                if(!mBluetooth.enable()) {
1315                                    Slog.e(TAG,"IBluetooth.enable() returned false");
1316                                }
1317                            }
1318                            else
1319                            {
1320                                if(!mBluetooth.enableNoAutoConnect()) {
1321                                    Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1322                                }
1323                            }
1324                        } catch (RemoteException e) {
1325                            Slog.e(TAG,"Unable to call enable()",e);
1326                        }
1327                    } finally {
1328                        mBluetoothLock.writeLock().unlock();
1329                    }
1330
1331                    if (!mEnable) {
1332                        waitForOnOff(true, false);
1333                        handleDisable();
1334                        waitForOnOff(false, false);
1335                    }
1336                    break;
1337                }
1338                case MESSAGE_TIMEOUT_BIND: {
1339                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
1340                    mBluetoothLock.writeLock().lock();
1341                    mBinding = false;
1342                    mBluetoothLock.writeLock().unlock();
1343
1344                    break;
1345                }
1346                case MESSAGE_BLUETOOTH_STATE_CHANGE:
1347                {
1348                    int prevState = msg.arg1;
1349                    int newState = msg.arg2;
1350                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
1351                    mState = newState;
1352                    bluetoothStateChangeHandler(prevState, newState);
1353                    // handle error state transition case from TURNING_ON to OFF
1354                    // unbind and rebind bluetooth service and enable bluetooth
1355                    if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
1356                            (newState == BluetoothAdapter.STATE_OFF) &&
1357                            (mBluetooth != null) && mEnable) {
1358                        recoverBluetoothServiceFromError();
1359                    }
1360                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1361                            (newState == BluetoothAdapter.STATE_BLE_ON) &&
1362                            (mBluetooth != null) && mEnable) {
1363                        recoverBluetoothServiceFromError();
1364                    }
1365                    // If we tried to enable BT while BT was in the process of shutting down,
1366                    // wait for the BT process to fully tear down and then force a restart
1367                    // here.  This is a bit of a hack (b/29363429).
1368                    if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) &&
1369                            (newState == BluetoothAdapter.STATE_OFF)) {
1370                        if (mEnable) {
1371                            Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
1372                            waitForOnOff(false, true);
1373                            Message restartMsg = mHandler.obtainMessage(
1374                                    MESSAGE_RESTART_BLUETOOTH_SERVICE);
1375                            mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
1376                        }
1377                    }
1378                    if (newState == BluetoothAdapter.STATE_ON ||
1379                            newState == BluetoothAdapter.STATE_BLE_ON) {
1380                        // bluetooth is working, reset the counter
1381                        if (mErrorRecoveryRetryCounter != 0) {
1382                            Slog.w(TAG, "bluetooth is recovered from error");
1383                            mErrorRecoveryRetryCounter = 0;
1384                        }
1385                    }
1386                    break;
1387                }
1388                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1389                {
1390                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
1391                    try {
1392                        mBluetoothLock.writeLock().lock();
1393                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
1394                            // if service is unbinded already, do nothing and return
1395                            if (mBluetooth == null) break;
1396                            mBluetooth = null;
1397                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1398                            mBluetoothGatt = null;
1399                            break;
1400                        } else {
1401                            Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
1402                            break;
1403                        }
1404                    } finally {
1405                        mBluetoothLock.writeLock().unlock();
1406                    }
1407
1408                    if (mEnable) {
1409                        mEnable = false;
1410                        // Send a Bluetooth Restart message
1411                        Message restartMsg = mHandler.obtainMessage(
1412                            MESSAGE_RESTART_BLUETOOTH_SERVICE);
1413                        mHandler.sendMessageDelayed(restartMsg,
1414                            SERVICE_RESTART_TIME_MS);
1415                    }
1416
1417                    sendBluetoothServiceDownCallback();
1418
1419                    // Send BT state broadcast to update
1420                    // the BT icon correctly
1421                    if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1422                            (mState == BluetoothAdapter.STATE_ON)) {
1423                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1424                                                    BluetoothAdapter.STATE_TURNING_OFF);
1425                        mState = BluetoothAdapter.STATE_TURNING_OFF;
1426                    }
1427                    if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1428                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1429                                                    BluetoothAdapter.STATE_OFF);
1430                    }
1431
1432                    mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1433                    mState = BluetoothAdapter.STATE_OFF;
1434                    break;
1435                }
1436                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1437                {
1438                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1439                        +" Restart IBluetooth service");
1440                    /* Enable without persisting the setting as
1441                     it doesnt change when IBluetooth
1442                     service restarts */
1443                    mEnable = true;
1444                    handleEnable(mQuietEnable);
1445                    break;
1446                }
1447
1448                case MESSAGE_TIMEOUT_UNBIND:
1449                {
1450                    Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
1451                    mBluetoothLock.writeLock().lock();
1452                    mUnbinding = false;
1453                    mBluetoothLock.writeLock().unlock();
1454                    break;
1455                }
1456
1457                case MESSAGE_USER_SWITCHED: {
1458                    if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
1459                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1460
1461                    /* disable and enable BT when detect a user switch */
1462                    if (mEnable && mBluetooth != null) {
1463                        try {
1464                            mBluetoothLock.readLock().lock();
1465                            if (mBluetooth != null) {
1466                                mBluetooth.unregisterCallback(mBluetoothCallback);
1467                            }
1468                        } catch (RemoteException re) {
1469                            Slog.e(TAG, "Unable to unregister", re);
1470                        } finally {
1471                            mBluetoothLock.readLock().unlock();
1472                        }
1473
1474                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1475                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1476                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1477                            mState = BluetoothAdapter.STATE_OFF;
1478                        }
1479                        if (mState == BluetoothAdapter.STATE_OFF) {
1480                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1481                            mState = BluetoothAdapter.STATE_TURNING_ON;
1482                        }
1483
1484                        waitForOnOff(true, false);
1485
1486                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1487                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1488                        }
1489
1490                        unbindAllBluetoothProfileServices();
1491                        // disable
1492                        handleDisable();
1493                        // Pbap service need receive STATE_TURNING_OFF intent to close
1494                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1495                                                    BluetoothAdapter.STATE_TURNING_OFF);
1496
1497                        boolean didDisableTimeout = !waitForOnOff(false, true);
1498
1499                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1500                                                    BluetoothAdapter.STATE_OFF);
1501                        sendBluetoothServiceDownCallback();
1502
1503                        try {
1504                            mBluetoothLock.writeLock().lock();
1505                            if (mBluetooth != null) {
1506                                mBluetooth = null;
1507                                // Unbind
1508                                mContext.unbindService(mConnection);
1509                            }
1510                            mBluetoothGatt = null;
1511                        } finally {
1512                            mBluetoothLock.writeLock().unlock();
1513                        }
1514
1515                        //
1516                        // If disabling Bluetooth times out, wait for an
1517                        // additional amount of time to ensure the process is
1518                        // shut down completely before attempting to restart.
1519                        //
1520                        if (didDisableTimeout) {
1521                            SystemClock.sleep(3000);
1522                        } else {
1523                            SystemClock.sleep(100);
1524                        }
1525
1526                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1527                        mState = BluetoothAdapter.STATE_OFF;
1528                        // enable
1529                        handleEnable(mQuietEnable);
1530                    } else if (mBinding || mBluetooth != null) {
1531                        Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1532                        userMsg.arg2 = 1 + msg.arg2;
1533                        // if user is switched when service is being binding
1534                        // delay sending MESSAGE_USER_SWITCHED
1535                        mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1536                        if (DBG) {
1537                            Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1538                        }
1539                    }
1540                    break;
1541                }
1542                case MESSAGE_USER_UNLOCKED: {
1543                    if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
1544                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1545
1546                    if (mEnable && !mBinding && (mBluetooth == null)) {
1547                        // We should be connected, but we gave up for some
1548                        // reason; maybe the Bluetooth service wasn't encryption
1549                        // aware, so try binding again.
1550                        if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
1551                        handleEnable(mQuietEnable);
1552                    }
1553                }
1554            }
1555        }
1556    }
1557
1558    private void handleEnable(boolean quietMode) {
1559        mQuietEnable = quietMode;
1560
1561        try {
1562            mBluetoothLock.writeLock().lock();
1563            if ((mBluetooth == null) && (!mBinding)) {
1564                //Start bind timeout and bind
1565                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1566                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1567                Intent i = new Intent(IBluetooth.class.getName());
1568                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1569                        UserHandle.CURRENT)) {
1570                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1571                } else {
1572                    mBinding = true;
1573                }
1574            } else if (mBluetooth != null) {
1575                //Enable bluetooth
1576                try {
1577                    if (!mQuietEnable) {
1578                        if(!mBluetooth.enable()) {
1579                            Slog.e(TAG,"IBluetooth.enable() returned false");
1580                        }
1581                    }
1582                    else {
1583                        if(!mBluetooth.enableNoAutoConnect()) {
1584                            Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1585                        }
1586                    }
1587                } catch (RemoteException e) {
1588                    Slog.e(TAG,"Unable to call enable()",e);
1589                }
1590            }
1591        } finally {
1592            mBluetoothLock.writeLock().unlock();
1593        }
1594    }
1595
1596    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1597        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1598        intent.setComponent(comp);
1599        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1600            Slog.e(TAG, "Fail to bind to: " + intent);
1601            return false;
1602        }
1603        return true;
1604    }
1605
1606    private void handleDisable() {
1607        try {
1608            mBluetoothLock.readLock().lock();
1609            if (mBluetooth != null) {
1610                if (DBG) Slog.d(TAG,"Sending off request.");
1611                if (!mBluetooth.disable()) {
1612                    Slog.e(TAG,"IBluetooth.disable() returned false");
1613                }
1614            }
1615        } catch (RemoteException e) {
1616            Slog.e(TAG,"Unable to call disable()",e);
1617        } finally {
1618            mBluetoothLock.readLock().unlock();
1619        }
1620    }
1621
1622    private boolean checkIfCallerIsForegroundUser() {
1623        int foregroundUser;
1624        int callingUser = UserHandle.getCallingUserId();
1625        int callingUid = Binder.getCallingUid();
1626        long callingIdentity = Binder.clearCallingIdentity();
1627        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1628        UserInfo ui = um.getProfileParent(callingUser);
1629        int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
1630        int callingAppId = UserHandle.getAppId(callingUid);
1631        boolean valid = false;
1632        try {
1633            foregroundUser = ActivityManager.getCurrentUser();
1634            valid = (callingUser == foregroundUser) ||
1635                    parentUser == foregroundUser    ||
1636                    callingAppId == Process.NFC_UID ||
1637                    callingAppId == mSystemUiUid;
1638            if (DBG) {
1639                Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1640                    + " callingUser=" + callingUser
1641                    + " parentUser=" + parentUser
1642                    + " foregroundUser=" + foregroundUser);
1643            }
1644        } finally {
1645            Binder.restoreCallingIdentity(callingIdentity);
1646        }
1647        return valid;
1648    }
1649
1650    private void sendBleStateChanged(int prevState, int newState) {
1651        if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1652        // Send broadcast message to everyone else
1653        Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1654        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1655        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1656        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1657        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1658    }
1659
1660    private void bluetoothStateChangeHandler(int prevState, int newState) {
1661        boolean isStandardBroadcast = true;
1662        if (prevState != newState) {
1663            //Notify all proxy objects first of adapter state change
1664            if (newState == BluetoothAdapter.STATE_BLE_ON ||
1665                    newState == BluetoothAdapter.STATE_OFF) {
1666                boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1667                   && newState == BluetoothAdapter.STATE_BLE_ON);
1668
1669                if (newState == BluetoothAdapter.STATE_OFF) {
1670                    // If Bluetooth is off, send service down event to proxy objects, and unbind
1671                    if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
1672                    sendBluetoothServiceDownCallback();
1673                    unbindAndFinish();
1674                    sendBleStateChanged(prevState, newState);
1675                    // Don't broadcast as it has already been broadcast before
1676                    isStandardBroadcast = false;
1677
1678                } else if (!intermediate_off) {
1679                    // connect to GattService
1680                    if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
1681                    if (mBluetoothGatt != null) {
1682                        if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
1683                        onBluetoothGattServiceUp();
1684                    } else {
1685                        if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
1686                        if (mContext.getPackageManager().hasSystemFeature(
1687                                                        PackageManager.FEATURE_BLUETOOTH_LE)) {
1688                            Intent i = new Intent(IBluetoothGatt.class.getName());
1689                            doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1690                        }
1691                    }
1692                    sendBleStateChanged(prevState, newState);
1693                    //Don't broadcase this as std intent
1694                    isStandardBroadcast = false;
1695
1696                } else if (intermediate_off){
1697                    if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
1698                    // For LE only mode, broadcast as is
1699                    sendBleStateChanged(prevState, newState);
1700                    sendBluetoothStateCallback(false); // BT is OFF for general users
1701                    // Broadcast as STATE_OFF
1702                    newState = BluetoothAdapter.STATE_OFF;
1703                    sendBrEdrDownCallback();
1704                }
1705            } else if (newState == BluetoothAdapter.STATE_ON) {
1706                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1707                sendBluetoothStateCallback(isUp);
1708                sendBleStateChanged(prevState, newState);
1709
1710            } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
1711                    newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1712                sendBleStateChanged(prevState, newState);
1713                isStandardBroadcast = false;
1714
1715            } else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
1716                    newState == BluetoothAdapter.STATE_TURNING_OFF) {
1717                sendBleStateChanged(prevState, newState);
1718            }
1719
1720            if (isStandardBroadcast) {
1721                if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1722                    // Show prevState of BLE_ON as OFF to standard users
1723                    prevState = BluetoothAdapter.STATE_OFF;
1724                }
1725                Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1726                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1727                intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1728                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1729                mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1730            }
1731        }
1732    }
1733
1734    /**
1735     *  if on is true, wait for state become ON
1736     *  if off is true, wait for state become OFF
1737     *  if both on and off are false, wait for state not ON
1738     */
1739    private boolean waitForOnOff(boolean on, boolean off) {
1740        int i = 0;
1741        while (i < 10) {
1742            try {
1743                mBluetoothLock.readLock().lock();
1744                if (mBluetooth == null) break;
1745                if (on) {
1746                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1747                } else if (off) {
1748                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1749                } else {
1750                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1751                }
1752            } catch (RemoteException e) {
1753                Slog.e(TAG, "getState()", e);
1754                break;
1755            } finally {
1756                mBluetoothLock.readLock().unlock();
1757            }
1758            if (on || off) {
1759                SystemClock.sleep(300);
1760            } else {
1761                SystemClock.sleep(50);
1762            }
1763            i++;
1764        }
1765        Slog.e(TAG,"waitForOnOff time out");
1766        return false;
1767    }
1768
1769    private void sendDisableMsg() {
1770        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1771    }
1772
1773    private void sendEnableMsg(boolean quietMode) {
1774        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1775                             quietMode ? 1 : 0, 0));
1776    }
1777
1778    private void recoverBluetoothServiceFromError() {
1779        Slog.e(TAG,"recoverBluetoothServiceFromError");
1780        try {
1781            mBluetoothLock.readLock().lock();
1782            if (mBluetooth != null) {
1783                //Unregister callback object
1784                mBluetooth.unregisterCallback(mBluetoothCallback);
1785            }
1786        } catch (RemoteException re) {
1787            Slog.e(TAG, "Unable to unregister", re);
1788        } finally {
1789            mBluetoothLock.readLock().unlock();
1790        }
1791
1792        SystemClock.sleep(500);
1793
1794        // disable
1795        handleDisable();
1796
1797        waitForOnOff(false, true);
1798
1799        sendBluetoothServiceDownCallback();
1800
1801        try {
1802            mBluetoothLock.writeLock().lock();
1803            if (mBluetooth != null) {
1804                mBluetooth = null;
1805                // Unbind
1806                mContext.unbindService(mConnection);
1807            }
1808            mBluetoothGatt = null;
1809        } finally {
1810            mBluetoothLock.writeLock().unlock();
1811        }
1812
1813        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1814        mState = BluetoothAdapter.STATE_OFF;
1815
1816        mEnable = false;
1817
1818        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1819            // Send a Bluetooth Restart message to reenable bluetooth
1820            Message restartMsg = mHandler.obtainMessage(
1821                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
1822            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1823        } else {
1824            // todo: notify user to power down and power up phone to make bluetooth work.
1825        }
1826    }
1827
1828    @Override
1829    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1830        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1831        String errorMsg = null;
1832        if (mBluetoothBinder == null) {
1833            errorMsg = "Bluetooth Service not connected";
1834        } else {
1835            try {
1836                mBluetoothBinder.dump(fd, args);
1837            } catch (RemoteException re) {
1838                errorMsg = "RemoteException while calling Bluetooth Service";
1839            }
1840        }
1841        if (errorMsg != null) {
1842            // Silently return if we are extracting metrics in Protobuf format
1843            if ((args.length > 0) && args[0].startsWith("--proto"))
1844                return;
1845            writer.println(errorMsg);
1846        }
1847    }
1848}
1849