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

Commit cb7ba3cf authored by Makoto Onuki's avatar Makoto Onuki
Browse files

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
parent b72d65fd
Loading
Loading
Loading
Loading
+7 −2
Original line number Original line Diff line number Diff line
@@ -6684,6 +6684,10 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    @Override
    public void appNotResponding(final String reason) {
    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);
        TimeoutRecord timeoutRecord = TimeoutRecord.forApp("App requested: " + reason);
        final int callingPid = Binder.getCallingPid();
        final int callingPid = Binder.getCallingPid();
@@ -6696,7 +6700,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
            }
            mAnrHelper.appNotResponding(app, null, app.info, null, null, false,
            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,
                mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
                        parentShortComponentName, parentProcess, aboveSystem, timeoutRecord);
                        parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
                        /*isContinuousAnr*/ true);
            }
            }
            return true;
            return true;
+9 −5
Original line number Original line Diff line number Diff line
@@ -96,13 +96,13 @@ class AnrHelper {
    void appNotResponding(ProcessRecord anrProcess, TimeoutRecord timeoutRecord) {
    void appNotResponding(ProcessRecord anrProcess, TimeoutRecord timeoutRecord) {
        appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
        appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
                null /* parentShortComponentName */, null /* parentProcess */,
                null /* parentShortComponentName */, null /* parentProcess */,
                false /* aboveSystem */, timeoutRecord);
                false /* aboveSystem */, timeoutRecord, /*isContinuousAnr*/ false);
    }
    }


    void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
    void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
            ApplicationInfo aInfo, String parentShortComponentName,
            ApplicationInfo aInfo, String parentShortComponentName,
            WindowProcessController parentProcess, boolean aboveSystem,
            WindowProcessController parentProcess, boolean aboveSystem,
            TimeoutRecord timeoutRecord) {
            TimeoutRecord timeoutRecord, boolean isContinuousAnr) {
        try {
        try {
            timeoutRecord.mLatencyTracker.appNotRespondingStarted();
            timeoutRecord.mLatencyTracker.appNotRespondingStarted();
            final int incomingPid = anrProcess.mPid;
            final int incomingPid = anrProcess.mPid;
@@ -132,7 +132,7 @@ class AnrHelper {
                timeoutRecord.mLatencyTracker.anrRecordPlacingOnQueueWithSize(mAnrRecords.size());
                timeoutRecord.mLatencyTracker.anrRecordPlacingOnQueueWithSize(mAnrRecords.size());
                mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                        parentShortComponentName, parentProcess, aboveSystem,
                        parentShortComponentName, parentProcess, aboveSystem,
                        mAuxiliaryTaskExecutor, timeoutRecord));
                        mAuxiliaryTaskExecutor, timeoutRecord, isContinuousAnr));
            }
            }
            startAnrConsumerIfNeeded();
            startAnrConsumerIfNeeded();
        } finally {
        } finally {
@@ -230,10 +230,12 @@ class AnrHelper {
        final boolean mAboveSystem;
        final boolean mAboveSystem;
        final ExecutorService mAuxiliaryTaskExecutor;
        final ExecutorService mAuxiliaryTaskExecutor;
        final long mTimestamp = SystemClock.uptimeMillis();
        final long mTimestamp = SystemClock.uptimeMillis();
        final boolean mIsContinuousAnr;
        AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
        AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
                ApplicationInfo aInfo, String parentShortComponentName,
                ApplicationInfo aInfo, String parentShortComponentName,
                WindowProcessController parentProcess, boolean aboveSystem,
                WindowProcessController parentProcess, boolean aboveSystem,
                ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord) {
                ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord,
                boolean isContinuousAnr) {
            mApp = anrProcess;
            mApp = anrProcess;
            mPid = anrProcess.mPid;
            mPid = anrProcess.mPid;
            mActivityShortComponentName = activityShortComponentName;
            mActivityShortComponentName = activityShortComponentName;
@@ -243,6 +245,7 @@ class AnrHelper {
            mParentProcess = parentProcess;
            mParentProcess = parentProcess;
            mAboveSystem = aboveSystem;
            mAboveSystem = aboveSystem;
            mAuxiliaryTaskExecutor = auxiliaryTaskExecutor;
            mAuxiliaryTaskExecutor = auxiliaryTaskExecutor;
            mIsContinuousAnr = isContinuousAnr;
        }
        }


        void appNotResponding(boolean onlyDumpSelf) {
        void appNotResponding(boolean onlyDumpSelf) {
@@ -250,7 +253,8 @@ class AnrHelper {
                mTimeoutRecord.mLatencyTracker.anrProcessingStarted();
                mTimeoutRecord.mLatencyTracker.anrProcessingStarted();
                mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
                mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
                        mParentShortComponentName, mParentProcess, mAboveSystem,
                        mParentShortComponentName, mParentProcess, mAboveSystem,
                        mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf);
                        mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf,
                        mIsContinuousAnr);
            } finally {
            } finally {
                mTimeoutRecord.mLatencyTracker.anrProcessingEnded();
                mTimeoutRecord.mLatencyTracker.anrProcessingEnded();
            }
            }
+12 −3
Original line number Original line Diff line number Diff line
@@ -169,9 +169,11 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
                            errState.getDialogController().clearAnrDialogs();
                            errState.getDialogController().clearAnrDialogs();
                        }
                        }
                        mService.mServices.scheduleServiceTimeoutLocked(app);
                        mService.mServices.scheduleServiceTimeoutLocked(app);
                        if (mData.isContinuousAnr) {
                            // If the app remains unresponsive, show the dialog again after a delay.
                            // If the app remains unresponsive, show the dialog again after a delay.
                            mService.mInternal.rescheduleAnrDialog(mData);
                            mService.mInternal.rescheduleAnrDialog(mData);
                        }
                        }
                    }
                    break;
                    break;
            }
            }


@@ -197,10 +199,17 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
        final ApplicationInfo aInfo;
        final ApplicationInfo aInfo;
        final boolean aboveSystem;
        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.proc = proc;
            this.aInfo = aInfo;
            this.aInfo = aInfo;
            this.aboveSystem = aboveSystem;
            this.aboveSystem = aboveSystem;
            this.isContinuousAnr = isContinuousAnr;
        }
        }
    }
    }
}
}
+4 −2
Original line number Original line Diff line number Diff line
@@ -263,7 +263,8 @@ class ProcessErrorStateRecord {
    void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
    void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, TimeoutRecord timeoutRecord,
            boolean aboveSystem, TimeoutRecord timeoutRecord,
            ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf) {
            ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf,
            boolean isContinuousAnr) {
        String annotation = timeoutRecord.mReason;
        String annotation = timeoutRecord.mReason;
        AnrLatencyTracker latencyTracker = timeoutRecord.mLatencyTracker;
        AnrLatencyTracker latencyTracker = timeoutRecord.mLatencyTracker;
        Future<?> updateCpuStatsNowFirstCall = null;
        Future<?> updateCpuStatsNowFirstCall = null;
@@ -630,7 +631,8 @@ class ProcessErrorStateRecord {
                // Bring up the infamous App Not Responding dialog
                // Bring up the infamous App Not Responding dialog
                Message msg = Message.obtain();
                Message msg = Message.obtain();
                msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
                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);
                mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
            }
            }
+7 −5
Original line number Original line Diff line number Diff line
@@ -119,12 +119,13 @@ public class AnrHelperTest {
        final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
        final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
                annotation);
                annotation);
        mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
        mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
                parentShortComponentName, parentProcess, aboveSystem, timeoutRecord);
                parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
                /*isContinuousAnr*/ false);


        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
                eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
                eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
                eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mExecutorService),
                eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mExecutorService),
                eq(false) /* onlyDumpSelf */);
                eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/);
    }
    }


    @Test
    @Test
@@ -137,13 +138,14 @@ public class AnrHelperTest {
            processingLatch.await();
            processingLatch.await();
            return null;
            return null;
        }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
        }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
                anyBoolean(), any(), any(), anyBoolean());
                anyBoolean(), any(), any(), anyBoolean(), anyBoolean());
        final ApplicationInfo appInfo = new ApplicationInfo();
        final ApplicationInfo appInfo = new ApplicationInfo();
        final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
        final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
                "annotation");
                "annotation");
        final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
        final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
                "activityShortComponentName", appInfo, "parentShortComponentName",
                "activityShortComponentName", appInfo, "parentShortComponentName",
                null /* parentProcess */, false /* aboveSystem */, timeoutRecord);
                null /* parentProcess */, false /* aboveSystem */, timeoutRecord,
                false /*isContinuousAnr*/);
        reportAnr.run();
        reportAnr.run();
        // This should be skipped because the pid is pending in queue.
        // This should be skipped because the pid is pending in queue.
        reportAnr.run();
        reportAnr.run();
@@ -160,6 +162,6 @@ public class AnrHelperTest {
        // There is only one ANR reported.
        // There is only one ANR reported.
        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
                anyString(), any(), any(), any(), anyBoolean(), any(), eq(mExecutorService),
                anyString(), any(), any(), any(), anyBoolean(), any(), eq(mExecutorService),
                anyBoolean());
                anyBoolean(), anyBoolean());
    }
    }
}
}
Loading