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

Commit b29e318e authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Schedule trimMemory after drawing the frame

Fixes jank issues where trimMemory gets scheduled during an
animation. trimMemory likely hits code that is not in the
page cache anymore, leading to high execution time because of page
misses. Scheduling it after the next frame has been drawn
minimizes the risk that this page miss actually causes jank.

Test: Boot, switch between a couple of apps.
Bug: 78611607
Change-Id: Ia1fc411fbe6ca07861183ae484124406681118e5
parent e4a8d4c7
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.ThreadedRenderer;
@@ -145,6 +146,7 @@ import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
import com.android.server.am.MemInfoDumpProto;
@@ -1406,7 +1408,15 @@ public final class ActivityThread extends ClientTransactionHandler {
        }

        public void scheduleTrimMemory(int level) {
            sendMessage(H.TRIM_MEMORY, null, level);
            final Runnable r = PooledLambda.obtainRunnable(ActivityThread::handleTrimMemory,
                    ActivityThread.this, level);
            // Schedule trimming memory after drawing the frame to minimize jank-risk.
            Choreographer choreographer = Choreographer.getMainThreadInstance();
            if (choreographer != null) {
                choreographer.postCallback(Choreographer.CALLBACK_COMMIT, r, null);
            } else {
                mH.post(r);
            }
        }

        public void scheduleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
@@ -1561,7 +1571,6 @@ public final class ActivityThread extends ClientTransactionHandler {
        public static final int SLEEPING                = 137;
        public static final int SET_CORE_SETTINGS       = 138;
        public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
        public static final int TRIM_MEMORY             = 140;
        public static final int DUMP_PROVIDER           = 141;
        public static final int UNSTABLE_PROVIDER_DIED  = 142;
        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
@@ -1607,7 +1616,6 @@ public final class ActivityThread extends ClientTransactionHandler {
                    case SLEEPING: return "SLEEPING";
                    case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
                    case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
                    case TRIM_MEMORY: return "TRIM_MEMORY";
                    case DUMP_PROVIDER: return "DUMP_PROVIDER";
                    case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
                    case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
@@ -1741,11 +1749,6 @@ public final class ActivityThread extends ClientTransactionHandler {
                case UPDATE_PACKAGE_COMPATIBILITY_INFO:
                    handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
                    break;
                case TRIM_MEMORY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
                    handleTrimMemory(msg.arg1);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case UNSTABLE_PROVIDER_DIED:
                    handleUnstableProviderDied((IBinder)msg.obj, false);
                    break;
@@ -5409,7 +5412,8 @@ public final class ActivityThread extends ClientTransactionHandler {
        BinderInternal.forceGc("mem");
    }

    final void handleTrimMemory(int level) {
    private void handleTrimMemory(int level) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
        if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);

        ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
@@ -5420,6 +5424,7 @@ public final class ActivityThread extends ClientTransactionHandler {
        }

        WindowManagerGlobal.getInstance().trimMemory(level);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    private void setupGraphicsSupport(Context context) {
+15 −1
Original line number Diff line number Diff line
@@ -106,10 +106,16 @@ public final class Choreographer {
            if (looper == null) {
                throw new IllegalStateException("The current thread must have a looper!");
            }
            return new Choreographer(looper, VSYNC_SOURCE_APP);
            Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
            if (looper == Looper.getMainLooper()) {
                mMainInstance = choreographer;
            }
            return choreographer;
        }
    };

    private static volatile Choreographer mMainInstance;

    // Thread local storage for the SF choreographer.
    private static final ThreadLocal<Choreographer> sSfThreadInstance =
            new ThreadLocal<Choreographer>() {
@@ -263,6 +269,14 @@ public final class Choreographer {
        return sSfThreadInstance.get();
    }

    /**
     * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
     * @hide
     */
    public static Choreographer getMainThreadInstance() {
        return mMainInstance;
    }

    /** Destroys the calling thread's choreographer
     * @hide
     */