From 261a9f94828187e7cf08034a45259eb18a51f80c Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 13 Sep 2019 16:08:18 -0700 Subject: [PATCH] AudioService: simplify/document locking In AudioDeviceBroker, mDeviceStateLock was the main lock and was previously used almost as a global synchronization, present on the handling of most messages, and numerous other methods without actually protecting the only states it maintains. Note that BtHelper and AudioDeviceInventory have their own sync model, so they don't need to be protected by a lock from AudioDeviceBroker. This CL renames mDeviceStateLock to mDeviceBrokerLock specifically protecting: - "force use" setting for communication - Bluetooth A2DP enabled (coming from AudioManager API) - all management of the message queue, both for enqueueing and removal (which was exposed to race condition since commit dc552e9 for A2DP (dis)connection. It also removes the lock used to synchronize the audio mode owner with the SCO operations: the only information AudioDeviceBroker needed from AudioService regarding audio mode was the PID of the mode owner. The new code uses an atomic integer to store/provide this information, instead of relying on a shared lock amongst multiple classes. Add test for behavior where media gets unmuted if it was muted when the user connects an A2DP headset. Bug: 140200704 Test: atest AudioDeviceBrokerTest ; atest AudioManagerTest Change-Id: If6a98d8aad61da6eef4b54ef9c57dc80d74be593 --- .../server/audio/AudioDeviceBroker.java | 523 +++++++++--------- .../server/audio/AudioDeviceInventory.java | 3 - .../android/server/audio/AudioService.java | 70 +-- .../com/android/server/audio/BtHelper.java | 30 - .../server/audio/AudioDeviceBrokerTest.java | 16 + 5 files changed, 307 insertions(+), 335 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 6010b1dc88c44..f7ac04041ed63 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -57,13 +57,6 @@ import java.io.PrintWriter; private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; - /** Forced device usage for communications sent to AudioSystem */ - private int mForcedUseForComm; - /** - * Externally reported force device usage state returned by getters: always consistent - * with requests by setters */ - private int mForcedUseForCommExt; - // Manages all connected devices, only ever accessed on the message loop private final AudioDeviceInventory mDeviceInventory; // Manages notifications to BT service @@ -71,24 +64,34 @@ import java.io.PrintWriter; //------------------------------------------------------------------- - // we use a different lock than mDeviceStateLock so as not to create - // lock contention between enqueueing a message and handling them - private static final Object sLastDeviceConnectionMsgTimeLock = new Object(); - @GuardedBy("sLastDeviceConnectionMsgTimeLock") + /** + * Lock to guard: + * - any changes to the message queue: enqueueing or removing any message + * - state of A2DP enabled + * - force use for communication + SCO changes + */ + private final Object mDeviceBrokerLock = new Object(); + + @GuardedBy("mDeviceBrokerLock") private static long sLastDeviceConnectMsgTime = 0; - // General lock to be taken whenever the state of the audio devices is to be checked or changed - private final Object mDeviceStateLock = new Object(); - // Request to override default use of A2DP for media. - @GuardedBy("mDeviceStateLock") + /** Request to override default use of A2DP for media */ + @GuardedBy("mDeviceBrokerLock") private boolean mBluetoothA2dpEnabled; - // lock always taken when accessing AudioService.mSetModeDeathHandlers - // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 - /*package*/ final Object mSetModeLock = new Object(); + /** Forced device usage for communications sent to AudioSystem */ + @GuardedBy("mDeviceBrokerLock") + private int mForcedUseForComm; + /** + * Externally reported force device usage state returned by getters: always consistent + * with requests by setters */ + @GuardedBy("mDeviceBrokerLock") + private int mForcedUseForCommExt; + //------------------------------------------------------------------- + /** Normal constructor used by AudioService */ /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { mContext = context; mAudioService = service; @@ -127,38 +130,37 @@ import java.io.PrintWriter; // All post* methods are asynchronous /*package*/ void onSystemReady() { - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.onSystemReady(); - } - } + mBtHelper.onSystemReady(); } /*package*/ void onAudioServerDied() { // Restore forced usage for communications and record - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { AudioSystem.setParameters( "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off")); onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied"); onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied"); + + // restore devices + sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE); } - // restore devices - sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE); } /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) { - sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, - useCase, config, eventSource); + synchronized (mDeviceBrokerLock) { + sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, + useCase, config, eventSource); + } } /*package*/ void toggleHdmiIfConnected_Async() { - sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE); + } } /*package*/ void disconnectAllBluetoothProfiles() { - synchronized (mDeviceStateLock) { mBtHelper.disconnectAllBluetoothProfiles(); - } } /** @@ -168,15 +170,11 @@ import java.io.PrintWriter; * @param intent */ /*package*/ void receiveBtEvent(@NonNull Intent intent) { - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.receiveBtEvent(intent); - } - } + mBtHelper.receiveBtEvent(intent); } /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { if (mBluetoothA2dpEnabled == on) { return; } @@ -196,7 +194,7 @@ import java.io.PrintWriter; * @return true if speakerphone state changed */ /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { final boolean wasOn = isSpeakerphoneOn(); if (on) { if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { @@ -214,7 +212,7 @@ import java.io.PrintWriter; } /*package*/ boolean isSpeakerphoneOn() { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER); } } @@ -223,9 +221,7 @@ import java.io.PrintWriter; @AudioService.ConnectionState int state, String address, String name, String caller) { //TODO move logging here just like in setBluetooth* methods - synchronized (mDeviceStateLock) { - mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller); - } + mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller); } private static final class BtDeviceConnectionInfo { @@ -259,27 +255,24 @@ import java.io.PrintWriter; final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile, suppressNoisyIntent, a2dpVolume); - // when receiving a request to change the connection state of a device, this last request - // is the source of truth, so cancel all previous requests - removeAllA2dpConnectionEvents(device); + synchronized (mDeviceBrokerLock) { + // when receiving a request to change the connection state of a device, this last + // request is the source of truth, so cancel all previous requests + mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, + device); + mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, + device); + mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, + device); + mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + device); - sendLMsgNoDelay( - state == BluetoothProfile.STATE_CONNECTED - ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION - : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, - SENDMSG_QUEUE, info); - } - - /** remove all previously scheduled connection and disconnection events for the given device */ - private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) { - mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, - device); - mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, - device); - mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, - device); - mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, - device); + sendLMsgNoDelay( + state == BluetoothProfile.STATE_CONNECTED + ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION + : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, + SENDMSG_QUEUE, info); + } } private static final class HearingAidDeviceConnectionInfo { @@ -305,28 +298,31 @@ import java.io.PrintWriter; boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo( device, state, suppressNoisyIntent, musicDevice, eventSource); - sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); + } } // never called by system components /*package*/ void setBluetoothScoOnByApp(boolean on) { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; } } /*package*/ boolean isBluetoothScoOnForApp() { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO; } } /*package*/ void setBluetoothScoOn(boolean on, String eventSource) { //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource); - synchronized (mDeviceStateLock) { + final boolean isBtScoOn = mBtHelper.isBluetoothScoOn(); + synchronized (mDeviceBrokerLock) { if (on) { // do not accept SCO ON if SCO audio is not connected - if (!mBtHelper.isBluetoothScoOn()) { + if (!isBtScoOn) { mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO; return; } @@ -346,58 +342,55 @@ import java.io.PrintWriter; } /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { - synchronized (mDeviceStateLock) { - return mDeviceInventory.startWatchingRoutes(observer); - } + return mDeviceInventory.startWatchingRoutes(observer); + } /*package*/ AudioRoutesInfo getCurAudioRoutes() { - synchronized (mDeviceStateLock) { - return mDeviceInventory.getCurAudioRoutes(); - } + return mDeviceInventory.getCurAudioRoutes(); } /*package*/ boolean isAvrcpAbsoluteVolumeSupported() { - synchronized (mDeviceStateLock) { - return mBtHelper.isAvrcpAbsoluteVolumeSupported(); - } + return mBtHelper.isAvrcpAbsoluteVolumeSupported(); } /*package*/ boolean isBluetoothA2dpOn() { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { return mBluetoothA2dpEnabled; } } /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) { - sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); + synchronized (mDeviceBrokerLock) { + sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); + } } /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) { - sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); + synchronized (mDeviceBrokerLock) { + sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); + } } /*package*/ void postDisconnectBluetoothSco(int exceptPid) { - sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid); + synchronized (mDeviceBrokerLock) { + sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid); + } } /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { - sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); + } } - @GuardedBy("mSetModeLock") /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource) { - synchronized (mDeviceStateLock) { - mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); - } + mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); } - @GuardedBy("mSetModeLock") /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) { - synchronized (mDeviceStateLock) { - mBtHelper.stopBluetoothScoForClient(cb, eventSource); - } + mBtHelper.stopBluetoothScoForClient(cb, eventSource); } //--------------------------------------------------------------------- @@ -460,77 +453,109 @@ import java.io.PrintWriter; //--------------------------------------------------------------------- // Message handling on behalf of helper classes /*package*/ void postBroadcastScoConnectionState(int state) { - sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); + synchronized (mDeviceBrokerLock) { + sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); + } } /*package*/ void postBroadcastBecomingNoisy() { - sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); + } } /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { - sendILMsg(state == BluetoothA2dp.STATE_CONNECTED - ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED - : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, - SENDMSG_QUEUE, - state, btDeviceInfo, delay); + synchronized (mDeviceBrokerLock) { + sendILMsg(state == BluetoothA2dp.STATE_CONNECTED + ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED + : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + SENDMSG_QUEUE, + state, btDeviceInfo, delay); + } } /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { - sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, - state, btDeviceInfo, delay); + synchronized (mDeviceBrokerLock) { + sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, + state, btDeviceInfo, delay); + } } /*package*/ void postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) { - sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay); + synchronized (mDeviceBrokerLock) { + sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, + connectionState, delay); + } } /*package*/ void postSetHearingAidConnectionState( @AudioService.BtProfileConnectionState int state, @NonNull BluetoothDevice device, int delay) { - sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE, - state, - device, - delay); + synchronized (mDeviceBrokerLock) { + sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE, + state, + device, + delay); + } } /*package*/ void postDisconnectA2dp() { - sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE); + } } /*package*/ void postDisconnectA2dpSink() { - sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE); + } } /*package*/ void postDisconnectHearingAid() { - sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); + } } /*package*/ void postDisconnectHeadset() { - sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); + } } /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); + } } /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); + } } /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, + headsetProfile); + } } /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, - hearingAidProfile); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, + hearingAidProfile); + } } /*package*/ void postScoClientDied(Object obj) { - sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); + } } //--------------------------------------------------------------------- @@ -545,7 +570,7 @@ import java.io.PrintWriter; .append(") from u/pid:").append(Binder.getCallingUid()).append("/") .append(Binder.getCallingPid()).append(" src:").append(source).toString(); - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { mBluetoothA2dpEnabled = on; mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); onSetForceUse( @@ -557,71 +582,85 @@ import java.io.PrintWriter; /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) { - synchronized (mDeviceStateLock) { - return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName); - } + return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName); } /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; - sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, - btDeviceInfo); + synchronized (mDeviceBrokerLock) { + sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, + btDeviceInfo); + } } /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) { - sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); + synchronized (mDeviceBrokerLock) { + sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); + } } /*package*/ void handleCancelFailureToConnectToBtHeadsetService() { - mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); + synchronized (mDeviceBrokerLock) { + mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); + } } /*package*/ void postReportNewRoutes() { - sendMsgNoDelay(MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); + synchronized (mDeviceBrokerLock) { + sendMsgNoDelay(MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); + } } /*package*/ void cancelA2dpDockTimeout() { - mBrokerHandler.removeMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); + synchronized (mDeviceBrokerLock) { + mBrokerHandler.removeMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); + } } + // FIXME: used by? /*package*/ void postA2dpActiveDeviceChange( @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { - sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo); + synchronized (mDeviceBrokerLock) { + sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo); + } } /*package*/ boolean hasScheduledA2dpDockTimeout() { - return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); + synchronized (mDeviceBrokerLock) { + return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); + } } // must be called synchronized on mConnectedDevices /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) { - return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, - new BtHelper.BluetoothA2dpDeviceInfo(btDevice)) - || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, - new BtHelper.BluetoothA2dpDeviceInfo(btDevice))); - } - - /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) { - sendILMsg(MSG_IL_BTA2DP_DOCK_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); - } - - /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { - synchronized (mDeviceStateLock) { - mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); + synchronized (mDeviceBrokerLock) { + return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, + new BtHelper.BluetoothA2dpDeviceInfo(btDevice)) + || mBrokerHandler.hasMessages( + MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + new BtHelper.BluetoothA2dpDeviceInfo(btDevice))); } } + /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) { + synchronized (mDeviceBrokerLock) { + sendILMsg(MSG_IL_BTA2DP_DOCK_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); + } + } + + /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { + mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); + } + /*package*/ boolean getBluetoothA2dpEnabled() { - synchronized (mDeviceStateLock) { + synchronized (mDeviceBrokerLock) { return mBluetoothA2dpEnabled; } } /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) { - synchronized (mDeviceStateLock) { - return mBtHelper.getA2dpCodec(device); - } + return mBtHelper.getA2dpCodec(device); } /*package*/ void dump(PrintWriter pw, String prefix) { @@ -709,156 +748,101 @@ import java.io.PrintWriter; public void handleMessage(Message msg) { switch (msg.what) { case MSG_RESTORE_DEVICES: - synchronized (mDeviceStateLock) { - mDeviceInventory.onRestoreDevices(); - mBtHelper.onAudioServerDiedRestoreA2dp(); - } + mDeviceInventory.onRestoreDevices(); + mBtHelper.onAudioServerDiedRestoreA2dp(); break; case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetWiredDeviceConnectionState( - (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj); - } + mDeviceInventory.onSetWiredDeviceConnectionState( + (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj); break; case MSG_I_BROADCAST_BT_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mBtHelper.onBroadcastScoConnectionState(msg.arg1); - } + mBtHelper.onBroadcastScoConnectionState(msg.arg1); break; case MSG_IIL_SET_FORCE_USE: // intended fall-through case MSG_IIL_SET_FORCE_BT_A2DP_USE: onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj); break; case MSG_REPORT_NEW_ROUTES: - synchronized (mDeviceStateLock) { - mDeviceInventory.onReportNewRoutes(); - } + mDeviceInventory.onReportNewRoutes(); break; case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetA2dpSinkConnectionState( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); - } + mDeviceInventory.onSetA2dpSinkConnectionState( + (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); break; case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetA2dpSourceConnectionState( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); - } + mDeviceInventory.onSetA2dpSourceConnectionState( + (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); break; case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetHearingAidConnectionState( - (BluetoothDevice) msg.obj, msg.arg1, - mAudioService.getHearingAidStreamType()); - } + mDeviceInventory.onSetHearingAidConnectionState( + (BluetoothDevice) msg.obj, msg.arg1, + mAudioService.getHearingAidStreamType()); break; case MSG_BT_HEADSET_CNCT_FAILED: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.resetBluetoothSco(); - } - } + mBtHelper.resetBluetoothSco(); break; case MSG_IL_BTA2DP_DOCK_TIMEOUT: // msg.obj == address of BTA2DP device - synchronized (mDeviceStateLock) { - mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1); - } + mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1); break; case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: final int a2dpCodec; final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; - synchronized (mDeviceStateLock) { - a2dpCodec = mBtHelper.getA2dpCodec(btDevice); - mDeviceInventory.onBluetoothA2dpActiveDeviceChange( - new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), - BtHelper.EVENT_DEVICE_CONFIG_CHANGE); - } + // FIXME why isn't the codec coming with the request? codec should be + // provided by BT when it calls + // AudioManager.handleBluetoothA2dpDeviceConfigChange(BluetoothDevice) + a2dpCodec = mBtHelper.getA2dpCodec(btDevice); + mDeviceInventory.onBluetoothA2dpActiveDeviceChange( + new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), + BtHelper.EVENT_DEVICE_CONFIG_CHANGE); break; case MSG_BROADCAST_AUDIO_BECOMING_NOISY: onSendBecomingNoisyIntent(); break; case MSG_II_SET_HEARING_AID_VOLUME: - synchronized (mDeviceStateLock) { - mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2); - } + mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2); break; case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME: - synchronized (mDeviceStateLock) { - mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); - } + mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); break; case MSG_I_DISCONNECT_BT_SCO: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.disconnectBluetoothSco(msg.arg1); - } - } + mBtHelper.disconnectBluetoothSco(msg.arg1); break; case MSG_L_SCOCLIENT_DIED: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.scoClientDied(msg.obj); - } - } + mBtHelper.scoClientDied(msg.obj); break; case MSG_TOGGLE_HDMI: - synchronized (mDeviceStateLock) { - mDeviceInventory.onToggleHdmi(); - } + mDeviceInventory.onToggleHdmi(); break; case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onBluetoothA2dpActiveDeviceChange( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, - BtHelper.EVENT_ACTIVE_DEVICE_CHANGE); - } + mDeviceInventory.onBluetoothA2dpActiveDeviceChange( + (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, + BtHelper.EVENT_ACTIVE_DEVICE_CHANGE); break; case MSG_DISCONNECT_A2DP: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectA2dp(); - } + mDeviceInventory.disconnectA2dp(); break; case MSG_DISCONNECT_A2DP_SINK: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectA2dpSink(); - } + mDeviceInventory.disconnectA2dpSink(); break; case MSG_DISCONNECT_BT_HEARING_AID: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectHearingAid(); - } + mDeviceInventory.disconnectHearingAid(); break; case MSG_DISCONNECT_BT_HEADSET: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.disconnectHeadset(); - } - } + mBtHelper.disconnectHeadset(); break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: - synchronized (mDeviceStateLock) { - mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); - } + mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: - synchronized (mDeviceStateLock) { - mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); - } + mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: - synchronized (mDeviceStateLock) { - mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); - } + mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); - } - } + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); break; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: { @@ -871,11 +855,9 @@ import java.io.PrintWriter; + " addr=" + info.mDevice.getAddress() + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy + " vol=" + info.mVolume)).printLog(TAG)); - synchronized (mDeviceStateLock) { - mDeviceInventory.setBluetoothA2dpDeviceConnectionState( - info.mDevice, info.mState, info.mProfile, info.mSupprNoisy, - AudioSystem.DEVICE_NONE, info.mVolume); - } + mDeviceInventory.setBluetoothA2dpDeviceConnectionState( + info.mDevice, info.mState, info.mProfile, info.mSupprNoisy, + AudioSystem.DEVICE_NONE, info.mVolume); } break; case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: { final HearingAidDeviceConnectionInfo info = @@ -885,10 +867,8 @@ import java.io.PrintWriter; + " addr=" + info.mDevice.getAddress() + " supprNoisy=" + info.mSupprNoisy + " src=" + info.mEventSource)).printLog(TAG)); - synchronized (mDeviceStateLock) { - mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( - info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); - } + mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( + info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); } break; default: Log.wtf(TAG, "Invalid message " + msg.what); @@ -973,46 +953,57 @@ import java.io.PrintWriter; /** If the msg is already queued, queue this one and leave the old. */ private static final int SENDMSG_QUEUE = 2; + @GuardedBy("mDeviceBrokerLock") private void sendMsg(int msg, int existingMsgPolicy, int delay) { sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay); } + @GuardedBy("mDeviceBrokerLock") private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) { sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay); } + @GuardedBy("mDeviceBrokerLock") private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) { sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay); } + @GuardedBy("mDeviceBrokerLock") private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) { sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay); } + @GuardedBy("mDeviceBrokerLock") private void sendMsgNoDelay(int msg, int existingMsgPolicy) { sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) { sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) { sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) { sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) { sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) { sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0); } + @GuardedBy("mDeviceBrokerLock") private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { if (existingMsgPolicy == SENDMSG_REPLACE) { @@ -1031,31 +1022,29 @@ import java.io.PrintWriter; Binder.restoreCallingIdentity(identity); } - synchronized (sLastDeviceConnectionMsgTimeLock) { - long time = SystemClock.uptimeMillis() + delay; + long time = SystemClock.uptimeMillis() + delay; - switch (msg) { - case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: - case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: - case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: - case MSG_IL_BTA2DP_DOCK_TIMEOUT: - case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: - case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: - if (sLastDeviceConnectMsgTime >= time) { - // add a little delay to make sure messages are ordered as expected - time = sLastDeviceConnectMsgTime + 30; - } - sLastDeviceConnectMsgTime = time; - break; - default: - break; - } - - mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), - time); + switch (msg) { + case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: + case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: + case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: + case MSG_IL_BTA2DP_DOCK_TIMEOUT: + case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: + case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: + if (sLastDeviceConnectMsgTime >= time) { + // add a little delay to make sure messages are ordered as expected + time = sLastDeviceConnectMsgTime + 30; + } + sLastDeviceConnectMsgTime = time; + break; + default: + break; } + + mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), + time); } //------------------------------------------------------------- diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 90973a888a9d2..3933fb2d5f464 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -159,7 +159,6 @@ public class AudioDeviceInventory { } // only public for mocking/spying - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @VisibleForTesting public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, @AudioService.BtProfileConnectionState int state) { @@ -284,7 +283,6 @@ public class AudioDeviceInventory { } } - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ void onBluetoothA2dpActiveDeviceChange( @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) { final BluetoothDevice btDevice = btInfo.getBtDevice(); @@ -557,7 +555,6 @@ public class AudioDeviceInventory { } // only public for mocking/spying - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @VisibleForTesting public void setBluetoothA2dpDeviceConnectionState( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a6ac17dc9b6a9..9371d13be7ef8 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -470,12 +470,11 @@ public class AudioService extends IAudioService.Stub // List of binder death handlers for setMode() client processes. // The last process to have called setMode() is at the top of the list. - // package-private so it can be accessed in AudioDeviceBroker.getSetModeDeathHandlers - //TODO candidate to be moved to separate class that handles synchronization - @GuardedBy("mDeviceBroker.mSetModeLock") - /*package*/ final ArrayList mSetModeDeathHandlers = + private final ArrayList mSetModeDeathHandlers = new ArrayList(); + private volatile int mCurrentModeOwnerPid = 0; + // true if boot sequence has been completed private boolean mSystemReady; // true if Intent.ACTION_USER_SWITCHED has ever been received @@ -3185,15 +3184,10 @@ public class AudioService extends IAudioService.Stub * @return 0 if nobody owns the mode */ /*package*/ int getModeOwnerPid() { - int modeOwnerPid = 0; - try { - modeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); - } catch (Exception e) { - // nothing to do, modeOwnerPid is not modified - } - return modeOwnerPid; + return mCurrentModeOwnerPid; } + private class SetModeDeathHandler implements IBinder.DeathRecipient { private IBinder mCb; // To be notified of client's death private int mPid; @@ -3207,7 +3201,7 @@ public class AudioService extends IAudioService.Stub public void binderDied() { int oldModeOwnerPid = 0; int newModeOwnerPid = 0; - synchronized (mDeviceBroker.mSetModeLock) { + synchronized (mSetModeDeathHandlers) { Log.w(TAG, "setMode() client died"); if (!mSetModeDeathHandlers.isEmpty()) { oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); @@ -3218,11 +3212,15 @@ public class AudioService extends IAudioService.Stub } else { newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG); } - } - // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all - // SCO connections not started by the application changing the mode when pid changes - if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) { - mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid); + + if (newModeOwnerPid != oldModeOwnerPid) { + mCurrentModeOwnerPid = newModeOwnerPid; + // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO + // connections not started by the application changing the mode when pid changes + if (newModeOwnerPid != 0) { + mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid); + } + } } } @@ -3245,15 +3243,17 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#setMode(int) */ public void setMode(int mode, IBinder cb, String callingPackage) { - if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); } + if (DEBUG_MODE) { + Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); + } if (!checkAudioSettingsPermission("setMode()")) { return; } - if ( (mode == AudioSystem.MODE_IN_CALL) && - (mContext.checkCallingOrSelfPermission( + if ((mode == AudioSystem.MODE_IN_CALL) + && (mContext.checkCallingOrSelfPermission( android.Manifest.permission.MODIFY_PHONE_STATE) - != PackageManager.PERMISSION_GRANTED)) { + != PackageManager.PERMISSION_GRANTED)) { Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); return; @@ -3265,7 +3265,7 @@ public class AudioService extends IAudioService.Stub int oldModeOwnerPid = 0; int newModeOwnerPid = 0; - synchronized (mDeviceBroker.mSetModeLock) { + synchronized (mSetModeDeathHandlers) { if (!mSetModeDeathHandlers.isEmpty()) { oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); } @@ -3273,17 +3273,21 @@ public class AudioService extends IAudioService.Stub mode = mMode; } newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage); - } - // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all - // SCO connections not started by the application changing the mode when pid changes - if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) { - mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid); + + if (newModeOwnerPid != oldModeOwnerPid) { + mCurrentModeOwnerPid = newModeOwnerPid; + // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all + // SCO connections not started by the application changing the mode when pid changes + if (newModeOwnerPid != 0) { + mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid); + } + } } } // setModeInt() returns a valid PID if the audio mode was successfully set to // any mode other than NORMAL. - @GuardedBy("mDeviceBroker.mSetModeLock") + @GuardedBy("mSetModeDeathHandlers") private int setModeInt(int mode, IBinder cb, int pid, String caller) { if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller=" + caller + ")"); } @@ -3622,9 +3626,7 @@ public class AudioService extends IAudioService.Stub !mSystemReady) { return; } - synchronized (mDeviceBroker.mSetModeLock) { - mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); - } + mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); } /** @see AudioManager#stopBluetoothSco() */ @@ -3636,9 +3638,7 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("stopBluetoothSco()") .append(") from u/pid:").append(Binder.getCallingUid()).append("/") .append(Binder.getCallingPid()).toString(); - synchronized (mDeviceBroker.mSetModeLock) { - mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); - } + mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); } @@ -4399,7 +4399,7 @@ public class AudioService extends IAudioService.Stub // NOTE: Locking order for synchronized objects related to volume or ringer mode management: // 1 mScoclient OR mSafeMediaVolumeState - // 2 mSetModeLock + // 2 mSetModeDeathHandlers // 3 mSettingsLock // 4 VolumeStreamState.class private class VolumeStreamState { diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 9f1a6bd15ac30..625b6b6904438 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -171,8 +171,6 @@ public class BtHelper { //---------------------------------------------------------------------- // Interface for AudioDeviceBroker - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onSystemReady() { mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR; resetBluetoothSco(); @@ -245,8 +243,6 @@ public class BtHelper { return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType()); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void receiveBtEvent(Intent intent) { final String action = intent.getAction(); if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { @@ -333,8 +329,6 @@ public class BtHelper { * * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept */ - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) { checkScoAudioState(); if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) { @@ -343,8 +337,6 @@ public class BtHelper { clearAllScoClients(exceptPid, true); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode, @NonNull String eventSource) { ScoClient client = getScoClient(cb, true); @@ -364,8 +356,6 @@ public class BtHelper { Binder.restoreCallingIdentity(ident); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb, @NonNull String eventSource) { ScoClient client = getScoClient(cb, false); @@ -423,8 +413,6 @@ public class BtHelper { mDeviceBroker.postDisconnectHearingAid(); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void resetBluetoothSco() { clearAllScoClients(0, false); mScoAudioState = SCO_STATE_INACTIVE; @@ -433,8 +421,6 @@ public class BtHelper { mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco"); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectHeadset() { setBtScoActiveDevice(null); mBluetoothHeadset = null; @@ -480,8 +466,6 @@ public class BtHelper { /*eventSource*/ "mBluetoothProfileServiceListener"); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { // Discard timeout message mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); @@ -568,8 +552,6 @@ public class BtHelper { return result; } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") private void setBtScoActiveDevice(BluetoothDevice btDevice) { Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice); @@ -652,8 +634,6 @@ public class BtHelper { }; //---------------------------------------------------------------------- - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void scoClientDied(Object obj) { final ScoClient client = (ScoClient) obj; Log.w(TAG, "SCO client died"); @@ -684,8 +664,6 @@ public class BtHelper { mDeviceBroker.postScoClientDied(this); } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") void incCount(int scoAudioMode) { if (!requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode)) { @@ -705,8 +683,6 @@ public class BtHelper { mStartcount++; } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") void decCount() { if (mStartcount == 0) { @@ -726,8 +702,6 @@ public class BtHelper { } } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") void clearCount(boolean stopSco) { if (mStartcount != 0) { @@ -764,8 +738,6 @@ public class BtHelper { return count; } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") private boolean requestScoState(int state, int scoAudioMode) { checkScoAudioState(); @@ -959,8 +931,6 @@ public class BtHelper { return null; } - // @GuardedBy("AudioDeviceBroker.mSetModeLock") - //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") @GuardedBy("BtHelper.this") private void clearAllScoClients(int exceptPid, boolean stopSco) { ScoClient savedClient = null; diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java index 5c2ad94720f01..29a8dada7d894 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -126,6 +126,22 @@ public class AudioDeviceBrokerTest { doTestConnectionDisconnectionReconnection(AudioService.BECOMING_NOISY_DELAY_MS / 2); } + /** + * Verify connecting an A2DP sink will call into AudioService to unmute media + */ + @Test + public void testA2dpConnectionUnmutesMedia() throws Exception { + Log.i(TAG, "testA2dpConnectionUnmutesMedia"); + Assert.assertNotNull("invalid null BT device", mFakeBtDevice); + + mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1); + Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); + verify(mMockAudioService, times(1)).postAccessoryPlugMediaUnmute( + ArgumentMatchers.eq(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); + + } + private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection) throws Exception { when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))