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

Commit c3a06e51 authored by Adrian Roos's avatar Adrian Roos
Browse files

Fix crash in AppErrors and clean up code

Fixes a crash in AppError's handleShowAppErrorUi due to missing serialization.

Also cleans up handleShowAnrUi.

Change-Id: Ie23a38a33d334ff328563b631fbf11454e7e4031
Fixes: 73050378
Test: manual; crash app / ANR app, verify dialog still works
parent ee3a2ba9
Loading
Loading
Loading
Loading
+32 −27
Original line number Diff line number Diff line
@@ -793,10 +793,20 @@ class AppErrors {
        AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
        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) {
            ProcessRecord proc = data.proc;
            AppErrorResult res = data.result;
            if (proc != null && proc.crashDialog != null) {
            final ProcessRecord proc = data.proc;
            final AppErrorResult res = data.result;
            if (proc == null) {
                Slog.e(TAG, "handleShowAppErrorUi: proc is null");
                return;
            }
            packageName = proc.info.packageName;
            userId = proc.userId;
            if (proc.crashDialog != null) {
                Slog.e(TAG, "App already has crash dialog: " + proc);
                if (res != null) {
                    res.set(AppErrorDialog.ALREADY_SHOWING);
@@ -806,8 +816,8 @@ class AppErrors {
            boolean isBackground = (UserHandle.getAppId(proc.uid)
                    >= Process.FIRST_APPLICATION_UID
                    && proc.pid != MY_PID);
            for (int userId : mService.mUserController.getCurrentProfileIds()) {
                isBackground &= (proc.userId != userId);
            for (int profileId : mService.mUserController.getCurrentProfileIds()) {
                isBackground &= (userId != profileId);
            }
            if (isBackground && !showBackground) {
                Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
@@ -828,7 +838,7 @@ class AppErrors {
                    mAppsNotReportingCrashes.contains(proc.info.packageName);
            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
                proc.crashDialog = new AppErrorDialog(mContext, mService, data);
                proc.crashDialog = dialogToShow = new AppErrorDialog(mContext, mService, data);
            } else {
                // The device is asleep, so just pretend that the user
                // saw a crash dialog and hit "force quit".
@@ -838,10 +848,9 @@ class AppErrors {
            }
        }
        // If we've created a crash dialog, show it without the lock held
        if(data.proc.crashDialog != null) {
            Slog.i(TAG, "Showing crash dialog for package " + data.proc.info.packageName
                    + " u" + data.proc.userId);
            data.proc.crashDialog.show();
        if (dialogToShow != null) {
            Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId);
            dialogToShow.show();
        }
    }

@@ -1071,14 +1080,8 @@ class AppErrors {

            // Bring up the infamous App Not Responding dialog
            Message msg = Message.obtain();
            HashMap<String, Object> map = new HashMap<String, Object>();
            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = map;
            msg.arg1 = aboveSystem ? 1 : 0;
            map.put("app", app);
            if (activity != null) {
                map.put("activity", activity);
            }
            msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);

            mService.mUiHandler.sendMessage(msg);
        }
@@ -1095,11 +1098,15 @@ class AppErrors {
    }

    void handleShowAnrUi(Message msg) {
        Dialog d = null;
        Dialog dialogToShow = null;
        synchronized (mService) {
            HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
            ProcessRecord proc = (ProcessRecord)data.get("app");
            if (proc != null && proc.anrDialog != null) {
            AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
            final ProcessRecord proc = data.proc;
            if (proc == null) {
                Slog.e(TAG, "handleShowAnrUi: proc is null");
                return;
            }
            if (proc.anrDialog != null) {
                Slog.e(TAG, "App already has anr dialog: " + proc);
                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                        AppNotRespondingDialog.ALREADY_SHOWING);
@@ -1118,10 +1125,8 @@ class AppErrors {
            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
            if (mService.canShowErrorDialogs() || showBackground) {
                d = new AppNotRespondingDialog(mService,
                        mContext, proc, (ActivityRecord)data.get("activity"),
                        msg.arg1 != 0);
                proc.anrDialog = d;
                dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
                proc.anrDialog = dialogToShow;
            } else {
                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                        AppNotRespondingDialog.CANT_SHOW);
@@ -1130,8 +1135,8 @@ class AppErrors {
            }
        }
        // If we've created a crash dialog, show it without the lock held
        if (d != null) {
            d.show();
        if (dialogToShow != null) {
            dialogToShow.show();
        }
    }

+23 −13
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import com.android.internal.logging.nano.MetricsProto;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
@@ -49,36 +48,35 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
    private final ActivityManagerService mService;
    private final ProcessRecord mProc;

    public AppNotRespondingDialog(ActivityManagerService service, Context context,
            ProcessRecord app, ActivityRecord activity, boolean aboveSystem) {
    public AppNotRespondingDialog(ActivityManagerService service, Context context, Data data) {
        super(context);

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

        setCancelable(false);

        int resid;
        CharSequence name1 = activity != null
                ? activity.info.loadLabel(context.getPackageManager())
        CharSequence name1 = data.activity != null
                ? data.activity.info.loadLabel(context.getPackageManager())
                : null;
        CharSequence name2 = null;
        if ((app.pkgList.size() == 1) &&
                (name2=context.getPackageManager().getApplicationLabel(app.info)) != null) {
        if ((mProc.pkgList.size() == 1) &&
                (name2=context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
            if (name1 != null) {
                resid = com.android.internal.R.string.anr_activity_application;
            } else {
                name1 = name2;
                name2 = app.processName;
                name2 = mProc.processName;
                resid = com.android.internal.R.string.anr_application_process;
            }
        } else {
            if (name1 != null) {
                name2 = app.processName;
                name2 = mProc.processName;
                resid = com.android.internal.R.string.anr_activity_process;
            } else {
                name1 = app.processName;
                name1 = mProc.processName;
                resid = com.android.internal.R.string.anr_process;
            }
        }
@@ -89,11 +87,11 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
                ? res.getString(resid, bidi.unicodeWrap(name1.toString()), bidi.unicodeWrap(name2.toString()))
                : res.getString(resid, bidi.unicodeWrap(name1.toString())));

        if (aboveSystem) {
        if (data.aboveSystem) {
            getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
        }
        WindowManager.LayoutParams attrs = getWindow().getAttributes();
        attrs.setTitle("Application Not Responding: " + app.info.processName);
        attrs.setTitle("Application Not Responding: " + mProc.info.processName);
        attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
        getWindow().setAttributes(attrs);
@@ -180,4 +178,16 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
            dismiss();
        }
    };

    static class Data {
        final ProcessRecord proc;
        final ActivityRecord activity;
        final boolean aboveSystem;

        Data(ProcessRecord proc, ActivityRecord activity, boolean aboveSystem) {
            this.proc = proc;
            this.activity = activity;
            this.aboveSystem = aboveSystem;
        }
    }
}