diff options
author | Zhihai Xu <zhihaixu@google.com> | 2012-10-08 17:57:03 -0700 |
---|---|---|
committer | Zhihai Xu <zhihaixu@google.com> | 2012-10-09 19:10:14 -0700 |
commit | 40874a096ba6448ebffea4b17486dbfbc957c0df (patch) | |
tree | f492c95f5c0f09b30f33a00e7a1aa0cac1adb5ff /services | |
parent | 7711260e4959686bb1d6f177a843c2108bb04710 (diff) | |
download | frameworks_base-40874a096ba6448ebffea4b17486dbfbc957c0df.zip frameworks_base-40874a096ba6448ebffea4b17486dbfbc957c0df.tar.gz frameworks_base-40874a096ba6448ebffea4b17486dbfbc957c0df.tar.bz2 |
Bluetooth multi-user updates: change bluetooth manager system service
to reject background user access. disable and enable Bluetooth when user is switched
bug 6925422
Change-Id: I52136e707da2d1ba8228c1bb8beef1414ead1893
Diffstat (limited to 'services')
-rwxr-xr-x | services/java/com/android/server/BluetoothManagerService.java | 463 |
1 files changed, 351 insertions, 112 deletions
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java index e7cd279..18182cd 100755 --- a/services/java/com/android/server/BluetoothManagerService.java +++ b/services/java/com/android/server/BluetoothManagerService.java @@ -4,6 +4,7 @@ package com.android.server; +import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; @@ -17,17 +18,21 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.os.Binder; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.Binder; +import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import java.util.List; import java.util.ArrayList; +import java.util.List; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; @@ -42,6 +47,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save //Maximum msec to wait for service restart private static final int SERVICE_RESTART_TIME_MS = 200; + //Maximum msec to delay MESSAGE_USER_SWITCHED + private static final int USER_SWITCHED_TIME_MS = 200; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; @@ -57,6 +64,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_TIMEOUT_UNBIND =101; private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; + private static final int MESSAGE_USER_SWITCHED = 300; private static final int MAX_SAVE_RETRIES=3; private final Context mContext; @@ -72,6 +80,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mBinding; private boolean mUnbinding; private boolean mQuietEnable = false; + private boolean mEnable; + private int mState; + private HandlerThread mThread; + private final BluetoothHandler mHandler; private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); @@ -106,23 +118,32 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { if (isAirplaneModeOn()) { - // disable without persisting the setting - handleDisable(false); - } else { - if (isBluetoothPersistedStateOn()) { - // enable without persisting the setting - handleEnable(false, false); - } + // disable without persisting the setting + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE, + 0, 0)); + } else if (isBluetoothPersistedStateOn()) { + // enable without persisting the setting + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, + 0, 0)); } + } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); } } }; BluetoothManagerService(Context context) { + mThread = new HandlerThread("BluetoothManager"); + mThread.start(); + mHandler = new BluetoothHandler(mThread.getLooper()); + mContext = context; mBluetooth = null; mBinding = false; mUnbinding = false; + mEnable = false; + mState = BluetoothAdapter.STATE_OFF; mAddress = null; mName = null; mContentResolver = context.getContentResolver(); @@ -130,6 +151,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); + filter.addAction(Intent.ACTION_USER_SWITCHED); registerForAirplaneMode(filter); mContext.registerReceiver(mReceiver, filter); boolean airplaneModeOn = isAirplaneModeOn(); @@ -139,7 +161,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (bluetoothOn) { //Enable if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); - enable(); + enableHelper(); } else if (!isNameAndAddressSet()) { //Sync the Bluetooth name and address from the Bluetooth Adapter if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); @@ -251,6 +273,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public boolean isEnabled() { + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"isEnabled(): not allowed for non-active user"); + return false; + } + synchronized(mConnection) { try { return (mBluetooth != null && mBluetooth.isEnabled()); @@ -266,10 +293,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); } - synchronized(mConnection) { - if (mBinding) return; - if (mConnection == null) mBinding = true; - } Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(msg); } @@ -277,21 +300,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub { { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); + + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user"); + return false; + } + if (DBG) { Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = " + mBinding); } - if (Binder.getCallingUid() != android.os.Process.NFC_UID) { + if (Binder.getCallingUid() != Process.NFC_UID) { throw new SecurityException("no permission to enable Bluetooth quietly"); } - synchronized(mConnection) { - if (mBinding) { - Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning.."); - return true; - } - if (mConnection == null) mBinding = true; - } - Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); msg.arg1=0; //No persist msg.arg2=1; //Quiet mode @@ -300,39 +321,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public boolean enable() { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permission"); - if (DBG) { - Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + - " mBinding = " + mBinding); + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"enable(): not allowed for non-active user"); + return false; } - synchronized(mConnection) { - if (mBinding) { - Log.w(TAG,"enable(): binding in progress. Returning.."); - return true; - } - if (mConnection == null) mBinding = true; - } - - Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); - msg.arg1=1; //persist - msg.arg2=0; //No Quiet Mode - mHandler.sendMessage(msg); - return true; + return enableHelper(); } public boolean disable(boolean persist) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); + + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"disable(): not allowed for non-active user"); + return false; + } + if (DBG) { Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); } - synchronized(mConnection) { - if (mBluetooth == null) return false; - } Message msg = mHandler.obtainMessage(MESSAGE_DISABLE); msg.arg1=(persist?1:0); mHandler.sendMessage(msg); @@ -348,13 +358,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub { synchronized (mConnection) { if (mUnbinding) return; mUnbinding = true; - if (mConnection != null) { + if (mBluetooth != null) { if (!mConnection.isGetNameAddressOnly()) { //Unregister callback object try { mBluetooth.unregisterCallback(mBluetoothCallback); } catch (RemoteException re) { - Log.e(TAG, "Unable to register BluetoothCallback",re); + Log.e(TAG, "Unable to unregister BluetoothCallback",re); } } if (DBG) Log.d(TAG, "Sending unbind request."); @@ -362,6 +372,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { //Unbind mContext.unbindService(mConnection); mUnbinding = false; + mBinding = false; } else { mUnbinding=false; } @@ -382,6 +393,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } /** + * Inform BluetoothAdapter instances that Adapter service is up + */ + private void sendBluetoothServiceUpCallback() { + if (!mConnection.isGetNameAddressOnly()) { + if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); + int n = mCallbacks.beginBroadcast(); + Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); + for (int i=0; i <n;i++) { + try { + mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); + } catch (RemoteException e) { + Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } + } + mCallbacks.finishBroadcast(); + } + } + /** * Inform BluetoothAdapter instances that Adapter service is down */ private void sendBluetoothServiceDownCallback() { @@ -402,6 +431,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public String getAddress() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); + + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"getAddress(): not allowed for non-active user"); + return mAddress; + } + synchronized(mConnection) { if (mBluetooth != null) { try { @@ -420,6 +455,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public String getName() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); + + if (!checkIfCallerIsForegroundUser()) { + Log.w(TAG,"getName(): not allowed for non-active user"); + return mName; + } + synchronized(mConnection) { if (mBluetooth != null) { try { @@ -464,7 +505,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); - private final Handler mHandler = new Handler() { + private class BluetoothHandler extends Handler { + public BluetoothHandler(Looper looper) { + super(looper); + } + @Override public void handleMessage(Message msg) { if (DBG) Log.d (TAG, "Message: " + msg.what); @@ -473,7 +518,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); synchronized(mConnection) { //Start bind request - if (mBluetooth == null) { + if ((mBluetooth == null) && (!mBinding)) { if (DBG) Log.d(TAG, "Binding to service to get name and address"); mConnection.setGetNameAddressOnly(true); //Start bind timeout and bind @@ -484,11 +529,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); + } else { + mBinding = true; } } else { Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); - mHandler.sendMessage(saveMsg); + saveMsg.arg1 = 0; + if (mBluetooth != null) { + mHandler.sendMessage(saveMsg); + } else { + // if enable is also called to bind the service + // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED + mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); + } } } break; @@ -508,8 +562,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (name != null && address != null) { storeNameAndAddress(name,address); - sendBluetoothServiceDownCallback(); - unbindAndFinish(); + if (mConnection.isGetNameAddressOnly()) { + unbindAndFinish(); + } } else { if (msg.arg1 < MAX_SAVE_RETRIES) { Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); @@ -518,10 +573,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); } else { Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); - sendBluetoothServiceDownCallback(); - unbindAndFinish(); + if (mConnection.isGetNameAddressOnly()) { + unbindAndFinish(); + } } } + } else { + // rebind service by Request GET NAME AND ADDRESS + // if service is unbinded by disable or + // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received + Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); + mHandler.sendMessage(getMsg); } } break; @@ -530,12 +592,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (DBG) { Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); } - + mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); + mEnable = true; handleEnable(msg.arg1 == 1, msg.arg2 ==1); break; case MESSAGE_DISABLE: - handleDisable(msg.arg1 == 1); + mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); + if (mEnable && mBluetooth != null) { + waitForOnOff(true, false); + mEnable = false; + handleDisable(msg.arg1 == 1); + waitForOnOff(false, false); + } else { + mEnable = false; + handleDisable(msg.arg1 == 1); + } break; case MESSAGE_REGISTER_ADAPTER: @@ -580,27 +652,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { //Request GET NAME AND ADDRESS Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); - return; + if (!mEnable) return; } + mConnection.setGetNameAddressOnly(false); //Register callback object try { mBluetooth.registerCallback(mBluetoothCallback); } catch (RemoteException re) { Log.e(TAG, "Unable to register BluetoothCallback",re); } - //Inform BluetoothAdapter instances that service is up - int n = mCallbacks.beginBroadcast(); - Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); - for (int i=0; i <n;i++) { + sendBluetoothServiceUpCallback(); + + //Check if name and address is loaded if not get it first. + if (!isNameAndAddressSet()) { try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); - } catch (RemoteException e) { - Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); - } + storeNameAndAddress(mBluetooth.getName(), + mBluetooth.getAddress()); + } catch (RemoteException e) {Log.e(TAG, "", e);}; } - mCallbacks.finishBroadcast(); //Do enable request try { @@ -619,12 +690,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Log.e(TAG,"Unable to call enable()",e); } } + + if (!mEnable) { + waitForOnOff(true, false); + handleDisable(false); + waitForOnOff(false, false); + } break; } case MESSAGE_TIMEOUT_BIND: { Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); synchronized(mConnection) { mBinding = false; + mEnable = false; } break; } @@ -633,51 +711,37 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int prevState = msg.arg1; int newState = msg.arg2; if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); - if (prevState != newState) { - //Notify all proxy objects first of adapter state change - if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { - boolean isUp = (newState==BluetoothAdapter.STATE_ON); - sendBluetoothStateCallback(isUp); - - //If Bluetooth is off, send service down event to proxy objects, and unbind - if (!isUp) { - sendBluetoothServiceDownCallback(); - unbindAndFinish(); - } - } - - //Send broadcast message to everyone else - Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); - intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); - intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, - BLUETOOTH_PERM); - } + mState = newState; + bluetoothStateChangeHandler(prevState, newState); break; } case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: { - if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); - sendBluetoothServiceDownCallback(); - - // Send BT state broadcast to update - // the BT icon correctly - Message stateChangeMsg = mHandler.obtainMessage( - MESSAGE_BLUETOOTH_STATE_CHANGE); - stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON; - stateChangeMsg.arg2 = - BluetoothAdapter.STATE_TURNING_OFF; - mHandler.sendMessage(stateChangeMsg); + Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); synchronized(mConnection) { + // if service is unbinded already, do nothing and return + if (mBluetooth == null) return; mBluetooth = null; } - // Send a Bluetooth Restart message - Message restartMsg = mHandler.obtainMessage( - MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, - SERVICE_RESTART_TIME_MS); + + if (mEnable) { + mEnable = false; + // Send a Bluetooth Restart message + Message restartMsg = mHandler.obtainMessage( + MESSAGE_RESTART_BLUETOOTH_SERVICE); + mHandler.sendMessageDelayed(restartMsg, + SERVICE_RESTART_TIME_MS); + } + + if (!mConnection.isGetNameAddressOnly()) { + sendBluetoothServiceDownCallback(); + + // Send BT state broadcast to update + // the BT icon correctly + bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, + BluetoothAdapter.STATE_TURNING_OFF); + mState = BluetoothAdapter.STATE_OFF; + } break; } case MESSAGE_RESTART_BLUETOOTH_SERVICE: @@ -687,6 +751,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /* Enable without persisting the setting as it doesnt change when IBluetooth service restarts */ + mEnable = true; handleEnable(false, mQuietEnable); break; } @@ -699,9 +764,66 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } + + case MESSAGE_USER_SWITCHED: + { + if (DBG) { + Log.d(TAG, "MESSAGE_USER_SWITCHED"); + } + mHandler.removeMessages(MESSAGE_USER_SWITCHED); + /* disable and enable BT when detect a user switch */ + if (mEnable && mBluetooth != null) { + synchronized (mConnection) { + if (mBluetooth != null) { + //Unregister callback object + try { + mBluetooth.unregisterCallback(mBluetoothCallback); + } catch (RemoteException re) { + Log.e(TAG, "Unable to unregister",re); + } + } + } + mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); + + waitForOnOff(true, false); + + bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); + + // disable + handleDisable(false); + + waitForOnOff(false, true); + + bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, + BluetoothAdapter.STATE_OFF); + mState = BluetoothAdapter.STATE_OFF; + sendBluetoothServiceDownCallback(); + synchronized (mConnection) { + if (mBluetooth != null) { + mBluetooth = null; + //Unbind + mContext.unbindService(mConnection); + } + } + SystemClock.sleep(100); + + // enable + handleEnable(false, mQuietEnable); + } else if (mBinding || mBluetooth != null) { + Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); + userMsg.arg2 = 1 + msg.arg2; + // if user is switched when service is being binding + // delay sending MESSAGE_USER_SWITCHED + mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); + if (DBG) { + Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); + } + } + break; + } } } - }; + } private void handleEnable(boolean persist, boolean quietMode) { if (persist) { @@ -711,18 +833,35 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mQuietEnable = quietMode; synchronized(mConnection) { - if (mBluetooth == null) { + if ((mBluetooth == null) && (!mBinding)) { //Start bind timeout and bind Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); mConnection.setGetNameAddressOnly(false); Intent i = new Intent(IBluetooth.class.getName()); - if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE, + if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); + } else { + mBinding = true; } - } else { + } else if (mBluetooth != null) { + if (mConnection.isGetNameAddressOnly()) { + // if GetNameAddressOnly is set, we can clear this flag, + // so the service won't be unbind + // after name and address are saved + mConnection.setGetNameAddressOnly(false); + //Register callback object + try { + mBluetooth.registerCallback(mBluetoothCallback); + } catch (RemoteException re) { + Log.e(TAG, "Unable to register BluetoothCallback",re); + } + //Inform BluetoothAdapter instances that service is up + sendBluetoothServiceUpCallback(); + } + //Check if name and address is loaded if not get it first. if (!isNameAndAddressSet()) { try { @@ -751,12 +890,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private void handleDisable(boolean persist) { + if (persist) { + persistBluetoothSetting(false); + } + synchronized(mConnection) { - if (mBluetooth != null ) { - if (persist) { - persistBluetoothSetting(false); - } - mConnection.setGetNameAddressOnly(false); + // don't need to disable if GetNameAddressOnly is set, + // service will be unbinded after Name and Address are saved + if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { if (DBG) Log.d(TAG,"Sending off request."); try { @@ -769,4 +910,102 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } } + + private boolean checkIfCallerIsForegroundUser() { + int foregroundUser; + int callingUser = UserHandle.getCallingUserId(); + long callingIdentity = Binder.clearCallingIdentity(); + boolean valid = false; + try { + foregroundUser = ActivityManager.getCurrentUser(); + valid = (callingUser == foregroundUser); + if (DBG) { + Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + + " callingUser=" + callingUser + + " foregroundUser=" + foregroundUser); + } + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + return valid; + } + + private boolean enableHelper() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH ADMIN permission"); + if (DBG) { + Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + + " mBinding = " + mBinding); + } + + Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); + msg.arg1=1; //persist + msg.arg2=0; //No Quiet Mode + mHandler.sendMessage(msg); + return true; + } + + private void bluetoothStateChangeHandler(int prevState, int newState) { + if (prevState != newState) { + //Notify all proxy objects first of adapter state change + if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { + boolean isUp = (newState==BluetoothAdapter.STATE_ON); + sendBluetoothStateCallback(isUp); + + //If Bluetooth is off, send service down event to proxy objects, and unbind + if (!isUp) { + //Only unbind with mEnable flag not set + //For race condition: disable and enable back-to-back + //Avoid unbind right after enable due to callback from disable + if ((!mEnable) && (mBluetooth != null)) { + sendBluetoothServiceDownCallback(); + unbindAndFinish(); + } + } + } + + //Send broadcast message to everyone else + Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); + intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); + intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, + BLUETOOTH_PERM); + } + } + + /** + * if on is true, wait for state become ON + * if off is true, wait for state become OFF + * if both on and off are false, wait for state not ON + */ + private boolean waitForOnOff(boolean on, boolean off) { + int i = 0; + while (i < 10) { + synchronized(mConnection) { + try { + if (mBluetooth == null) break; + if (on) { + if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; + } else if (off) { + if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; + } else { + if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; + } + } catch (RemoteException e) { + Log.e(TAG, "getState()", e); + break; + } + } + if (on || off) { + SystemClock.sleep(300); + } else { + SystemClock.sleep(50); + } + i++; + } + Log.e(TAG,"waitForOnOff time out"); + return false; + } } |