From c3a06e515666f999e6080ea71ca2a55a7d62338b Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 16 Feb 2018 18:33:17 +0100 Subject: [PATCH] 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 --- .../core/java/com/android/server/am/AppErrors.java | 59 ++++++++++++---------- .../android/server/am/AppNotRespondingDialog.java | 36 ++++++++----- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 9776c4d2f947..ed098795d1d8 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -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 map = new HashMap(); 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 data = (HashMap) 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(); } } diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index d9c6a3023903..8a88a69a7d82 100644 --- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java @@ -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; + } + } } -- 2.11.0