diff options
| author | 2024-10-30 14:22:31 +0000 | |
|---|---|---|
| committer | 2024-10-31 09:18:54 +0000 | |
| commit | 94a9fc5800397efeccdc87177033e7a4a1386ca0 (patch) | |
| tree | d2d7efde60775323f45834525b2a92b3a5b69e8a | |
| parent | 5754baa4be5715b164d3a924e2cd0b327823ee74 (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.java | 17 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 140 |
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) { |