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

Commit a5ee29be authored by Lee Shombert's avatar Lee Shombert Committed by Android (Google) Code Review
Browse files

Merge "Freeze processes that ANR" into main

parents 20d12f1c 59f3f15c
Loading
Loading
Loading
Loading
+22 −0
Original line number Original line Diff line number Diff line
@@ -80,6 +80,9 @@ public class TimeoutRecord {
    /** Latency tracker associated with this instance. */
    /** Latency tracker associated with this instance. */
    public final AnrLatencyTracker mLatencyTracker;
    public final AnrLatencyTracker mLatencyTracker;


    /** A handle to the timer that expired.  A value of null means "no timer". */
    private AutoCloseable mExpiredTimer;

    private TimeoutRecord(@TimeoutKind int kind, @NonNull String reason, long endUptimeMillis,
    private TimeoutRecord(@TimeoutKind int kind, @NonNull String reason, long endUptimeMillis,
            boolean endTakenBeforeLocks) {
            boolean endTakenBeforeLocks) {
        this.mKind = kind;
        this.mKind = kind;
@@ -87,6 +90,7 @@ public class TimeoutRecord {
        this.mEndUptimeMillis = endUptimeMillis;
        this.mEndUptimeMillis = endUptimeMillis;
        this.mEndTakenBeforeLocks = endTakenBeforeLocks;
        this.mEndTakenBeforeLocks = endTakenBeforeLocks;
        this.mLatencyTracker = new AnrLatencyTracker(kind, endUptimeMillis);
        this.mLatencyTracker = new AnrLatencyTracker(kind, endUptimeMillis);
        this.mExpiredTimer = null;
    }
    }


    private static TimeoutRecord endingNow(@TimeoutKind int kind, String reason) {
    private static TimeoutRecord endingNow(@TimeoutKind int kind, String reason) {
@@ -197,4 +201,22 @@ public class TimeoutRecord {
    public static TimeoutRecord forAppStart(String reason) {
    public static TimeoutRecord forAppStart(String reason) {
        return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason);
        return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason);
    }
    }

    /** Record the ID of the timer that expired. */
    @NonNull
    public TimeoutRecord setExpiredTimer(@Nullable AutoCloseable handle) {
        mExpiredTimer = handle;
        return this;
    }

    /** Close the ExpiredTimer, if one is present. */
    public void closeExpiredTimer() {
        try {
            if (mExpiredTimer != null) mExpiredTimer.close();
        } catch (Exception e) {
            // mExpiredTimer.close() should never, ever throw.  If it does, just rethrow as a
            // RuntimeException.
            throw new RuntimeException(e);
        }
    }
}
}
+9 −3
Original line number Original line Diff line number Diff line
@@ -775,7 +775,8 @@ public final class ActiveServices {
        this.mFGSLogger = new ForegroundServiceTypeLoggerModule();
        this.mFGSLogger = new ForegroundServiceTypeLoggerModule();
        this.mActiveServiceAnrTimer = new ProcessAnrTimer(service,
        this.mActiveServiceAnrTimer = new ProcessAnrTimer(service,
                ActivityManagerService.SERVICE_TIMEOUT_MSG,
                ActivityManagerService.SERVICE_TIMEOUT_MSG,
                "SERVICE_TIMEOUT");
                "SERVICE_TIMEOUT",
                new AnrTimer.Args().freeze(true));
        this.mShortFGSAnrTimer = new ServiceAnrTimer(service,
        this.mShortFGSAnrTimer = new ServiceAnrTimer(service,
                ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG,
                ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG,
                "SHORT_FGS_TIMEOUT");
                "SHORT_FGS_TIMEOUT");
@@ -7521,7 +7522,7 @@ public final class ActiveServices {
                    }
                    }
                }
                }
                if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
                if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
                    mActiveServiceAnrTimer.accept(proc);
                    final AutoCloseable timer = mActiveServiceAnrTimer.accept(proc);
                    Slog.w(TAG, "Timeout executing service: " + timeout);
                    Slog.w(TAG, "Timeout executing service: " + timeout);
                    StringWriter sw = new StringWriter();
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
@@ -7534,7 +7535,7 @@ public final class ActiveServices {
                            LAST_ANR_LIFETIME_DURATION_MSECS);
                            LAST_ANR_LIFETIME_DURATION_MSECS);
                    long waitedMillis = now - timeout.executingStart;
                    long waitedMillis = now - timeout.executingStart;
                    timeoutRecord = TimeoutRecord.forServiceExec(timeout.shortInstanceName,
                    timeoutRecord = TimeoutRecord.forServiceExec(timeout.shortInstanceName,
                            waitedMillis);
                            waitedMillis).setExpiredTimer(timer);
                } else {
                } else {
                    mActiveServiceAnrTimer.discard(proc);
                    mActiveServiceAnrTimer.discard(proc);
                    final long delay = psr.shouldExecServicesFg()
                    final long delay = psr.shouldExecServicesFg()
@@ -7639,6 +7640,11 @@ public final class ActiveServices {
            super(Objects.requireNonNull(am).mHandler, msg, label);
            super(Objects.requireNonNull(am).mHandler, msg, label);
        }
        }


        ProcessAnrTimer(ActivityManagerService am, int msg, String label,
                @NonNull AnrTimer.Args args) {
            super(Objects.requireNonNull(am).mHandler, msg, label, args);
        }

        @Override
        @Override
        public int getPid(@NonNull ProcessRecord proc) {
        public int getPid(@NonNull ProcessRecord proc) {
            return proc.getPid();
            return proc.getPid();
+5 −4
Original line number Original line Diff line number Diff line
@@ -1337,7 +1337,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        BroadcastAnrTimer(@NonNull Handler handler) {
        BroadcastAnrTimer(@NonNull Handler handler) {
            super(Objects.requireNonNull(handler),
            super(Objects.requireNonNull(handler),
                    MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT",
                    MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT",
                new AnrTimer.Args().extend(true));
                    new AnrTimer.Args().extend(true).freeze(true));
        }
        }


        @Override
        @Override
@@ -1455,11 +1455,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            r.anrCount++;
            r.anrCount++;
            if (app != null && !app.isDebugging()) {
            if (app != null && !app.isDebugging()) {
                mAnrTimer.accept(queue);
                final AutoCloseable timer = mAnrTimer.accept(queue);
                final String packageName = getReceiverPackageName(receiver);
                final String packageName = getReceiverPackageName(receiver);
                final String className = getReceiverClassName(receiver);
                final String className = getReceiverClassName(receiver);
                mService.appNotResponding(queue.app,
                TimeoutRecord tr = TimeoutRecord.forBroadcastReceiver(r.intent, packageName,
                        TimeoutRecord.forBroadcastReceiver(r.intent, packageName, className));
                        className).setExpiredTimer(timer);
                mService.appNotResponding(queue.app, tr);
            } else {
            } else {
                mAnrTimer.discard(queue);
                mAnrTimer.discard(queue);
            }
            }
+4 −0
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.server.ResourcePressureUtil;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.wm.WindowProcessController;
import com.android.server.wm.WindowProcessController;
import com.android.server.utils.AnrTimer;


import java.io.File;
import java.io.File;
import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -302,6 +303,9 @@ class ProcessErrorStateRecord {
        SparseBooleanArray lastPids = new SparseBooleanArray(20);
        SparseBooleanArray lastPids = new SparseBooleanArray(20);
        ActivityManagerService.VolatileDropboxEntryStates volatileDropboxEntriyStates = null;
        ActivityManagerService.VolatileDropboxEntryStates volatileDropboxEntriyStates = null;


        // Release the expired timer preparatory to starting the dump or returning without dumping.
        timeoutRecord.closeExpiredTimer();

        if (mApp.isDebugging()) {
        if (mApp.isDebugging()) {
            Slog.i(TAG, "Skipping debugged app ANR: " + this + " " + annotation);
            Slog.i(TAG, "Skipping debugged app ANR: " + this + " " + annotation);
            return;
            return;
+154 −19
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.utils;
import static android.text.TextUtils.formatSimple;
import static android.text.TextUtils.formatSimple;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Handler;
import android.os.Message;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemClock;
@@ -26,6 +27,7 @@ import android.os.Trace;
import android.text.TextUtils;
import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.CloseGuard;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.LongSparseArray;
@@ -93,7 +95,7 @@ public abstract class AnrTimer<V> implements AutoCloseable {
     * tracks give a sense of handler latency: the time between timer expiration and ANR
     * tracks give a sense of handler latency: the time between timer expiration and ANR
     * collection.
     * collection.
     */
     */
    private final static String TRACK = "AnrTimer";
    private final static String TRACK = "AnrTimerTrack";


    /**
    /**
     * Enable debug messages.
     * Enable debug messages.
@@ -127,6 +129,13 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        return Flags.anrTimerService();
        return Flags.anrTimerService();
    }
    }


    /**
     * Return true if freezing is enabled.  This has no effect if the service is not enabled.
     */
    private static boolean anrTimerFreezerEnabled() {
        return Flags.anrTimerFreezer();
    }

    /**
    /**
     * This class allows test code to provide instance-specific overrides.
     * This class allows test code to provide instance-specific overrides.
     */
     */
@@ -134,6 +143,10 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        boolean anrTimerServiceEnabled() {
        boolean anrTimerServiceEnabled() {
            return AnrTimer.anrTimerServiceEnabled();
            return AnrTimer.anrTimerServiceEnabled();
        }
        }

        boolean anrTimerFreezerEnabled() {
            return AnrTimer.anrTimerFreezerEnabled();
        }
    }
    }


    /** The default injector. */
    /** The default injector. */
@@ -150,6 +163,9 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        /** Grant timer extensions when the system is heavily loaded. */
        /** Grant timer extensions when the system is heavily loaded. */
        private boolean mExtend = false;
        private boolean mExtend = false;


        /** Freeze ANR'ed processes. */
        boolean mFreeze = false;

        // This is only used for testing, so it is limited to package visibility.
        // This is only used for testing, so it is limited to package visibility.
        Args injector(@NonNull Injector injector) {
        Args injector(@NonNull Injector injector) {
            mInjector = injector;
            mInjector = injector;
@@ -160,6 +176,58 @@ public abstract class AnrTimer<V> implements AutoCloseable {
            mExtend = flag;
            mExtend = flag;
            return this;
            return this;
        }
        }

        public Args freeze(boolean enable) {
            mFreeze = enable;
            return this;
        }
    }

    /**
     * A target process may be modified when its timer expires.  The modification (if any) will be
     * undone if the expiration is discarded, but is persisted if the expiration is accepted.  If
     * the expiration is accepted, then a TimerLock is returned to the client.  The client must
     * close the TimerLock to complete the state machine.
     */
    private class TimerLock implements AutoCloseable {
        // Detect failures to close.
        private final CloseGuard mGuard = new CloseGuard();

        // A lock to ensure closing is thread-safe.
        private final Object mLock = new Object();

        // Allow multiple calls to close().
        private boolean mClosed = false;

        // The native timer ID that must be closed.  This may be zero.
        final int mTimerId;

        TimerLock(int timerId) {
            mTimerId = timerId;
            mGuard.open("AnrTimer.release");
        }

        @Override
        public void close() {
            synchronized (mLock) {
                if (!mClosed) {
                    AnrTimer.this.release(this);
                    mGuard.close();
                    mClosed = true;
                }
            }
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                // Note that guard could be null if the constructor threw.
                if (mGuard != null) mGuard.warnIfOpen();
                close();
            } finally {
                super.finalize();
            }
        }
    }
    }


    /**
    /**
@@ -334,6 +402,7 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        final String label =
        final String label =
                formatSimple("%s(%d,%d,%d,%s,%d)", op, timerId, pid, uid, mLabel, milliseconds);
                formatSimple("%s(%d,%d,%d,%s,%d)", op, timerId, pid, uid, mLabel, milliseconds);
        Trace.instantForTrack(TRACE_TAG, TRACK, label);
        Trace.instantForTrack(TRACE_TAG, TRACK, label);
        if (DEBUG) Log.i(TAG, label);
    }
    }


    /**
    /**
@@ -342,6 +411,16 @@ public abstract class AnrTimer<V> implements AutoCloseable {
    private void trace(String op, int timerId) {
    private void trace(String op, int timerId) {
        final String label = formatSimple("%s(%d)", op, timerId);
        final String label = formatSimple("%s(%d)", op, timerId);
        Trace.instantForTrack(TRACE_TAG, TRACK, label);
        Trace.instantForTrack(TRACE_TAG, TRACK, label);
        if (DEBUG) Log.i(TAG, label);
    }

    /**
     * Generate a trace point with a pid and uid but no timer ID.
     */
    private static void trace(String op, int pid, int uid) {
        final String label = formatSimple("%s(%d,%d)", op, pid, uid);
        Trace.instantForTrack(TRACE_TAG, TRACK, label);
        if (DEBUG) Log.i(TAG, label);
    }
    }


    /**
    /**
@@ -353,10 +432,13 @@ public abstract class AnrTimer<V> implements AutoCloseable {


        abstract boolean cancel(@NonNull V arg);
        abstract boolean cancel(@NonNull V arg);


        abstract boolean accept(@NonNull V arg);
        @Nullable
        abstract TimerLock accept(@NonNull V arg);


        abstract boolean discard(@NonNull V arg);
        abstract boolean discard(@NonNull V arg);


        abstract void release(@NonNull TimerLock timer);

        abstract boolean enabled();
        abstract boolean enabled();


        abstract void dump(IndentingPrintWriter pw, boolean verbose);
        abstract void dump(IndentingPrintWriter pw, boolean verbose);
@@ -385,8 +467,9 @@ public abstract class AnrTimer<V> implements AutoCloseable {


        /** accept() is a no-op when the feature is disabled. */
        /** accept() is a no-op when the feature is disabled. */
        @Override
        @Override
        boolean accept(@NonNull V arg) {
        @Nullable
            return true;
        TimerLock accept(@NonNull V arg) {
            return null;
        }
        }


        /** discard() is a no-op when the feature is disabled. */
        /** discard() is a no-op when the feature is disabled. */
@@ -395,6 +478,11 @@ public abstract class AnrTimer<V> implements AutoCloseable {
            return true;
            return true;
        }
        }


        /** release() is a no-op when the feature is disabled. */
        @Override
        void release(@NonNull TimerLock timer) {
        }

        /** The feature is not enabled. */
        /** The feature is not enabled. */
        @Override
        @Override
        boolean enabled() {
        boolean enabled() {
@@ -441,9 +529,11 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        @GuardedBy("mLock")
        @GuardedBy("mLock")
        private int mTotalRestarted = 0;
        private int mTotalRestarted = 0;


        /** Fetch the native tag (an integer) for the given label. */
        /** Create the native AnrTimerService that will host all timers from this instance. */
        FeatureEnabled() {
        FeatureEnabled() {
            mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend);
            mNative = nativeAnrTimerCreate(mLabel,
                    mArgs.mExtend,
                    mArgs.mFreeze && mArgs.mInjector.anrTimerFreezerEnabled());
            if (mNative == 0) throw new IllegalArgumentException("unable to create native timer");
            if (mNative == 0) throw new IllegalArgumentException("unable to create native timer");
            synchronized (sAnrTimerList) {
            synchronized (sAnrTimerList) {
                sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this));
                sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this));
@@ -494,19 +584,26 @@ public abstract class AnrTimer<V> implements AutoCloseable {


        /**
        /**
         * Accept a timer in the framework-level handler.  The timeout has been accepted and the
         * Accept a timer in the framework-level handler.  The timeout has been accepted and the
         * timeout handler is executing.
         * client's timeout handler is executing.  If the function returns a non-null TimerLock then
         * the associated process may have been paused (or otherwise modified in preparation for
         * debugging). The TimerLock must be closed to allow the process to continue, or to be
         * dumped in an AnrReport.
         */
         */
        @Override
        @Override
        boolean accept(@NonNull V arg) {
        @Nullable
        TimerLock accept(@NonNull V arg) {
            synchronized (mLock) {
            synchronized (mLock) {
                Integer timer = removeLocked(arg);
                Integer timer = removeLocked(arg);
                if (timer == null) {
                if (timer == null) {
                    notFoundLocked("accept", arg);
                    notFoundLocked("accept", arg);
                    return false;
                    return null;
                }
                }
                nativeAnrTimerAccept(mNative, timer);
                boolean accepted = nativeAnrTimerAccept(mNative, timer);
                trace("accept", timer);
                trace("accept", timer);
                return true;
                // If "accepted" is true then the native layer has pending operations against this
                // timer.  Wrap the timer ID in a TimerLock and return it to the caller.  If
                // "accepted" is false then the native later does not have any pending operations.
                return accepted ? new TimerLock(timer) : null;
            }
            }
        }
        }


@@ -529,6 +626,21 @@ public abstract class AnrTimer<V> implements AutoCloseable {
            }
            }
        }
        }


        /**
         * Unfreeze an app that was frozen because its timer had expired.  This method catches
         * errors that might be thrown by the unfreeze method.  This method does nothing if
         * freezing is not enabled or if the AnrTimer never froze the timer.  Note that the native
         * release method returns false only if the timer's process was frozen, is still frozen,
         * and could not be unfrozen.
         */
        @Override
        void release(@NonNull TimerLock t) {
            if (t.mTimerId == 0) return;
            if (!nativeAnrTimerRelease(mNative, t.mTimerId)) {
                Log.e(TAG, "failed to release id=" + t.mTimerId, new Exception(TAG));
            }
        }

        /** The feature is enabled. */
        /** The feature is enabled. */
        @Override
        @Override
        boolean enabled() {
        boolean enabled() {
@@ -616,16 +728,20 @@ public abstract class AnrTimer<V> implements AutoCloseable {
    /**
    /**
     * Accept the expired timer associated with arg.  This indicates that the caller considers the
     * Accept the expired timer associated with arg.  This indicates that the caller considers the
     * timer expiration to be a true ANR.  (See {@link #discard} for an alternate response.)  The
     * timer expiration to be a true ANR.  (See {@link #discard} for an alternate response.)  The
     * function returns true if an expired timer was found and false if a running timer was found or
     * function returns a {@link TimerLock} if an expired timer was found and null otherwise.
     * if no timer was found.  After this call, the timer does not exist.  It is an error to accept
     * After this call, the timer does not exist.  It is an error to accept a running timer,
     * a running timer, however, the running timer will be canceled.
     * however, the running timer will be canceled.
     *
     *
     * Note: the return value is always true if the feature is not enabled.
     * If a non-null TimerLock is returned, the TimerLock must be closed before the target process
     * is dumped (for an ANR report) or continued.
     *
     * Note: the return value is always null if the feature is not enabled.
     *
     *
     * @param arg The key by which the timer is known.  This is never examined or modified.
     * @param arg The key by which the timer is known.  This is never examined or modified.
     * @return True if an expired timer was accepted.
     * @return A TimerLock if an expired timer was accepted.
     */
     */
    public boolean accept(@NonNull V arg) {
    @Nullable
    public TimerLock accept(@NonNull V arg) {
        return mFeature.accept(arg);
        return mFeature.accept(arg);
    }
    }


@@ -646,6 +762,13 @@ public abstract class AnrTimer<V> implements AutoCloseable {
        return mFeature.discard(arg);
        return mFeature.discard(arg);
    }
    }


    /**
     * Release an expired timer.
     */
    private void release(@NonNull TimerLock t) {
        mFeature.release(t);
    }

    /**
    /**
     * The notifier that a timer has fired.  The timerId and original pid/uid are supplied.  The
     * The notifier that a timer has fired.  The timerId and original pid/uid are supplied.  The
     * elapsed time is the actual time since the timer was scheduled, which may be different from
     * elapsed time is the actual time since the timer was scheduled, which may be different from
@@ -826,7 +949,7 @@ public abstract class AnrTimer<V> implements AutoCloseable {
     * Unlike the other methods, this is an instance method: the "this" parameter is passed into
     * Unlike the other methods, this is an instance method: the "this" parameter is passed into
     * the native layer.
     * the native layer.
     */
     */
    private native long nativeAnrTimerCreate(String name, boolean extend);
    private native long nativeAnrTimerCreate(String name, boolean extend, boolean freeze);


    /** Release the native resources.  No further operations are premitted. */
    /** Release the native resources.  No further operations are premitted. */
    private static native int nativeAnrTimerClose(long service);
    private static native int nativeAnrTimerClose(long service);
@@ -840,12 +963,24 @@ public abstract class AnrTimer<V> implements AutoCloseable {
     */
     */
    private static native boolean nativeAnrTimerCancel(long service, int timerId);
    private static native boolean nativeAnrTimerCancel(long service, int timerId);


    /** Accept an expired timer by ID.  Return true if the timer was found. */
    /**
     * Accept an expired timer by ID.  Return true if the timer must be released.  Return false if
     * the native layer is completely finished with this timer.
     */
    private static native boolean nativeAnrTimerAccept(long service, int timerId);
    private static native boolean nativeAnrTimerAccept(long service, int timerId);


    /** Discard an expired timer by ID.  Return true if the timer was found.  */
    /** Discard an expired timer by ID.  Return true if the timer was found.  */
    private static native boolean nativeAnrTimerDiscard(long service, int timerId);
    private static native boolean nativeAnrTimerDiscard(long service, int timerId);


    /**
     * Release (unfreeze) the process associated with the timer, if the process was previously
     * frozen by the service.  The function returns false if three conditions are true: the timer
     * does exist, the timer's process was frozen, and the timer's process could not be unfrozen.
     * Otherwise, the function returns true.  In other words, a return value of value means there
     * is a process that is unexpectedly stuck in the frozen state.
     */
    private static native boolean nativeAnrTimerRelease(long service, int timerId);

    /** Retrieve runtime dump information from the native layer. */
    /** Retrieve runtime dump information from the native layer. */
    private static native String[] nativeAnrTimerDump(long service);
    private static native String[] nativeAnrTimerDump(long service);
}
}
Loading