AudioService: fix lock ordering between BtHelper and AudioDeviceBroker
Make calls from BtHelper to AudioDeviceBroker that don't come
from the AudioDeviceBroker event thread asynchronous
Bug: 123934346
Test: see bug
Change-Id: Id471141b3f5d9e481bf2e51c8ecd862c16b8d0cd
(cherry picked from commit b946515dd859f9808f1e77ca3cc3d52e6c7890b2)
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index a3bae52..0dc73d9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -381,11 +381,11 @@
//---------------------------------------------------------------------
// Message handling on behalf of helper classes
- /*package*/ void broadcastScoConnectionState(int state) {
+ /*package*/ void postBroadcastScoConnectionState(int state) {
sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
}
- /*package*/ void broadcastBecomingNoisy() {
+ /*package*/ void postBroadcastBecomingNoisy() {
sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
}
@@ -415,6 +415,22 @@
delay);
}
+ /*package*/ void postDisconnectA2dp() {
+ sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
+ }
+
+ /*package*/ void postDisconnectA2dpSink() {
+ sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
+ }
+
+ /*package*/ void postDisconnectHearingAid() {
+ sendMsgNoDelay(MSG_DISCONNECT_HEARING_AID, SENDMSG_QUEUE);
+ }
+
+ /*package*/ void postDisconnectHeadset() {
+ sendMsgNoDelay(MSG_DISCONNECT_HEADSET, SENDMSG_QUEUE);
+ }
+
//---------------------------------------------------------------------
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
// only call from a "handle"* method or "on"* method
@@ -444,23 +460,6 @@
}
}
- /*package*/ void handleDisconnectA2dp() {
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dp();
- }
- }
- /*package*/ void handleDisconnectA2dpSink() {
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dpSink();
- }
- }
-
- /*package*/ void handleDisconnectHearingAid() {
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectHearingAid();
- }
- }
-
/*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
@@ -482,7 +481,7 @@
state, btDeviceInfo, delay);
}
- /*package*/ void handleSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
+ /*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,
@@ -710,6 +709,26 @@
(BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
}
break;
+ case MSG_DISCONNECT_A2DP:
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectA2dp();
+ }
+ break;
+ case MSG_DISCONNECT_A2DP_SINK:
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectA2dpSink();
+ }
+ break;
+ case MSG_DISCONNECT_HEARING_AID:
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectHearingAid();
+ }
+ break;
+ case MSG_DISCONNECT_HEADSET:
+ synchronized (mDeviceStateLock) {
+ mBtHelper.disconnectHeadset();
+ }
+ break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -745,6 +764,10 @@
private static final int MSG_I_DISCONNECT_BT_SCO = 16;
private static final int MSG_TOGGLE_HDMI = 17;
private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
+ private static final int MSG_DISCONNECT_A2DP = 19;
+ private static final int MSG_DISCONNECT_A2DP_SINK = 20;
+ private static final int MSG_DISCONNECT_HEARING_AID = 21;
+ private static final int MSG_DISCONNECT_HEADSET = 22;
private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 11fdc8f..37f0496 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -859,7 +859,7 @@
// also checks whether media routing if affected by a dynamic policy
if (((device == musicDevice) || mDeviceBroker.isInCommunication())
&& (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()) {
- mDeviceBroker.broadcastBecomingNoisy();
+ mDeviceBroker.postBroadcastBecomingNoisy();
delay = 1000;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index de63d0e..a6643d4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5120,7 +5120,7 @@
if (mUserSwitchedReceived) {
// attempt to stop music playback for background user except on first user
// switch (i.e. first boot)
- mDeviceBroker.broadcastBecomingNoisy();
+ mDeviceBroker.postBroadcastBecomingNoisy();
}
mUserSwitchedReceived = true;
// the current audio focus owner is no longer valid
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index b63af8a..e918997 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -374,10 +374,10 @@
}
/*package*/ synchronized void disconnectAllBluetoothProfiles() {
- mDeviceBroker.handleDisconnectA2dp();
- mDeviceBroker.handleDisconnectA2dpSink();
- disconnectHeadset();
- mDeviceBroker.handleDisconnectHearingAid();
+ mDeviceBroker.postDisconnectA2dp();
+ mDeviceBroker.postDisconnectA2dpSink();
+ mDeviceBroker.postDisconnectHeadset();
+ mDeviceBroker.postDisconnectHearingAid();
}
/*package*/ synchronized void resetBluetoothSco() {
@@ -388,9 +388,14 @@
mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
}
+ /*package*/ synchronized void disconnectHeadset() {
+ setBtScoActiveDevice(null);
+ mBluetoothHeadset = null;
+ }
+
//----------------------------------------------------------------------
private void broadcastScoConnectionState(int state) {
- mDeviceBroker.broadcastScoConnectionState(state);
+ mDeviceBroker.postBroadcastScoConnectionState(state);
}
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -487,7 +492,7 @@
btDevice = deviceList.get(0);
final @BluetoothProfile.BtProfileState int state =
proxy.getConnectionState(btDevice);
- mDeviceBroker.handleSetA2dpSourceConnectionState(
+ mDeviceBroker.postSetA2dpSourceConnectionState(
state, new BluetoothA2dpDeviceInfo(btDevice));
}
break;
@@ -558,19 +563,19 @@
switch (profile) {
case BluetoothProfile.A2DP:
- mDeviceBroker.handleDisconnectA2dp();
+ mDeviceBroker.postDisconnectA2dp();
break;
case BluetoothProfile.A2DP_SINK:
- mDeviceBroker.handleDisconnectA2dpSink();
+ mDeviceBroker.postDisconnectA2dpSink();
break;
case BluetoothProfile.HEADSET:
- disconnectHeadset();
+ mDeviceBroker.postDisconnectHeadset();
break;
case BluetoothProfile.HEARING_AID:
- mDeviceBroker.handleDisconnectHearingAid();
+ mDeviceBroker.postDisconnectHearingAid();
break;
default:
@@ -579,11 +584,6 @@
}
};
- private void disconnectHeadset() {
- setBtScoActiveDevice(null);
- mBluetoothHeadset = null;
- }
-
//----------------------------------------------------------------------
private class ScoClient implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death