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

Commit 371a2550 authored by Lee Shombert's avatar Lee Shombert
Browse files

Extend ANR timer to ActiveServices

Implement SERVICE_TIMEOUT, SHORT_FGS_ANR_TIMEOUT, and
FOREGROUND_TIMEOUT with AnrTimer instances.

This also changes the AnrTimer.Error timestamp to be a long
(milliseconds since the epoch) instead of a string.

A few editorial updates were made to address comments from earlier
changes. Comments were updated in BroadcastQueueModernImpl and some
method names were changed in AnrTimer.

Test: atest
 * FrameworksServicesTests:com.android.server.am
 * FrameworksMockingServicesTests:com.android.server.am
 * CtsAppTestCases

Bug: 282428924

Change-Id: I0ff70a9d5b7d4e2b66125aaedebf4bc0064f871c
parent 20994455
Loading
Loading
Loading
Loading
+67 −28
Original line number Diff line number Diff line
@@ -409,6 +409,13 @@ public final class ActiveServices {

    AppWidgetManagerInternal mAppWidgetManagerInternal;

    /**
     * The available ANR timers.
     */
    private final ProcessAnrTimer mActiveServiceAnrTimer;
    private final ServiceAnrTimer mShortFGSAnrTimer;
    private final ServiceAnrTimer mServiceFGAnrTimer;

    // allowlisted packageName.
    ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();

@@ -663,6 +670,15 @@ public final class ActiveServices {

        final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
        this.mFGSLogger = new ForegroundServiceTypeLoggerModule();
        this.mActiveServiceAnrTimer = new ProcessAnrTimer(service,
                ActivityManagerService.SERVICE_TIMEOUT_MSG,
                "SERVICE_TIMEOUT");
        this.mShortFGSAnrTimer = new ServiceAnrTimer(service,
                ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG,
                "FGS_TIMEOUT");
        this.mServiceFGAnrTimer = new ServiceAnrTimer(service,
                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG,
                "SERVICE_FOREGROUND_TIMEOUT");
    }

    void systemServicesReady() {
@@ -2083,8 +2099,7 @@ public final class ActiveServices {
                r.fgRequired = false;
                r.fgWaiting = false;
                alreadyStartedOp = stopProcStatsOp = true;
                mAm.mHandler.removeMessages(
                        ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
                mServiceFGAnrTimer.cancel(r);
            }

            final ProcessServiceRecord psr = r.app.mServices;
@@ -3313,7 +3328,7 @@ public final class ActiveServices {
    }

    void unscheduleShortFgsTimeoutLocked(ServiceRecord sr) {
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
        mShortFGSAnrTimer.cancel(sr);
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG,
                sr);
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
@@ -3387,9 +3402,11 @@ public final class ActiveServices {
                    Slog.d(TAG_SERVICE, "[STALE] Short FGS timed out: " + sr
                            + " " + sr.getShortFgsTimedEventDescription(nowUptime));
                }
                mShortFGSAnrTimer.discard(sr);
                return;
            }
            Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
            mShortFGSAnrTimer.accept(sr);
            traceInstant("short FGS timeout: ", sr);

            logFGSStateChangeLocked(sr,
@@ -3413,11 +3430,10 @@ public final class ActiveServices {
                        msg, sr.getShortFgsInfo().getProcStateDemoteTime());
            }

            {
                final Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
                mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
            }
            // ServiceRecord.getAnrTime() is an absolute time with a reference that is not "now".
            // Compute the time from "now" when starting the anr timer.
            mShortFGSAnrTimer.start(sr,
                    sr.getShortFgsInfo().getAnrTime() - SystemClock.uptimeMillis());
        }
    }

@@ -4847,8 +4863,7 @@ public final class ActiveServices {
        // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
        // again.
        if (r.fgRequired && r.fgWaiting) {
            mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            mServiceFGAnrTimer.cancel(r);
            r.fgWaiting = false;
        }

@@ -5691,8 +5706,7 @@ public final class ActiveServices {
            }
            mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
            mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            mServiceFGAnrTimer.cancel(r);
            if (r.app != null) {
                Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
@@ -6128,7 +6142,7 @@ public final class ActiveServices {
                if (psr.numberOfExecutingServices() == 0) {
                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                            "No more executingServices of " + r.shortInstanceName);
                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                    if (r.app.mPid != 0) mActiveServiceAnrTimer.cancel(r.app);
                } else if (r.executeFg) {
                    // Need to re-evaluate whether the app still needs to be in the foreground.
                    for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
@@ -6816,13 +6830,16 @@ public final class ActiveServices {
            synchronized (mAm) {
                if (proc.isDebugging()) {
                    // The app's being debugged, ignore timeout.
                    mActiveServiceAnrTimer.discard(proc);
                    return;
                }
                final ProcessServiceRecord psr = proc.mServices;
                if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null
                        || proc.isKilled()) {
                    mActiveServiceAnrTimer.discard(proc);
                    return;
                }
                mActiveServiceAnrTimer.accept(proc);
                final long now = SystemClock.uptimeMillis();
                final long maxTime =  now
                        - (psr.shouldExecServicesFg()
@@ -6855,12 +6872,11 @@ public final class ActiveServices {
                    timeoutRecord = TimeoutRecord.forServiceExec(timeout.shortInstanceName,
                            waitedMillis);
                } else {
                    Message msg = mAm.mHandler.obtainMessage(
                            ActivityManagerService.SERVICE_TIMEOUT_MSG);
                    msg.obj = proc;
                    mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
                    final long delay = psr.shouldExecServicesFg()
                                       ? (nextTime + mAm.mConstants.SERVICE_TIMEOUT) :
                            (nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT));
                                       (nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT)
                                       - SystemClock.uptimeMillis();
                    mActiveServiceAnrTimer.start(proc, delay);
                }
            }

@@ -6886,12 +6902,15 @@ public final class ActiveServices {
            synchronized (mAm) {
                timeoutRecord.mLatencyTracker.waitingOnAMSLockEnded();
                if (!r.fgRequired || !r.fgWaiting || r.destroying) {
                    mServiceFGAnrTimer.discard(r);
                    return;
                }

                mServiceFGAnrTimer.accept(r);
                app = r.app;
                if (app != null && app.isDebugging()) {
                    // The app's being debugged; let it ride
                    mServiceFGAnrTimer.discard(r);
                    return;
                }

@@ -6948,26 +6967,46 @@ public final class ActiveServices {
                ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
    }

    private static class ProcessAnrTimer extends AnrTimer<ProcessRecord> {

        ProcessAnrTimer(ActivityManagerService am, int msg, String label) {
            super(Objects.requireNonNull(am).mHandler, msg, label);
        }

        void start(@NonNull ProcessRecord proc, long millis) {
            start(proc, proc.getPid(), proc.uid, millis);
        }
    }

    private static class ServiceAnrTimer extends AnrTimer<ServiceRecord> {

        ServiceAnrTimer(ActivityManagerService am, int msg, String label) {
            super(Objects.requireNonNull(am).mHandler, msg, label);
        }

        void start(@NonNull ServiceRecord service, long millis) {
            start(service,
                    (service.app != null) ? service.app.getPid() : 0,
                    service.appInfo.uid,
                    millis);
        }
    }

    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
        final long delay = proc.mServices.shouldExecServicesFg()
                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT;
        mActiveServiceAnrTimer.start(proc, delay);
    }

    void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
        if (r.app.mServices.numberOfExecutingServices() == 0 || r.app.getThread() == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
        msg.obj = r;
        r.fgWaiting = true;
        mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs);
        mServiceFGAnrTimer.start(r, mAm.mConstants.mServiceStartForegroundTimeoutMs);
    }

    final class ServiceDumper {
+99 −30
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -44,7 +45,6 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@@ -150,7 +150,7 @@ class AnrTimer<V> {
        /** A partial stack that localizes the caller of the operation. */
        final StackTraceElement[] stack;
        /** The date, in local time, the error was created. */
        final String date;
        final long timestamp;

        Error(@NonNull String issue, @NonNull String operation, @NonNull String tag,
                @NonNull StackTraceElement[] stack, @NonNull String arg) {
@@ -159,7 +159,7 @@ class AnrTimer<V> {
            this.tag = tag;
            this.stack = stack;
            this.arg = arg;
            this.date = new Date().toString();
            this.timestamp = SystemClock.elapsedRealtime();
        }
    }

@@ -347,20 +347,23 @@ class AnrTimer<V> {
         * main Looper.
         */
        @NonNull
        Handler getHandler(@NonNull Handler.Callback callback) {
        Handler newHandler(@NonNull Handler.Callback callback) {
            Looper looper = mReferenceHandler.getLooper();
            if (looper == null) looper = Looper.getMainLooper();
            return new Handler(looper, callback);
        };
        }

        /** Return a CpuTracker. */
        /**
         * Return a CpuTracker. The default behavior is to create a new CpuTracker but this changes
         * for unit tests.
         **/
        @NonNull
        CpuTracker getTracker() {
        CpuTracker newTracker() {
            return new CpuTracker();
        }

        /** Return true if the feature is enabled. */
        boolean getFeatureEnabled() {
        boolean isFeatureEnabled() {
            return anrTimerServiceEnabled();
        }
    }
@@ -401,8 +404,8 @@ class AnrTimer<V> {
        /** Create a HandlerTimerService that directly uses the supplied handler and tracker. */
        @VisibleForTesting
        HandlerTimerService(@NonNull Injector injector) {
            mHandler = injector.getHandler(this::expires);
            mCpu = injector.getTracker();
            mHandler = injector.newHandler(this::expires);
            mCpu = injector.newTracker();
        }

        /** Post a message with the specified timeout.  The timer is not modified. */
@@ -513,7 +516,26 @@ class AnrTimer<V> {
    private final FeatureSwitch mFeature;

    /**
     * The common constructor.  A null injector results in a normal, production timer.
     * Create one AnrTimer instance.  The instance is given a handler and a "what".  Individual
     * timers are started with {@link #start}.  If a timer expires, then a {@link Message} is sent
     * immediately to the handler with {@link Message.what} set to what and {@link Message.obj} set
     * to the timer key.
     *
     * AnrTimer instances have a label, which must be unique.  The label is used for reporting and
     * debug.
     *
     * If an individual timer expires internally, and the "extend" parameter is true, then the
     * AnrTimer may extend the individual timer rather than immediately delivering the timeout to
     * the client.  The extension policy is not part of the instance.
     *
     * This method accepts an {@link #Injector} to tune behavior for testing.  This method should
     * not be called directly by regular clients.
     *
     * @param handler The handler to which the expiration message will be delivered.
     * @param what The "what" parameter for the expiration message.
     * @param label A name for this instance.
     * @param extend A flag to indicate if expired timers can be granted extensions.
     * @param injector An {@link #Injector} to tune behavior for testing.
     */
    @VisibleForTesting
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
@@ -522,7 +544,7 @@ class AnrTimer<V> {
        mWhat = what;
        mLabel = label;
        mExtend = extend;
        boolean enabled = injector.getFeatureEnabled();
        boolean enabled = injector.isFeatureEnabled();
        if (!enabled) {
            mFeature = new FeatureDisabled();
            mTimerService = null;
@@ -538,14 +560,25 @@ class AnrTimer<V> {
    }

    /**
     * Create one timer instance for production.  The client can ask for extensible timeouts.
     * Create an AnrTimer instance with the default {@link #Injector}.  See {@link AnrTimer(Handler,
     * int, String, boolean, Injector} for a functional description.
     *
     * @param handler The handler to which the expiration message will be delivered.
     * @param what The "what" parameter for the expiration message.
     * @param label A name for this instance.
     * @param extend A flag to indicate if expired timers can be granted extensions.
     */
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
        this(handler, what, label, extend, new Injector(handler));
    }

    /**
     * Create one timer instance for production.  There are no extensible timeouts.
     * Create an AnrTimer instance with the default {@link #Injector} and with extensions disabled.
     * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description.
     *
     * @param handler The handler to which the expiration message will be delivered.
     * @param what The "what" parameter for the expiration message.
     * @param label A name for this instance.
     */
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
        this(handler, what, label, false);
@@ -555,6 +588,8 @@ class AnrTimer<V> {
     * Return true if the service is enabled on this instance.  Clients should use this method to
     * decide if the feature is enabled, and not read the flags directly.  This method should be
     * deleted if and when the feature is enabled permanently.
     *
     * @return true if the service is flag-enabled.
     */
    boolean serviceEnabled() {
        return mFeature.enabled();
@@ -642,7 +677,7 @@ class AnrTimer<V> {
    }

    /**
     * Report something about a timer.
     * Generate a log message for a timer.
     */
    private void report(@NonNull Timer timer, @NonNull String msg) {
        Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
@@ -654,9 +689,13 @@ class AnrTimer<V> {
     */
    private abstract class FeatureSwitch {
        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs);

        abstract boolean cancel(@NonNull V arg);

        abstract boolean accept(@NonNull V arg);

        abstract boolean discard(@NonNull V arg);

        abstract boolean enabled();
    }

@@ -666,6 +705,7 @@ class AnrTimer<V> {
     */
    private class FeatureDisabled extends FeatureSwitch {
        /** Start a timer by sending a message to the client's handler. */
        @Override
        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
            final Message msg = mHandler.obtainMessage(mWhat, arg);
            mHandler.sendMessageDelayed(msg, timeoutMs);
@@ -673,22 +713,26 @@ class AnrTimer<V> {
        }

        /** Cancel a timer by removing the message from the client's handler. */
        @Override
        boolean cancel(@NonNull V arg) {
            mHandler.removeMessages(mWhat, arg);
            return true;
        }

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

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

        /** The feature is not enabled. */
        @Override
        boolean enabled() {
            return false;
        }
@@ -703,16 +747,17 @@ class AnrTimer<V> {
        /**
         * Start a timer.
         */
        @Override
        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this);
            synchronized (mLock) {
                Timer old = mTimerMap.get(arg);
                // There is an existing timer.  If the timer was running, then cancel the running
                // timer and restart it.  If the timer was expired record a protocol error and
                // discard the expired timer.
                if (old != null) {
                    // There is an existing timer.  This is a protocol error in the client.
                    // Record the error and then clean up by canceling running timers and
                    // discarding expired timers.
                    restartedLocked(old.status, arg);
                    if (old.status == TIMER_EXPIRED) {
                      restartedLocked(old.status, arg);
                        discard(arg);
                    } else {
                        cancel(arg);
@@ -735,6 +780,7 @@ class AnrTimer<V> {
        /**
         * Cancel a timer.  Return false if the timer was not found.
         */
        @Override
        boolean cancel(@NonNull V arg) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
@@ -755,6 +801,7 @@ class AnrTimer<V> {
         * Accept a timer in the framework-level handler.  The timeout has been accepted and the
         * timeout handler is executing.  Return false if the timer was not found.
         */
        @Override
        boolean accept(@NonNull V arg) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
@@ -775,6 +822,7 @@ class AnrTimer<V> {
         * longer interesting.  No statistics are collected.  Return false if the time was not
         * found.
         */
        @Override
        boolean discard(@NonNull V arg) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
@@ -791,40 +839,58 @@ class AnrTimer<V> {
        }

        /** The feature is enabled. */
        @Override
        boolean enabled() {
            return true;
        }
    }

    /**
     * Start a timer associated with arg.  If a timer already exists with the same arg, then that
     * timer is canceled and a new timer is created.  This returns false if the timer cannot be
     * created.
     * Start a timer associated with arg.  The same object must be used to cancel, accept, or
     * discard a timer later.  If a timer already exists with the same arg, then the existing timer
     * is canceled and a new timer is created.
     *
     * @param arg The key by which the timer is known.  This is never examined or modified.
     * @param pid The Linux process ID of the target being timed.
     * @param uid The Linux user ID of the target being timed.
     * @param timeoutMs The timer timeout, in milliseconds.
     * @return true if the timer was successfully created.
     */
    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
        return mFeature.start(arg, pid, uid, timeoutMs);
    }

    /**
     * Cancel a running timer and remove it from any list.  This returns true if the timer was
     * found and false otherwise.  It is not an error to cancel a non-existent timer.  It is also
     * not an error to cancel an expired timer.
     * Cancel the running timer associated with arg.  The timer is forgotten.  If the timer has
     * expired, the call is treated as a discard.  No errors are reported if the timer does not
     * exist or if the timer has expired.
     *
     * @return true if the timer was found and was running.
     */
    boolean cancel(@NonNull V arg) {
        return mFeature.cancel(arg);
    }

    /**
     * Accept an expired timer.  This returns false if the timer was not found or if the timer was
     * not expired.
     * 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.)  It is
     * an error to accept a running timer, however the running timer will be canceled.
     *
     * @return true if the timer was found and was expired.
     */
    boolean accept(@NonNull V arg) {
        return mFeature.accept(arg);
    }

    /**
     * Discard an expired timer.  This returns false if the timer was not found or if the timer was
     * not expired.
     * Discard the expired timer associated with arg.  This indicates that the caller considers the
     * timer expiration to be a false ANR.  ((See {@link #accept} for an alternate response.)  One
     * reason to discard an expired timer is if the process being timed was also being debugged:
     * such a process could be stopped at a breakpoint and its failure to respond would not be an
     * error.  It is an error to discard a running timer, however the running timer will be
     * canceled.
     *
     * @return true if the timer was found and was expired.
     */
    boolean discard(@NonNull V arg) {
        return mFeature.discard(arg);
@@ -913,7 +979,10 @@ class AnrTimer<V> {
    private static void dump(IndentingPrintWriter ipw, int seq, Error err) {
        ipw.format("%2d: op:%s tag:%s issue:%s arg:%s\n", seq, err.operation, err.tag,
                err.issue, err.arg);
        ipw.format("    date:%s\n", err.date);

        final long offset = System.currentTimeMillis() - SystemClock.elapsedRealtime();
        final long etime = offset + err.timestamp;
        ipw.println("    date:" + TimeMigrationUtils.formatMillisWithFixedFormat(etime));
        ipw.increaseIndent();
        for (int i = 0; i < err.stack.length; i++) {
            ipw.println("    " + err.stack[i].toString());
+10 −5
Original line number Diff line number Diff line
@@ -258,7 +258,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private static final int MSG_PROCESS_FREEZABLE_CHANGED = 6;
    private static final int MSG_UID_STATE_CHANGED = 7;

    // Required when Flags.anrTimerServiceEnabled is false.
    // Required when Flags.anrTimerServiceEnabled is false.  This constant should be deleted if and
    // when the flag is fused on.
    private static final int MSG_DELIVERY_TIMEOUT_SOFT = 8;

    private void enqueueUpdateRunningList() {
@@ -274,7 +275,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                updateRunningList();
                return true;
            }
            // Required when Flags.anrTimerServiceEnabled is false.
            // Required when Flags.anrTimerServiceEnabled is false.  This case should be deleted if
            // and when the flag is fused on.
            case MSG_DELIVERY_TIMEOUT_SOFT: {
                synchronized (mService) {
                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
@@ -1169,7 +1171,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        r.resultTo = null;
    }

    // Required when Flags.anrTimerServiceEnabled is false.
    // Required when Flags.anrTimerServiceEnabled is false.  This function can be replaced with a
    // single call to {@code mAnrTimer.start()} if and when the flag is fused on.
    private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue,
            int softTimeoutMillis) {
        if (mAnrTimer.serviceEnabled()) {
@@ -1181,7 +1184,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        }
    }

    // Required when Flags.anrTimerServiceEnabled is false.
    // Required when Flags.anrTimerServiceEnabled is false. This function can be replaced with a
    // single call to {@code mAnrTimer.cancel()} if and when the flag is fused on.
    private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
        mAnrTimer.cancel(queue);
        if (!mAnrTimer.serviceEnabled()) {
@@ -1189,7 +1193,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        }
    }

    // Required when Flags.anrTimerServiceEnabled is false.
    // Required when Flags.anrTimerServiceEnabled is false.  This function can be deleted entirely
    // if and when the flag is fused on.
    private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
            int softTimeoutMillis) {
        if (queue.app != null) {
+7 −3

File changed.

Preview size limit exceeded, changes collapsed.