Merge "AudioDeviceBroker: strengthen setcommunicationDevice implementation"

This commit is contained in:
Eric Laurent
2022-11-02 19:00:17 +00:00
committed by Android (Google) Code Review

View File

@@ -286,22 +286,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid);
}
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = null;
if (on) {
device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
} else {
CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
if (client == null || !client.requestsSpeakerphone()) {
return;
}
}
postSetCommunicationRouteForClient(new CommunicationClientInfo(
cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
}
/**
@@ -311,6 +298,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @param device Device selected or null to unselect.
* @param eventSource for logging purposes
*/
private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000;
/*package*/ boolean setCommunicationDevice(
IBinder cb, int pid, AudioDeviceInfo device, String eventSource) {
@@ -318,21 +308,53 @@ import java.util.concurrent.atomic.AtomicBoolean;
Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid);
}
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
AudioDeviceAttributes deviceAttr = null;
if (device != null) {
deviceAttr = new AudioDeviceAttributes(device);
} else {
CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
if (client == null) {
return false;
AudioDeviceAttributes deviceAttr =
(device != null) ? new AudioDeviceAttributes(device) : null;
CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr,
device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true);
postSetCommunicationDeviceForClient(deviceInfo);
boolean status;
synchronized (deviceInfo) {
final long start = System.currentTimeMillis();
long elapsed = 0;
while (deviceInfo.mWaitForStatus) {
try {
deviceInfo.wait(SET_COMMUNICATION_DEVICE_TIMEOUT_MS - elapsed);
} catch (InterruptedException e) {
elapsed = System.currentTimeMillis() - start;
if (elapsed >= SET_COMMUNICATION_DEVICE_TIMEOUT_MS) {
deviceInfo.mStatus = false;
deviceInfo.mWaitForStatus = false;
}
}
postSetCommunicationRouteForClient(new CommunicationClientInfo(
cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
status = deviceInfo.mStatus;
}
return status;
}
/**
* Sets or resets the communication device for matching client. If no client matches and the
* request is to reset for a given device (deviceInfo.mOn == false), the method is a noop.
* @param deviceInfo information on the device and requester {@link #CommunicationDeviceInfo}
* @return true if the communication device is set or reset
*/
@GuardedBy("mDeviceStateLock")
/*package*/ boolean onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo) {
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
}
if (!deviceInfo.mOn) {
CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid);
if (client == null || (deviceInfo.mDevice != null
&& !deviceInfo.mDevice.equals(client.getDevice()))) {
return false;
}
}
AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device,
deviceInfo.mScoAudioMode, deviceInfo.mEventSource);
return true;
}
@@ -390,7 +412,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
mBtHelper.stopBluetoothSco(eventSource);
}
sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
updateCommunicationRoute(eventSource);
}
/**
@@ -424,7 +446,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
CommunicationRouteClient crc = topCommunicationRouteClient();
AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "requestedCommunicationDevice, device: "
Log.v(TAG, "requestedCommunicationDevice: "
+ device + " mAudioModeOwner: " + mAudioModeOwner.toString());
}
return device;
@@ -822,37 +844,22 @@ import java.util.concurrent.atomic.AtomicBoolean;
@NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "startBluetoothScoForClient_Sync, pid: " + pid);
}
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
postSetCommunicationRouteForClient(new CommunicationClientInfo(
cb, pid, device, scoAudioMode, eventSource));
}
Log.v(TAG, "startBluetoothScoForClient, pid: " + pid);
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
true, scoAudioMode, eventSource, false));
}
/*package*/ void stopBluetoothScoForClient(
IBinder cb, int pid, @NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "stopBluetoothScoForClient_Sync, pid: " + pid);
}
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
if (client == null || !client.requestsBluetoothSco()) {
return;
}
postSetCommunicationRouteForClient(new CommunicationClientInfo(
cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid);
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
}
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
@@ -990,7 +997,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
//---------------------------------------------------------------------
// Message handling on behalf of helper classes
// Message handling on behalf of helper classes.
// Each of these methods posts a message to mBrokerHandler message queue.
/*package*/ void postBroadcastScoConnectionState(int state) {
sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
}
@@ -1046,28 +1054,34 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
}
/*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) {
sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info);
/*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT, SENDMSG_QUEUE, info);
}
/*package*/ void postScoAudioStateChanged(int state) {
sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
}
/*package*/ static final class CommunicationClientInfo {
final @NonNull IBinder mCb;
final int mPid;
final @NonNull AudioDeviceAttributes mDevice;
final int mScoAudioMode;
final @NonNull String mEventSource;
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mPid; // Requester process ID
final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset.
final boolean mOn; // true if setting, false if resetting
final int mScoAudioMode; // only used for SCO: requested audio mode
final @NonNull String mEventSource; // caller identifier for logging
boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent)
boolean mStatus = false; // completion status only used if mWaitForStatus is true
CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device,
int scoAudioMode, @NonNull String eventSource) {
CommunicationDeviceInfo(@NonNull IBinder cb, int pid,
@Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode,
@NonNull String eventSource, boolean waitForStatus) {
mCb = cb;
mPid = pid;
mDevice = device;
mOn = on;
mScoAudioMode = scoAudioMode;
mEventSource = eventSource;
mWaitForStatus = waitForStatus;
}
// redefine equality op so we can match messages intended for this client
@@ -1079,21 +1093,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (this == o) {
return true;
}
if (!(o instanceof CommunicationClientInfo)) {
if (!(o instanceof CommunicationDeviceInfo)) {
return false;
}
return mCb.equals(((CommunicationClientInfo) o).mCb)
&& mPid == ((CommunicationClientInfo) o).mPid;
return mCb.equals(((CommunicationDeviceInfo) o).mCb)
&& mPid == ((CommunicationDeviceInfo) o).mPid;
}
@Override
public String toString() {
return "CommunicationClientInfo mCb=" + mCb.toString()
+"mPid=" + mPid
+"mDevice=" + mDevice.toString()
+"mScoAudioMode=" + mScoAudioMode
+"mEventSource=" + mEventSource;
return "CommunicationDeviceInfo mCb=" + mCb.toString()
+ " mPid=" + mPid
+ " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
+ " mOn=" + mOn
+ " mScoAudioMode=" + mScoAudioMode
+ " mEventSource=" + mEventSource
+ " mWaitForStatus=" + mWaitForStatus
+ " mStatus=" + mStatus;
}
}
@@ -1297,7 +1314,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
updateActiveCommunicationDevice();
mDeviceInventory.onRestoreDevices();
mBtHelper.onAudioServerDiedRestoreA2dp();
onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
updateCommunicationRoute("MSG_RESTORE_DEVICES");
}
}
break;
@@ -1392,12 +1409,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
break;
case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT:
case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT:
CommunicationDeviceInfo deviceInfo = (CommunicationDeviceInfo) msg.obj;
boolean status;
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
CommunicationClientInfo info = (CommunicationClientInfo) msg.obj;
setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice,
info.mScoAudioMode, info.mEventSource);
status = onSetCommunicationDeviceForClient(deviceInfo);
}
}
synchronized (deviceInfo) {
if (deviceInfo.mWaitForStatus) {
deviceInfo.mStatus = status;
deviceInfo.mWaitForStatus = false;
deviceInfo.notify();
}
}
break;
@@ -1410,14 +1434,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
break;
case MSG_L_UPDATE_COMMUNICATION_ROUTE:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
onUpdateCommunicationRoute((String) msg.obj);
}
}
break;
case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
@@ -1568,8 +1584,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 37;
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42;
private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
@@ -1793,18 +1808,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
AudioDeviceAttributes getDevice() {
return mDevice;
}
boolean requestsBluetoothSco() {
return mDevice != null
&& mDevice.getType()
== AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
}
boolean requestsSpeakerphone() {
return mDevice != null
&& mDevice.getType()
== AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
}
}
// @GuardedBy("mSetModeLock")
@@ -1852,14 +1855,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
private void onUpdateCommunicationRoute(String eventSource) {
private void updateCommunicationRoute(String eventSource) {
AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice();
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: "
Log.v(TAG, "updateCommunicationRoute, preferredCommunicationDevice: "
+ preferredCommunicationDevice + " eventSource: " + eventSource);
}
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
"onUpdateCommunicationRoute, preferredCommunicationDevice: "
"updateCommunicationRoute, preferredCommunicationDevice: "
+ preferredCommunicationDevice + " eventSource: " + eventSource)));
if (preferredCommunicationDevice == null
@@ -1895,7 +1898,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
private void onUpdateCommunicationRouteClient(String eventSource) {
onUpdateCommunicationRoute(eventSource);
updateCommunicationRoute(eventSource);
CommunicationRouteClient crc = topCommunicationRouteClient();
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "