Loading core/java/com/android/internal/os/TimeoutRecord.java +22 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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); } } } } services/core/java/com/android/server/am/ActiveServices.java +9 −3 Original line number Original line Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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); Loading @@ -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() Loading Loading @@ -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(); Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +5 −4 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } } Loading services/core/java/com/android/server/am/ProcessErrorStateRecord.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading services/core/java/com/android/server/utils/AnrTimer.java +154 −19 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. */ */ Loading @@ -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. */ Loading @@ -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; Loading @@ -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(); } } } } /** /** Loading Loading @@ -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); } } /** /** Loading @@ -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); } } /** /** Loading @@ -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); Loading Loading @@ -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. */ Loading @@ -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() { Loading Loading @@ -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)); Loading Loading @@ -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; } } } } Loading @@ -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() { Loading Loading @@ -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); } } Loading @@ -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 Loading Loading @@ -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); Loading @@ -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
core/java/com/android/internal/os/TimeoutRecord.java +22 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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); } } } }
services/core/java/com/android/server/am/ActiveServices.java +9 −3 Original line number Original line Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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); Loading @@ -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() Loading Loading @@ -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(); Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +5 −4 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } } Loading
services/core/java/com/android/server/am/ProcessErrorStateRecord.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
services/core/java/com/android/server/utils/AnrTimer.java +154 −19 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. */ */ Loading @@ -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. */ Loading @@ -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; Loading @@ -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(); } } } } /** /** Loading Loading @@ -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); } } /** /** Loading @@ -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); } } /** /** Loading @@ -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); Loading Loading @@ -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. */ Loading @@ -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() { Loading Loading @@ -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)); Loading Loading @@ -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; } } } } Loading @@ -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() { Loading Loading @@ -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); } } Loading @@ -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 Loading Loading @@ -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); Loading @@ -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); } }