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

Commit c4ecaa52 authored by jiabin's avatar jiabin
Browse files

Reduce time consuming when a lot of audio port event happen continually.

Since the AudioPortEventHandler runs in application's main thread, it
may cause ANR if there are a lot of setForceUse calling by the
application continually in a short time. The root cause is that there
may be a lot of audio port event from the native side when there are a
lot of device switching request. In this case, updating audio port cache
may take a long time due to inconsistency between audio port generation
and patches generation.
To solve this problem, we only check the generation once when ports and
patches are both requested to return earlier. In the meantime, we only
repeat the last audio port event since we will refresh the ports cache
every time when we receive the event.

Bug: 64952619
Test: keep switching output device in hangout video/voice chat
Change-Id: I3164c4e331950a481b76ce890d8c1403fd9b98ee
parent d35b250a
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -4119,7 +4119,15 @@ public class AudioManager {
                        Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
                        Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
                        return status;
                        return status;
                    }
                    }
                } while (patchGeneration[0] != portGeneration[0]);
                    // Loop until patch generation is the same as port generation unless audio ports
                    // and audio patches are not null.
                } while (patchGeneration[0] != portGeneration[0]
                        && (ports == null || patches == null));
                // If the patch generation doesn't equal port generation, return ERROR here in case
                // of mismatch between audio ports and audio patches.
                if (patchGeneration[0] != portGeneration[0]) {
                    return ERROR;
                }


                for (int i = 0; i < newPatches.size(); i++) {
                for (int i = 0; i < newPatches.size(); i++) {
                    for (int j = 0; j < newPatches.get(i).sources().length; j++) {
                    for (int j = 0; j < newPatches.get(i).sources().length; j++) {
+22 −4
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;
package android.media;


import android.os.Handler;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import java.util.ArrayList;
import java.util.ArrayList;
@@ -30,6 +31,7 @@ import java.lang.ref.WeakReference;


class AudioPortEventHandler {
class AudioPortEventHandler {
    private Handler mHandler;
    private Handler mHandler;
    private HandlerThread mHandlerThread;
    private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
    private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
            new ArrayList<AudioManager.OnAudioPortUpdateListener>();
            new ArrayList<AudioManager.OnAudioPortUpdateListener>();


@@ -40,6 +42,8 @@ class AudioPortEventHandler {
    private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
    private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
    private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
    private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;


    private static final long RESCHEDULE_MESSAGE_DELAY_MS = 100;

    /**
    /**
     * Accessed by native methods: JNI Callback context.
     * Accessed by native methods: JNI Callback context.
     */
     */
@@ -51,11 +55,12 @@ class AudioPortEventHandler {
            if (mHandler != null) {
            if (mHandler != null) {
                return;
                return;
            }
            }
            // find the looper for our new event handler
            // create a new thread for our new event handler
            Looper looper = Looper.getMainLooper();
            mHandlerThread = new HandlerThread(TAG);
            mHandlerThread.start();


            if (looper != null) {
            if (mHandlerThread.getLooper() != null) {
                mHandler = new Handler(looper) {
                mHandler = new Handler(mHandlerThread.getLooper()) {
                    @Override
                    @Override
                    public void handleMessage(Message msg) {
                    public void handleMessage(Message msg) {
                        ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
                        ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
@@ -86,6 +91,12 @@ class AudioPortEventHandler {
                        if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
                        if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
                            int status = AudioManager.updateAudioPortCache(ports, patches, null);
                            int status = AudioManager.updateAudioPortCache(ports, patches, null);
                            if (status != AudioManager.SUCCESS) {
                            if (status != AudioManager.SUCCESS) {
                                // Since audio ports and audio patches are not null, the return
                                // value could be ERROR due to inconsistency between port generation
                                // and patch generation. In this case, we need to reschedule the
                                // message to make sure the native callback is done.
                                sendMessageDelayed(obtainMessage(msg.what, msg.obj),
                                        RESCHEDULE_MESSAGE_DELAY_MS);
                                return;
                                return;
                            }
                            }
                        }
                        }
@@ -132,6 +143,9 @@ class AudioPortEventHandler {
    @Override
    @Override
    protected void finalize() {
    protected void finalize() {
        native_finalize();
        native_finalize();
        if (mHandlerThread.isAlive()) {
            mHandlerThread.quit();
        }
    }
    }
    private native void native_finalize();
    private native void native_finalize();


@@ -168,6 +182,10 @@ class AudioPortEventHandler {
            Handler handler = eventHandler.handler();
            Handler handler = eventHandler.handler();
            if (handler != null) {
            if (handler != null) {
                Message m = handler.obtainMessage(what, arg1, arg2, obj);
                Message m = handler.obtainMessage(what, arg1, arg2, obj);
                if (what != AUDIOPORT_EVENT_NEW_LISTENER) {
                    // Except AUDIOPORT_EVENT_NEW_LISTENER, we can only respect the last message.
                    handler.removeMessages(what);
                }
                handler.sendMessage(m);
                handler.sendMessage(m);
            }
            }
        }
        }