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

Commit 314f88ca authored by Lee Shombert's avatar Lee Shombert
Browse files

Slight refactor of AnrTimer APIs

An expired AnrTimer must be accepted with a TimeoutRecord; the call to
accept will attach any interesting expiration results to the
TimeoutRecord as the "expiredTimer".  Existing clients are changed to
use this new API.

Flag: EXEMPT refactor
Bug: 408440679
Test: atest
 * FrameworksServicesTests:AnrTimerTest
 * FrameworksServicesTests:com.android.server.am
 * FrameworksMockingServicesTests:com.android.server.am
Change-Id: Ic1e4e7726503754029e4607dfcd24335d7e38f22
parent 43e4a4ec
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -202,17 +202,25 @@ public class TimeoutRecord {
        return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason);
    }

    /** Record the ID of the timer that expired. */
    /**
     * Record the timer that expired. The argument is an opaque handle. If an expired timer had
     * already been set, close it now.
     */
    @NonNull
    public TimeoutRecord setExpiredTimer(@Nullable AutoCloseable handle) {
        // Close the current value of mExpiredTimer, if it not null.
        closeExpiredTimer();
        mExpiredTimer = handle;
        return this;
    }

    /** Close the ExpiredTimer, if one is present. */
    /** Close the ExpiredTimer, if one is present. getExpiredTimer will return null after this. */
    public void closeExpiredTimer() {
        try {
            if (mExpiredTimer != null) mExpiredTimer.close();
            if (mExpiredTimer != null) {
                mExpiredTimer.close();
                mExpiredTimer = null;
            }
        } catch (Exception e) {
            // mExpiredTimer.close() should never, ever throw.  If it does, just rethrow as a
            // RuntimeException.
+4 −4
Original line number Diff line number Diff line
@@ -3727,7 +3727,7 @@ public final class ActiveServices {
                mShortFGSAnrTimer.discard(sr);
                return;
            }
            mShortFGSAnrTimer.accept(sr);
            mShortFGSAnrTimer.accept(sr, tr);

            final String message = "Short FGS ANR'ed: " + sr;
            if (DEBUG_SHORT_SERVICE) {
@@ -7566,7 +7566,6 @@ public final class ActiveServices {
                    }
                }
                if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
                    final AutoCloseable timer = mActiveServiceAnrTimer.accept(proc);
                    Slog.w(TAG, "Timeout executing service: " + timeout);
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
@@ -7579,7 +7578,8 @@ public final class ActiveServices {
                            LAST_ANR_LIFETIME_DURATION_MSECS);
                    long waitedMillis = now - timeout.executingStart;
                    timeoutRecord = TimeoutRecord.forServiceExec(timeout.shortInstanceName,
                            waitedMillis).setExpiredTimer(timer);
                            waitedMillis);
                    mActiveServiceAnrTimer.accept(proc, timeoutRecord);
                } else {
                    mActiveServiceAnrTimer.discard(proc);
                    final long delay = psr.shouldExecServicesFg()
@@ -7623,7 +7623,7 @@ public final class ActiveServices {
                    return;
                }

                mServiceFGAnrTimer.accept(r);
                mServiceFGAnrTimer.accept(r, timeoutRecord);

                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Service foreground-required timeout for " + r);
+2 −2
Original line number Diff line number Diff line
@@ -1469,11 +1469,11 @@ class BroadcastQueueImpl extends BroadcastQueue {
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            r.anrCount++;
            if (app != null && !app.isDebugging()) {
                final AutoCloseable timer = mAnrTimer.accept(queue);
                final String packageName = getReceiverPackageName(receiver);
                final String className = getReceiverClassName(receiver);
                TimeoutRecord tr = TimeoutRecord.forBroadcastReceiver(r.intent, packageName,
                        className).setExpiredTimer(timer);
                        className);
                mAnrTimer.accept(queue, tr);
                mService.appNotResponding(queue.app, tr);
            } else {
                mAnrTimer.discard(queue);
+9 −11
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Keep;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.RingBuffer;

import java.lang.ref.WeakReference;
@@ -692,21 +693,18 @@ public abstract class AnrTimer<V> implements AutoCloseable {
    /**
     * 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
     * function returns a {@link TimerLock} if an expired timer was found and null otherwise.
     * After this call, the timer does not exist.  It is an error to accept a running timer,
     * however, the running timer will be canceled.
     * function stores a {@link TimerLock} in the {@link TimeoutRecord} argument.  The TimerLock
     * records information about the expired timer for retrieval during ANR report generation.
     * After this call, the timer does not exist.
     *
     * 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.
     * It is a protocol error to accept a running timer, however, the running timer will be
     * canceled.
     *
     * @param arg The key by which the timer is known.  This is never examined or modified.
     * @return A TimerLock if an expired timer was accepted.
     * @param timeoutRecord The TimeoutRecord that will hold information about the expired timer.
     */
    @Nullable
    public TimerLock accept(@NonNull V arg) {
        return mFeature.accept(arg);
    public void accept(@NonNull V arg, @NonNull TimeoutRecord timeoutRecord) {
        timeoutRecord.setExpiredTimer(mFeature.accept(arg));
    }

    /**