Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94a9fc58 authored by Eric Laurent's avatar Eric Laurent
Browse files

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
parent 5754baa4
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -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;
+112 −28
Original line number Diff line number Diff line
@@ -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,15 +4796,43 @@ 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);
        }
    }
    private final IRecordingConfigDispatcher mVoiceRecordingActivityMonitor =
@@ -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) {