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

Commit eb918da0 authored by Lingyu Feng's avatar Lingyu Feng Committed by Android (Google) Code Review
Browse files

Merge "Move error dialogs to default display when connected display is...

Merge "Move error dialogs to default display when connected display is switched to mirroring" into main
parents 828bad5e a8b00124
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -696,6 +696,17 @@ public abstract class ActivityManagerInternal {
     */
    public abstract void rescheduleAnrDialog(Object data);

    /**
     * Move all the error dialogs (including {@code com.android.server.am.AppErrorDialog},
     * {@code com.android.server.am.AppNotRespondingDialog},
     * {@code com.android.server.am.StrictModeViolationDialog},
     * and {@code com.android.server.am.AppWaitingForDebuggerDialog}) to the default display.
     *
     * @param displayId The display id of the display where the error dialogs are showing and need
     *                  to be moved.
     */
    public abstract void moveErrorDialogsToDefaultDisplay(int displayId);

    /**
     * Sends {@link android.content.Intent#ACTION_CONFIGURATION_CHANGED} with all the appropriate
     * flags.
+16 −0
Original line number Diff line number Diff line
@@ -17431,6 +17431,22 @@ public class ActivityManagerService extends IActivityManager.Stub
            mUiHandler.sendMessageDelayed(msg, InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
        }
        @Override
        public void moveErrorDialogsToDefaultDisplay(int displayId) {
            mUiHandler.post(() -> {
                synchronized (mProcLock) {
                    mProcessList.forEachLruProcessesLOSP(false, app -> {
                        if (app.getThread() == null) {
                            return;
                        }
                        ErrorDialogController controller = app.mErrorState.getDialogController();
                        controller.moveAllErrorDialogsToDefaultDisplay(displayId);
                    });
                }
            });
        }
        @Override
        public void broadcastGlobalConfigurationChanged(int changes, boolean initLocale) {
            synchronized (ActivityManagerService.this) {
+11 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen

    private final ActivityManagerService mService;
    private final ActivityManagerGlobalLock mProcLock;
    private final Data mData;
    private final AppErrorResult mResult;
    private final ProcessRecord mProc;
    private final boolean mIsRestartable;
@@ -62,6 +63,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen

        mService = service;
        mProcLock = service.mProcLock;
        mData = data;
        mProc = data.proc;
        mResult = data.result;
        mIsRestartable = (data.taskId != INVALID_TASK_ID || data.isRestartableForService)
@@ -151,6 +153,15 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
        super.dismiss();
    }

    void remove() {
        // Only dismiss the dialog to remove the window from the display, do not set result.
        super.dismiss();
    }

    Data getData() {
        return mData;
    }

    private void setResult(int result) {
        synchronized (mProcLock) {
            if (mProc != null) {
+4 −0
Original line number Diff line number Diff line
@@ -137,6 +137,10 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
        }
    }

    Data getData() {
        return mData;
    }

    private final Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            Intent appErrorIntent = null;
+164 −0
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.server.am;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AnrController;
import android.app.Dialog;
import android.content.Context;
import android.view.Display;

import com.android.internal.annotations.GuardedBy;

@@ -104,6 +106,22 @@ final class ErrorDialogController {
        clearWaitingDialog();
    }

    /**
     * If there are any error dialogs on the display, close them and show a corresponding new one on
     * the default display if one doesn't already exist there.
     */
    @GuardedBy("mProcLock")
    void moveAllErrorDialogsToDefaultDisplay(int displayId) {
        if (displayId == Display.DEFAULT_DISPLAY) {
            return;
        }

        moveCrashDialogToDefaultDisplay(displayId);
        moveAnrDialogToDefaultDisplay(displayId);
        moveViolationDialogToDefaultDisplay(displayId);
        moveWaitingDialogToDefaultDisplay(displayId);
    }

    @GuardedBy("mProcLock")
    void clearCrashDialogs() {
        clearCrashDialogs(true /* needDismiss */);
@@ -236,6 +254,152 @@ final class ErrorDialogController {
        mAnrController = controller;
    }

    @GuardedBy("mProcLock")
    @Nullable
    private <T extends BaseErrorDialog> T findDialogOnDisplay(@NonNull List<T> dialogs,
            int displayId) {
        for (int i = dialogs.size() - 1; i >= 0; i--) {
            T dialog = dialogs.get(i);
            if (dialog == null) {
                continue;
            }

            if (dialog.getContext().getDisplayId() == displayId && dialog.isShowing()) {
                return dialog;
            }
        }
        return null;
    }

    /**
     * If a crash dialog is showing on the display, close it and show a new one on the default
     * display if one doesn't already exist there.
     *
     * @param displayId The display id of the display where the crash dialog is showing and needs to
     *                  be moved.
     */
    @GuardedBy("mProcLock")
    private void  moveCrashDialogToDefaultDisplay(int displayId) {
        if (!hasCrashDialogs()) {
            return;
        }

        AppErrorDialog dialogToRemoved = findDialogOnDisplay(mCrashDialogs, displayId);
        if (dialogToRemoved == null) {
            return;
        }
        AppErrorDialog.Data data = dialogToRemoved.getData();
        mCrashDialogs.remove(dialogToRemoved);
        mService.mUiHandler.post(dialogToRemoved::remove);

        boolean showingInDefaultDisplay =
                (findDialogOnDisplay(mCrashDialogs, Display.DEFAULT_DISPLAY) != null);
        if (showingInDefaultDisplay || data == null) {
            return;
        }

        // If there is no crash dialog showing in the default display, show a new one.
        // TODO(b/412589019): Use WindowContext instead.
        Context c = mService.mWmInternal.getDisplayUiContext(Display.DEFAULT_DISPLAY);
        AppErrorDialog newDialog = new AppErrorDialog(c, mService, data);
        mCrashDialogs.add(newDialog);
        mService.mUiHandler.post(newDialog::show);
    }

    /**
     * If a ANR dialog is showing on the display, close it and show a new one on the default display
     * if one doesn't already exist there.
     *
     * @param displayId The display id of the display where the ANR dialog is showing and needs to
     *                  be moved.
     */
    @GuardedBy("mProcLock")
    private void moveAnrDialogToDefaultDisplay(int displayId) {
        if (!hasAnrDialogs()) {
            return;
        }

        AppNotRespondingDialog dialogToRemoved = findDialogOnDisplay(mAnrDialogs, displayId);
        if (dialogToRemoved == null) {
            return;
        }
        AppNotRespondingDialog.Data data = dialogToRemoved.getData();
        mAnrDialogs.remove(dialogToRemoved);
        mService.mUiHandler.post(dialogToRemoved::dismiss);

        boolean showingInDefaultDisplay =
                (findDialogOnDisplay(mAnrDialogs, Display.DEFAULT_DISPLAY) != null);
        if (showingInDefaultDisplay || data == null) {
            return;
        }

        // If there is no ANR dialog showing in the default display, show a new one.
        // TODO(b/412589019): Use WindowContext instead.
        Context c = mService.mWmInternal.getDisplayUiContext(Display.DEFAULT_DISPLAY);
        AppNotRespondingDialog newDialog = new AppNotRespondingDialog(mService, c, data);
        mAnrDialogs.add(newDialog);
        mService.mUiHandler.post(newDialog::show);
    }

    /**
     * If a strict mode violation dialog is showing on the display, close it and show a new one on
     * the default display if one doesn't already exist there.
     *
     * @param displayId The display id of the display where the violation dialog is showing and
     *                  needs to be moved.
     */
    @GuardedBy("mProcLock")
    private void moveViolationDialogToDefaultDisplay(int displayId) {
        if (!hasViolationDialogs()) {
            return;
        }

        StrictModeViolationDialog dialogToRemoved =
                findDialogOnDisplay(mViolationDialogs, displayId);
        if (dialogToRemoved == null) {
            return;
        }
        AppErrorResult result = dialogToRemoved.getResult();
        mViolationDialogs.remove(dialogToRemoved);
        mService.mUiHandler.post(dialogToRemoved::dismiss);

        boolean showingInDefaultDisplay =
                (findDialogOnDisplay(mViolationDialogs, Display.DEFAULT_DISPLAY) != null);
        if (showingInDefaultDisplay || result == null) {
            return;
        }

        // If there is no violation dialog showing in the default display, show a new one.
        // TODO(b/412589019): Use WindowContext instead.
        Context c = mService.mWmInternal.getDisplayUiContext(Display.DEFAULT_DISPLAY);
        StrictModeViolationDialog newDialog =
                new StrictModeViolationDialog(c, mService, result, mApp);
        mViolationDialogs.add(newDialog);
        mService.mUiHandler.post(newDialog::show);
    }

    /**
     * If a debug waiting dialog is showing on the display, close it and show a new one on the
     * default display if one doesn't already exist there.
     *
     * @param displayId The display id of the display where the waiting dialog is showing and needs
     *                  to be moved.
     */
    @GuardedBy("mProcLock")
    private void moveWaitingDialogToDefaultDisplay(int displayId) {
        if (mWaitDialog == null || mWaitDialog.getContext().getDisplayId() != displayId) {
            return;
        }

        // The debug waiting dialog is showing on the display, remove this and show a new one on the
        // default display.
        mWaitDialog.dismiss();
        Context c = mService.mWmInternal.getDisplayUiContext(Display.DEFAULT_DISPLAY);
        mWaitDialog = new AppWaitingForDebuggerDialog(mService, c, mApp);
        mService.mUiHandler.post(mWaitDialog::show);
    }


    /**
     * Helper function to collect contexts from crashed app located displays.
     *
Loading