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

Commit b9c0eaa8 authored by Varun Shah's avatar Varun Shah
Browse files

Add logic to re-raise ANR dialogs if the user taps wait.

When the user taps "wait" on the ANR dialog, redisplay the dialog
after a specified timeout (currently 5 seconds). If the app becomes
responsive, cancel any pending delayed dialogs and dismiss the
dialog if it's currently visible.

Bug: 171218828
Test: manual (test app)
Test: atest AnrTest
Change-Id: I4ca34bb8cc60bcde3ff571566553f44246d78ddc
parent 077c6329
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -411,6 +411,13 @@ public abstract class ActivityManagerInternal {
     */
    public abstract void inputDispatchingResumed(int pid);

    /**
     * User tapped "wait" in the ANR dialog - reschedule the dialog to be shown again at a later
     * time.
     * @param data AppNotRespondingDialog.Data object
     */
    public abstract void rescheduleAnrDialog(Object data);

    /**
     * Sends {@link android.content.Intent#ACTION_CONFIGURATION_CHANGED} with all the appropriate
     * flags.
+17 −2
Original line number Diff line number Diff line
@@ -257,6 +257,7 @@ import android.os.IDeviceIdentifiersPolicyService;
import android.os.IPermissionController;
import android.os.IProcessInfoService;
import android.os.IProgressListener;
import android.os.InputConstants;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -15985,8 +15986,22 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        public void inputDispatchingResumed(int pid) {
            // TODO (b/171218828)
            return;
            final ProcessRecord proc;
            synchronized (mPidsSelfLocked) {
                proc = mPidsSelfLocked.get(pid);
            }
            if (proc != null) {
                mAppErrors.handleDismissAnrDialogs(proc);
            }
        }
        @Override
        public void rescheduleAnrDialog(Object data) {
            Message msg = Message.obtain();
            msg.what = SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = (AppNotRespondingDialog.Data) data;
            mUiHandler.sendMessageDelayed(msg, InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
        }
        @Override
+19 −0
Original line number Diff line number Diff line
@@ -1058,6 +1058,7 @@ class AppErrors {
        }
        synchronized (mProcLock) {
            final ProcessErrorStateRecord errState = proc.mErrorState;
            errState.setAnrData(data);
            if (!proc.isPersistent()) {
                packageList = proc.getPackageListWithVersionCode();
            }
@@ -1109,6 +1110,24 @@ class AppErrors {
        }
    }

    void handleDismissAnrDialogs(ProcessRecord proc) {
        synchronized (mProcLock) {
            final ProcessErrorStateRecord errState = proc.mErrorState;

            // Cancel any rescheduled ANR dialogs
            mService.mUiHandler.removeMessages(
                    ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG, errState.getAnrData());

            // Dismiss any ANR dialogs currently visible
            if (errState.getDialogController().hasAnrDialogs()) {
                errState.setNotResponding(false);
                errState.setNotRespondingReport(null);
                errState.getDialogController().clearAnrDialogs();
            }
            proc.mErrorState.setAnrData(null);
        }
    }

    /**
     * Information about a process that is currently marked as bad.
     */
+4 −0
Original line number Diff line number Diff line
@@ -48,12 +48,14 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli

    private final ActivityManagerService mService;
    private final ProcessRecord mProc;
    private final Data mData;

    public AppNotRespondingDialog(ActivityManagerService service, Context context, Data data) {
        super(context);

        mService = service;
        mProc = data.proc;
        mData = data;
        Resources res = context.getResources();

        setCancelable(false);
@@ -165,6 +167,8 @@ 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);
                    }
                    break;
            }
+16 −0
Original line number Diff line number Diff line
@@ -116,6 +116,12 @@ class ProcessErrorStateRecord {
    @CompositeRWLock({"mService", "mProcLock"})
    private ComponentName mErrorReportReceiver;

    /**
     * ANR dialog data used to dismiss any visible ANR dialogs if the app becomes responsive.
     */
    @CompositeRWLock({"mService", "mProcLock"})
    private AppNotRespondingDialog.Data mAnrData;

    /**
     * Optional local handler to be invoked in the process crash.
     */
@@ -209,6 +215,16 @@ class ProcessErrorStateRecord {
        return mDialogController;
    }

    @GuardedBy({"mService", "mProcLock"})
    void setAnrData(AppNotRespondingDialog.Data data) {
        mAnrData = data;
    }

    @GuardedBy(anyOf = {"mService", "mProcLock"})
    AppNotRespondingDialog.Data getAnrData() {
        return mAnrData;
    }

    ProcessErrorStateRecord(ProcessRecord app) {
        mApp = app;
        mService = app.mService;
Loading