From 8b8eb41e9b25197db9f2a69f0c19de7a0e62aa46 Mon Sep 17 00:00:00 2001 From: Ben Miles Date: Mon, 10 May 2021 18:31:23 +0100 Subject: [PATCH] Log subject in ANR dump file for ANRs + watchdogs This is needed to be able to have access to the Subject header in bug reports and the ApplicationExitInfo API. Adds the subject to the top of the ANR dump file. Where the dump file is copied into the dropbox entry, the subject is no longer passed in explicitly to the call to addErrorToDropBox to avoid including the subject twice in the dropbox entry. Verified e2e by triggering an ANR and confirming that the subject appears at the top of the ANR file. Test: atest FrameworksServicesTests Bug: b/188122403 Change-Id: If2ee927a56e3f93c521307ca6355df7f560ea494 --- .../server/SystemServerInitThreadPool.java | 2 +- .../java/com/android/server/Watchdog.java | 7 +++-- .../server/am/ActivityManagerService.java | 30 +++++++++++++++++-- .../server/am/ProcessErrorStateRecord.java | 4 +-- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java index ed25452cf4028..364e73381bb9a 100644 --- a/services/core/java/com/android/server/SystemServerInitThreadPool.java +++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java @@ -192,7 +192,7 @@ public final class SystemServerInitThreadPool implements Dumpable { final ArrayList pids = new ArrayList<>(); pids.add(Process.myPid()); ActivityManagerService.dumpStackTraces(pids, null, null, - Watchdog.getInterestingNativePids(), null); + Watchdog.getInterestingNativePids(), null, null); } @Override diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 670f557b81e97..6644b28f1c4d4 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -658,7 +658,7 @@ public class Watchdog { // We've waited half the deadlock-detection interval. Pull a stack // trace and wait another half. ActivityManagerService.dumpStackTraces(pids, null, null, - getInterestingNativePids(), null); + getInterestingNativePids(), null, subject); continue; } @@ -674,7 +674,7 @@ public class Watchdog { StringWriter tracesFileException = new StringWriter(); final File stack = ActivityManagerService.dumpStackTraces( pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids(), - tracesFileException); + tracesFileException, subject); // Give some extra time to make sure the stack traces get written. // The system's been hanging for a minute, another second or two won't hurt much. @@ -699,7 +699,8 @@ public class Watchdog { if (mActivity != null) { mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, null, - localSubject, report.toString(), stack, null, null, null, null); + null, report.toString(), stack, null, null, null, null); + } FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, localSubject); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d3955eb6d19a9..5f9576120cc5c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -407,6 +407,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -3153,7 +3154,23 @@ public class ActivityManagerService extends IActivityManager.Stub ProcessCpuTracker processCpuTracker, SparseArray lastPids, ArrayList nativePids, StringWriter logExceptionCreatingFile) { return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePids, - logExceptionCreatingFile, null); + logExceptionCreatingFile, null, null); + } + + /** + * If a stack trace dump file is configured, dump process stack traces. + * @param firstPids of dalvik VM processes to dump stack traces for first + * @param lastPids of dalvik VM processes to dump stack traces for last + * @param nativePids optional list of native pids to dump stack crawls + * @param logExceptionCreatingFile optional writer to which we log errors creating the file + * @param subject optional line related to the error + */ + public static File dumpStackTraces(ArrayList firstPids, + ProcessCpuTracker processCpuTracker, SparseArray lastPids, + ArrayList nativePids, StringWriter logExceptionCreatingFile, + String subject) { + return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePids, + logExceptionCreatingFile, null, subject); } /** @@ -3163,7 +3180,7 @@ public class ActivityManagerService extends IActivityManager.Stub /* package */ static File dumpStackTraces(ArrayList firstPids, ProcessCpuTracker processCpuTracker, SparseArray lastPids, ArrayList nativePids, StringWriter logExceptionCreatingFile, - long[] firstPidOffsets) { + long[] firstPidOffsets, String subject) { ArrayList extraPids = null; Slog.i(TAG, "dumpStackTraces pids=" + lastPids + " nativepids=" + nativePids); @@ -3215,6 +3232,15 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } + if (subject != null) { + try (FileOutputStream fos = new FileOutputStream(tracesFile, true)) { + String header = "Subject: " + subject + "\n"; + fos.write(header.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + Slog.w(TAG, "Exception writing subject to ANR dump file:", e); + } + } + Pair offsets = dumpStackTraces( tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids); if (firstPidOffsets != null) { diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 66d4779698bdc..41edd75ab4a44 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -377,7 +377,7 @@ class ProcessErrorStateRecord { final long[] offsets = new long[2]; File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, - nativePids, tracesFileException, offsets); + nativePids, tracesFileException, offsets, annotation); if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); @@ -467,7 +467,7 @@ class ProcessErrorStateRecord { final ProcessRecord parentPr = parentProcess != null ? (ProcessRecord) parentProcess.mOwner : null; mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName, - parentShortComponentName, parentPr, annotation, report.toString(), tracesFile, + parentShortComponentName, parentPr, null, report.toString(), tracesFile, null, new Float(loadingProgress), incrementalMetrics, errorId); if (mApp.getWindowProcessController().appNotResponding(info.toString(),