Loading services/core/java/com/android/server/am/ActiveServices.java +67 −28 Original line number Original line Diff line number Diff line Loading @@ -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<>(); Loading Loading @@ -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() { Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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()); } } } } } Loading Loading @@ -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; } } Loading Loading @@ -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); Loading Loading @@ -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--) { Loading Loading @@ -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() Loading Loading @@ -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); } } } } Loading @@ -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; } } Loading Loading @@ -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 { Loading services/core/java/com/android/server/am/AnrTimer.java +99 −30 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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(); } } } } Loading Loading @@ -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(); } } } } Loading Loading @@ -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. */ Loading Loading @@ -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, Loading @@ -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; Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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)); Loading @@ -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(); } } Loading @@ -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); Loading @@ -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; } } Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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()); Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +10 −5 Original line number Original line Diff line number Diff line Loading @@ -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() { Loading @@ -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); Loading Loading @@ -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()) { Loading @@ -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()) { Loading @@ -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) { Loading services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java +7 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/am/ActiveServices.java +67 −28 Original line number Original line Diff line number Diff line Loading @@ -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<>(); Loading Loading @@ -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() { Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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()); } } } } } Loading Loading @@ -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; } } Loading Loading @@ -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); Loading Loading @@ -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--) { Loading Loading @@ -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() Loading Loading @@ -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); } } } } Loading @@ -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; } } Loading Loading @@ -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 { Loading
services/core/java/com/android/server/am/AnrTimer.java +99 −30 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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(); } } } } Loading Loading @@ -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(); } } } } Loading Loading @@ -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. */ Loading Loading @@ -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, Loading @@ -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; Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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)); Loading @@ -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(); } } Loading @@ -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); Loading @@ -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; } } Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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()); Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +10 −5 Original line number Original line Diff line number Diff line Loading @@ -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() { Loading @@ -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); Loading Loading @@ -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()) { Loading @@ -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()) { Loading @@ -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) { Loading
services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java +7 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes