From 89f6bfea0750a84654cb3a7c80d3dff191a9814c Mon Sep 17 00:00:00 2001 From: Zim Date: Mon, 26 Jun 2023 22:38:42 +0100 Subject: [PATCH] Add a new ANR category on BIND_APPLICATION_TIMEOUT In 6c8b9089701172796c0a520a790112465c431ccb we enabled the feature to delay scheduling Broadcasts or Services to an app during startup until after after its bindApplication. This mitigates Broadcast and Service ANRs caused by slow app startup. What would have been an ANR is now treated as a slow process startup and apps don't have any visibility into that. We now add a new timeout, BIND_APPLICATION_TIMEOUT that starts counting after we call bindApplication on the app. If we hit the timeout, it means the app took too long to run its app startup code and we trigger an ANR so that apps can get explicit feedback on their apps. Note that the PROC_START_TIMEOUT which always existed now only gets triggered if we don't get to call bindApplication on the app. This indicates an OS problem that apps cannot do anything about. Test: atest ActivityManagerTest Bug: 253908737 Change-Id: Iaad8d39221dc9b3877d784d8a79f8de1678eea88 --- .../android/internal/os/TimeoutRecord.java | 7 ++++++ .../server/am/ActivityManagerService.java | 23 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/java/com/android/internal/os/TimeoutRecord.java b/core/java/com/android/internal/os/TimeoutRecord.java index a0e29347d07f8..f8a5520c26d50 100644 --- a/core/java/com/android/internal/os/TimeoutRecord.java +++ b/core/java/com/android/internal/os/TimeoutRecord.java @@ -58,6 +58,7 @@ public class TimeoutRecord { int APP_REGISTERED = 7; int SHORT_FGS_TIMEOUT = 8; int JOB_SERVICE = 9; + int APP_START = 10; } /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ @@ -186,4 +187,10 @@ public class TimeoutRecord { public static TimeoutRecord forJobService(String reason) { return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason); } + + /** Record for app startup timeout. */ + @NonNull + public static TimeoutRecord forAppStart(String reason) { + return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason); + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7ba720eedfba8..81858ee6e2c92 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -559,6 +559,10 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real. static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + + // How long we wait for a launched process to complete its app startup before we ANR. + static final int BIND_APPLICATION_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + // How long we wait to kill an application zygote, after the last process using // it has gone away. static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; @@ -1624,6 +1628,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79; static final int ADD_UID_TO_OBSERVER_MSG = 80; static final int REMOVE_UID_FROM_OBSERVER_MSG = 81; + static final int BIND_APPLICATION_TIMEOUT_MSG = 82; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1976,6 +1981,16 @@ public class ActivityManagerService extends IActivityManager.Stub case UPDATE_CACHED_APP_HIGH_WATERMARK: { mAppProfiler.mCachedAppsWatermarkData.updateCachedAppsSnapshot((long) msg.obj); } break; + case BIND_APPLICATION_TIMEOUT_MSG: { + ProcessRecord app = (ProcessRecord) msg.obj; + + final String anrMessage; + synchronized (app) { + anrMessage = "Process " + app + " failed to complete startup"; + } + + mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage)); + } break; } } } @@ -4734,6 +4749,12 @@ public class ActivityManagerService extends IActivityManager.Stub app.getDisabledCompatChanges(), serializedSystemFontMap, app.getStartElapsedTime(), app.getStartUptime()); } + + Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_MSG); + msg.obj = app; + mHandler.sendMessageDelayed(msg, BIND_APPLICATION_TIMEOUT); + mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); + if (profilerInfo != null) { profilerInfo.closeFd(); profilerInfo = null; @@ -4808,7 +4829,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app != null && app.getStartUid() == uid && app.getStartSeq() == startSeq) { - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); + mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_MSG, app); } else { Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid + ". Uid: " + uid);