diff options
| author | 2023-01-11 14:11:35 -0800 | |
|---|---|---|
| committer | 2023-01-17 12:00:10 -0800 | |
| commit | cb7ba3cfd5cd16f9b64db6dad363da9db5be13c4 (patch) | |
| tree | 8b0cd5bde4187b8ff83f222c3d41adb02fb520b5 | |
| parent | b72d65fd3014d61356bcdc67cf40714cd81b50b6 (diff) | |
Do not repeat ANR dialogs, except for "input" ANRs
The ANR dialog's behavior changed in
I4ca34bb8cc60bcde3ff571566553f44246d78ddc such that even if the user
presses "wait" on the ANR dialog, the dialog will re-appear unless the
app starts responding again.
However, the "stop the repeat" was only implemented for input ANRs,
so for other kinds of ANRs (e.g. the broadcast ANR), the dialog would
keep showing up even after the app starts behaving normally.
This change will change the behavior so that only input ANRs will
repeatedly show up.
Fix: 263182141
Test: Manual test: Make shore "short service" ANR dialog will not repeat
Test: Manual test: Make shore input ANR dialog will actually repeat
Test: atest FrameworksServicesTests:AnrHelperTest
Test: atest FrameworksServicesTests:ProcessRecordTests
Change-Id: Id9b34cef605a65ff29b5569e72945790695d7abf
6 files changed, 41 insertions, 18 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fc6d30bf58c9..1e3f69fc173b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6684,6 +6684,10 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void appNotResponding(final String reason) { + appNotResponding(reason, /*isContinuousAnr*/ false); + } + + public void appNotResponding(final String reason, boolean isContinuousAnr) { TimeoutRecord timeoutRecord = TimeoutRecord.forApp("App requested: " + reason); final int callingPid = Binder.getCallingPid(); @@ -6696,7 +6700,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mAnrHelper.appNotResponding(app, null, app.info, null, null, false, - timeoutRecord); + timeoutRecord, isContinuousAnr); } } @@ -18325,7 +18329,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo, - parentShortComponentName, parentProcess, aboveSystem, timeoutRecord); + parentShortComponentName, parentProcess, aboveSystem, timeoutRecord, + /*isContinuousAnr*/ true); } return true; diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java index 71c80ea4f045..463a2f84aa6b 100644 --- a/services/core/java/com/android/server/am/AnrHelper.java +++ b/services/core/java/com/android/server/am/AnrHelper.java @@ -96,13 +96,13 @@ class AnrHelper { void appNotResponding(ProcessRecord anrProcess, TimeoutRecord timeoutRecord) { appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */, null /* parentShortComponentName */, null /* parentProcess */, - false /* aboveSystem */, timeoutRecord); + false /* aboveSystem */, timeoutRecord, /*isContinuousAnr*/ false); } void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, - TimeoutRecord timeoutRecord) { + TimeoutRecord timeoutRecord, boolean isContinuousAnr) { try { timeoutRecord.mLatencyTracker.appNotRespondingStarted(); final int incomingPid = anrProcess.mPid; @@ -132,7 +132,7 @@ class AnrHelper { timeoutRecord.mLatencyTracker.anrRecordPlacingOnQueueWithSize(mAnrRecords.size()); mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo, parentShortComponentName, parentProcess, aboveSystem, - mAuxiliaryTaskExecutor, timeoutRecord)); + mAuxiliaryTaskExecutor, timeoutRecord, isContinuousAnr)); } startAnrConsumerIfNeeded(); } finally { @@ -230,10 +230,12 @@ class AnrHelper { final boolean mAboveSystem; final ExecutorService mAuxiliaryTaskExecutor; final long mTimestamp = SystemClock.uptimeMillis(); + final boolean mIsContinuousAnr; AnrRecord(ProcessRecord anrProcess, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, - ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord) { + ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord, + boolean isContinuousAnr) { mApp = anrProcess; mPid = anrProcess.mPid; mActivityShortComponentName = activityShortComponentName; @@ -243,6 +245,7 @@ class AnrHelper { mParentProcess = parentProcess; mAboveSystem = aboveSystem; mAuxiliaryTaskExecutor = auxiliaryTaskExecutor; + mIsContinuousAnr = isContinuousAnr; } void appNotResponding(boolean onlyDumpSelf) { @@ -250,7 +253,8 @@ class AnrHelper { mTimeoutRecord.mLatencyTracker.anrProcessingStarted(); mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo, mParentShortComponentName, mParentProcess, mAboveSystem, - mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf); + mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf, + mIsContinuousAnr); } finally { mTimeoutRecord.mLatencyTracker.anrProcessingEnded(); } diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index 5fe842752e81..d3e91da3d330 100644 --- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java @@ -169,8 +169,10 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli errState.getDialogController().clearAnrDialogs(); } mService.mServices.scheduleServiceTimeoutLocked(app); - // If the app remains unresponsive, show the dialog again after a delay. - mService.mInternal.rescheduleAnrDialog(mData); + if (mData.isContinuousAnr) { + // If the app remains unresponsive, show the dialog again after a delay. + mService.mInternal.rescheduleAnrDialog(mData); + } } break; } @@ -197,10 +199,17 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli final ApplicationInfo aInfo; final boolean aboveSystem; - Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem) { + // If true, then even if the user presses "WAIT" on the ANR dialog, + // we'll show it again until the app start responding again. + // (we only use it for input dispatch ANRs) + final boolean isContinuousAnr; + + Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem, + boolean isContinuousAnr) { this.proc = proc; this.aInfo = aInfo; this.aboveSystem = aboveSystem; + this.isContinuousAnr = isContinuousAnr; } } } diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 68d906be65de..9bb63d306f3c 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -263,7 +263,8 @@ class ProcessErrorStateRecord { void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, TimeoutRecord timeoutRecord, - ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf) { + ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf, + boolean isContinuousAnr) { String annotation = timeoutRecord.mReason; AnrLatencyTracker latencyTracker = timeoutRecord.mLatencyTracker; Future<?> updateCpuStatsNowFirstCall = null; @@ -630,7 +631,8 @@ class ProcessErrorStateRecord { // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; - msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem); + msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem, + isContinuousAnr); mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs); } diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java index e6ab73a6f924..162855a7caa7 100644 --- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java @@ -119,12 +119,13 @@ public class AnrHelperTest { final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive( annotation); mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo, - parentShortComponentName, parentProcess, aboveSystem, timeoutRecord); + parentShortComponentName, parentProcess, aboveSystem, timeoutRecord, + /*isContinuousAnr*/ false); verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding( eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName), eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mExecutorService), - eq(false) /* onlyDumpSelf */); + eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/); } @Test @@ -137,13 +138,14 @@ public class AnrHelperTest { processingLatch.await(); return null; }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(), - anyBoolean(), any(), any(), anyBoolean()); + anyBoolean(), any(), any(), anyBoolean(), anyBoolean()); final ApplicationInfo appInfo = new ApplicationInfo(); final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive( "annotation"); final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp, "activityShortComponentName", appInfo, "parentShortComponentName", - null /* parentProcess */, false /* aboveSystem */, timeoutRecord); + null /* parentProcess */, false /* aboveSystem */, timeoutRecord, + false /*isContinuousAnr*/); reportAnr.run(); // This should be skipped because the pid is pending in queue. reportAnr.run(); @@ -160,6 +162,6 @@ public class AnrHelperTest { // There is only one ANR reported. verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding( anyString(), any(), any(), any(), anyBoolean(), any(), eq(mExecutorService), - anyBoolean()); + anyBoolean(), anyBoolean()); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java index 9cada91f1db0..6350e225a429 100644 --- a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java @@ -202,6 +202,7 @@ public class ProcessRecordTests { TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchNoFocusedWindow(annotation); processErrorState.appNotResponding(null /* activityShortComponentName */, null /* aInfo */, null /* parentShortComponentName */, null /* parentProcess */, - false /* aboveSystem */, timeoutRecord, mExecutorService, false /* onlyDumpSelf */); + false /* aboveSystem */, timeoutRecord, mExecutorService, false /* onlyDumpSelf */, + false /*isContinuousAnr*/); } } |