summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Laurent <elaurent@google.com> 2024-10-30 14:22:31 +0000
committer Eric Laurent <elaurent@google.com> 2024-10-31 09:18:54 +0000
commit94a9fc5800397efeccdc87177033e7a4a1386ca0 (patch)
treed2d7efde60775323f45834525b2a92b3a5b69e8a
parent5754baa4be5715b164d3a924e2cd0b327823ee74 (diff)
Reapply "AudioService: synchronize audio mode and focus for Telecom"
Reland commit 15f9e56e with fixes to possible leaks in audio mode reset counter. - Use separate message types to avoid overwritting the sender's signal request if another message with REPLACE policy is sent. - Reset the counter systematcially in case of timeout to avoid sticky error conditons. - Reset the counter in case of error processing AudioSystem.setPhoneState() in onUpdateAudioMode(). Also similarly reset the communication device update count in case of timeout in AudioDeviceBroker.setCommunicationDevice(). This reverts commit 38818052dc43a4322d2ae0e113e6544175c198b0. Bug: 375018522 Bug: 350415723 Test: make Flag: EXEMPT bug fix Change-Id: Iacd348b6da01af08796b26232f94d9177a4a591b
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java17
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java140
2 files changed, 124 insertions, 33 deletions
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index c4257d4a4477..a3b20b93ef02 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -693,6 +693,8 @@ public class AudioDeviceBroker {
elapsed = System.currentTimeMillis() - start;
if (elapsed >= SET_COMMUNICATION_DEVICE_TIMEOUT_MS) {
Log.e(TAG, "Timeout waiting for communication device update.");
+ // reset counter to avoid sticky out of sync condition
+ mCommunicationDeviceUpdateCount = 0;
break;
}
}
@@ -1341,9 +1343,9 @@ public class AudioDeviceBroker {
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
}
- /*package*/ void postSetModeOwner(int mode, int pid, int uid) {
- sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
- new AudioModeInfo(mode, pid, uid));
+ /*package*/ void postSetModeOwner(int mode, int pid, int uid, boolean signal) {
+ sendLMsgNoDelay(signal ? MSG_L_SET_MODE_OWNER_SIGNAL : MSG_L_SET_MODE_OWNER,
+ SENDMSG_REPLACE, new AudioModeInfo(mode, pid, uid));
}
/*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
@@ -2026,7 +2028,8 @@ public class AudioDeviceBroker {
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
- case MSG_I_SET_MODE_OWNER:
+ case MSG_L_SET_MODE_OWNER:
+ case MSG_L_SET_MODE_OWNER_SIGNAL:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
mAudioModeOwner = (AudioModeInfo) msg.obj;
@@ -2037,6 +2040,9 @@ public class AudioDeviceBroker {
}
}
}
+ if (msg.what == MSG_L_SET_MODE_OWNER_SIGNAL) {
+ mAudioService.decrementAudioModeResetCount();
+ }
break;
case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT:
@@ -2196,7 +2202,8 @@ public class AudioDeviceBroker {
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
- private static final int MSG_I_SET_MODE_OWNER = 16;
+ private static final int MSG_L_SET_MODE_OWNER = 16;
+ private static final int MSG_L_SET_MODE_OWNER_SIGNAL = 17;
private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 49ab153b4bf4..7ea32954d997 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -457,7 +457,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_UPDATE_AUDIO_MODE = 36;
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
private static final int MSG_BT_DEV_CHANGED = 38;
-
+ private static final int MSG_UPDATE_AUDIO_MODE_SIGNAL = 39;
private static final int MSG_DISPATCH_AUDIO_MODE = 40;
private static final int MSG_ROUTING_UPDATED = 41;
private static final int MSG_INIT_HEADTRACKING_SENSORS = 42;
@@ -1956,7 +1956,7 @@ public class AudioService extends IAudioService.Stub
// Restore call state
synchronized (mDeviceBroker.mSetModeLock) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), true /*force*/);
+ mContext.getPackageName(), true /*force*/, false /*signal*/);
}
final int forSys;
synchronized (mSettingsLock) {
@@ -4796,14 +4796,42 @@ public class AudioService extends IAudioService.Stub
}
}
if (updateAudioMode) {
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- existingMsgPolicy,
- AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(),
- mContext.getPackageName(),
- delay);
+ postUpdateAudioMode(existingMsgPolicy, AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(), mContext.getPackageName(),
+ false /*signal*/, delay);
+ }
+ }
+ }
+
+ static class UpdateAudioModeInfo {
+ UpdateAudioModeInfo(int mode, int pid, String packageName) {
+ mMode = mode;
+ mPid = pid;
+ mPackageName = packageName;
+ }
+ private final int mMode;
+ private final int mPid;
+ private final String mPackageName;
+
+ int getMode() {
+ return mMode;
+ }
+ int getPid() {
+ return mPid;
+ }
+ String getPackageName() {
+ return mPackageName;
+ }
+ }
+
+ void postUpdateAudioMode(int msgPolicy, int mode, int pid, String packageName,
+ boolean signal, int delay) {
+ synchronized (mAudioModeResetLock) {
+ if (signal) {
+ mAudioModeResetCount++;
}
+ sendMsg(mAudioHandler, signal ? MSG_UPDATE_AUDIO_MODE_SIGNAL : MSG_UPDATE_AUDIO_MODE,
+ msgPolicy, 0, 0, new UpdateAudioModeInfo(mode, pid, packageName), delay);
}
}
@@ -6303,13 +6331,9 @@ public class AudioService extends IAudioService.Stub
} else {
SetModeDeathHandler h = mSetModeDeathHandlers.get(index);
mSetModeDeathHandlers.remove(index);
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- SENDMSG_QUEUE,
- AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(),
- mContext.getPackageName(),
- 0);
+ postUpdateAudioMode(SENDMSG_QUEUE, AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(), mContext.getPackageName(),
+ false /*signal*/, 0);
}
}
}
@@ -6555,19 +6579,14 @@ public class AudioService extends IAudioService.Stub
}
}
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- SENDMSG_REPLACE,
- mode,
- pid,
- callingPackage,
- 0);
+ postUpdateAudioMode(SENDMSG_REPLACE, mode, pid, callingPackage,
+ hasModifyPhoneStatePermission && mode == AudioSystem.MODE_NORMAL, 0);
}
}
@GuardedBy("mDeviceBroker.mSetModeLock")
void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage,
- boolean force) {
+ boolean force, boolean signal) {
if (requestedMode == AudioSystem.MODE_CURRENT) {
requestedMode = getMode();
}
@@ -6582,7 +6601,7 @@ public class AudioService extends IAudioService.Stub
}
if (DEBUG_MODE) {
Log.v(TAG, "onUpdateAudioMode() new mode: " + mode + ", current mode: "
- + mMode.get() + " requested mode: " + requestedMode);
+ + mMode.get() + " requested mode: " + requestedMode + " signal: " + signal);
}
if (mode != mMode.get() || force) {
int status = AudioSystem.SUCCESS;
@@ -6628,8 +6647,11 @@ public class AudioService extends IAudioService.Stub
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwner(mode, pid, uid);
+ mDeviceBroker.postSetModeOwner(mode, pid, uid, signal);
} else {
+ // reset here to avoid sticky out of sync condition (would have been reset
+ // by AudioDeviceBroker processing MSG_L_SET_MODE_OWNER_SIGNAL message)
+ resetAudioModeResetCount();
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
}
@@ -10367,7 +10389,7 @@ public class AudioService extends IAudioService.Stub
h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), false /*force*/);
+ mContext.getPackageName(), false /*force*/, false /*signal*/);
}
}
break;
@@ -10396,8 +10418,11 @@ public class AudioService extends IAudioService.Stub
break;
case MSG_UPDATE_AUDIO_MODE:
+ case MSG_UPDATE_AUDIO_MODE_SIGNAL:
synchronized (mDeviceBroker.mSetModeLock) {
- onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
+ UpdateAudioModeInfo info = (UpdateAudioModeInfo) msg.obj;
+ onUpdateAudioMode(info.getMode(), info.getPid(), info.getPackageName(),
+ false /*force*/, msg.what == MSG_UPDATE_AUDIO_MODE_SIGNAL);
}
break;
@@ -11115,9 +11140,68 @@ public class AudioService extends IAudioService.Stub
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
mmi.record();
+ //delay abandon focus requests from Telecom if an audio mode reset from Telecom
+ // is still being processed
+ final boolean abandonFromTelecom = (mContext.checkCallingOrSelfPermission(
+ MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
+ && ((aa != null && aa.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ || AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId));
+ if (abandonFromTelecom) {
+ synchronized (mAudioModeResetLock) {
+ final long start = java.lang.System.currentTimeMillis();
+ long elapsed = 0;
+ while (mAudioModeResetCount > 0) {
+ if (DEBUG_MODE) {
+ Log.i(TAG, "Abandon focus from Telecom, waiting for mode change");
+ }
+ try {
+ mAudioModeResetLock.wait(
+ AUDIO_MODE_RESET_TIMEOUT_MS - elapsed);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting for audio mode reset");
+ }
+ elapsed = java.lang.System.currentTimeMillis() - start;
+ if (elapsed >= AUDIO_MODE_RESET_TIMEOUT_MS) {
+ Log.e(TAG, "Timeout waiting for audio mode reset");
+ // reset count to avoid sticky out of sync state.
+ resetAudioModeResetCount();
+ break;
+ }
+ }
+ if (DEBUG_MODE && elapsed != 0) {
+ Log.i(TAG, "Abandon focus from Telecom done waiting");
+ }
+ }
+ }
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
}
+ /** synchronization between setMode(NORMAL) and abandonAudioFocus() from Telecom */
+ private static final long AUDIO_MODE_RESET_TIMEOUT_MS = 3000;
+
+ private final Object mAudioModeResetLock = new Object();
+
+ @GuardedBy("mAudioModeResetLock")
+ private int mAudioModeResetCount = 0;
+
+ void decrementAudioModeResetCount() {
+ synchronized (mAudioModeResetLock) {
+ if (mAudioModeResetCount > 0) {
+ mAudioModeResetCount--;
+ } else {
+ Log.w(TAG, "mAudioModeResetCount already 0");
+ }
+ mAudioModeResetLock.notify();
+ }
+ }
+
+ private void resetAudioModeResetCount() {
+ synchronized (mAudioModeResetLock) {
+ mAudioModeResetCount = 0;
+ mAudioModeResetLock.notify();
+ }
+ }
+
/** see {@link AudioManager#abandonAudioFocusForTest(AudioFocusRequest, String)} */
public int abandonAudioFocusForTest(IAudioFocusDispatcher fd, String clientId,
AudioAttributes aa, String callingPackageName) {