BluetoothManagerService.java revision 7ee53be300573c9bdc71607d32d4a642e4ad3dc8
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().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                    if (mBluetooth == null) {
1157                        handleEnable(msg.arg1 == 1);
1158                    } else {
1159                        //
1160                        // We need to wait until transitioned to STATE_OFF and
1161                        // the previous Bluetooth process has exited. The
1162                        // waiting period has three components:
1163                        // (a) Wait until the local state is STATE_OFF. This
1164                        //     is accomplished by "waitForOnOff(false, true)".
1165                        // (b) Wait until the STATE_OFF state is updated to
1166                        //     all components.
1167                        // (c) Wait until the Bluetooth process exits, and
1168                        //     ActivityManager detects it.
1169                        // The waiting for (b) and (c) is accomplished by
1170                        // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
1171                        // message. On slower devices, that delay needs to be
1172                        // on the order of (2 * SERVICE_RESTART_TIME_MS).
1173                        //
1174                        waitForOnOff(false, true);
1175                        mQuietEnable = (msg.arg1 == 1);
1176                        Message restartMsg = mHandler.obtainMessage(
1177                                MESSAGE_RESTART_BLUETOOTH_SERVICE);
1178                        mHandler.sendMessageDelayed(restartMsg,
1179                                2 * SERVICE_RESTART_TIME_MS);
1180                    }
1181                    break;
1182
1183                case MESSAGE_DISABLE:
1184                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1185                    if (mEnable && mBluetooth != null) {
1186                        waitForOnOff(true, false);
1187                        mEnable = false;
1188                        handleDisable();
1189                        waitForOnOff(false, false);
1190                    } else {
1191                        mEnable = false;
1192                        handleDisable();
1193                    }
1194                    break;
1195
1196                case MESSAGE_REGISTER_ADAPTER:
1197                {
1198                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1199                    boolean added = mCallbacks.register(callback);
1200                    Slog.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
1201                }
1202                    break;
1203                case MESSAGE_UNREGISTER_ADAPTER:
1204                {
1205                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
1206                    boolean removed = mCallbacks.unregister(callback);
1207                    Slog.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
1208                    break;
1209                }
1210                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1211                {
1212                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1213                    if (callback != null) {
1214                        mStateChangeCallbacks.register(callback);
1215                    }
1216                    break;
1217                }
1218                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1219                {
1220                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1221                    if (callback != null) {
1222                        mStateChangeCallbacks.unregister(callback);
1223                    }
1224                    break;
1225                }
1226                case MESSAGE_ADD_PROXY_DELAYED:
1227                {
1228                    ProfileServiceConnections psc = mProfileServices.get(
1229                            new Integer(msg.arg1));
1230                    if (psc == null) {
1231                        break;
1232                    }
1233                    IBluetoothProfileServiceConnection proxy =
1234                            (IBluetoothProfileServiceConnection) msg.obj;
1235                    psc.addProxy(proxy);
1236                    break;
1237                }
1238                case MESSAGE_BIND_PROFILE_SERVICE:
1239                {
1240                    ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1241                    removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1242                    if (psc == null) {
1243                        break;
1244                    }
1245                    psc.bindService();
1246                    break;
1247                }
1248                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1249                {
1250                    if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
1251
1252                    IBinder service = (IBinder) msg.obj;
1253                    try {
1254                        mBluetoothLock.writeLock().lock();
1255                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1256                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1257                            onBluetoothGattServiceUp();
1258                            break;
1259                        } // else must be SERVICE_IBLUETOOTH
1260
1261                        //Remove timeout
1262                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1263
1264                        mBinding = false;
1265                        mBluetoothBinder = service;
1266                        mBluetooth = IBluetooth.Stub.asInterface(service);
1267
1268                        if (!isNameAndAddressSet()) {
1269                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1270                            mHandler.sendMessage(getMsg);
1271                            if (mGetNameAddressOnly) return;
1272                        }
1273
1274                        try {
1275                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1276                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1277                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1278                                Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
1279                            }
1280                        } catch (RemoteException e) {
1281                            Slog.e(TAG,"Unable to call configHciSnoopLog", e);
1282                        }
1283
1284                        //Register callback object
1285                        try {
1286                            mBluetooth.registerCallback(mBluetoothCallback);
1287                        } catch (RemoteException re) {
1288                            Slog.e(TAG, "Unable to register BluetoothCallback",re);
1289                        }
1290                        //Inform BluetoothAdapter instances that service is up
1291                        sendBluetoothServiceUpCallback();
1292
1293                        //Do enable request
1294                        try {
1295                            if (mQuietEnable == false) {
1296                                if(!mBluetooth.enable()) {
1297                                    Slog.e(TAG,"IBluetooth.enable() returned false");
1298                                }
1299                            }
1300                            else
1301                            {
1302                                if(!mBluetooth.enableNoAutoConnect()) {
1303                                    Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1304                                }
1305                            }
1306                        } catch (RemoteException e) {
1307                            Slog.e(TAG,"Unable to call enable()",e);
1308                        }
1309                    } finally {
1310                        mBluetoothLock.writeLock().unlock();
1311                    }
1312
1313                    if (!mEnable) {
1314                        waitForOnOff(true, false);
1315                        handleDisable();
1316                        waitForOnOff(false, false);
1317                    }
1318                    break;
1319                }
1320                case MESSAGE_TIMEOUT_BIND: {
1321                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
1322                    mBluetoothLock.writeLock().lock();
1323                    mBinding = false;
1324                    mBluetoothLock.writeLock().unlock();
1325
1326                    break;
1327                }
1328                case MESSAGE_BLUETOOTH_STATE_CHANGE:
1329                {
1330                    int prevState = msg.arg1;
1331                    int newState = msg.arg2;
1332                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
1333                    mState = newState;
1334                    bluetoothStateChangeHandler(prevState, newState);
1335                    // handle error state transition case from TURNING_ON to OFF
1336                    // unbind and rebind bluetooth service and enable bluetooth
1337                    if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
1338                        (newState == BluetoothAdapter.STATE_OFF) &&
1339                        (mBluetooth != null) && mEnable) {
1340                        recoverBluetoothServiceFromError();
1341                    }
1342                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1343                        (newState == BluetoothAdapter.STATE_BLE_ON) &&
1344                        (mBluetooth != null) && mEnable) {
1345                        recoverBluetoothServiceFromError();
1346                    }
1347                    if (newState == BluetoothAdapter.STATE_ON ||
1348                        newState == BluetoothAdapter.STATE_BLE_ON) {
1349                        // bluetooth is working, reset the counter
1350                        if (mErrorRecoveryRetryCounter != 0) {
1351                            Slog.w(TAG, "bluetooth is recovered from error");
1352                            mErrorRecoveryRetryCounter = 0;
1353                        }
1354                    }
1355                    break;
1356                }
1357                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1358                {
1359                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
1360                    try {
1361                        mBluetoothLock.writeLock().lock();
1362                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
1363                            // if service is unbinded already, do nothing and return
1364                            if (mBluetooth == null) break;
1365                            mBluetooth = null;
1366                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1367                            mBluetoothGatt = null;
1368                            break;
1369                        } else {
1370                            Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
1371                            break;
1372                        }
1373                    } finally {
1374                        mBluetoothLock.writeLock().unlock();
1375                    }
1376
1377                    if (mEnable) {
1378                        mEnable = false;
1379                        // Send a Bluetooth Restart message
1380                        Message restartMsg = mHandler.obtainMessage(
1381                            MESSAGE_RESTART_BLUETOOTH_SERVICE);
1382                        mHandler.sendMessageDelayed(restartMsg,
1383                            SERVICE_RESTART_TIME_MS);
1384                    }
1385
1386                    sendBluetoothServiceDownCallback();
1387
1388                    // Send BT state broadcast to update
1389                    // the BT icon correctly
1390                    if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1391                        (mState == BluetoothAdapter.STATE_ON)) {
1392                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1393                                                    BluetoothAdapter.STATE_TURNING_OFF);
1394                        mState = BluetoothAdapter.STATE_TURNING_OFF;
1395                    }
1396                    if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1397                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1398                                                    BluetoothAdapter.STATE_OFF);
1399                    }
1400
1401                    mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1402                    mState = BluetoothAdapter.STATE_OFF;
1403                    break;
1404                }
1405                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1406                {
1407                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1408                        +" Restart IBluetooth service");
1409                    /* Enable without persisting the setting as
1410                     it doesnt change when IBluetooth
1411                     service restarts */
1412                    mEnable = true;
1413                    handleEnable(mQuietEnable);
1414                    break;
1415                }
1416
1417                case MESSAGE_TIMEOUT_UNBIND:
1418                {
1419                    Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
1420                    mBluetoothLock.writeLock().lock();
1421                    mUnbinding = false;
1422                    mBluetoothLock.writeLock().unlock();
1423                    break;
1424                }
1425
1426                case MESSAGE_USER_SWITCHED: {
1427                    if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
1428                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1429
1430                    /* disable and enable BT when detect a user switch */
1431                    if (mEnable && mBluetooth != null) {
1432                        try {
1433                            mBluetoothLock.readLock().lock();
1434                            if (mBluetooth != null) {
1435                                mBluetooth.unregisterCallback(mBluetoothCallback);
1436                            }
1437                        } catch (RemoteException re) {
1438                            Slog.e(TAG, "Unable to unregister", re);
1439                        } finally {
1440                            mBluetoothLock.readLock().unlock();
1441                        }
1442
1443                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1444                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1445                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1446                            mState = BluetoothAdapter.STATE_OFF;
1447                        }
1448                        if (mState == BluetoothAdapter.STATE_OFF) {
1449                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1450                            mState = BluetoothAdapter.STATE_TURNING_ON;
1451                        }
1452
1453                        waitForOnOff(true, false);
1454
1455                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1456                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1457                        }
1458
1459                        unbindAllBluetoothProfileServices();
1460                        // disable
1461                        handleDisable();
1462                        // Pbap service need receive STATE_TURNING_OFF intent to close
1463                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1464                                                    BluetoothAdapter.STATE_TURNING_OFF);
1465
1466                        waitForOnOff(false, true);
1467
1468                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1469                                                    BluetoothAdapter.STATE_OFF);
1470                        sendBluetoothServiceDownCallback();
1471
1472                        try {
1473                            mBluetoothLock.writeLock().lock();
1474                            if (mBluetooth != null) {
1475                                mBluetooth = null;
1476                                // Unbind
1477                                mContext.unbindService(mConnection);
1478                            }
1479                            mBluetoothGatt = null;
1480                        } finally {
1481                            mBluetoothLock.writeLock().unlock();
1482                        }
1483
1484                        SystemClock.sleep(100);
1485
1486                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1487                        mState = BluetoothAdapter.STATE_OFF;
1488                        // enable
1489                        handleEnable(mQuietEnable);
1490                    } else if (mBinding || mBluetooth != null) {
1491                        Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1492                        userMsg.arg2 = 1 + msg.arg2;
1493                        // if user is switched when service is being binding
1494                        // delay sending MESSAGE_USER_SWITCHED
1495                        mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1496                        if (DBG) {
1497                            Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1498                        }
1499                    }
1500                    break;
1501                }
1502                case MESSAGE_USER_UNLOCKED: {
1503                    if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
1504                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1505
1506                    if (mEnable && !mBinding && (mBluetooth == null)) {
1507                        // We should be connected, but we gave up for some
1508                        // reason; maybe the Bluetooth service wasn't encryption
1509                        // aware, so try binding again.
1510                        if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
1511                        handleEnable(mQuietEnable);
1512                    }
1513                }
1514            }
1515        }
1516    }
1517
1518    private void handleEnable(boolean quietMode) {
1519        mQuietEnable = quietMode;
1520
1521        try {
1522            mBluetoothLock.writeLock().lock();
1523            if ((mBluetooth == null) && (!mBinding)) {
1524                //Start bind timeout and bind
1525                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1526                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1527                Intent i = new Intent(IBluetooth.class.getName());
1528                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1529                        UserHandle.CURRENT)) {
1530                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1531                } else {
1532                    mBinding = true;
1533                }
1534            } else if (mBluetooth != null) {
1535                //Enable bluetooth
1536                try {
1537                    if (!mQuietEnable) {
1538                        if(!mBluetooth.enable()) {
1539                            Slog.e(TAG,"IBluetooth.enable() returned false");
1540                        }
1541                    }
1542                    else {
1543                        if(!mBluetooth.enableNoAutoConnect()) {
1544                            Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1545                        }
1546                    }
1547                } catch (RemoteException e) {
1548                    Slog.e(TAG,"Unable to call enable()",e);
1549                }
1550            }
1551        } finally {
1552            mBluetoothLock.writeLock().unlock();
1553        }
1554    }
1555
1556    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1557        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1558        intent.setComponent(comp);
1559        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1560            Slog.e(TAG, "Fail to bind to: " + intent);
1561            return false;
1562        }
1563        return true;
1564    }
1565
1566    private void handleDisable() {
1567        try {
1568            mBluetoothLock.readLock().lock();
1569            if (mBluetooth != null) {
1570                if (DBG) Slog.d(TAG,"Sending off request.");
1571                if (!mBluetooth.disable()) {
1572                    Slog.e(TAG,"IBluetooth.disable() returned false");
1573                }
1574            }
1575        } catch (RemoteException e) {
1576            Slog.e(TAG,"Unable to call disable()",e);
1577        } finally {
1578            mBluetoothLock.readLock().unlock();
1579        }
1580    }
1581
1582    private boolean checkIfCallerIsForegroundUser() {
1583        int foregroundUser;
1584        int callingUser = UserHandle.getCallingUserId();
1585        int callingUid = Binder.getCallingUid();
1586        long callingIdentity = Binder.clearCallingIdentity();
1587        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1588        UserInfo ui = um.getProfileParent(callingUser);
1589        int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
1590        int callingAppId = UserHandle.getAppId(callingUid);
1591        boolean valid = false;
1592        try {
1593            foregroundUser = ActivityManager.getCurrentUser();
1594            valid = (callingUser == foregroundUser) ||
1595                    parentUser == foregroundUser    ||
1596                    callingAppId == Process.NFC_UID ||
1597                    callingAppId == mSystemUiUid;
1598            if (DBG) {
1599                Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1600                    + " callingUser=" + callingUser
1601                    + " parentUser=" + parentUser
1602                    + " foregroundUser=" + foregroundUser);
1603            }
1604        } finally {
1605            Binder.restoreCallingIdentity(callingIdentity);
1606        }
1607        return valid;
1608    }
1609
1610    private void sendBleStateChanged(int prevState, int newState) {
1611        if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1612        // Send broadcast message to everyone else
1613        Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1614        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1615        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1616        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1617        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1618    }
1619
1620    private void bluetoothStateChangeHandler(int prevState, int newState) {
1621        boolean isStandardBroadcast = true;
1622        if (prevState != newState) {
1623            //Notify all proxy objects first of adapter state change
1624            if (newState == BluetoothAdapter.STATE_BLE_ON
1625                   || newState == BluetoothAdapter.STATE_OFF) {
1626                boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1627                   && newState == BluetoothAdapter.STATE_BLE_ON);
1628
1629                if (newState == BluetoothAdapter.STATE_OFF) {
1630                    // If Bluetooth is off, send service down event to proxy objects, and unbind
1631                    if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
1632                    sendBluetoothServiceDownCallback();
1633                    unbindAndFinish();
1634                    sendBleStateChanged(prevState, newState);
1635                    // Don't broadcast as it has already been broadcast before
1636                    isStandardBroadcast = false;
1637
1638                } else if (!intermediate_off) {
1639                    // connect to GattService
1640                    if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
1641                    if (mBluetoothGatt != null) {
1642                        if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
1643                        onBluetoothGattServiceUp();
1644                    } else {
1645                        if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
1646                        if (mContext.getPackageManager().hasSystemFeature(
1647                                                        PackageManager.FEATURE_BLUETOOTH_LE)) {
1648                            Intent i = new Intent(IBluetoothGatt.class.getName());
1649                            doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1650                        }
1651                    }
1652                    sendBleStateChanged(prevState, newState);
1653                    //Don't broadcase this as std intent
1654                    isStandardBroadcast = false;
1655
1656                } else if (intermediate_off){
1657                    if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
1658                    // For LE only mode, broadcast as is
1659                    sendBleStateChanged(prevState, newState);
1660                    sendBluetoothStateCallback(false); // BT is OFF for general users
1661                    // Broadcast as STATE_OFF
1662                    newState = BluetoothAdapter.STATE_OFF;
1663                    sendBrEdrDownCallback();
1664                }
1665            } else if (newState == BluetoothAdapter.STATE_ON) {
1666                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1667                sendBluetoothStateCallback(isUp);
1668                sendBleStateChanged(prevState, newState);
1669
1670            } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
1671                || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1672                sendBleStateChanged(prevState, newState);
1673                isStandardBroadcast = false;
1674
1675            } else if (newState == BluetoothAdapter.STATE_TURNING_ON
1676                || newState == BluetoothAdapter.STATE_TURNING_OFF) {
1677                sendBleStateChanged(prevState, newState);
1678            }
1679
1680            if (isStandardBroadcast) {
1681                if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1682                    // Show prevState of BLE_ON as OFF to standard users
1683                    prevState = BluetoothAdapter.STATE_OFF;
1684                }
1685                Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1686                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1687                intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1688                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1689                mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1690            }
1691        }
1692    }
1693
1694    /**
1695     *  if on is true, wait for state become ON
1696     *  if off is true, wait for state become OFF
1697     *  if both on and off are false, wait for state not ON
1698     */
1699    private boolean waitForOnOff(boolean on, boolean off) {
1700        int i = 0;
1701        while (i < 10) {
1702            try {
1703                mBluetoothLock.readLock().lock();
1704                if (mBluetooth == null) break;
1705                if (on) {
1706                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1707                } else if (off) {
1708                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1709                } else {
1710                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1711                }
1712            } catch (RemoteException e) {
1713                Slog.e(TAG, "getState()", e);
1714                break;
1715            } finally {
1716                mBluetoothLock.readLock().unlock();
1717            }
1718            if (on || off) {
1719                SystemClock.sleep(300);
1720            } else {
1721                SystemClock.sleep(50);
1722            }
1723            i++;
1724        }
1725        Slog.e(TAG,"waitForOnOff time out");
1726        return false;
1727    }
1728
1729    private void sendDisableMsg() {
1730        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1731    }
1732
1733    private void sendEnableMsg(boolean quietMode) {
1734        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1735                             quietMode ? 1 : 0, 0));
1736    }
1737
1738    private void recoverBluetoothServiceFromError() {
1739        Slog.e(TAG,"recoverBluetoothServiceFromError");
1740        try {
1741            mBluetoothLock.readLock().lock();
1742            if (mBluetooth != null) {
1743                //Unregister callback object
1744                mBluetooth.unregisterCallback(mBluetoothCallback);
1745            }
1746        } catch (RemoteException re) {
1747            Slog.e(TAG, "Unable to unregister", re);
1748        } finally {
1749            mBluetoothLock.readLock().unlock();
1750        }
1751
1752        SystemClock.sleep(500);
1753
1754        // disable
1755        handleDisable();
1756
1757        waitForOnOff(false, true);
1758
1759        sendBluetoothServiceDownCallback();
1760
1761        try {
1762            mBluetoothLock.writeLock().lock();
1763            if (mBluetooth != null) {
1764                mBluetooth = null;
1765                // Unbind
1766                mContext.unbindService(mConnection);
1767            }
1768            mBluetoothGatt = null;
1769        } finally {
1770            mBluetoothLock.writeLock().unlock();
1771        }
1772
1773        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1774        mState = BluetoothAdapter.STATE_OFF;
1775
1776        mEnable = false;
1777
1778        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1779            // Send a Bluetooth Restart message to reenable bluetooth
1780            Message restartMsg = mHandler.obtainMessage(
1781                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
1782            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1783        } else {
1784            // todo: notify user to power down and power up phone to make bluetooth work.
1785        }
1786    }
1787
1788    @Override
1789    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1790        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1791        String errorMsg = null;
1792        if (mBluetoothBinder == null) {
1793            errorMsg = "Bluetooth Service not connected";
1794        } else {
1795            try {
1796                mBluetoothBinder.dump(fd, args);
1797            } catch (RemoteException re) {
1798                errorMsg = "RemoteException while calling Bluetooth Service";
1799            }
1800        }
1801        if (errorMsg != null) {
1802            // Silently return if we are extracting metrics in Protobuf format
1803            if ((args.length > 0) && args[0].startsWith("--proto"))
1804                return;
1805            writer.println(errorMsg);
1806        }
1807    }
1808}
1809