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

Commit 173ae780 authored by Charles Chen's avatar Charles Chen
Browse files

Enable show error dialogs on the secondary display

There are four kinds of error dialogs showing on devices. We'll take different approaches on them:

1. AppErrorDialog: show on displays with app crashed windows. If none, show on the last used display.
2. AppAnrDialog: show on displays with ANR windows. If none, show on the last used display.
   For background ANR(if users enable it), show on the last used display.
3. StrictModeViolationDialog: show on displays with violated app located.
   If none, show on the last used display.
4. DebugWaitingDialog: show on the last used display.

Also introduce ErrorDialogController to consolidate error dialog logic
in ProcessRecord and use another variable for StrictModeViolationDialog.

fixes 117877476
Test: atest ProcessRecordTests AppErrorDialogTest
Test: atest AmStartOptionsTests#testDashD

Change-Id: Iddd3a2ce0d1037a9a294ce6cb51f181f998cd42e
parent 247901bb
Loading
Loading
Loading
Loading
+64 −86
Original line number Diff line number Diff line
@@ -158,7 +158,6 @@ import android.app.ApplicationErrorReport;
import android.app.ApplicationThreadConstants;
import android.app.BroadcastOptions;
import android.app.ContentProviderHolder;
import android.app.Dialog;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IApplicationThread;
@@ -1635,16 +1634,13 @@ public class ActivityManagerService extends IActivityManager.Stub
                            Slog.e(TAG, "App not found when showing strict mode dialog.");
                            break;
                        }
                    if (proc.crashDialog != null) {
                        if (proc.getDialogController().hasViolationDialogs()) {
                            Slog.e(TAG, "App already has strict mode dialog: " + proc);
                            return;
                        }
                        AppErrorResult res = (AppErrorResult) data.get("result");
                        if (mAtmInternal.showStrictModeViolationDialog()) {
                        Dialog d = new StrictModeViolationDialog(mUiContext,
                                ActivityManagerService.this, res, proc);
                        d.show();
                        proc.crashDialog = d;
                            proc.getDialogController().showViolationDialogs(res);
                        } else {
                            // The device is asleep, so just pretend that the user
                            // saw a crash dialog and hit "force quit".
@@ -1658,18 +1654,11 @@ public class ActivityManagerService extends IActivityManager.Stub
                        ProcessRecord app = (ProcessRecord) msg.obj;
                        if (msg.arg1 != 0) {
                            if (!app.waitedForDebugger) {
                            Dialog d = new AppWaitingForDebuggerDialog(
                                    ActivityManagerService.this,
                                    mUiContext, app);
                            app.waitDialog = d;
                                app.getDialogController().showDebugWaitingDialogs();
                                app.waitedForDebugger = true;
                            d.show();
                            }
                        } else {
                        if (app.waitDialog != null) {
                            app.waitDialog.dismiss();
                            app.waitDialog = null;
                        }
                            app.getDialogController().clearWaitingDialog();
                        }
                    }
                } break;
@@ -9367,9 +9356,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
    void killAppAtUsersRequest(ProcessRecord app) {
        synchronized (this) {
            mAppErrors.killAppAtUserRequestLocked(app, fromDialog);
            mAppErrors.killAppAtUserRequestLocked(app);
        }
    }
@@ -13991,18 +13980,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        ProcessList.abortNextPssTime(app.procStateMemTracker);
        // Dismiss any open dialogs.
        if (app.crashDialog != null && !app.forceCrashReport) {
            app.crashDialog.dismiss();
            app.crashDialog = null;
        }
        if (app.anrDialog != null) {
            app.anrDialog.dismiss();
            app.anrDialog = null;
        }
        if (app.waitDialog != null) {
            app.waitDialog.dismiss();
            app.waitDialog = null;
        }
        app.getDialogController().clearAllErrorDialogs();
        app.setCrashing(false);
        app.setNotResponding(false);
+4 −2
Original line number Diff line number Diff line
@@ -167,8 +167,10 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen

    private void setResult(int result) {
        synchronized (mService) {
            if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
                mProc.crashDialog = null;
            if (mProc != null) {
                // Don't dismiss again since it leads to recursive call between dismiss and this
                // method.
                mProc.getDialogController().clearCrashDialogs(false /* needDismiss */);
            }
        }
        mResult.set(result);
+7 −25
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_N
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -313,13 +312,8 @@ class AppErrors {
        }
    }

    void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
        if (app.anrDialog == fromDialog) {
            app.anrDialog = null;
        }
        if (app.waitDialog == fromDialog) {
            app.waitDialog = null;
        }
    void killAppAtUserRequestLocked(ProcessRecord app) {
        app.getDialogController().clearAllErrorDialogs();
        killAppImmediateLocked(app, "user-terminated", "user request after error");
    }

@@ -795,7 +789,6 @@ class AppErrors {
        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;

        AppErrorDialog dialogToShow = null;
        final String packageName;
        final int userId;
        synchronized (mService) {
@@ -807,7 +800,7 @@ class AppErrors {
            }
            packageName = proc.info.packageName;
            userId = proc.userId;
            if (proc.crashDialog != null) {
            if (proc.getDialogController().hasCrashDialogs()) {
                Slog.e(TAG, "App already has crash dialog: " + proc);
                if (res != null) {
                    res.set(AppErrorDialog.ALREADY_SHOWING);
@@ -840,7 +833,7 @@ class AppErrors {
            if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
                    && !crashSilenced
                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
                proc.crashDialog = dialogToShow = new AppErrorDialog(mContext, mService, data);
                proc.getDialogController().showCrashDialogs(data);
            } else {
                // The device is asleep, so just pretend that the user
                // saw a crash dialog and hit "force quit".
@@ -849,11 +842,6 @@ class AppErrors {
                }
            }
        }
        // If we've created a crash dialog, show it without the lock held
        if (dialogToShow != null) {
            Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId);
            dialogToShow.show();
        }
    }

    private void stopReportingCrashesLocked(ProcessRecord proc) {
@@ -864,7 +852,6 @@ class AppErrors {
    }

    void handleShowAnrUi(Message msg) {
        Dialog dialogToShow = null;
        List<VersionedPackage> packageList = null;
        synchronized (mService) {
            AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
@@ -876,7 +863,7 @@ class AppErrors {
            if (!proc.isPersistent()) {
                packageList = proc.getPackageListWithVersionCode();
            }
            if (proc.anrDialog != null) {
            if (proc.getDialogController().hasAnrDialogs()) {
                Slog.e(TAG, "App already has anr dialog: " + proc);
                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                        AppNotRespondingDialog.ALREADY_SHOWING);
@@ -886,18 +873,13 @@ class AppErrors {
            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
            if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
                dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
                proc.anrDialog = dialogToShow;
                proc.getDialogController().showAnrDialogs(data);
            } else {
                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                        AppNotRespondingDialog.CANT_SHOW);
                // Just kill the app if there is no dialog to be shown.
                mService.killAppAtUsersRequest(proc, null);
            }
                mService.killAppAtUsersRequest(proc);
            }
        // If we've created a crash dialog, show it without the lock held
        if (dialogToShow != null) {
            dialogToShow.show();
        }
        // Notify PackageWatchdog without the lock held
        if (packageList != null) {
+6 −8
Original line number Diff line number Diff line
@@ -16,13 +16,10 @@

package com.android.server.am;

import android.content.pm.ApplicationInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
@@ -35,6 +32,9 @@ import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;

final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnClickListener {
    private static final String TAG = "AppNotRespondingDialog";

@@ -145,7 +145,7 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
            switch (msg.what) {
                case FORCE_CLOSE:
                    // Kill the application.
                    mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this);
                    mService.killAppAtUsersRequest(mProc);
                    break;
                case WAIT_AND_REPORT:
                case WAIT:
@@ -160,9 +160,7 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli

                        app.setNotResponding(false);
                        app.notRespondingReport = null;
                        if (app.anrDialog == AppNotRespondingDialog.this) {
                            app.anrDialog = null;
                        }
                        app.getDialogController().clearAnrDialogs();
                        mService.mServices.scheduleServiceTimeoutLocked(app);
                    }
                    break;
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ final class AppWaitingForDebuggerDialog extends BaseErrorDialog {
            switch (msg.what) {
                case 1:
                    // Kill the application.
                    mService.killAppAtUsersRequest(mProc, AppWaitingForDebuggerDialog.this);
                    mService.killAppAtUsersRequest(mProc);
                    break;
            }
        }
Loading