From b3beae79aea336eb6f9587118a5eee8f77d41522 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 13 Aug 2020 11:52:50 -0700 Subject: [PATCH 1/2] audio: additional speakerphone and audio mode fixes - Do not re-evaluate speakerphone state when audio mode owner changes but the new mode is RINGTONE. - Do not log IN_COMMUNICATION mode timeout in case of playback or capture inactivity by mode owner if the owner has MODIFY_PHONE_STATE permission: in this case it is the telephony framework or the app in Dialer role managing the call on behalf of another app. Bug: 161564483 Test: manual regression test with cell and VoIP calls. Change-Id: I86b6d31a164461e143cc5cfc1369884ed14cc95a (cherry picked from commit 1536fc19e57c7ae5a03dd579db831b8e7b9b63c5) --- .../server/audio/AudioDeviceBroker.java | 8 +++-- .../android/server/audio/AudioService.java | 29 ++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 45f95fd3f6638..22b0aebca6c4f 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -476,8 +476,8 @@ import java.util.concurrent.atomic.AtomicBoolean; sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); } - /*package*/ void postSetModeOwnerPid(int pid) { - sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid); + /*package*/ void postSetModeOwnerPid(int pid, int mode) { + sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode); } /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { @@ -949,7 +949,9 @@ import java.util.concurrent.atomic.AtomicBoolean; synchronized (mDeviceStateLock) { if (mModeOwnerPid != msg.arg1) { mModeOwnerPid = msg.arg1; - updateSpeakerphoneOn("setNewModeOwner"); + if (msg.arg2 != AudioSystem.MODE_RINGTONE) { + updateSpeakerphoneOn("setNewModeOwner"); + } if (mModeOwnerPid != 0) { mBtHelper.disconnectBluetoothSco(mModeOwnerPid); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index c4eca605206db..e78638894914d 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3680,13 +3680,15 @@ public class AudioService extends IAudioService.Stub private final IBinder mCb; // To be notified of client's death private final int mPid; private final int mUid; - private String mPackage; + private final boolean mIsPrivileged; + private final String mPackage; private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client - SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) { + SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) { mCb = cb; mPid = pid; mUid = uid; + mIsPrivileged = isPrivileged; mPackage = caller; } @@ -3698,12 +3700,13 @@ public class AudioService extends IAudioService.Stub if (index < 0) { Log.w(TAG, "unregistered setMode() client died"); } else { - newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, mUid, TAG); + newModeOwnerPid = setModeInt( + AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, 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 - mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid); + mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode()); } public int getPid() { @@ -3729,6 +3732,10 @@ public class AudioService extends IAudioService.Stub public String getPackage() { return mPackage; } + + public boolean isPrivileged() { + return mIsPrivileged; + } } /** @see AudioManager#setMode(int) */ @@ -3780,18 +3787,19 @@ public class AudioService extends IAudioService.Stub + " without permission or being mode owner"); return; } - newModeOwnerPid = setModeInt( - mode, cb, callingPid, Binder.getCallingUid(), callingPackage); + newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(), + hasModifyPhoneStatePermission, 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 - mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid); + mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode()); } // setModeInt() returns a valid PID if the audio mode was successfully set to // any mode other than NORMAL. @GuardedBy("mDeviceBroker.mSetModeLock") - private int setModeInt(int mode, IBinder cb, int pid, int uid, String caller) { + private int setModeInt( + int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) { if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", uid=" + uid + ", caller=" + caller + ")"); @@ -3843,7 +3851,7 @@ public class AudioService extends IAudioService.Stub } } else { if (hdlr == null) { - hdlr = new SetModeDeathHandler(cb, pid, uid, caller); + hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller); } // Register for client death notification try { @@ -3902,7 +3910,8 @@ public class AudioService extends IAudioService.Stub // change of mode may require volume to be re-applied on some devices updateAbsVolumeMultiModeDevices(oldMode, actualMode); - if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) { + if (actualMode == AudioSystem.MODE_IN_COMMUNICATION + && !hdlr.isPrivileged()) { sendMsg(mAudioHandler, MSG_CHECK_MODE_FOR_UID, SENDMSG_QUEUE, From 4bd9165371c93dc55d497ef0b66365f2f1f76693 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 25 Aug 2020 17:49:15 -0700 Subject: [PATCH 2/2] audio service: add watchdog for audio mode Add a watchdog to remove an application from the audio mode owner stack if it has requested mode IN_COMMUNICATION and has not been playing or capturing audio for more than 3 seconds. This will prevent volume, routing and recording issues when misbehaving apps do not properly reset the audio mode at the end of a call. Bug: 161564483 Test: Manual regression tests for VoIP use cases Change-Id: I7c6f57a2c9a6c31d107a1bba2d7dfac6e3f275bd (cherry picked from commit 852cd7d7d4734081162ea7be8650bbbcfd3a862b) --- services/core/java/com/android/server/audio/AudioService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e78638894914d..fe619690ae345 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6428,8 +6428,8 @@ public class AudioService extends IAudioService.Stub CHECK_MODE_FOR_UID_PERIOD_MS); break; } - // For now just log the fact that an app is hogging the audio mode. - // TODO(b/160260850): remove abusive app from audio mode stack. + setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(), + h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID"); mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid())); } break;