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

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

Merge "Extend ANR timer to ActiveServices" into main

parents bb756a05 371a2550
Loading
Loading
Loading
Loading
+67 −28
Original line number Original line Diff line number Diff line
@@ -409,6 +409,13 @@ public final class ActiveServices {


    AppWidgetManagerInternal mAppWidgetManagerInternal;
    AppWidgetManagerInternal mAppWidgetManagerInternal;


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

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


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


        final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
        final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
        this.mFGSLogger = new ForegroundServiceTypeLoggerModule();
        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() {
    void systemServicesReady() {
@@ -2083,8 +2099,7 @@ public final class ActiveServices {
                r.fgRequired = false;
                r.fgRequired = false;
                r.fgWaiting = false;
                r.fgWaiting = false;
                alreadyStartedOp = stopProcStatsOp = true;
                alreadyStartedOp = stopProcStatsOp = true;
                mAm.mHandler.removeMessages(
                mServiceFGAnrTimer.cancel(r);
                        ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            }
            }


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


    void unscheduleShortFgsTimeoutLocked(ServiceRecord sr) {
    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,
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG,
                sr);
                sr);
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_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
                    Slog.d(TAG_SERVICE, "[STALE] Short FGS timed out: " + sr
                            + " " + sr.getShortFgsTimedEventDescription(nowUptime));
                            + " " + sr.getShortFgsTimedEventDescription(nowUptime));
                }
                }
                mShortFGSAnrTimer.discard(sr);
                return;
                return;
            }
            }
            Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
            Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
            mShortFGSAnrTimer.accept(sr);
            traceInstant("short FGS timeout: ", sr);
            traceInstant("short FGS timeout: ", sr);


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


            {
            // ServiceRecord.getAnrTime() is an absolute time with a reference that is not "now".
                final Message msg = mAm.mHandler.obtainMessage(
            // Compute the time from "now" when starting the anr timer.
                        ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
            mShortFGSAnrTimer.start(sr,
                mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
                    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
        // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
        // again.
        // again.
        if (r.fgRequired && r.fgWaiting) {
        if (r.fgRequired && r.fgWaiting) {
            mAm.mHandler.removeMessages(
            mServiceFGAnrTimer.cancel(r);
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            r.fgWaiting = false;
            r.fgWaiting = false;
        }
        }


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


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


@@ -6948,26 +6967,46 @@ public final class ActiveServices {
                ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
                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) {
    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
        if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
            return;
            return;
        }
        }
        Message msg = mAm.mHandler.obtainMessage(
        final long delay = proc.mServices.shouldExecServicesFg()
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT;
        msg.obj = proc;
        mActiveServiceAnrTimer.start(proc, delay);
        mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
    }
    }


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


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


@@ -150,7 +150,7 @@ class AnrTimer<V> {
        /** A partial stack that localizes the caller of the operation. */
        /** A partial stack that localizes the caller of the operation. */
        final StackTraceElement[] stack;
        final StackTraceElement[] stack;
        /** The date, in local time, the error was created. */
        /** 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,
        Error(@NonNull String issue, @NonNull String operation, @NonNull String tag,
                @NonNull StackTraceElement[] stack, @NonNull String arg) {
                @NonNull StackTraceElement[] stack, @NonNull String arg) {
@@ -159,7 +159,7 @@ class AnrTimer<V> {
            this.tag = tag;
            this.tag = tag;
            this.stack = stack;
            this.stack = stack;
            this.arg = arg;
            this.arg = arg;
            this.date = new Date().toString();
            this.timestamp = SystemClock.elapsedRealtime();
        }
        }
    }
    }


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


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


        /** Post a message with the specified timeout.  The timer is not modified. */
        /** Post a message with the specified timeout.  The timer is not modified. */
@@ -513,7 +516,26 @@ class AnrTimer<V> {
    private final FeatureSwitch mFeature;
    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
    @VisibleForTesting
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
@@ -522,7 +544,7 @@ class AnrTimer<V> {
        mWhat = what;
        mWhat = what;
        mLabel = label;
        mLabel = label;
        mExtend = extend;
        mExtend = extend;
        boolean enabled = injector.getFeatureEnabled();
        boolean enabled = injector.isFeatureEnabled();
        if (!enabled) {
        if (!enabled) {
            mFeature = new FeatureDisabled();
            mFeature = new FeatureDisabled();
            mTimerService = null;
            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) {
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
        this(handler, what, label, extend, new Injector(handler));
        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) {
    AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
        this(handler, what, label, false);
        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
     * 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
     * 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.
     * deleted if and when the feature is enabled permanently.
     *
     * @return true if the service is flag-enabled.
     */
     */
    boolean serviceEnabled() {
    boolean serviceEnabled() {
        return mFeature.enabled();
        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) {
    private void report(@NonNull Timer timer, @NonNull String msg) {
        Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
        Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
@@ -654,9 +689,13 @@ class AnrTimer<V> {
     */
     */
    private abstract class FeatureSwitch {
    private abstract class FeatureSwitch {
        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs);
        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs);

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

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

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

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


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


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


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


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


        /** The feature is not enabled. */
        /** The feature is not enabled. */
        @Override
        boolean enabled() {
        boolean enabled() {
            return false;
            return false;
        }
        }
@@ -703,16 +747,17 @@ class AnrTimer<V> {
        /**
        /**
         * Start a timer.
         * Start a timer.
         */
         */
        @Override
        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this);
            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this);
            synchronized (mLock) {
            synchronized (mLock) {
                Timer old = mTimerMap.get(arg);
                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) {
                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) {
                    if (old.status == TIMER_EXPIRED) {
                      restartedLocked(old.status, arg);
                        discard(arg);
                        discard(arg);
                    } else {
                    } else {
                        cancel(arg);
                        cancel(arg);
@@ -735,6 +780,7 @@ class AnrTimer<V> {
        /**
        /**
         * Cancel a timer.  Return false if the timer was not found.
         * Cancel a timer.  Return false if the timer was not found.
         */
         */
        @Override
        boolean cancel(@NonNull V arg) {
        boolean cancel(@NonNull V arg) {
            synchronized (mLock) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
                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
         * 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.
         * timeout handler is executing.  Return false if the timer was not found.
         */
         */
        @Override
        boolean accept(@NonNull V arg) {
        boolean accept(@NonNull V arg) {
            synchronized (mLock) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
                Timer timer = removeLocked(arg);
@@ -775,6 +822,7 @@ class AnrTimer<V> {
         * longer interesting.  No statistics are collected.  Return false if the time was not
         * longer interesting.  No statistics are collected.  Return false if the time was not
         * found.
         * found.
         */
         */
        @Override
        boolean discard(@NonNull V arg) {
        boolean discard(@NonNull V arg) {
            synchronized (mLock) {
            synchronized (mLock) {
                Timer timer = removeLocked(arg);
                Timer timer = removeLocked(arg);
@@ -791,40 +839,58 @@ class AnrTimer<V> {
        }
        }


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


    /**
    /**
     * Start a timer associated with arg.  If a timer already exists with the same arg, then that
     * Start a timer associated with arg.  The same object must be used to cancel, accept, or
     * timer is canceled and a new timer is created.  This returns false if the timer cannot be
     * discard a timer later.  If a timer already exists with the same arg, then the existing timer
     * created.
     * 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) {
    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
        return mFeature.start(arg, pid, uid, 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
     * Cancel the running timer associated with arg.  The timer is forgotten.  If the timer has
     * found and false otherwise.  It is not an error to cancel a non-existent timer.  It is also
     * expired, the call is treated as a discard.  No errors are reported if the timer does not
     * not an error to cancel an expired timer.
     * exist or if the timer has expired.
     *
     * @return true if the timer was found and was running.
     */
     */
    boolean cancel(@NonNull V arg) {
    boolean cancel(@NonNull V arg) {
        return mFeature.cancel(arg);
        return mFeature.cancel(arg);
    }
    }


    /**
    /**
     * Accept an expired timer.  This returns false if the timer was not found or if the timer was
     * Accept the expired timer associated with arg.  This indicates that the caller considers the
     * not expired.
     * 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) {
    boolean accept(@NonNull V arg) {
        return mFeature.accept(arg);
        return mFeature.accept(arg);
    }
    }


    /**
    /**
     * Discard an expired timer.  This returns false if the timer was not found or if the timer was
     * Discard the expired timer associated with arg.  This indicates that the caller considers the
     * not expired.
     * 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) {
    boolean discard(@NonNull V arg) {
        return mFeature.discard(arg);
        return mFeature.discard(arg);
@@ -913,7 +979,10 @@ class AnrTimer<V> {
    private static void dump(IndentingPrintWriter ipw, int seq, Error err) {
    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,
        ipw.format("%2d: op:%s tag:%s issue:%s arg:%s\n", seq, err.operation, err.tag,
                err.issue, err.arg);
                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();
        ipw.increaseIndent();
        for (int i = 0; i < err.stack.length; i++) {
        for (int i = 0; i < err.stack.length; i++) {
            ipw.println("    " + err.stack[i].toString());
            ipw.println("    " + err.stack[i].toString());
+10 −5
Original line number Original line 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_PROCESS_FREEZABLE_CHANGED = 6;
    private static final int MSG_UID_STATE_CHANGED = 7;
    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 static final int MSG_DELIVERY_TIMEOUT_SOFT = 8;


    private void enqueueUpdateRunningList() {
    private void enqueueUpdateRunningList() {
@@ -274,7 +275,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                updateRunningList();
                updateRunningList();
                return true;
                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: {
            case MSG_DELIVERY_TIMEOUT_SOFT: {
                synchronized (mService) {
                synchronized (mService) {
                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
@@ -1169,7 +1171,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        r.resultTo = null;
        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,
    private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue,
            int softTimeoutMillis) {
            int softTimeoutMillis) {
        if (mAnrTimer.serviceEnabled()) {
        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) {
    private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
        mAnrTimer.cancel(queue);
        mAnrTimer.cancel(queue);
        if (!mAnrTimer.serviceEnabled()) {
        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,
    private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
            int softTimeoutMillis) {
            int softTimeoutMillis) {
        if (queue.app != null) {
        if (queue.app != null) {
+7 −3

File changed.

Preview size limit exceeded, changes collapsed.