From 51cc98adbe85abba702efb121fd0366263bc7d7a Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Mon, 15 Oct 2018 10:41:05 -0700 Subject: [PATCH] Moved appNotResponding handling into ProcessRecord (23/n) Allows for better seperation of AMS and ATMS, also the method mostly accessed internal variables in ProcessRecord so it make sense for it to be in that class. Also, move inputDispatchingTimedOut back to AM side because it involves lots of process stuff. Test: Existing test pass Bug: 80414790 Change-Id: I45b98dc550ff121e9df4bf004b2667af2426b79d --- .../android/app/ActivityManagerInternal.java | 6 + .../java/com/android/server/Watchdog.java | 2 +- .../com/android/server/am/ActiveServices.java | 4 +- .../server/am/ActivityManagerService.java | 117 ++++++-- .../com/android/server/am/ActivityRecord.java | 8 +- .../server/am/ActivityTaskManagerService.java | 84 +----- .../java/com/android/server/am/AppErrors.java | 267 +---------------- .../server/am/AppNotRespondingDialog.java | 11 +- .../com/android/server/am/BroadcastQueue.java | 2 +- .../com/android/server/am/ProcessRecord.java | 273 ++++++++++++++++++ .../server/am/WindowProcessController.java | 15 + .../server/am/WindowProcessListener.java | 5 + .../wm/ActivityTaskManagerInternal.java | 1 - .../server/wm/InputManagerCallback.java | 2 +- 14 files changed, 425 insertions(+), 372 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 7ae2ded9f241d..d00650d40d8f8 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -244,4 +244,10 @@ public abstract class ActivityManagerInternal { public abstract void updateOomLevelsForDisplay(int displayId); public abstract boolean isActivityStartsLoggingEnabled(); public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing); + + /** Input dispatch timeout to a window, start the ANR process. */ + public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason); + public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName, + ApplicationInfo aInfo, String parentShortComponentName, Object parentProc, + boolean aboveSystem, String reason); } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 0b836f0d186fb..9cc550daa5a71 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -528,7 +528,7 @@ public class Watchdog extends Thread { Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { mActivity.addErrorToDropBox( - "watchdog", null, "system_server", null, null, + "watchdog", null, "system_server", null, null, null, subject, null, stack, null); } }; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f4ec1f9d5b279..7235312363120 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3641,7 +3641,7 @@ public final class ActiveServices { } if (anrMessage != null) { - mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage); + proc.appNotResponding(null, null, null, null, false, anrMessage); } } @@ -3666,7 +3666,7 @@ public final class ActiveServices { } if (app != null) { - mAm.mAppErrors.appNotResponding(app, null, null, false, + app.appNotResponding(null, null, null, null, false, "Context.startForegroundService() did not then call Service.startForeground(): " + r); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 248678767b586..877d1f44c021a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.Manifest.permission.CHANGE_CONFIGURATION; import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; +import static android.Manifest.permission.FILTER_EVENTS; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; @@ -148,6 +149,7 @@ import static com.android.server.am.ActivityTaskManagerService.DUMP_LASTANR_TRAC import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_CMD; import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD; import static com.android.server.am.ActivityTaskManagerService.DUMP_STARTER_CMD; +import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; import static com.android.server.am.MemoryStatUtil.hasMemcg; import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; @@ -8119,8 +8121,8 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.post(new Runnable() { @Override public void run() { - mAppErrors.appNotResponding(host, null, null, false, - "ContentProvider not responding"); + host.appNotResponding( + null, null, null, null, false, "ContentProvider not responding"); } }); } @@ -9790,7 +9792,8 @@ public class ActivityManagerService extends IActivityManager.Stub crashInfo.crashTag = crashInfo.crashTag + " " + relaunchReasonString; } - addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo); + addErrorToDropBox( + eventType, r, processName, null, null, null, null, null, null, crashInfo); mAppErrors.crashApplication(r, crashInfo); } @@ -9962,7 +9965,7 @@ public class ActivityManagerService extends IActivityManager.Stub StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName, callingPid); - addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo); + addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo); return r; } @@ -10061,17 +10064,18 @@ public class ActivityManagerService extends IActivityManager.Stub * Write a description of an error (crash, WTF, ANR) to the drop box. * @param eventType to include in the drop box tag ("crash", "wtf", etc.) * @param process which caused the error, null means the system server - * @param activity which triggered the error, null if unknown - * @param parent activity related to the error, null if unknown + * @param activityShortComponentName which triggered the error, null if unknown + * @param parentShortComponentName activity related to the error, null if unknown + * @param parentProcess parent process * @param subject line related to the error, null if absent * @param report in long form describing the error, null if absent * @param dataFile text file to include in the report, null if none * @param crashInfo giving an application stack trace, null if absent */ public void addErrorToDropBox(String eventType, - ProcessRecord process, String processName, ActivityRecord activity, - ActivityRecord parent, String subject, - final String report, final File dataFile, + ProcessRecord process, String processName, String activityShortComponentName, + String parentShortComponentName, ProcessRecord parentProcess, + String subject, final String report, final File dataFile, final ApplicationErrorReport.CrashInfo crashInfo) { // NOTE -- this must never acquire the ActivityManagerService lock, // otherwise the watchdog may be prevented from resetting the system. @@ -10101,14 +10105,16 @@ public class ActivityManagerService extends IActivityManager.Stub .append(process.isInterestingToUserLocked() ? "Yes" : "No") .append("\n"); } - if (activity != null) { - sb.append("Activity: ").append(activity.shortComponentName).append("\n"); + if (activityShortComponentName != null) { + sb.append("Activity: ").append(activityShortComponentName).append("\n"); } - if (parent != null && parent.app != null && parent.app.getPid() != process.pid) { - sb.append("Parent-Process: ").append(parent.app.mName).append("\n"); - } - if (parent != null && parent != activity) { - sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n"); + if (parentShortComponentName != null) { + if (parentProcess != null && parentProcess.pid != process.pid) { + sb.append("Parent-Process: ").append(parentProcess.processName).append("\n"); + } + if (!parentShortComponentName.equals(activityShortComponentName)) { + sb.append("Parent-Activity: ").append(parentShortComponentName).append("\n"); + } } if (subject != null) { sb.append("Subject: ").append(subject).append("\n"); @@ -13983,7 +13989,7 @@ public class ActivityManagerService extends IActivityManager.Stub dropBuilder.append(catSw.toString()); StatsLog.write(StatsLog.LOW_MEM_REPORTED); addErrorToDropBox("lowmem", null, "system_server", null, - null, tag.toString(), dropBuilder.toString(), null, null); + null, null, tag.toString(), dropBuilder.toString(), null, null); //Slog.i(TAG, "Sent to dropbox:"); //Slog.i(TAG, dropBuilder.toString()); synchronized (ActivityManagerService.this) { @@ -20295,6 +20301,83 @@ public class ActivityManagerService extends IActivityManager.Stub : UsageEvents.Event.KEYGUARD_HIDDEN); } } + + @Override + public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) { + synchronized (ActivityManagerService.this) { + return ActivityManagerService.this.inputDispatchingTimedOut( + pid, aboveSystem, reason); + } + } + + @Override + public boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName, + ApplicationInfo aInfo, String parentShortComponentName, Object parentProc, + boolean aboveSystem, String reason) { + return ActivityManagerService.this.inputDispatchingTimedOut((ProcessRecord) proc, + activityShortComponentName, aInfo, parentShortComponentName, + (WindowProcessController) parentProc, aboveSystem, reason); + + } + } + + long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { + if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + FILTER_EVENTS); + } + ProcessRecord proc; + long timeout; + synchronized (this) { + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(pid); + } + timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS; + } + + if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) { + return -1; + } + + return timeout; + } + + /** + * Handle input dispatching timeouts. + * @return whether input dispatching should be aborted or not. + */ + boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName, + ApplicationInfo aInfo, String parentShortComponentName, + WindowProcessController parentProcess, boolean aboveSystem, String reason) { + if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + FILTER_EVENTS); + } + + final String annotation; + if (reason == null) { + annotation = "Input dispatching timed out"; + } else { + annotation = "Input dispatching timed out (" + reason + ")"; + } + + if (proc != null) { + synchronized (this) { + if (proc.isDebugging()) { + return false; + } + + if (proc.getActiveInstrumentation() != null) { + Bundle info = new Bundle(); + info.putString("shortMsg", "keyDispatchingTimedOut"); + info.putString("longMsg", annotation); + finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info); + return true; + } + } + proc.appNotResponding(activityShortComponentName, aInfo, + parentShortComponentName, parentProcess, aboveSystem, annotation); + } + + return true; } /** diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index d837118f05d46..966cbd198673d 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -2114,12 +2114,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo windowFromSameProcessAsActivity = !hasProcess() || app.getPid() == windowPid || windowPid == -1; } + if (windowFromSameProcessAsActivity) { - return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason); + return service.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner, + anrActivity.shortComponentName, anrActivity.appInfo, shortComponentName, + app, false, reason); } else { // In this case another process added windows using this activity token. So, we call the // generic service input dispatch timed out method so that the right process is blamed. - return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0; + return service.mAmInternal.inputDispatchingTimedOut( + windowPid, false /* aboveSystem */, reason) < 0; } } diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index b7bbfe8feed07..cb729a85ef827 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -295,9 +295,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; // How long we wait until we timeout on key dispatching. - private static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000; + public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000; // How long we wait until we timeout on key dispatching during instrumentation. - private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000; + static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000; /** Used to indicate that an app transition should be animated. */ static final boolean ANIMATE = true; @@ -4932,70 +4932,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } private static long getInputDispatchingTimeoutLocked(WindowProcessController r) { - if (r != null && (r.isInstrumenting() || r.isUsingWrapper())) { - return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; - } - return KEY_DISPATCHING_TIMEOUT_MS; - } - - long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { - if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " + FILTER_EVENTS); - } - WindowProcessController proc; - long timeout; - synchronized (mGlobalLock) { - proc = mPidMap.get(pid); - timeout = getInputDispatchingTimeoutLocked(proc); - } - - if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) { - return -1; - } - - return timeout; - } - - /** - * Handle input dispatching timeouts. - * Returns whether input dispatching should be aborted or not. - */ - boolean inputDispatchingTimedOut(final WindowProcessController proc, - final ActivityRecord activity, final ActivityRecord parent, - final boolean aboveSystem, String reason) { - if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " + FILTER_EVENTS); - } - - final String annotation; - if (reason == null) { - annotation = "Input dispatching timed out"; - } else { - annotation = "Input dispatching timed out (" + reason + ")"; - } - - if (proc != null) { - synchronized (mGlobalLock) { - if (proc.isDebugging()) { - return false; - } - - if (proc.isInstrumenting()) { - Bundle info = new Bundle(); - info.putString("shortMsg", "keyDispatchingTimedOut"); - info.putString("longMsg", annotation); - mAm.finishInstrumentationLocked( - (ProcessRecord) proc.mOwner, Activity.RESULT_CANCELED, info); - return true; - } - } - mH.post(() -> { - mAm.mAppErrors.appNotResponding( - (ProcessRecord) proc.mOwner, activity, parent, aboveSystem, annotation); - }); - } - - return true; + return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS; } /** @@ -6030,14 +5967,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - @Override - public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) { - synchronized (mGlobalLock) { - return ActivityTaskManagerService.this.inputDispatchingTimedOut( - pid, aboveSystem, reason); - } - } - @Override public void onProcessMapped(int pid, WindowProcessController proc) { synchronized (mGlobalLock) { @@ -6619,19 +6548,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (mHomeProcess != null && (dumpPackage == null || mHomeProcess.mPkgList.contains(dumpPackage))) { - ((ProcessRecord) mHomeProcess.mOwner).writeToProto(proto, HOME_PROC); + mHomeProcess.writeToProto(proto, HOME_PROC); } if (mPreviousProcess != null && (dumpPackage == null || mPreviousProcess.mPkgList.contains(dumpPackage))) { - ((ProcessRecord) mPreviousProcess.mOwner).writeToProto(proto, PREVIOUS_PROC); + mPreviousProcess.writeToProto(proto, PREVIOUS_PROC); proto.write(PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime); } if (mHeavyWeightProcess != null && (dumpPackage == null || mHeavyWeightProcess.mPkgList.contains(dumpPackage))) { - ((ProcessRecord) mHeavyWeightProcess.mOwner).writeToProto( - proto, HEAVY_WEIGHT_PROC); + mHeavyWeightProcess.writeToProto(proto, HEAVY_WEIGHT_PROC); } for (Map.Entry entry diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index be1f9ea9e1343..feea3bd6e802b 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -582,27 +582,12 @@ class AppErrors { app.setCrashing(true); app.crashingReport = generateProcessError(app, ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); - startAppProblemLocked(app); + app.startAppProblemLocked(); app.getWindowProcessController().stopFreezingActivities(); return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace, data); } - void startAppProblemLocked(ProcessRecord app) { - // If this app is not running under the current user, then we - // can't give it a report button because that would require - // launching the report UI under a different user. - app.errorReportReceiver = null; - - for (int userId : mService.mUserController.getCurrentProfileIds()) { - if (app.userId == userId) { - app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( - mContext, app.info.packageName, app.info.flags); - } - } - mService.skipCurrentReceiverLocked(app); - } - /** * Generate a process error record, suitable for attachment to a ProcessRecord. * @@ -616,7 +601,7 @@ class AppErrors { * * @return Returns a fully-formed ProcessErrorStateInfo record. */ - private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app, + ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app, int condition, String activity, String shortMsg, String longMsg, String stackTrace) { ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo(); @@ -855,259 +840,13 @@ class AppErrors { } } - void stopReportingCrashesLocked(ProcessRecord proc) { + private void stopReportingCrashesLocked(ProcessRecord proc) { if (mAppsNotReportingCrashes == null) { mAppsNotReportingCrashes = new ArraySet<>(); } mAppsNotReportingCrashes.add(proc.info.packageName); } - static boolean isInterestingForBackgroundTraces(ProcessRecord app) { - // The system_server is always considered interesting. - if (app.pid == MY_PID) { - return true; - } - - // A package is considered interesting if any of the following is true : - // - // - It's displaying an activity. - // - It's the SystemUI. - // - It has an overlay or a top UI visible. - // - // NOTE: The check whether a given ProcessRecord belongs to the systemui - // process is a bit of a kludge, but the same pattern seems repeated at - // several places in the system server. - return app.isInterestingToUserLocked() || - (app.info != null && "com.android.systemui".equals(app.info.packageName)) || - (app.hasTopUi() || app.hasOverlayUi()); - } - - final void appNotResponding(ProcessRecord app, ActivityRecord activity, - ActivityRecord parent, boolean aboveSystem, final String annotation) { - ArrayList firstPids = new ArrayList(5); - SparseArray lastPids = new SparseArray(20); - - if (mService.mActivityTaskManager.mController != null) { - try { - // 0 == continue, -1 = kill process immediately - int res = mService.mActivityTaskManager.mController.appEarlyNotResponding( - app.processName, app.pid, annotation); - if (res < 0 && app.pid != MY_PID) { - app.kill("anr", true); - } - } catch (RemoteException e) { - mService.mActivityTaskManager.mController = null; - Watchdog.getInstance().setActivityController(null); - } - } - - long anrTime = SystemClock.uptimeMillis(); - if (ActivityManagerService.MONITOR_CPU_USAGE) { - mService.updateCpuStatsNow(); - } - - // Unless configured otherwise, swallow ANRs in background processes & kill the process. - boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; - - boolean isSilentANR; - - synchronized (mService) { - // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. - if (mService.mActivityTaskManager.mShuttingDown) { - Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation); - return; - } else if (app.isNotResponding()) { - Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation); - return; - } else if (app.isCrashing()) { - Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation); - return; - } else if (app.killedByAm) { - Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation); - return; - } else if (app.killed) { - Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation); - return; - } - - // In case we come through here for the same app before completing - // this one, mark as anring now so we will bail out. - app.setNotResponding(true); - - // Log the ANR to the event log. - EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid, - app.processName, app.info.flags, annotation); - - // Dump thread traces as quickly as we can, starting with "interesting" processes. - firstPids.add(app.pid); - - // Don't dump other PIDs if it's a background ANR - isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app); - if (!isSilentANR) { - int parentPid = app.pid; - if (parent != null && parent.app != null && parent.app.getPid() > 0) { - parentPid = parent.app.getPid(); - } - if (parentPid != app.pid) firstPids.add(parentPid); - - if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); - - for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) { - ProcessRecord r = mService.mLruProcesses.get(i); - if (r != null && r.thread != null) { - int pid = r.pid; - if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) { - if (r.isPersistent()) { - firstPids.add(pid); - if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); - } else if (r.treatLikeActivity) { - firstPids.add(pid); - if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r); - } else { - lastPids.put(pid, Boolean.TRUE); - if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); - } - } - } - } - } - } - - // Log the ANR to the main log. - StringBuilder info = new StringBuilder(); - info.setLength(0); - info.append("ANR in ").append(app.processName); - if (activity != null && activity.shortComponentName != null) { - info.append(" (").append(activity.shortComponentName).append(")"); - } - info.append("\n"); - info.append("PID: ").append(app.pid).append("\n"); - if (annotation != null) { - info.append("Reason: ").append(annotation).append("\n"); - } - if (parent != null && parent != activity) { - info.append("Parent: ").append(parent.shortComponentName).append("\n"); - } - - ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); - - // don't dump native PIDs for background ANRs unless it is the process of interest - String[] nativeProcs = null; - if (isSilentANR) { - for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { - if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) { - nativeProcs = new String[] { app.processName }; - break; - } - } - } else { - nativeProcs = NATIVE_STACKS_OF_INTEREST; - } - - int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs); - ArrayList nativePids = null; - - if (pids != null) { - nativePids = new ArrayList(pids.length); - for (int i : pids) { - nativePids.add(i); - } - } - - // For background ANRs, don't pass the ProcessCpuTracker to - // avoid spending 1/2 second collecting stats to rank lastPids. - File tracesFile = ActivityManagerService.dumpStackTraces( - firstPids, - (isSilentANR) ? null : processCpuTracker, - (isSilentANR) ? null : lastPids, - nativePids); - - String cpuInfo = null; - if (ActivityManagerService.MONITOR_CPU_USAGE) { - mService.updateCpuStatsNow(); - synchronized (mService.mProcessCpuTracker) { - cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime); - } - info.append(processCpuTracker.printCurrentLoad()); - info.append(cpuInfo); - } - - info.append(processCpuTracker.printCurrentState(anrTime)); - - Slog.e(TAG, info.toString()); - if (tracesFile == null) { - // There is no trace file, so dump (only) the alleged culprit's threads to the log - Process.sendSignal(app.pid, Process.SIGNAL_QUIT); - } - - StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName, - activity == null ? "unknown": activity.shortComponentName, annotation, - (app.info != null) ? (app.info.isInstantApp() - ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE - : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE) - : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE, - app != null ? (app.isInterestingToUserLocked() - ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND - : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND) - : StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN); - mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation, - cpuInfo, tracesFile, null); - - if (mService.mActivityTaskManager.mController != null) { - try { - // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately - int res = mService.mActivityTaskManager.mController.appNotResponding( - app.processName, app.pid, info.toString()); - if (res != 0) { - if (res < 0 && app.pid != MY_PID) { - app.kill("anr", true); - } else { - synchronized (mService) { - mService.mServices.scheduleServiceTimeoutLocked(app); - } - } - return; - } - } catch (RemoteException e) { - mService.mActivityTaskManager.mController = null; - Watchdog.getInstance().setActivityController(null); - } - } - - synchronized (mService) { - mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid); - - if (isSilentANR) { - app.kill("bg anr", true); - return; - } - - // Set the app's notResponding state, and look up the errorReportReceiver - makeAppNotRespondingLocked(app, - activity != null ? activity.shortComponentName : null, - annotation != null ? "ANR " + annotation : "ANR", - info.toString()); - - // Bring up the infamous App Not Responding dialog - Message msg = Message.obtain(); - msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; - msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem); - - mService.mUiHandler.sendMessage(msg); - } - } - - private void makeAppNotRespondingLocked(ProcessRecord app, - String activity, String shortMsg, String longMsg) { - app.setNotResponding(true); - app.notRespondingReport = generateProcessError(app, - ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, - activity, shortMsg, longMsg, null); - startAppProblemLocked(app); - app.getWindowProcessController().stopFreezingActivities(); - } - void handleShowAnrUi(Message msg) { Dialog dialogToShow = null; synchronized (mService) { diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index 7c983ff427ad5..cb76e2fafebdc 100644 --- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.content.pm.ApplicationInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -58,8 +59,8 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli setCancelable(false); int resid; - CharSequence name1 = data.activity != null - ? data.activity.info.loadLabel(context.getPackageManager()) + CharSequence name1 = data.aInfo != null + ? data.aInfo.loadLabel(context.getPackageManager()) : null; CharSequence name2 = null; if ((mProc.pkgList.size() == 1) && @@ -181,12 +182,12 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli static class Data { final ProcessRecord proc; - final ActivityRecord activity; + final ApplicationInfo aInfo; final boolean aboveSystem; - Data(ProcessRecord proc, ActivityRecord activity, boolean aboveSystem) { + Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem) { this.proc = proc; - this.activity = activity; + this.aInfo = aInfo; this.aboveSystem = aboveSystem; } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index e2035f67031af..a13cf4d3d2d15 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -191,7 +191,7 @@ public final class BroadcastQueue { @Override public void run() { - mService.mAppErrors.appNotResponding(mApp, null, null, false, mAnnotation); + mApp.appNotResponding(null, null, null, null, false, mAnnotation); } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 145791cdc9431..1aa538d4abd1f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -18,10 +18,14 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityManagerService.MY_PID; import android.app.ActivityManager; +import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.IApplicationThread; import android.content.ComponentName; @@ -32,16 +36,19 @@ import android.content.res.Configuration; import android.os.Binder; import android.os.Debug; import android.os.IBinder; +import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.EventLog; import android.util.Slog; +import android.util.SparseArray; import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -49,7 +56,10 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.ProcessCpuTracker; +import com.android.server.Watchdog; +import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -735,6 +745,7 @@ final class ProcessRecord implements WindowProcessListener { } } + @Override public void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); proto.write(ProcessRecordProto.PID, pid); @@ -1168,4 +1179,266 @@ final class ProcessRecord implements WindowProcessListener { public long getCpuTime() { return mService.mProcessCpuTracker.getCpuTimeForPid(pid); } + + public long getInputDispatchingTimeout() { + return mWindowProcessController.getInputDispatchingTimeout(); + } + + void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, + String parentShortComponentName, WindowProcessController parentProcess, + boolean aboveSystem, String annotation) { + ArrayList firstPids = new ArrayList<>(5); + SparseArray lastPids = new SparseArray<>(20); + + if (mService.mActivityTaskManager.mController != null) { + try { + // 0 == continue, -1 = kill process immediately + int res = mService.mActivityTaskManager.mController.appEarlyNotResponding( + processName, pid, annotation); + if (res < 0 && pid != MY_PID) { + kill("anr", true); + } + } catch (RemoteException e) { + mService.mActivityTaskManager.mController = null; + Watchdog.getInstance().setActivityController(null); + } + } + + long anrTime = SystemClock.uptimeMillis(); + if (ActivityManagerService.MONITOR_CPU_USAGE) { + mService.updateCpuStatsNow(); + } + + // Unless configured otherwise, swallow ANRs in background processes & kill the process. + boolean showBackground = Settings.Secure.getInt(mService.mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + + boolean isSilentANR; + + synchronized (mService) { + // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. + if (mService.mActivityTaskManager.mShuttingDown) { + Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation); + return; + } else if (isNotResponding()) { + Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation); + return; + } else if (isCrashing()) { + Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation); + return; + } else if (killedByAm) { + Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation); + return; + } else if (killed) { + Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation); + return; + } + + // In case we come through here for the same app before completing + // this one, mark as anring now so we will bail out. + setNotResponding(true); + + // Log the ANR to the event log. + EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags, + annotation); + + // Dump thread traces as quickly as we can, starting with "interesting" processes. + firstPids.add(pid); + + // Don't dump other PIDs if it's a background ANR + isSilentANR = !showBackground && !isInterestingForBackgroundTraces(); + if (!isSilentANR) { + int parentPid = pid; + if (parentProcess != null && parentProcess.getPid() > 0) { + parentPid = parentProcess.getPid(); + } + if (parentPid != pid) firstPids.add(parentPid); + + if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID); + + for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) { + ProcessRecord r = mService.mLruProcesses.get(i); + if (r != null && r.thread != null) { + int myPid = r.pid; + if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) { + if (r.isPersistent()) { + firstPids.add(myPid); + if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); + } else if (r.treatLikeActivity) { + firstPids.add(myPid); + if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r); + } else { + lastPids.put(myPid, Boolean.TRUE); + if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); + } + } + } + } + } + } + + // Log the ANR to the main log. + StringBuilder info = new StringBuilder(); + info.setLength(0); + info.append("ANR in ").append(processName); + if (activityShortComponentName != null) { + info.append(" (").append(activityShortComponentName).append(")"); + } + info.append("\n"); + info.append("PID: ").append(pid).append("\n"); + if (annotation != null) { + info.append("Reason: ").append(annotation).append("\n"); + } + if (parentShortComponentName != null + && parentShortComponentName.equals(activityShortComponentName)) { + info.append("Parent: ").append(parentShortComponentName).append("\n"); + } + + ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); + + // don't dump native PIDs for background ANRs unless it is the process of interest + String[] nativeProcs = null; + if (isSilentANR) { + for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { + if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) { + nativeProcs = new String[] { processName }; + break; + } + } + } else { + nativeProcs = NATIVE_STACKS_OF_INTEREST; + } + + int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs); + ArrayList nativePids = null; + + if (pids != null) { + nativePids = new ArrayList<>(pids.length); + for (int i : pids) { + nativePids.add(i); + } + } + + // For background ANRs, don't pass the ProcessCpuTracker to + // avoid spending 1/2 second collecting stats to rank lastPids. + File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, + (isSilentANR) ? null : processCpuTracker, (isSilentANR) ? null : lastPids, + nativePids); + + String cpuInfo = null; + if (ActivityManagerService.MONITOR_CPU_USAGE) { + mService.updateCpuStatsNow(); + synchronized (mService.mProcessCpuTracker) { + cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime); + } + info.append(processCpuTracker.printCurrentLoad()); + info.append(cpuInfo); + } + + info.append(processCpuTracker.printCurrentState(anrTime)); + + Slog.e(TAG, info.toString()); + if (tracesFile == null) { + // There is no trace file, so dump (only) the alleged culprit's threads to the log + Process.sendSignal(pid, Process.SIGNAL_QUIT); + } + + StatsLog.write(StatsLog.ANR_OCCURRED, uid, processName, + activityShortComponentName == null ? "unknown": activityShortComponentName, + annotation, + (this.info != null) ? (this.info.isInstantApp() + ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE + : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE) + : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE, + isInterestingToUserLocked() + ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND + : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND); + mService.addErrorToDropBox("anr", this, processName, activityShortComponentName, + parentShortComponentName, (ProcessRecord) parentProcess.mOwner, annotation, + cpuInfo, tracesFile, null); + + if (mService.mActivityTaskManager.mController != null) { + try { + // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately + int res = mService.mActivityTaskManager.mController.appNotResponding( + processName, pid, info.toString()); + if (res != 0) { + if (res < 0 && pid != MY_PID) { + kill("anr", true); + } else { + synchronized (mService) { + mService.mServices.scheduleServiceTimeoutLocked(this); + } + } + return; + } + } catch (RemoteException e) { + mService.mActivityTaskManager.mController = null; + Watchdog.getInstance().setActivityController(null); + } + } + + synchronized (mService) { + mService.mBatteryStatsService.noteProcessAnr(processName, uid); + + if (isSilentANR) { + kill("bg anr", true); + return; + } + + // Set the app's notResponding state, and look up the errorReportReceiver + makeAppNotRespondingLocked(activityShortComponentName, + annotation != null ? "ANR " + annotation : "ANR", info.toString()); + + // Bring up the infamous App Not Responding dialog + Message msg = Message.obtain(); + msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; + msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem); + + mService.mUiHandler.sendMessage(msg); + } + } + + private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) { + setNotResponding(true); + notRespondingReport = mService.mAppErrors.generateProcessError(this, + ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, + activity, shortMsg, longMsg, null); + startAppProblemLocked(); + getWindowProcessController().stopFreezingActivities(); + } + + void startAppProblemLocked() { + // If this app is not running under the current user, then we can't give it a report button + // because that would require launching the report UI under a different user. + errorReportReceiver = null; + + for (int userId : mService.mUserController.getCurrentProfileIds()) { + if (this.userId == userId) { + errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( + mService.mContext, info.packageName, info.flags); + } + } + mService.skipCurrentReceiverLocked(this); + } + + private boolean isInterestingForBackgroundTraces() { + // The system_server is always considered interesting. + if (pid == MY_PID) { + return true; + } + + // A package is considered interesting if any of the following is true : + // + // - It's displaying an activity. + // - It's the SystemUI. + // - It has an overlay or a top UI visible. + // + // NOTE: The check whether a given ProcessRecord belongs to the systemui + // process is a bit of a kludge, but the same pattern seems repeated at + // several places in the system server. + return isInterestingToUserLocked() || + (info != null && "com.android.systemui".equals(info.packageName)) + || (hasTopUi() || hasOverlayUi()); + } } diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java index 7e3893b38c31c..0445cee99b85a 100644 --- a/services/core/java/com/android/server/am/WindowProcessController.java +++ b/services/core/java/com/android/server/am/WindowProcessController.java @@ -30,6 +30,8 @@ import static com.android.server.am.ActivityStack.ActivityState.PAUSED; import static com.android.server.am.ActivityStack.ActivityState.PAUSING; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.ActivityState.STOPPING; +import static com.android.server.am.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; +import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; import android.app.Activity; import android.app.ActivityThread; @@ -44,6 +46,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.wm.ConfigurationContainer; @@ -622,6 +625,13 @@ public class WindowProcessController extends ConfigurationContainer