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