From 517b04f1485e17c93ad21bb303e8d1acade86ba6 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 2 Jun 2014 16:20:37 -0700 Subject: BluetoothAvrcpController: Move AVRCP controller support to new BluetoothProfile subclass Change-Id: Id988040a7ce623ed68e0349920301ff48db1fbce --- .../bluetooth/BluetoothAvrcpController.java | 260 +++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 framework/java/android/bluetooth/BluetoothAvrcpController.java (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java new file mode 100644 index 0000000000..b53a8fc0f6 --- /dev/null +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -0,0 +1,260 @@ +/* + * 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.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides the public APIs to control the Bluetooth AVRCP Controller + * profile. + * + *

BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothAvrcpController proxy object. + * + * {@hide} + */ +public final class BluetoothAvrcpController implements BluetoothProfile { + private static final String TAG = "BluetoothAvrcpController"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + /** + * Intent used to broadcast the change in connection state of the AVRCP Controller + * profile. + * + *

This intent will have 3 extras: + *

+ * + *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; + + private Context mContext; + private ServiceListener mServiceListener; + private IBluetoothAvrcpController mService; + private BluetoothAdapter mAdapter; + + final private 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); + } + } + } + } + }; + + /** + * Create a BluetoothAvrcpController proxy object for interacting with the local + * Bluetooth AVRCP service. + * + */ + /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) { + 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(IBluetoothAvrcpController.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 AVRCP Controller Service with " + intent); + return false; + } + return true; + } + + /*package*/ void close() { + mServiceListener = null; + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG,"",e); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + + public void finalize() { + close(); + } + + /** + * {@inheritDoc} + */ + public List getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + if (mService != null && isEnabled()) { + try { + return mService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList(); + } + + /** + * {@inheritDoc} + */ + public List getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + if (mService != null && isEnabled()) { + try { + return mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList(); + } + + /** + * {@inheritDoc} + */ + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + if (mService != null && isEnabled() + && isValidDevice(device)) { + try { + return mService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) { + if (DBG) Log.d(TAG, "sendPassThroughCmd"); + if (mService != null && isEnabled()) { + try { + mService.sendPassThroughCmd(device, keyCode, keyState); + return; + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e); + return; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothAvrcpController.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, + BluetoothAvrcpController.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} -- cgit v1.2.3 From 25e84d4f5d76fdb421c597752117089b6c73e5b7 Mon Sep 17 00:00:00 2001 From: Sanket Agarwal Date: Wed, 21 Oct 2015 18:23:27 -0700 Subject: Add support for AVRCP 1.3. * Add metadata support. * Add player settings support. * Add playback support. A2DP Settings App support. Bluetooth: A2DP Sink support for Settings App - add support for A2DP Sink in Settings App. This will enable connection initiation and updation on Settings App - add framework Apis to support A2DP Sink. Any third party Apps can access A2DP Sink priority of device and playing state of device - add support for key to set priority. This manages priority of device for A2DP Sink profile Change-Id: If5f9139f37cdb9d200387877c7801075205c78a0 --- .../bluetooth/BluetoothAvrcpController.java | 208 ++++++++++++++++++--- 1 file changed, 182 insertions(+), 26 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index b53a8fc0f6..444e4293fe 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -20,6 +20,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.media.MediaMetadata; +import android.media.session.PlaybackState; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -28,8 +30,8 @@ import java.util.ArrayList; import java.util.List; /** - * This class provides the public APIs to control the Bluetooth AVRCP Controller - * profile. + * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently + * supports player information, playback support and track metadata. * *

BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get @@ -39,7 +41,7 @@ import java.util.List; */ public final class BluetoothAvrcpController implements BluetoothProfile { private static final String TAG = "BluetoothAvrcpController"; - private static final boolean DBG = true; + private static final boolean DBG = false; private static final boolean VDBG = false; /** @@ -61,7 +63,63 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * receive. */ public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; + "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; + + /** + * Intent used to broadcast the change in metadata state of playing track on the AVRCP + * AG. + * + *

This intent will have the two extras: + *

+ */ + public static final String ACTION_TRACK_EVENT = + "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT"; + + + /** + * Intent used to broadcast the change in player application setting state on AVRCP AG. + * + *

This intent will have the following extras: + *

+ */ + public static final String ACTION_PLAYER_SETTING = + "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING"; + + public static final String EXTRA_METADATA = + "android.bluetooth.avrcp-controller.profile.extra.METADATA"; + + public static final String EXTRA_PLAYBACK = + "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK"; + + public static final String EXTRA_PLAYER_SETTING = + "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; + + /* + * KeyCoded for Pass Through Commands + */ + public static final int PASS_THRU_CMD_ID_PLAY = 0x44; + public static final int PASS_THRU_CMD_ID_PAUSE = 0x46; + public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41; + public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42; + public static final int PASS_THRU_CMD_ID_STOP = 0x45; + public static final int PASS_THRU_CMD_ID_FF = 0x49; + public static final int PASS_THRU_CMD_ID_REWIND = 0x48; + public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B; + public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C; + /* Key State Variables */ + public static final int KEY_STATE_PRESSED = 0; + public static final int KEY_STATE_RELEASED = 1; + /* Group Navigation Key Codes */ + public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00; + public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01; + private Context mContext; private ServiceListener mServiceListener; @@ -69,33 +127,33 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private BluetoothAdapter mAdapter; final private 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); - } + 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); + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) Log.d(TAG,"Binding service..."); + doBind(); } + } catch (Exception re) { + Log.e(TAG,"",re); } } } - }; + } + }; /** * Create a BluetoothAvrcpController proxy object for interacting with the local @@ -223,6 +281,104 @@ public final class BluetoothAvrcpController implements BluetoothProfile { if (mService == null) Log.w(TAG, "Proxy not attached to service"); } + /** + * Gets the player application settings. + * + * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error. + */ + public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { + if (DBG) Log.d(TAG, "getPlayerSettings"); + BluetoothAvrcpPlayerSettings settings = null; + if (mService != null && isEnabled()) { + try { + settings = mService.getPlayerSettings(device); + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in getMetadata() " + e); + return null; + } + } + return settings; + } + + /** + * Gets the metadata for the current track. + * + * This should be usually called when application UI needs to be updated, eg. when the track + * changes or immediately after connecting and getting the current state. + * @return the {@link MediaMetadata} or {@link null} if there is an error. + */ + public MediaMetadata getMetadata(BluetoothDevice device) { + if (DBG) Log.d(TAG, "getMetadata"); + MediaMetadata metadata = null; + if (mService != null && isEnabled()) { + try { + metadata = mService.getMetadata(device); + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in getMetadata() " + e); + return null; + } + } + return metadata; + } + + /** + * Gets the playback state for current track. + * + * When the application is first connecting it can use current track state to get playback info. + * For all further updates it should listen to notifications. + * @return the {@link PlaybackState} or {@link null} if there is an error. + */ + public PlaybackState getPlaybackState(BluetoothDevice device) { + if (DBG) Log.d(TAG, "getPlaybackState"); + PlaybackState playbackState = null; + if (mService != null && isEnabled()) { + try { + playbackState = mService.getPlaybackState(device); + } catch (RemoteException e) { + Log.e(TAG, + "Error talking to BT service in getPlaybackState() " + e); + return null; + } + } + return playbackState; + } + + /** + * Sets the player app setting for current player. + * returns true in case setting is supported by remote, false otherwise + */ + public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { + if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); + if (mService != null && isEnabled()) { + try { + return mService.setPlayerApplicationSetting(plAppSetting); + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /* + * Send Group Navigation Command to Remote. + * possible keycode values: next_grp, previous_grp defined above + */ + public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { + Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); + if (mService != null && isEnabled()) { + try { + mService.sendGroupNavigationCmd(device, keyCode, keyState); + return; + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e); + return; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + } + private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); -- cgit v1.2.3 From 76e183f594a6178f45dcfb296aabf12623e22665 Mon Sep 17 00:00:00 2001 From: Sanket Agarwal Date: Wed, 3 Aug 2016 12:57:34 -0700 Subject: Remove APIs that are not directly usable This API is now exposed via MediaBrowser. Bug: b/28791287 Change-Id: I0a8a185934fd7aaa9f2b5eac7398955fa380060f --- .../bluetooth/BluetoothAvrcpController.java | 98 ---------------------- 1 file changed, 98 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 444e4293fe..a395aa470f 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -65,21 +65,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; - /** - * Intent used to broadcast the change in metadata state of playing track on the AVRCP - * AG. - * - *

This intent will have the two extras: - *

- */ - public static final String ACTION_TRACK_EVENT = - "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT"; - - /** * Intent used to broadcast the change in player application setting state on AVRCP AG. * @@ -92,35 +77,9 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public static final String ACTION_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING"; - public static final String EXTRA_METADATA = - "android.bluetooth.avrcp-controller.profile.extra.METADATA"; - - public static final String EXTRA_PLAYBACK = - "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK"; - public static final String EXTRA_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; - /* - * KeyCoded for Pass Through Commands - */ - public static final int PASS_THRU_CMD_ID_PLAY = 0x44; - public static final int PASS_THRU_CMD_ID_PAUSE = 0x46; - public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41; - public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42; - public static final int PASS_THRU_CMD_ID_STOP = 0x45; - public static final int PASS_THRU_CMD_ID_FF = 0x49; - public static final int PASS_THRU_CMD_ID_REWIND = 0x48; - public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B; - public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C; - /* Key State Variables */ - public static final int KEY_STATE_PRESSED = 0; - public static final int KEY_STATE_RELEASED = 1; - /* Group Navigation Key Codes */ - public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00; - public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01; - - private Context mContext; private ServiceListener mServiceListener; private IBluetoothAvrcpController mService; @@ -267,20 +226,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile { return BluetoothProfile.STATE_DISCONNECTED; } - public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) { - if (DBG) Log.d(TAG, "sendPassThroughCmd"); - if (mService != null && isEnabled()) { - try { - mService.sendPassThroughCmd(device, keyCode, keyState); - return; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e); - return; - } - } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); - } - /** * Gets the player application settings. * @@ -300,49 +245,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile { return settings; } - /** - * Gets the metadata for the current track. - * - * This should be usually called when application UI needs to be updated, eg. when the track - * changes or immediately after connecting and getting the current state. - * @return the {@link MediaMetadata} or {@link null} if there is an error. - */ - public MediaMetadata getMetadata(BluetoothDevice device) { - if (DBG) Log.d(TAG, "getMetadata"); - MediaMetadata metadata = null; - if (mService != null && isEnabled()) { - try { - metadata = mService.getMetadata(device); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getMetadata() " + e); - return null; - } - } - return metadata; - } - - /** - * Gets the playback state for current track. - * - * When the application is first connecting it can use current track state to get playback info. - * For all further updates it should listen to notifications. - * @return the {@link PlaybackState} or {@link null} if there is an error. - */ - public PlaybackState getPlaybackState(BluetoothDevice device) { - if (DBG) Log.d(TAG, "getPlaybackState"); - PlaybackState playbackState = null; - if (mService != null && isEnabled()) { - try { - playbackState = mService.getPlaybackState(device); - } catch (RemoteException e) { - Log.e(TAG, - "Error talking to BT service in getPlaybackState() " + e); - return null; - } - } - return playbackState; - } - /** * Sets the player app setting for current player. * returns true in case setting is supported by remote, false otherwise -- cgit v1.2.3 From 73458a81e89e0f1955f326d8d29e710a9b4eb746 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 4 Nov 2016 11:23:46 -0600 Subject: Detect non-oneway calls leaving system_server. To protect system stability, any Binder calls leaving the system_server must carefully be performed using FLAG_ONEWAY (or the 'oneway' verb in AIDL) which prevents the call from blocking indefinitely on the remote process. In this CL, the system_server uses the new Binder.setWarnOnBlocking() method to enable detection by default for all remote Binder interfaces. It can also use Binder.allowBlocking() to allow blocking calls on certain remote interfaces that have been determined to be safe. This CL adds the 'oneway' verb to several interfaces and methods where it should have been added, and marks a handful of system ContentProviders as being safe to call into. Also, we assume that any services obtained from ServiceManager are part of the core OS, and are okay to make blocking calls to. Test: builds, boots, runs with minimal logs triggered Bug: 32715088 Change-Id: Ide476e120cb40436a94b7faf7615c943d691f4c0 --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index a395aa470f..0261b1b35e 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.media.MediaMetadata; import android.media.session.PlaybackState; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -284,7 +285,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothAvrcpController.Stub.asInterface(service); + mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, -- cgit v1.2.3 From 910201beb0bde1dcf6b33e4ec5d1eb60042419d8 Mon Sep 17 00:00:00 2001 From: Jack He Date: Tue, 22 Aug 2017 16:06:54 -0700 Subject: Fix checkstyle errors (1/2) * Automatic style corrections through IDE Bug: 63596319 Test: make checkbuild, no manual changes, no functional changes Change-Id: I2397d55abc34c9b7a9b748bec6137778df3421a7 --- .../bluetooth/BluetoothAvrcpController.java | 87 +++++++++++----------- 1 file changed, 43 insertions(+), 44 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 0261b1b35e..1a0ae149f1 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -20,8 +20,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.media.MediaMetadata; -import android.media.session.PlaybackState; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -34,7 +32,7 @@ import java.util.List; * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently * supports player information, playback support and track metadata. * - *

BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP + *

BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get * the BluetoothAvrcpController proxy object. * @@ -51,9 +49,9 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * *

This intent will have 3 extras: *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • + *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • + *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • + *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • *
* *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of @@ -64,19 +62,19 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * receive. */ public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; + "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; /** * Intent used to broadcast the change in player application setting state on AVRCP AG. * *

This intent will have the following extras: *

    - *
  • {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the - * most recent player setting.
  • + *
  • {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the + * most recent player setting.
  • *
*/ public static final String ACTION_PLAYER_SETTING = - "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING"; + "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING"; public static final String EXTRA_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; @@ -87,38 +85,37 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private BluetoothAdapter mAdapter; final private 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); + 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(); + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) Log.d(TAG, "Binding service..."); + doBind(); + } + } catch (Exception re) { + Log.e(TAG, "", re); } - } catch (Exception re) { - Log.e(TAG,"",re); } } } - } - }; + }; /** * Create a BluetoothAvrcpController proxy object for interacting with the local * Bluetooth AVRCP service. - * */ /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) { mContext = context; @@ -129,7 +126,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { try { mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); } catch (RemoteException e) { - Log.e(TAG,"",e); + Log.e(TAG, "", e); } } @@ -155,7 +152,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { try { mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); } catch (Exception e) { - Log.e(TAG,"",e); + Log.e(TAG, "", e); } } @@ -165,7 +162,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { - Log.e(TAG,"",re); + Log.e(TAG, "", re); } } } @@ -215,7 +212,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); if (mService != null && isEnabled() - && isValidDevice(device)) { + && isValidDevice(device)) { try { return mService.getConnectionState(device); } catch (RemoteException e) { @@ -269,7 +266,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * possible keycode values: next_grp, previous_grp defined above */ public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { - Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); + Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + + keyState); if (mService != null && isEnabled()) { try { mService.sendGroupNavigationCmd(device, keyCode, keyState); @@ -292,6 +290,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { BluetoothAvrcpController.this); } } + public void onServiceDisconnected(ComponentName className) { if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; @@ -302,18 +301,18 @@ public final class BluetoothAvrcpController implements BluetoothProfile { }; private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; } private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; + if (device == null) return false; - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; } private static void log(String msg) { - Log.d(TAG, msg); + Log.d(TAG, msg); } } -- cgit v1.2.3 From 9e045d26d0128826b40520f523307d8d16473779 Mon Sep 17 00:00:00 2001 From: Jack He Date: Tue, 22 Aug 2017 21:21:23 -0700 Subject: Fix checkstyle errors (2/2) * Manual style corrections with IDE assistance * Variable name refactors are done through IDE * Corrected general style errors such as: - "final private var" -> "private final var" - "&&", "+", "||" should not be at the end of line - Non-static private variable should be like "mVar" - Private static variable should be like "sVar" - Code file should always end with newline - Inherited methods should be annotated with @Override and no @hide tags - Public methods should always have a JavaDoc entry - "int[] array" is preferred over "int array[]" - private methods should be accessed without "this." when there is no name collisions. - "boolean ? true : false" -> boolean - "boolean ? false : true" -> !boolean - "boolean == true" OR "boolean != false" -> boolean - "boolean != true" OR "boolean == false" -> !boolean Bug: 63596319 Test: make checkbuild, no functional changes Change-Id: Iabdc2be912a32dd63a53213d175cf1bfef268ccd --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 1a0ae149f1..7528aa9721 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -84,7 +84,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private IBluetoothAvrcpController mService; private BluetoothAdapter mAdapter; - final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new IBluetoothStateChangeCallback.Stub() { public void onBluetoothStateChange(boolean up) { if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); @@ -168,6 +168,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { } } + @Override public void finalize() { close(); } @@ -175,6 +176,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { /** * {@inheritDoc} */ + @Override public List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); if (mService != null && isEnabled()) { @@ -192,6 +194,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { /** * {@inheritDoc} */ + @Override public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); if (mService != null && isEnabled()) { @@ -209,6 +212,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { /** * {@inheritDoc} */ + @Override public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); if (mService != null && isEnabled() @@ -261,7 +265,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { return false; } - /* + /** * Send Group Navigation Command to Remote. * possible keycode values: next_grp, previous_grp defined above */ -- cgit v1.2.3 From 1f686f645294d624f8b61e4761fd14787a496c75 Mon Sep 17 00:00:00 2001 From: Jack He Date: Thu, 17 Aug 2017 12:11:18 -0700 Subject: Bluetooth: Thread-safe binder invocation * Binder object may become null between null check and actual invocation if using a instance private variable assignable by service connection callbacks * The solution to this problem without locking is to assign existing binder variable to a local final variable before the null check * Any further invocation to a disconnected binder object will result in RemoteException that is caught by the try-catch block * Read and write to volatile variable is always atomic and hence thread-safe * Removed unnecessary synchronization in BluetoothAdapter constructor * Private mConnection objects should be final * Simplfied several return statements where booleans can be returned directly * Removed unnecessary catches for NPE since there won't be any Bug: 64724692 Test: make, pair and use devices, no functional change Change-Id: Ifc9d6337c0d451a01484b61243230725d5314f8e --- .../bluetooth/BluetoothAvrcpController.java | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 7528aa9721..5f0e5d9744 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -81,7 +81,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private Context mContext; private ServiceListener mServiceListener; - private IBluetoothAvrcpController mService; + private volatile IBluetoothAvrcpController mService; private BluetoothAdapter mAdapter; private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = @@ -179,15 +179,16 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - if (mService != null && isEnabled()) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled()) { try { - return mService.getConnectedDevices(); + return service.getConnectedDevices(); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); } } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); + if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); } @@ -197,15 +198,16 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - if (mService != null && isEnabled()) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled()) { try { - return mService.getDevicesMatchingConnectionStates(states); + return service.getDevicesMatchingConnectionStates(states); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); } } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); + if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); } @@ -215,16 +217,16 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - if (mService != null && isEnabled() - && isValidDevice(device)) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled() && isValidDevice(device)) { try { - return mService.getConnectionState(device); + return service.getConnectionState(device); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return BluetoothProfile.STATE_DISCONNECTED; } } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); + if (service == null) Log.w(TAG, "Proxy not attached to service"); return BluetoothProfile.STATE_DISCONNECTED; } @@ -236,9 +238,10 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { if (DBG) Log.d(TAG, "getPlayerSettings"); BluetoothAvrcpPlayerSettings settings = null; - if (mService != null && isEnabled()) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled()) { try { - settings = mService.getPlayerSettings(device); + settings = service.getPlayerSettings(device); } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in getMetadata() " + e); return null; @@ -253,15 +256,16 @@ public final class BluetoothAvrcpController implements BluetoothProfile { */ public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); - if (mService != null && isEnabled()) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled()) { try { - return mService.setPlayerApplicationSetting(plAppSetting); + return service.setPlayerApplicationSetting(plAppSetting); } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e); return false; } } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); + if (service == null) Log.w(TAG, "Proxy not attached to service"); return false; } @@ -272,23 +276,23 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); - if (mService != null && isEnabled()) { + final IBluetoothAvrcpController service = mService; + if (service != null && isEnabled()) { try { - mService.sendGroupNavigationCmd(device, keyCode, keyState); + service.sendGroupNavigationCmd(device, keyCode, keyState); return; } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e); return; } } - if (mService == null) Log.w(TAG, "Proxy not attached to service"); + if (service == null) Log.w(TAG, "Proxy not attached to service"); } private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service)); - if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, BluetoothAvrcpController.this); @@ -305,15 +309,11 @@ public final class BluetoothAvrcpController implements BluetoothProfile { }; private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; + return mAdapter.getState() == BluetoothAdapter.STATE_ON; } - private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; + private static boolean isValidDevice(BluetoothDevice device) { + return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); } private static void log(String msg) { -- cgit v1.2.3 From 6edd25f33e4e4bed4fdd9eb815012111e59ad2a7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Feb 2018 13:25:31 -0700 Subject: Pass in the user defined by Context. The majority of Manager-style classes already use Context.getUserId() when making calls into the OS, so clean up the remaining callers to unify behind this strategy. This gives @SystemApi developers a nice clean interface to interact across user boundaries, instead of manually adding "AsUser" or "ForUser" method variants, which would quickly become unsustainable. Test: builds, boots Bug: 72863821 Exempt-From-Owner-Approval: trivial changes Change-Id: Ib772ec4438e57a2ad4950821b9432f9842998451 --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 5f0e5d9744..e7c8944788 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -138,7 +138,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - android.os.Process.myUserHandle())) { + mContext.getUser())) { Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent); return false; } -- cgit v1.2.3 From 86999c2001953beead860b15a898adad0092ebf9 Mon Sep 17 00:00:00 2001 From: jovanak Date: Mon, 15 Oct 2018 17:50:19 -0700 Subject: Makes bluetooth profile services bind to current (foreground) user. If profile services are created from a singleton process (like SystemUI), they need to be re-bind to a new foreground user when we switch to a secondary user. This is achieved by binding to UserHandle.CURRENT_OR_SELF. If the process doesn't have adequate permissions to bind to current, it will bind to self (which is the same as the previous behavior). Change-Id: Ib1134a1a62887d6f5b2c97301dccd3223ade9ed2 Fixes: 117517812 Test: ran the existing core bluetooth tests; manual testing on a mojave, verifying that the service correctly rebinds from sys ui after user switch. --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index e7c8944788..c447868d6f 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -23,6 +23,7 @@ import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; @@ -138,7 +139,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - mContext.getUser())) { + UserHandle.CURRENT_OR_SELF)) { Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent); return false; } -- cgit v1.2.3 From 70d76596569ec6c17761bdc4099015e756e7b61b Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Tue, 26 Mar 2019 21:38:08 +0800 Subject: 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 Change-Id: Id0d85866d386962b94d2d966f0a864b1da165d13 --- .../bluetooth/BluetoothAvrcpController.java | 130 +++++---------------- 1 file changed, 26 insertions(+), 104 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index c447868d6f..4e7e4415c5 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -16,14 +16,10 @@ package android.bluetooth; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; @@ -80,93 +76,32 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public static final String EXTRA_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; - private Context mContext; - private ServiceListener mServiceListener; - private volatile IBluetoothAvrcpController mService; private BluetoothAdapter mAdapter; - - 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 final BluetoothProfileConnector mProfileConnector = + new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER, + "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) { + @Override + public IBluetoothAvrcpController getServiceInterface(IBinder service) { + return IBluetoothAvrcpController.Stub.asInterface( + Binder.allowBlocking(service)); } - }; + }; /** * Create a BluetoothAvrcpController proxy object for interacting with the local * Bluetooth AVRCP service. */ - /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) { - mContext = context; - mServiceListener = l; + /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) { 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(IBluetoothAvrcpController.class.getName()); - ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); - intent.setComponent(comp); - if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - UserHandle.CURRENT_OR_SELF)) { - Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent); - return false; - } - return true; + mProfileConnector.connect(context, listener); } /*package*/ void close() { - mServiceListener = null; - 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); - } - } - } + private IBluetoothAvrcpController getService() { + return mProfileConnector.getService(); } @Override @@ -180,7 +115,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled()) { try { return service.getConnectedDevices(); @@ -199,7 +135,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled()) { try { return service.getDevicesMatchingConnectionStates(states); @@ -218,7 +155,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @Override public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { return service.getConnectionState(device); @@ -239,7 +177,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { if (DBG) Log.d(TAG, "getPlayerSettings"); BluetoothAvrcpPlayerSettings settings = null; - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled()) { try { settings = service.getPlayerSettings(device); @@ -257,7 +196,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { */ public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled()) { try { return service.setPlayerApplicationSetting(plAppSetting); @@ -277,7 +217,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); - final IBluetoothAvrcpController service = mService; + final IBluetoothAvrcpController service = + getService(); if (service != null && isEnabled()) { try { service.sendGroupNavigationCmd(device, keyCode, keyState); @@ -290,25 +231,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile { if (service == null) Log.w(TAG, "Proxy not attached to service"); } - private final ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service)); - if (mServiceListener != null) { - mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, - BluetoothAvrcpController.this); - } - } - - public void onServiceDisconnected(ComponentName className) { - if (DBG) Log.d(TAG, "Proxy object disconnected"); - mService = null; - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER); - } - } - }; - private boolean isEnabled() { return mAdapter.getState() == BluetoothAdapter.STATE_ON; } -- cgit v1.2.3 From 8f80e4a05b3f1b227f40de5ec0e9a6297154ffc0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Apr 2021 08:06:09 -0600 Subject: Update Bluetooth API annotations. Recent work has introduced a new "Nearby devices" runtime permission which protects all existing Bluetooth APIs; we've done this by defining a to convert the old BLUETOOTH and BLUETOOTH_ADMIN permissions into one of three new permissions: * BLUETOOTH_ADVERTISE: Required to be able to advertise to nearby Bluetooth devices. * BLUETOOTH_CONNECT: Allows applications to connect to paired bluetooth devices. * BLUETOOTH_SCAN: Required to be able to discover and pair nearby Bluetooth devices. At its core, this change begins updating the Bluetooth APIs to have correct @RequiresPermission indicating which permission is actually enforced internally. To ensure alignment across Binder, the newly added "RequiresPermissionChecker" Error Prone checker was used to discover any inconsistencies, ensuring correctness from server-side enforcement up through to the public APIs. In addition, since developers will continue building apps for both modern and legacy platforms, this change introduces new auto-doc annotations which will emit helpful consistent documentation describing the behavior of older devices that are still using the old permission model. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I02aa127e8e07f239561f4f2a3bbdfc6fccb82f7f --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 4e7e4415c5..887cf3f08b 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -16,6 +16,10 @@ package android.bluetooth; +import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; +import android.bluetooth.annotations.RequiresBluetoothConnectPermission; +import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -54,10 +58,10 @@ public final class BluetoothAvrcpController implements BluetoothProfile { *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - *

Requires {@link android.Manifest.permission#BLUETOOTH} permission to - * receive. */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; -- cgit v1.2.3 From 3614e0a2a9aa949c68f3afb52fcee71a4fa39e48 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Apr 2021 15:34:54 -0600 Subject: Add missing Bluetooth API permission enforcement. Recent work has been using Error Prone rules and annotations to reflect the current state of permission enforcement across the Bluetooth stack, and we're now in a position were we can add new permission enforcement that had been missing. We've currently standardized on saying that APIs that return device or Bluetooth state information (without sharing details about any particular remote Bluetooth device) do not need to be permission protected. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I37a9e03ecdca6f7a6eb9d7f094e2f95a97036612 --- .../java/android/bluetooth/BluetoothAvrcpController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 887cf3f08b..5148d5b431 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -117,6 +117,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * {@inheritDoc} */ @Override + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothAvrcpController service = @@ -137,6 +139,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * {@inheritDoc} */ @Override + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothAvrcpController service = @@ -157,6 +161,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * {@inheritDoc} */ @Override + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothAvrcpController service = @@ -178,6 +184,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error. */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { if (DBG) Log.d(TAG, "getPlayerSettings"); BluetoothAvrcpPlayerSettings settings = null; @@ -198,6 +206,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * Sets the player app setting for current player. * returns true in case setting is supported by remote, false otherwise */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); final IBluetoothAvrcpController service = @@ -218,6 +228,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * Send Group Navigation Command to Remote. * possible keycode values: next_grp, previous_grp defined above */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); -- cgit v1.2.3 From d7c55664839ca7e6237cd0ef0f36eb51a4ee7ae6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 20 Apr 2021 12:30:37 -0600 Subject: Annotations for Bluetooth broadcast intents. Recent work has been using Error Prone rules and annotations to reflect the current state of permission enforcement across the Bluetooth stack, and we're now in a position were we can add new permission enforcement that had been missing. We've currently standardized on saying that APIs that return device or Bluetooth state information (without sharing details about any particular remote Bluetooth device) do not need to be permission protected. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I53ac7a4fe1dea57316048c3cac4fa237b6ba3d38 --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 5148d5b431..cac676d7dc 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -17,7 +17,9 @@ package android.bluetooth; import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; import android.annotation.SuppressLint; +import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.Context; @@ -62,6 +64,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; @@ -74,6 +77,9 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * most recent player setting. * */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING"; -- cgit v1.2.3 From f9e176c3dcafb82f251a123751578539e3484deb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 22 Apr 2021 16:01:29 -0600 Subject: More AttributionSource plumbing. To prepare for future work which will plumb AttributionSource values through all remaining AIDLs, we need profiles to interact directly with the specific BluetoothAdapter they were created from. This is how we'll ensure that the relevant AttributionSource can be chained down from the original Context they're obtained from. This change also marks getDefaultAdapter() as deprecated to clearly communicate that BluetoothManager.getAdapter() is the best-practice path to obtaining a correctly scoped BluetoothAdapter instance. Bug: 183626112 Test: atest BluetoothInstrumentationTests Change-Id: I1e15170d7679019bbb6e396279d6e633e3dad4d6 --- .../java/android/bluetooth/BluetoothAvrcpController.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index cac676d7dc..be3d5ee9ef 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.AttributionSource; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -86,7 +87,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public static final String EXTRA_PLAYER_SETTING = "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; - private BluetoothAdapter mAdapter; + private final BluetoothAdapter mAdapter; + private final AttributionSource mAttributionSource; private final BluetoothProfileConnector mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER, "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) { @@ -101,8 +103,10 @@ public final class BluetoothAvrcpController implements BluetoothProfile { * Create a BluetoothAvrcpController proxy object for interacting with the local * Bluetooth AVRCP service. */ - /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) { - mAdapter = BluetoothAdapter.getDefaultAdapter(); + /* package */ BluetoothAvrcpController(Context context, ServiceListener listener, + BluetoothAdapter adapter) { + mAdapter = adapter; + mAttributionSource = adapter.getAttributionSource(); mProfileConnector.connect(context, listener); } @@ -131,7 +135,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return service.getConnectedDevices(); + return BluetoothDevice.setAttributionSource( + service.getConnectedDevices(), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); @@ -153,7 +158,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return service.getDevicesMatchingConnectionStates(states); + return BluetoothDevice.setAttributionSource( + service.getDevicesMatchingConnectionStates(states), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); -- cgit v1.2.3 From 43ee69eed974cd7ebc4784416a6e1e251464cc36 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 23 Apr 2021 14:13:57 -0600 Subject: Long-tail of AttributionSource plumbing. Wires up AttributionSource across the remaining long-tail of Bluetooth AIDL interfaces, ensuring that developers can accurately make calls chained back to a specific Context. Moves "for data delivery" permission checks to happen in a single location on each interface to ensure they're performed consistently with the new AttributionSource arguments. Note that "for data delivery" isn't the best name; it's designed to represent that the requested action was performed and should result in the relevant appop being noted for the caller. This change has the positive side effect of ensuring that all interfaces are consistently enforcing the BLUETOOTH_CONNECT permission, even in the case where BLUETOOTH_PRIVILEGED is also required; this is what ensures that revoking the "Nearby devices" permission takes effect for all callers. Additionally, standardizing on enforcing permissions closer to the AIDL entry point reduces the need for @RequiresPermission annotations to be carried around inside the Bluetooth stack. Bug: 183626112 Test: atest BluetoothInstrumentationTests Change-Id: I8023dda654e325b8bfa2f0cdb994ad63a2b429d4 --- .../java/android/bluetooth/BluetoothAvrcpController.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index be3d5ee9ef..0b43e71aba 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -136,7 +136,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { if (service != null && isEnabled()) { try { return BluetoothDevice.setAttributionSource( - service.getConnectedDevices(), mAttributionSource); + service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); @@ -159,7 +159,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile { if (service != null && isEnabled()) { try { return BluetoothDevice.setAttributionSource( - service.getDevicesMatchingConnectionStates(states), mAttributionSource); + service.getDevicesMatchingConnectionStates(states, mAttributionSource), + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return new ArrayList(); @@ -181,7 +182,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device); + return service.getConnectionState(device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return BluetoothProfile.STATE_DISCONNECTED; @@ -205,7 +206,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - settings = service.getPlayerSettings(device); + settings = service.getPlayerSettings(device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in getMetadata() " + e); return null; @@ -226,7 +227,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return service.setPlayerApplicationSetting(plAppSetting); + return service.setPlayerApplicationSetting(plAppSetting, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e); return false; @@ -249,7 +250,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - service.sendGroupNavigationCmd(device, keyCode, keyState); + service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource); return; } catch (RemoteException e) { Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e); -- cgit v1.2.3 From 98f3044ce87c7ab9d2a0efbfb8ef6a16872262df Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 3 Jun 2021 09:26:53 -0600 Subject: More Binder call AttributionSource assignment. Since developers can use a BluetoothDevice object can make remote calls, it needs to have an accurate AttributionSource. Previous CLs had updated many places where these BluetoothDevice instances were passed across Binder interfaces, but this change updates several remaining locations which had been missed. Introduces new "Attributable" marker interface to offer consistent tooling when applying AttributionSource updates. Bug: 187097694 Test: atest BluetoothInstrumentationTests Change-Id: Icad3b9726591f0fbad58a493cefa5a0af7648280 --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 0b43e71aba..d27c276480 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -135,7 +136,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -158,7 +159,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { -- cgit v1.2.3 From d517127a57b499305f82ec6eea6da8e0bd485e87 Mon Sep 17 00:00:00 2001 From: William Escande Date: Tue, 14 Dec 2021 16:16:11 +0100 Subject: Copy attributable to Bluetooth Attributable is called by bluetooth and it's hidden. By copying into bluetooth we are now allowed to call it Bug: 210467788 Test: build Tag: #refactor Change-Id: I73ea07c9439988ab5477c82799f718c6d81513be --- framework/java/android/bluetooth/BluetoothAvrcpController.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index d27c276480..536dfb0a66 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -18,11 +18,9 @@ package android.bluetooth; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; -import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; -- cgit v1.2.3 From b86023dde0fbbe539e2415942ffe1c97108654f8 Mon Sep 17 00:00:00 2001 From: William Escande Date: Thu, 16 Dec 2021 16:07:55 +0100 Subject: Remove allowBlocking from all BluetoothProfiles Since Bluetooth is becoming a mainline module, it can no longer call the allowBlocking hidden api. Instead, all interface are moved to be oneway and use a synchronous data to handle the return value. Bug: 200200870 Test: Build + start Bt and play something on speaker Tag: #refactor Merged-In: I776a6322faadca1504bce24f2b6b041e756b6448 Change-Id: I776a6322faadca1504bce24f2b6b041e756b6448 --- .../bluetooth/BluetoothAvrcpController.java | 135 ++++++++++++--------- 1 file changed, 80 insertions(+), 55 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAvrcpController.java') diff --git a/framework/java/android/bluetooth/BluetoothAvrcpController.java b/framework/java/android/bluetooth/BluetoothAvrcpController.java index 536dfb0a66..81fc3e11e9 100644 --- a/framework/java/android/bluetooth/BluetoothAvrcpController.java +++ b/framework/java/android/bluetooth/BluetoothAvrcpController.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -23,13 +25,15 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently @@ -93,8 +97,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) { @Override public IBluetoothAvrcpController getServiceInterface(IBinder service) { - return IBluetoothAvrcpController.Stub.asInterface( - Binder.allowBlocking(service)); + return IBluetoothAvrcpController.Stub.asInterface(service); } }; @@ -130,19 +133,24 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final List defaultValue = new ArrayList(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList(); + return defaultValue; } /** @@ -153,20 +161,24 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final List defaultValue = new ArrayList(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList(); + return defaultValue; } /** @@ -177,18 +189,21 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothAvrcpController service = getService(); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -201,17 +216,22 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { if (DBG) Log.d(TAG, "getPlayerSettings"); BluetoothAvrcpPlayerSettings settings = null; - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final BluetoothAvrcpPlayerSettings defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - settings = service.getPlayerSettings(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getMetadata() " + e); - return null; + final SynchronousResultReceiver recv = + new SynchronousResultReceiver(); + service.getPlayerSettings(device, mAttributionSource, recv); + settings = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return settings; + return defaultValue; } /** @@ -222,18 +242,21 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.setPlayerApplicationSetting(plAppSetting, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e); - return false; + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setPlayerApplicationSetting(plAppSetting, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -245,18 +268,20 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource); - return; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); return; + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); } private boolean isEnabled() { -- cgit v1.2.3