Loading Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \ core/java/android/bluetooth/IBluetoothCallback.aidl \ core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \ core/java/android/bluetooth/IBluetoothHealth.aidl \ Loading core/java/android/bluetooth/BluetoothHeadset.java +61 −38 Original line number Diff line number Diff line Loading @@ -20,9 +20,10 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; Loading Loading @@ -221,11 +222,14 @@ public final class BluetoothHeadset implements BluetoothProfile { */ public static final int STATE_AUDIO_CONNECTED = 12; private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100; private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101; private Context mContext; private ServiceListener mServiceListener; private IBluetoothHeadset mService; private BluetoothAdapter mAdapter; private boolean mIsClosed; final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new IBluetoothStateChangeCallback.Stub() { Loading @@ -233,14 +237,7 @@ public final class BluetoothHeadset implements BluetoothProfile { if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); if (!up) { if (VDBG) Log.d(TAG,"Unbinding service..."); synchronized (mConnection) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } doUnbind(); } else { synchronized (mConnection) { try { Loading @@ -263,6 +260,7 @@ public final class BluetoothHeadset implements BluetoothProfile { mContext = context; mServiceListener = l; mAdapter = BluetoothAdapter.getDefaultAdapter(); mIsClosed = false; IBluetoothManager mgr = mAdapter.getBluetoothManager(); if (mgr != null) { Loading @@ -277,15 +275,26 @@ public final class BluetoothHeadset implements BluetoothProfile { } boolean doBind() { Intent intent = new Intent(IBluetoothHeadset.class.getName()); ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, android.os.Process.myUserHandle())) { Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent); try { return mAdapter.getBluetoothManager().bindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG, "Unable to bind HeadsetService", e); } return false; } return true; void doUnbind() { synchronized (mConnection) { if (mService != null) { try { mAdapter.getBluetoothManager().unbindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG,"Unable to unbind HeadsetService", e); } } } } /** Loading @@ -305,18 +314,8 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG,"",e); } } synchronized (mConnection) { if (mService != null) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } } mServiceListener = null; mIsClosed = true; doUnbind(); } /** Loading Loading @@ -930,21 +929,21 @@ public final class BluetoothHeadset implements BluetoothProfile { return false; } private final ServiceConnection mConnection = new ServiceConnection() { private final IBluetoothProfileServiceConnection mConnection = new IBluetoothProfileServiceConnection.Stub() { @Override public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothHeadset.Stub.asInterface(service); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } @Override public void onServiceDisconnected(ComponentName className) { if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_DISCONNECTED)); } }; Loading @@ -968,4 +967,28 @@ public final class BluetoothHeadset implements BluetoothProfile { private static void log(String msg) { Log.d(TAG, msg); } private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_HEADSET_SERVICE_CONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } break; } case MESSAGE_HEADSET_SERVICE_DISCONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } if (mIsClosed){ mServiceListener = null; } break; } } } }; } core/java/android/bluetooth/IBluetoothManager.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.bluetooth; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; /** Loading @@ -38,6 +39,9 @@ interface IBluetoothManager boolean disable(boolean persist); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); String getAddress(); String getName(); } core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl 0 → 100755 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; import android.content.ComponentName; import android.os.IBinder; /** * Callback for bluetooth profile connections. * * {@hide} */ interface IBluetoothProfileServiceConnection { void onServiceConnected(in ComponentName comp, in IBinder service); void onServiceDisconnected(in ComponentName comp); } services/core/java/com/android/server/BluetoothManagerService.java +229 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.server; import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothHeadset; import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading @@ -32,6 +35,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading @@ -42,12 +46,18 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Log; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.List; import java.util.Vector; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; Loading @@ -67,6 +77,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int ERROR_RESTART_TIME_MS = 3000; //Maximum msec to delay MESSAGE_USER_SWITCHED private static final int USER_SWITCHED_TIME_MS = 200; // Delay for the addProxy function in msec private static final int ADD_PROXY_DELAY_MS = 100; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; Loading @@ -83,6 +95,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; private static final int MAX_SAVE_RETRIES=3; private static final int MAX_ERROR_RESTART_RETRIES=6; Loading Loading @@ -127,6 +141,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private int mErrorRecoveryRetryCounter; private final int mSystemUiUid; // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -499,6 +518,187 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return mBluetoothGatt; } @Override public boolean bindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { if (!mEnable) { if (DBG) { Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile + ", while Bluetooth was disabled"); } return false; } synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { if (DBG) { Log.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + bluetoothProfile); } Intent intent = null; if (bluetoothProfile == BluetoothProfile.HEADSET) { intent = new Intent(IBluetoothHeadset.class.getName()); } else { return false; } psc = new ProfileServiceConnections(intent); mProfileServices.put(new Integer(bluetoothProfile), psc); psc.bindService(); } } // Introducing a delay to give the client app time to prepare Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); addProxyMsg.arg1 = bluetoothProfile; addProxyMsg.obj = proxy; mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); return true; } @Override public void unbindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { return; } psc.removeProxy(proxy); } } private void unbindAllBluetoothProfileServices() { synchronized (mProfileServices) { for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); mContext.unbindService(psc); psc.removeAllProxies(); } mProfileServices.clear(); } } /** * This class manages the clients connected to a given ProfileService * and maintains the connection with that service. */ final private class ProfileServiceConnections implements ServiceConnection, IBinder.DeathRecipient { final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = new RemoteCallbackList <IBluetoothProfileServiceConnection>(); IBinder mService; ComponentName mClassName; Intent mIntent; ProfileServiceConnections(Intent intent) { mService = null; mClassName = null; mIntent = intent; } private void bindService() { if (mIntent != null && mService == null) { if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { Log.w(TAG, "Unable to bind with intent: " + mIntent + ". Triggering retry."); } Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void addProxy(IBluetoothProfileServiceConnection proxy) { mProxies.register(proxy); if (mService != null) { try{ proxy.onServiceConnected(mClassName, mService); } catch (RemoteException e) { Log.e(TAG, "Unable to connect to proxy", e); } } else { if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessage(msg); } } } private void removeProxy(IBluetoothProfileServiceConnection proxy) { if (proxy != null) { if (mProxies.unregister(proxy)) { try { proxy.onServiceDisconnected(mClassName); } catch (RemoteException e) { Log.e(TAG, "Unable to disconnect proxy", e); } } } else { Log.w(TAG, "Trying to remove a null proxy"); } } private void removeAllProxies() { onServiceDisconnected(mClassName); mProxies.kill(); } @Override public void onServiceConnected(ComponentName className, IBinder service) { // remove timeout message mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); mService = service; mClassName = className; try { mService.linkToDeath(this, 0); } catch (RemoteException e) { Log.e(TAG, "Unable to linkToDeath", e); } int n = mProxies.beginBroadcast(); for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceConnected(className, service); } catch (RemoteException e) { Log.e(TAG, "Unable to connect to proxy", e); } } mProxies.finishBroadcast(); } @Override public void onServiceDisconnected(ComponentName className) { if (mService == null) { return; } mService.unlinkToDeath(this, 0); mService = null; mClassName = null; int n = mProxies.beginBroadcast(); for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceDisconnected(className); } catch (RemoteException e) { Log.e(TAG, "Unable to disconnect from proxy", e); } } mProxies.finishBroadcast(); } @Override public void binderDied() { if (DBG) { Log.w(TAG, "Profile service for profile: " + mClassName + " died."); } onServiceDisconnected(mClassName); // Trigger rebind Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void sendBluetoothStateCallback(boolean isUp) { int n = mStateChangeCallbacks.beginBroadcast(); if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); Loading Loading @@ -803,6 +1003,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } case MESSAGE_ADD_PROXY_DELAYED: { ProfileServiceConnections psc = mProfileServices.get( new Integer(msg.arg1)); if (psc == null) { break; } IBluetoothProfileServiceConnection proxy = (IBluetoothProfileServiceConnection) msg.obj; psc.addProxy(proxy); break; } case MESSAGE_BIND_PROFILE_SERVICE: { ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { break; } psc.bindService(); break; } case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); Loading Loading @@ -1005,6 +1227,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); } unbindAllBluetoothProfileServices(); // disable handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close Loading Loading @@ -1129,16 +1352,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int callingUser = UserHandle.getCallingUserId(); int callingUid = Binder.getCallingUid(); long callingIdentity = Binder.clearCallingIdentity(); UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); UserInfo ui = um.getProfileParent(callingUser); int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; int callingAppId = UserHandle.getAppId(callingUid); boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); valid = (callingUser == foregroundUser) || parentUser == foregroundUser || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid; if (DBG) { Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" + callingUser + " parentUser=" + parentUser + " foregroundUser=" + foregroundUser); } } finally { Loading @@ -1165,6 +1393,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else { //If Bluetooth is off, send service down event to proxy objects, and unbind if (!isUp && canUnbindBluetoothService()) { unbindAllBluetoothProfileServices(); sendBluetoothServiceDownCallback(); unbindAndFinish(); } Loading Loading
Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \ core/java/android/bluetooth/IBluetoothCallback.aidl \ core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \ core/java/android/bluetooth/IBluetoothHealth.aidl \ Loading
core/java/android/bluetooth/BluetoothHeadset.java +61 −38 Original line number Diff line number Diff line Loading @@ -20,9 +20,10 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; Loading Loading @@ -221,11 +222,14 @@ public final class BluetoothHeadset implements BluetoothProfile { */ public static final int STATE_AUDIO_CONNECTED = 12; private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100; private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101; private Context mContext; private ServiceListener mServiceListener; private IBluetoothHeadset mService; private BluetoothAdapter mAdapter; private boolean mIsClosed; final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new IBluetoothStateChangeCallback.Stub() { Loading @@ -233,14 +237,7 @@ public final class BluetoothHeadset implements BluetoothProfile { if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); if (!up) { if (VDBG) Log.d(TAG,"Unbinding service..."); synchronized (mConnection) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } doUnbind(); } else { synchronized (mConnection) { try { Loading @@ -263,6 +260,7 @@ public final class BluetoothHeadset implements BluetoothProfile { mContext = context; mServiceListener = l; mAdapter = BluetoothAdapter.getDefaultAdapter(); mIsClosed = false; IBluetoothManager mgr = mAdapter.getBluetoothManager(); if (mgr != null) { Loading @@ -277,15 +275,26 @@ public final class BluetoothHeadset implements BluetoothProfile { } boolean doBind() { Intent intent = new Intent(IBluetoothHeadset.class.getName()); ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, android.os.Process.myUserHandle())) { Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent); try { return mAdapter.getBluetoothManager().bindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG, "Unable to bind HeadsetService", e); } return false; } return true; void doUnbind() { synchronized (mConnection) { if (mService != null) { try { mAdapter.getBluetoothManager().unbindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG,"Unable to unbind HeadsetService", e); } } } } /** Loading @@ -305,18 +314,8 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG,"",e); } } synchronized (mConnection) { if (mService != null) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } } mServiceListener = null; mIsClosed = true; doUnbind(); } /** Loading Loading @@ -930,21 +929,21 @@ public final class BluetoothHeadset implements BluetoothProfile { return false; } private final ServiceConnection mConnection = new ServiceConnection() { private final IBluetoothProfileServiceConnection mConnection = new IBluetoothProfileServiceConnection.Stub() { @Override public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothHeadset.Stub.asInterface(service); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } @Override public void onServiceDisconnected(ComponentName className) { if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_DISCONNECTED)); } }; Loading @@ -968,4 +967,28 @@ public final class BluetoothHeadset implements BluetoothProfile { private static void log(String msg) { Log.d(TAG, msg); } private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_HEADSET_SERVICE_CONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } break; } case MESSAGE_HEADSET_SERVICE_DISCONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } if (mIsClosed){ mServiceListener = null; } break; } } } }; }
core/java/android/bluetooth/IBluetoothManager.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.bluetooth; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; /** Loading @@ -38,6 +39,9 @@ interface IBluetoothManager boolean disable(boolean persist); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); String getAddress(); String getName(); }
core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl 0 → 100755 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; import android.content.ComponentName; import android.os.IBinder; /** * Callback for bluetooth profile connections. * * {@hide} */ interface IBluetoothProfileServiceConnection { void onServiceConnected(in ComponentName comp, in IBinder service); void onServiceDisconnected(in ComponentName comp); }
services/core/java/com/android/server/BluetoothManagerService.java +229 −0 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.server; import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothHeadset; import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading @@ -32,6 +35,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading @@ -42,12 +46,18 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Log; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.List; import java.util.Vector; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; Loading @@ -67,6 +77,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int ERROR_RESTART_TIME_MS = 3000; //Maximum msec to delay MESSAGE_USER_SWITCHED private static final int USER_SWITCHED_TIME_MS = 200; // Delay for the addProxy function in msec private static final int ADD_PROXY_DELAY_MS = 100; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; Loading @@ -83,6 +95,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; private static final int MAX_SAVE_RETRIES=3; private static final int MAX_ERROR_RESTART_RETRIES=6; Loading Loading @@ -127,6 +141,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private int mErrorRecoveryRetryCounter; private final int mSystemUiUid; // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -499,6 +518,187 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return mBluetoothGatt; } @Override public boolean bindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { if (!mEnable) { if (DBG) { Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile + ", while Bluetooth was disabled"); } return false; } synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { if (DBG) { Log.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + bluetoothProfile); } Intent intent = null; if (bluetoothProfile == BluetoothProfile.HEADSET) { intent = new Intent(IBluetoothHeadset.class.getName()); } else { return false; } psc = new ProfileServiceConnections(intent); mProfileServices.put(new Integer(bluetoothProfile), psc); psc.bindService(); } } // Introducing a delay to give the client app time to prepare Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); addProxyMsg.arg1 = bluetoothProfile; addProxyMsg.obj = proxy; mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); return true; } @Override public void unbindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { return; } psc.removeProxy(proxy); } } private void unbindAllBluetoothProfileServices() { synchronized (mProfileServices) { for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); mContext.unbindService(psc); psc.removeAllProxies(); } mProfileServices.clear(); } } /** * This class manages the clients connected to a given ProfileService * and maintains the connection with that service. */ final private class ProfileServiceConnections implements ServiceConnection, IBinder.DeathRecipient { final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = new RemoteCallbackList <IBluetoothProfileServiceConnection>(); IBinder mService; ComponentName mClassName; Intent mIntent; ProfileServiceConnections(Intent intent) { mService = null; mClassName = null; mIntent = intent; } private void bindService() { if (mIntent != null && mService == null) { if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { Log.w(TAG, "Unable to bind with intent: " + mIntent + ". Triggering retry."); } Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void addProxy(IBluetoothProfileServiceConnection proxy) { mProxies.register(proxy); if (mService != null) { try{ proxy.onServiceConnected(mClassName, mService); } catch (RemoteException e) { Log.e(TAG, "Unable to connect to proxy", e); } } else { if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessage(msg); } } } private void removeProxy(IBluetoothProfileServiceConnection proxy) { if (proxy != null) { if (mProxies.unregister(proxy)) { try { proxy.onServiceDisconnected(mClassName); } catch (RemoteException e) { Log.e(TAG, "Unable to disconnect proxy", e); } } } else { Log.w(TAG, "Trying to remove a null proxy"); } } private void removeAllProxies() { onServiceDisconnected(mClassName); mProxies.kill(); } @Override public void onServiceConnected(ComponentName className, IBinder service) { // remove timeout message mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); mService = service; mClassName = className; try { mService.linkToDeath(this, 0); } catch (RemoteException e) { Log.e(TAG, "Unable to linkToDeath", e); } int n = mProxies.beginBroadcast(); for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceConnected(className, service); } catch (RemoteException e) { Log.e(TAG, "Unable to connect to proxy", e); } } mProxies.finishBroadcast(); } @Override public void onServiceDisconnected(ComponentName className) { if (mService == null) { return; } mService.unlinkToDeath(this, 0); mService = null; mClassName = null; int n = mProxies.beginBroadcast(); for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceDisconnected(className); } catch (RemoteException e) { Log.e(TAG, "Unable to disconnect from proxy", e); } } mProxies.finishBroadcast(); } @Override public void binderDied() { if (DBG) { Log.w(TAG, "Profile service for profile: " + mClassName + " died."); } onServiceDisconnected(mClassName); // Trigger rebind Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void sendBluetoothStateCallback(boolean isUp) { int n = mStateChangeCallbacks.beginBroadcast(); if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); Loading Loading @@ -803,6 +1003,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } case MESSAGE_ADD_PROXY_DELAYED: { ProfileServiceConnections psc = mProfileServices.get( new Integer(msg.arg1)); if (psc == null) { break; } IBluetoothProfileServiceConnection proxy = (IBluetoothProfileServiceConnection) msg.obj; psc.addProxy(proxy); break; } case MESSAGE_BIND_PROFILE_SERVICE: { ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { break; } psc.bindService(); break; } case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); Loading Loading @@ -1005,6 +1227,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); } unbindAllBluetoothProfileServices(); // disable handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close Loading Loading @@ -1129,16 +1352,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int callingUser = UserHandle.getCallingUserId(); int callingUid = Binder.getCallingUid(); long callingIdentity = Binder.clearCallingIdentity(); UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); UserInfo ui = um.getProfileParent(callingUser); int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; int callingAppId = UserHandle.getAppId(callingUid); boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); valid = (callingUser == foregroundUser) || parentUser == foregroundUser || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid; if (DBG) { Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" + callingUser + " parentUser=" + parentUser + " foregroundUser=" + foregroundUser); } } finally { Loading @@ -1165,6 +1393,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else { //If Bluetooth is off, send service down event to proxy objects, and unbind if (!isUp && canUnbindBluetoothService()) { unbindAllBluetoothProfileServices(); sendBluetoothServiceDownCallback(); unbindAndFinish(); } Loading