summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothMapClient.java
diff options
context:
space:
mode:
authorUgo Yu <ugoyu@google.com>2019-03-26 21:38:08 +0800
committerUgo Yu <ugoyu@google.com>2019-05-02 17:25:52 +0800
commit1652b94a121a19863c554551c57406cbef504ce8 (patch)
treec482242e179383379c6e7be3c6e15998115d81fd /framework/java/android/bluetooth/BluetoothMapClient.java
parentcb43dd0c105f49903ba1108f4d20f4b0d1ab99f1 (diff)
Fix binder leakage when turning off Bluetooth
* In current design, Bluetooth AdapterState stops all BR/EDR profiles' service and triggers onServiceDisconnected callback to all binder clients before BluetoothManagerService invokes onBluetoothStateChange(false), which means unbind service would never be called in framework. * Do unbind service when onServiceDisconnected is invoked. * Move profile binder logic to BluetoothProfileConnector except: - BluetoothHeadset: its binder logic is in BluetoothManagerService - BluetoothPbap: it has an individual ServiceListener Bug: 129037442 Bug: 129437895 Test: Bluetooth ON/OFF stress test. adb shell dumpsys activity services | egrep "com.android.bluetooth" to check whether AppBindRecord for com.android.bluetooth grows Merged-In: Id0d85866d386962b94d2d966f0a864b1da165d13 Change-Id: Id0d85866d386962b94d2d966f0a864b1da165d13
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothMapClient.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothMapClient.java137
1 files changed, 28 insertions, 109 deletions
diff --git a/framework/java/android/bluetooth/BluetoothMapClient.java b/framework/java/android/bluetooth/BluetoothMapClient.java
index 559a59b68b..ec0180c5ad 100644
--- a/framework/java/android/bluetooth/BluetoothMapClient.java
+++ b/framework/java/android/bluetooth/BluetoothMapClient.java
@@ -18,11 +18,9 @@ package android.bluetooth;
import android.annotation.UnsupportedAppUsage;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
import android.net.Uri;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -60,11 +58,6 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String EXTRA_SENDER_CONTACT_NAME =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
- private volatile IBluetoothMapClient mService;
- private final Context mContext;
- private ServiceListener mServiceListener;
- private BluetoothAdapter mAdapter;
-
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
@@ -75,64 +68,23 @@ public final class BluetoothMapClient implements BluetoothProfile {
private static final int UPLOADING_FEATURE_BITMASK = 0x08;
- private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
- new IBluetoothStateChangeCallback.Stub() {
- public void onBluetoothStateChange(boolean up) {
- 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);
- }
- }
- } else {
- synchronized (mConnection) {
- try {
- if (mService == null) {
- if (VDBG) Log.d(TAG, "Binding service...");
- doBind();
- }
- } catch (Exception re) {
- Log.e(TAG, "", re);
- }
- }
- }
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
+ "BluetoothMapClient", IBluetoothMapClient.class.getName()) {
+ @Override
+ public IBluetoothMapClient getServiceInterface(IBinder service) {
+ return IBluetoothMapClient.Stub.asInterface(Binder.allowBlocking(service));
}
- };
+ };
/**
* Create a BluetoothMapClient proxy object.
*/
- /*package*/ BluetoothMapClient(Context context, ServiceListener l) {
+ /*package*/ BluetoothMapClient(Context context, ServiceListener listener) {
if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object");
- mContext = context;
- mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- doBind();
- }
-
- boolean doBind() {
- Intent intent = new Intent(IBluetoothMapClient.class.getName());
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
- Log.e(TAG, "Could not bind to Bluetooth MAP MCE Service with " + intent);
- return false;
- }
- return true;
+ mProfileConnector.connect(context, listener);
}
protected void finalize() throws Throwable {
@@ -150,26 +102,11 @@ public final class BluetoothMapClient implements BluetoothProfile {
* are ok.
*/
public void close() {
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
+ mProfileConnector.disconnect();
+ }
- synchronized (mConnection) {
- if (mService != null) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG, "", re);
- }
- }
- }
- mServiceListener = null;
+ private IBluetoothMapClient getService() {
+ return mProfileConnector.getService();
}
/**
@@ -179,7 +116,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null) {
try {
return service.isConnected(device);
@@ -199,7 +136,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public boolean connect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null) {
try {
return service.connect(device);
@@ -221,7 +158,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public boolean disconnect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "disconnect(" + device + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.disconnect(device);
@@ -241,7 +178,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG, "getConnectedDevices()");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) {
try {
return service.getConnectedDevices();
@@ -262,7 +199,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) {
try {
return service.getDevicesMatchingConnectionStates(states);
@@ -283,7 +220,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override
public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.getConnectionState(device);
@@ -307,7 +244,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) {
@@ -336,7 +273,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public int getPriority(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.getPriority(device);
@@ -365,7 +302,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
PendingIntent sentIntent, PendingIntent deliveredIntent) {
if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent);
@@ -385,7 +322,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/
public boolean getUnreadMessages(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
- final IBluetoothMapClient service = mService;
+ final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.getUnreadMessages(device);
@@ -405,34 +342,16 @@ public final class BluetoothMapClient implements BluetoothProfile {
* MapSupportedFeatures field is set. False is returned otherwise.
*/
public boolean isUploadingSupported(BluetoothDevice device) {
+ final IBluetoothMapClient service = getService();
try {
- return (mService != null && isEnabled() && isValidDevice(device))
- && ((mService.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
+ return (service != null && isEnabled() && isValidDevice(device))
+ && ((service.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage());
}
return false;
}
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothMapClient.Stub.asInterface(service);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.MAP_CLIENT,
- BluetoothMapClient.this);
- }
- }
-
- public void onServiceDisconnected(ComponentName className) {
- if (DBG) Log.d(TAG, "Proxy object disconnected");
- mService = null;
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.MAP_CLIENT);
- }
- }
- };
-
private boolean isEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;