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
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6010b1dc..f7ac040 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 @@
     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 @@
 
 
     //-------------------------------------------------------------------
-    // 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 @@
     // 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 @@
      * @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 @@
      * @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 @@
     }
 
     /*package*/ boolean isSpeakerphoneOn() {
-        synchronized (mDeviceStateLock) {
+        synchronized (mDeviceBrokerLock) {
             return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
         }
     }
@@ -223,9 +221,7 @@
             @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 @@
         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 @@
             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 @@
     }
 
     /*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 @@
     //---------------------------------------------------------------------
     // 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 @@
                 .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 @@
 
     /*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 @@
         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 @@
                                     + " 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 @@
                                     + " 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 @@
     /** 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 @@
             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 90973a8..3933fb2 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 @@
     }
 
     // only public for mocking/spying
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     @VisibleForTesting
     public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
             @AudioService.BtProfileConnectionState int state) {
@@ -284,7 +283,6 @@
         }
     }
 
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ void onBluetoothA2dpActiveDeviceChange(
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
         final BluetoothDevice btDevice = btInfo.getBtDevice();
@@ -557,7 +555,6 @@
     }
 
     // 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 a6ac17d..9371d13 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 @@
 
     // 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<SetModeDeathHandler> mSetModeDeathHandlers =
+    private final ArrayList<SetModeDeathHandler> mSetModeDeathHandlers =
             new ArrayList<SetModeDeathHandler>();
 
+    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 @@
      * @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 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 @@
                 } 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 @@
 
     /** @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 @@
 
         int oldModeOwnerPid = 0;
         int newModeOwnerPid = 0;
-        synchronized (mDeviceBroker.mSetModeLock) {
+        synchronized (mSetModeDeathHandlers) {
             if (!mSetModeDeathHandlers.isEmpty()) {
                 oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
             }
@@ -3273,17 +3273,21 @@
                 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 @@
                 !mSystemReady) {
             return;
         }
-        synchronized (mDeviceBroker.mSetModeLock) {
-            mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource);
-        }
+        mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource);
     }
 
     /** @see AudioManager#stopBluetoothSco() */
@@ -3636,9 +3638,7 @@
         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 @@
 
     // 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 9f1a6bd..625b6b6 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 @@
     //----------------------------------------------------------------------
     // 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 @@
         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 @@
      *
      * @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 @@
         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 @@
         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 @@
         mDeviceBroker.postDisconnectHearingAid();
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void resetBluetoothSco() {
         clearAllScoClients(0, false);
         mScoAudioState = SCO_STATE_INACTIVE;
@@ -433,8 +421,6 @@
         mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void disconnectHeadset() {
         setBtScoActiveDevice(null);
         mBluetoothHeadset = null;
@@ -480,8 +466,6 @@
                 /*eventSource*/ "mBluetoothProfileServiceListener");
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
         // Discard timeout message
         mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
@@ -568,8 +552,6 @@
         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 @@
             };
 
     //----------------------------------------------------------------------
-    // @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 @@
             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 @@
             mStartcount++;
         }
 
-        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-        // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
         @GuardedBy("BtHelper.this")
         void decCount() {
             if (mStartcount == 0) {
@@ -726,8 +702,6 @@
             }
         }
 
-        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-        // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
         @GuardedBy("BtHelper.this")
         void clearCount(boolean stopSco) {
             if (mStartcount != 0) {
@@ -764,8 +738,6 @@
             return count;
         }
 
-        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-        //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
         @GuardedBy("BtHelper.this")
         private boolean requestScoState(int state, int scoAudioMode) {
             checkScoAudioState();
@@ -959,8 +931,6 @@
         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 5c2ad94..29a8dad 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 @@
         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))