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