diff options
7 files changed, 107 insertions, 39 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index caaaf519eaca..d4812dd612c3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -50,6 +50,7 @@ import android.app.RemoteServiceException.BadUserInitiatedJobNotificationExcepti import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException; import android.app.RemoteServiceException.CrashedByAdbException; import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException; +import android.app.RemoteServiceException.ForegroundServiceDidNotStopInTimeException; import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; @@ -2236,6 +2237,9 @@ public final class ActivityThread extends ClientTransactionHandler case ForegroundServiceDidNotStartInTimeException.TYPE_ID: throw generateForegroundServiceDidNotStartInTimeException(message, extras); + case ForegroundServiceDidNotStopInTimeException.TYPE_ID: + throw generateForegroundServiceDidNotStopInTimeException(message, extras); + case CannotPostForegroundServiceNotificationException.TYPE_ID: throw new CannotPostForegroundServiceNotificationException(message); @@ -2266,6 +2270,15 @@ public final class ActivityThread extends ClientTransactionHandler throw new ForegroundServiceDidNotStartInTimeException(message, inner); } + private ForegroundServiceDidNotStopInTimeException + generateForegroundServiceDidNotStopInTimeException(String message, Bundle extras) { + final String serviceClassName = + ForegroundServiceDidNotStopInTimeException.getServiceClassNameFromExtras(extras); + final Exception inner = (serviceClassName == null) ? null + : Service.getStartForegroundServiceStackTrace(serviceClassName); + throw new ForegroundServiceDidNotStopInTimeException(message, inner); + } + class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java index c5ad1105397e..c624c43405a3 100644 --- a/core/java/android/app/RemoteServiceException.java +++ b/core/java/android/app/RemoteServiceException.java @@ -71,6 +71,33 @@ public class RemoteServiceException extends AndroidRuntimeException { } /** + * Exception used to crash an app process when it didn't stop after hitting its time limit. + * + * @hide + */ + public static class ForegroundServiceDidNotStopInTimeException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 7; + + private static final String KEY_SERVICE_CLASS_NAME = "serviceclassname"; + + public ForegroundServiceDidNotStopInTimeException(String msg, Throwable cause) { + super(msg, cause); + } + + public static Bundle createExtrasForService(@NonNull ComponentName service) { + Bundle b = new Bundle(); + b.putString(KEY_SERVICE_CLASS_NAME, service.getClassName()); + return b; + } + + @Nullable + public static String getServiceClassNameFromExtras(@Nullable Bundle extras) { + return (extras == null) ? null : extras.getString(KEY_SERVICE_CLASS_NAME); + } + } + + /** * Exception used to crash an app process when the system received a RemoteException * while posting a notification of a foreground service. * diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 726064e39778..aaddaa62a32f 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -1198,8 +1198,7 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * Callback called when a particular foreground service type has timed out. * * <p>This callback is meant to give the app a small grace period of a few seconds to finish - * the foreground service of the associated type - if it fails to do so, the app will be - * declared an ANR. + * the foreground service of the associated type - if it fails to do so, the app will crash. * * <p>The foreground service of the associated type can be stopped within the time limit by * {@link android.app.Service#stopSelf()}, diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig index 9cf83b9c88e9..bb24fd19315e 100644 --- a/core/java/android/app/activity_manager.aconfig +++ b/core/java/android/app/activity_manager.aconfig @@ -60,3 +60,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "backstage_power" + name: "enable_fgs_timeout_crash_behavior" + description: "Enable the new behavior where the app is crashed once an FGS times out." + bug: "339526947" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index bef5c6125551..94bf813d3696 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -157,6 +157,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException; +import android.app.RemoteServiceException.ForegroundServiceDidNotStopInTimeException; import android.app.Service; import android.app.ServiceStartArgs; import android.app.StartForegroundCalledOnStoppedServiceException; @@ -784,7 +785,7 @@ public final class ActiveServices { ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, "SERVICE_FOREGROUND_TIMEOUT"); this.mFGSAnrTimer = new ServiceAnrTimer(service, - ActivityManagerService.SERVICE_FGS_ANR_TIMEOUT_MSG, + ActivityManagerService.SERVICE_FGS_CRASH_TIMEOUT_MSG, "FGS_TIMEOUT"); } @@ -2456,12 +2457,14 @@ public final class ActiveServices { + " foreground service type " + ServiceInfo.foregroundServiceTypeToLabel( foregroundServiceType); - if (!android.app.Flags.gateFgsTimeoutAnrBehavior()) { + // Only throw an exception if the new ANR behavior + // ("do nothing") is not gated or the new crashing logic gate + // is enabled; otherwise, reset the limit temporarily. + if (!android.app.Flags.gateFgsTimeoutAnrBehavior() + || android.app.Flags.enableFgsTimeoutCrashBehavior()) { throw new ForegroundServiceStartNotAllowedException( exceptionMsg); } else { - // Only throw an exception above while the new ANR behavior - // is not gated, otherwise, reset the limit temporarily. Slog.wtf(TAG, exceptionMsg); fgsTypeInfo.reset(); } @@ -3936,12 +3939,12 @@ public final class ActiveServices { Slog.w(TAG_SERVICE, "Exception from scheduleTimeoutServiceForType: " + e); } - // ANR the service after giving the service some time to clean up. - mFGSAnrTimer.start(sr, mAm.mConstants.mFgsAnrExtraWaitDuration); + // Crash the service after giving the service some time to clean up. + mFGSAnrTimer.start(sr, mAm.mConstants.mFgsCrashExtraWaitDuration); } } - void onFgsAnrTimeout(ServiceRecord sr) { + void onFgsCrashTimeout(ServiceRecord sr) { final int fgsType = getTimeLimitedFgsType(sr.foregroundServiceType); if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { return; // no timed out FGS type was found (either it was stopped or it switched types) @@ -3956,20 +3959,36 @@ public final class ActiveServices { return; } - final TimeoutRecord tr = TimeoutRecord.forFgsTimeout(reason); - tr.mLatencyTracker.waitingOnAMSLockStarted(); - synchronized (mAm) { - tr.mLatencyTracker.waitingOnAMSLockEnded(); - - Slog.e(TAG_SERVICE, "FGS ANR'ed: " + sr); - traceInstant("FGS ANR: ", sr); - if (sr.app != null) { - mAm.appNotResponding(sr.app, tr); + if (android.app.Flags.enableFgsTimeoutCrashBehavior()) { + // Crash the app + synchronized (mAm) { + Slog.e(TAG_SERVICE, "FGS Crashed: " + sr); + traceInstant("FGS Crash: ", sr); + if (sr.app != null) { + mAm.crashApplicationWithTypeWithExtras(sr.app.uid, sr.app.getPid(), + sr.app.info.packageName, sr.app.userId, reason, false /*force*/, + ForegroundServiceDidNotStopInTimeException.TYPE_ID, + ForegroundServiceDidNotStopInTimeException + .createExtrasForService(sr.getComponentName())); + } } + } else { + // ANR the app if the new crash behavior is not enabled + final TimeoutRecord tr = TimeoutRecord.forFgsTimeout(reason); + tr.mLatencyTracker.waitingOnAMSLockStarted(); + synchronized (mAm) { + tr.mLatencyTracker.waitingOnAMSLockEnded(); - // TODO: Can we close the ANR dialog here, if it's still shown? Currently, the ANR - // dialog really doesn't remember the "cause" (especially if there have been multiple - // ANRs), so it's not doable. + Slog.e(TAG_SERVICE, "FGS ANR'ed: " + sr); + traceInstant("FGS ANR: ", sr); + if (sr.app != null) { + mAm.appNotResponding(sr.app, tr); + } + + // TODO: Can we close the ANR dialog here, if it's still shown? Currently, the ANR + // dialog really doesn't remember the "cause" (especially if there have been + // multiple ANRs), so it's not doable. + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 9e06b7535cdf..26aa0535d43e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -1115,17 +1115,17 @@ final class ActivityManagerConstants extends ContentObserver { /** * If a service of a timeout-enforced type doesn't finish within this duration after its - * timeout, then we'll declare an ANR. + * timeout, then we'll crash the app. * i.e. if the time limit for a type is 1 hour, and this extra duration is 10 seconds, then - * the app will be ANR'ed 1 hour and 10 seconds after it started. + * the app will crash 1 hour and 10 seconds after it started. */ - private static final String KEY_FGS_ANR_EXTRA_WAIT_DURATION = "fgs_anr_extra_wait_duration"; + private static final String KEY_FGS_CRASH_EXTRA_WAIT_DURATION = "fgs_crash_extra_wait_duration"; - /** @see #KEY_FGS_ANR_EXTRA_WAIT_DURATION */ - static final long DEFAULT_FGS_ANR_EXTRA_WAIT_DURATION = 10_000; + /** @see #KEY_FGS_CRASH_EXTRA_WAIT_DURATION */ + static final long DEFAULT_FGS_CRASH_EXTRA_WAIT_DURATION = 10_000; - /** @see #KEY_FGS_ANR_EXTRA_WAIT_DURATION */ - public volatile long mFgsAnrExtraWaitDuration = DEFAULT_FGS_ANR_EXTRA_WAIT_DURATION; + /** @see #KEY_FGS_CRASH_EXTRA_WAIT_DURATION */ + public volatile long mFgsCrashExtraWaitDuration = DEFAULT_FGS_CRASH_EXTRA_WAIT_DURATION; /** @see #KEY_USE_TIERED_CACHED_ADJ */ public boolean USE_TIERED_CACHED_ADJ = DEFAULT_USE_TIERED_CACHED_ADJ; @@ -1315,8 +1315,8 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_SHORT_FGS_ANR_EXTRA_WAIT_DURATION: updateShortFgsAnrExtraWaitDuration(); break; - case KEY_FGS_ANR_EXTRA_WAIT_DURATION: - updateFgsAnrExtraWaitDuration(); + case KEY_FGS_CRASH_EXTRA_WAIT_DURATION: + updateFgsCrashExtraWaitDuration(); break; case KEY_PROACTIVE_KILLS_ENABLED: updateProactiveKillsEnabled(); @@ -2199,11 +2199,11 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_DATA_SYNC_FGS_TIMEOUT_DURATION); } - private void updateFgsAnrExtraWaitDuration() { - mFgsAnrExtraWaitDuration = DeviceConfig.getLong( + private void updateFgsCrashExtraWaitDuration() { + mFgsCrashExtraWaitDuration = DeviceConfig.getLong( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - KEY_FGS_ANR_EXTRA_WAIT_DURATION, - DEFAULT_FGS_ANR_EXTRA_WAIT_DURATION); + KEY_FGS_CRASH_EXTRA_WAIT_DURATION, + DEFAULT_FGS_CRASH_EXTRA_WAIT_DURATION); } private void updateEnableWaitForFinishAttachApplication() { @@ -2456,8 +2456,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mMediaProcessingFgsTimeoutDuration); pw.print(" "); pw.print(KEY_DATA_SYNC_FGS_TIMEOUT_DURATION); pw.print("="); pw.println(mDataSyncFgsTimeoutDuration); - pw.print(" "); pw.print(KEY_FGS_ANR_EXTRA_WAIT_DURATION); - pw.print("="); pw.println(mFgsAnrExtraWaitDuration); + pw.print(" "); pw.print(KEY_FGS_CRASH_EXTRA_WAIT_DURATION); + pw.print("="); pw.println(mFgsCrashExtraWaitDuration); pw.print(" "); pw.print(KEY_USE_TIERED_CACHED_ADJ); pw.print("="); pw.println(USE_TIERED_CACHED_ADJ); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 00c2df67c8f0..46ed1fd79874 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1670,7 +1670,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int BIND_APPLICATION_TIMEOUT_SOFT_MSG = 82; static final int BIND_APPLICATION_TIMEOUT_HARD_MSG = 83; static final int SERVICE_FGS_TIMEOUT_MSG = 84; - static final int SERVICE_FGS_ANR_TIMEOUT_MSG = 85; + static final int SERVICE_FGS_CRASH_TIMEOUT_MSG = 85; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -2041,8 +2041,8 @@ public class ActivityManagerService extends IActivityManager.Stub case SERVICE_FGS_TIMEOUT_MSG: { mServices.onFgsTimeout((ServiceRecord) msg.obj); } break; - case SERVICE_FGS_ANR_TIMEOUT_MSG: { - mServices.onFgsAnrTimeout((ServiceRecord) msg.obj); + case SERVICE_FGS_CRASH_TIMEOUT_MSG: { + mServices.onFgsCrashTimeout((ServiceRecord) msg.obj); } break; } } |