Loading proto/src/criticalevents/critical_event_log.proto +31 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ message CriticalEventProto { oneof event { Watchdog watchdog = 2; HalfWatchdog half_watchdog = 3; AppNotResponding anr = 4; } message Watchdog { Loading @@ -75,4 +76,34 @@ message CriticalEventProto { // Required. optional string subject = 1; } message AppNotResponding { // The ANR subject. // Optional, may be redacted for privacy. optional string subject = 1; // Name of the ANRing process. // Optional, may be redacted for privacy. optional string process = 2; // PID of the ANRing process. // Required. optional int32 pid = 3; // UID of the ANRing process. // Required. optional int32 uid = 4; // Category of the ANRing process (DATA_APP, SYSTEM_APP, etc). // Required. optional ProcessClass process_class = 5; } // Mirrors definition & values in {@link android.server.ServerProtoEnums}. enum ProcessClass { PROCESS_CLASS_UNKNOWN = 0; DATA_APP = 1; SYSTEM_APP = 2; SYSTEM_SERVER = 3; } } No newline at end of file services/core/java/com/android/server/Watchdog.java +4 −2 Original line number Diff line number Diff line Loading @@ -666,7 +666,8 @@ public class Watchdog { if (doWaitedHalfDump) { // Get critical event log before logging the half watchdog so that it doesn't // occur in the log. String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); CriticalEventLog.getInstance().logHalfWatchdog(subject); // We've waited half the deadlock-detection interval. Pull a stack Loading @@ -693,7 +694,8 @@ public class Watchdog { // Get critical event log before logging the watchdog so that it doesn't occur in the // log. String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); CriticalEventLog.getInstance().logWatchdog(subject, errorId); long anrTime = SystemClock.uptimeMillis(); Loading services/core/java/com/android/server/am/ProcessErrorStateRecord.java +7 −1 Original line number Diff line number Diff line Loading @@ -332,6 +332,13 @@ class ProcessErrorStateRecord { } } // Get critical event log before logging the ANR so that it doesn't occur in the log. final String criticalEventLog = CriticalEventLog.getInstance().logLinesForTraceFile( mApp.getProcessClassEnum(), mApp.processName, mApp.uid); CriticalEventLog.getInstance().logAnr(annotation, mApp.getProcessClassEnum(), mApp.processName, mApp.uid, mApp.mPid); // Log the ANR to the main log. StringBuilder info = new StringBuilder(); info.setLength(0); Loading Loading @@ -401,7 +408,6 @@ class ProcessErrorStateRecord { StringWriter tracesFileException = new StringWriter(); // To hold the start and end offset to the ANR trace file respectively. final long[] offsets = new long[2]; final String criticalEventLog = CriticalEventLog.getInstance().logLinesForAnrFile(); File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, nativePids, tracesFileException, offsets, annotation, criticalEventLog); Loading services/core/java/com/android/server/criticalevents/CriticalEventLog.java +126 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.criticalevents; import android.os.Handler; import android.os.HandlerThread; import android.server.ServerProtoEnums; import android.util.Slog; import com.android.framework.protobuf.nano.MessageNanoPrinter; Loading @@ -26,6 +27,7 @@ import com.android.internal.util.RingBuffer; import com.android.server.criticalevents.nano.CriticalEventLogProto; import com.android.server.criticalevents.nano.CriticalEventLogStorageProto; import com.android.server.criticalevents.nano.CriticalEventProto; import com.android.server.criticalevents.nano.CriticalEventProto.AppNotResponding; import com.android.server.criticalevents.nano.CriticalEventProto.HalfWatchdog; import com.android.server.criticalevents.nano.CriticalEventProto.Watchdog; Loading @@ -49,6 +51,9 @@ import java.util.UUID; public class CriticalEventLog { private static final String TAG = CriticalEventLog.class.getSimpleName(); /** UID for system_server. */ private static final int AID_SYSTEM = 1000; private static CriticalEventLog sInstance; /** Name of the file the log is saved to. */ Loading Loading @@ -153,6 +158,27 @@ public class CriticalEventLog { log(event); } /** * Logs an ANR. * * @param subject the ANR subject line. * @param processClassEnum {@link android.server.ServerProtoEnums} value for the ANRing process. * @param processName name of the ANRing process. * @param uid uid of the ANRing process. * @param pid pid of the ANRing process. */ public void logAnr(String subject, int processClassEnum, String processName, int uid, int pid) { AppNotResponding anr = new AppNotResponding(); anr.subject = subject; anr.processClass = processClassEnum; anr.process = processName; anr.uid = uid; anr.pid = pid; CriticalEventProto event = new CriticalEventProto(); event.setAnr(anr); log(event); } private void log(CriticalEventProto event) { event.timestampMs = getWallTimeMillis(); mEvents.append(event); Loading @@ -160,14 +186,37 @@ public class CriticalEventLog { } /** * Returns recent critical events in text format to include in logs such as ANR files. * Returns recent critical events in text format to include in system server ANR stack trace * file. * * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. */ public String logLinesForAnrFile() { public String logLinesForSystemServerTraceFile() { return logLinesForTraceFile(ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", AID_SYSTEM); } /** * Returns recent critical events in text format to include in logs such as ANR stack trace * files. * * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. * * Some data in the returned log may be redacted for privacy. For example, a log for a data * app will not include specific crash information for a different data app. See * {@link LogSanitizer} for more information. * * @param traceProcessClassEnum {@link android.server.ServerProtoEnums} value for the process * the ANR trace file is for. * @param traceProcessName name of the process the ANR trace file is for. * @param traceUid uid of the process the ANR trace file is for. */ public String logLinesForTraceFile(int traceProcessClassEnum, String traceProcessName, int traceUid) { CriticalEventLogProto outputLogProto = getOutputLogProto(traceProcessClassEnum, traceProcessName, traceUid); return new StringBuilder() .append("--- CriticalEventLog ---\n") .append(MessageNanoPrinter.print(getRecentEvents())) .append(MessageNanoPrinter.print(outputLogProto)) .append('\n').toString(); } Loading @@ -177,12 +226,20 @@ public class CriticalEventLog { * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. */ @VisibleForTesting protected CriticalEventLogProto getRecentEvents() { protected CriticalEventLogProto getOutputLogProto(int traceProcessClassEnum, String traceProcessName, int traceUid) { CriticalEventLogProto log = new CriticalEventLogProto(); log.timestampMs = getWallTimeMillis(); log.windowMs = mWindowMs; log.capacity = mEvents.capacity(); log.events = recentEventsWithMinTimestamp(log.timestampMs - mWindowMs); CriticalEventProto[] events = recentEventsWithMinTimestamp(log.timestampMs - mWindowMs); LogSanitizer sanitizer = new LogSanitizer(traceProcessClassEnum, traceProcessName, traceUid); for (int i = 0; i < events.length; i++) { events[i] = sanitizer.process(events[i]); } log.events = events; return log; } Loading Loading @@ -325,4 +382,68 @@ public class CriticalEventLog { } } } /** * Redacts private data app fields from the critical event protos. * * When a critical event log is requested, this class is used to redact specific information * so that the trace file for a data app does not leak private information about other data * apps. */ private static class LogSanitizer { /** * The {@link CriticalEventProto.ProcessClass} of the process the output trace file is for. */ int mTraceProcessClassEnum; /** The name of the process that the output trace file is for. */ String mTraceProcessName; /** The uid of the process that the output trace file is for. */ int mTraceUid; LogSanitizer(int traceProcessClassEnum, String traceProcessName, int traceUid) { mTraceProcessClassEnum = traceProcessClassEnum; mTraceProcessName = traceProcessName; mTraceUid = traceUid; } /** * Redacts information from a critical event proto where necessary. * * This function does not mutate its input. If redaction happens, it returns a new proto. * Otherwise, it returns the original proto. */ CriticalEventProto process(CriticalEventProto event) { if (event.hasAnr()) { AppNotResponding anr = event.getAnr(); if (shouldSanitize(anr.processClass, anr.process, anr.uid)) { return sanitizeAnr(event); } } return event; } private boolean shouldSanitize(int processClassEnum, String processName, int uid) { boolean sameApp = processName != null && processName.equals(mTraceProcessName) && mTraceUid == uid; // Only sanitize when both the ANR event and trace file are for different data apps. return processClassEnum == CriticalEventProto.DATA_APP && mTraceProcessClassEnum == CriticalEventProto.DATA_APP && !sameApp; } private static CriticalEventProto sanitizeAnr(CriticalEventProto base) { CriticalEventProto sanitized = new CriticalEventProto(); sanitized.timestampMs = base.timestampMs; AppNotResponding anr = new AppNotResponding(); sanitized.setAnr(anr); // Do not set subject and process. anr.processClass = base.getAnr().processClass; anr.uid = base.getAnr().uid; anr.pid = base.getAnr().pid; return sanitized; } } } services/core/java/com/android/server/wm/AnrController.java +1 −1 Original line number Diff line number Diff line Loading @@ -213,7 +213,7 @@ class AnrController { } } String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); final File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, null /* processCpuTracker */, null /* lastPids */, nativePids, null /* logExceptionCreatingFile */, "Pre-dump", criticalEvents); Loading Loading
proto/src/criticalevents/critical_event_log.proto +31 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ message CriticalEventProto { oneof event { Watchdog watchdog = 2; HalfWatchdog half_watchdog = 3; AppNotResponding anr = 4; } message Watchdog { Loading @@ -75,4 +76,34 @@ message CriticalEventProto { // Required. optional string subject = 1; } message AppNotResponding { // The ANR subject. // Optional, may be redacted for privacy. optional string subject = 1; // Name of the ANRing process. // Optional, may be redacted for privacy. optional string process = 2; // PID of the ANRing process. // Required. optional int32 pid = 3; // UID of the ANRing process. // Required. optional int32 uid = 4; // Category of the ANRing process (DATA_APP, SYSTEM_APP, etc). // Required. optional ProcessClass process_class = 5; } // Mirrors definition & values in {@link android.server.ServerProtoEnums}. enum ProcessClass { PROCESS_CLASS_UNKNOWN = 0; DATA_APP = 1; SYSTEM_APP = 2; SYSTEM_SERVER = 3; } } No newline at end of file
services/core/java/com/android/server/Watchdog.java +4 −2 Original line number Diff line number Diff line Loading @@ -666,7 +666,8 @@ public class Watchdog { if (doWaitedHalfDump) { // Get critical event log before logging the half watchdog so that it doesn't // occur in the log. String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); CriticalEventLog.getInstance().logHalfWatchdog(subject); // We've waited half the deadlock-detection interval. Pull a stack Loading @@ -693,7 +694,8 @@ public class Watchdog { // Get critical event log before logging the watchdog so that it doesn't occur in the // log. String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); CriticalEventLog.getInstance().logWatchdog(subject, errorId); long anrTime = SystemClock.uptimeMillis(); Loading
services/core/java/com/android/server/am/ProcessErrorStateRecord.java +7 −1 Original line number Diff line number Diff line Loading @@ -332,6 +332,13 @@ class ProcessErrorStateRecord { } } // Get critical event log before logging the ANR so that it doesn't occur in the log. final String criticalEventLog = CriticalEventLog.getInstance().logLinesForTraceFile( mApp.getProcessClassEnum(), mApp.processName, mApp.uid); CriticalEventLog.getInstance().logAnr(annotation, mApp.getProcessClassEnum(), mApp.processName, mApp.uid, mApp.mPid); // Log the ANR to the main log. StringBuilder info = new StringBuilder(); info.setLength(0); Loading Loading @@ -401,7 +408,6 @@ class ProcessErrorStateRecord { StringWriter tracesFileException = new StringWriter(); // To hold the start and end offset to the ANR trace file respectively. final long[] offsets = new long[2]; final String criticalEventLog = CriticalEventLog.getInstance().logLinesForAnrFile(); File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, nativePids, tracesFileException, offsets, annotation, criticalEventLog); Loading
services/core/java/com/android/server/criticalevents/CriticalEventLog.java +126 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.criticalevents; import android.os.Handler; import android.os.HandlerThread; import android.server.ServerProtoEnums; import android.util.Slog; import com.android.framework.protobuf.nano.MessageNanoPrinter; Loading @@ -26,6 +27,7 @@ import com.android.internal.util.RingBuffer; import com.android.server.criticalevents.nano.CriticalEventLogProto; import com.android.server.criticalevents.nano.CriticalEventLogStorageProto; import com.android.server.criticalevents.nano.CriticalEventProto; import com.android.server.criticalevents.nano.CriticalEventProto.AppNotResponding; import com.android.server.criticalevents.nano.CriticalEventProto.HalfWatchdog; import com.android.server.criticalevents.nano.CriticalEventProto.Watchdog; Loading @@ -49,6 +51,9 @@ import java.util.UUID; public class CriticalEventLog { private static final String TAG = CriticalEventLog.class.getSimpleName(); /** UID for system_server. */ private static final int AID_SYSTEM = 1000; private static CriticalEventLog sInstance; /** Name of the file the log is saved to. */ Loading Loading @@ -153,6 +158,27 @@ public class CriticalEventLog { log(event); } /** * Logs an ANR. * * @param subject the ANR subject line. * @param processClassEnum {@link android.server.ServerProtoEnums} value for the ANRing process. * @param processName name of the ANRing process. * @param uid uid of the ANRing process. * @param pid pid of the ANRing process. */ public void logAnr(String subject, int processClassEnum, String processName, int uid, int pid) { AppNotResponding anr = new AppNotResponding(); anr.subject = subject; anr.processClass = processClassEnum; anr.process = processName; anr.uid = uid; anr.pid = pid; CriticalEventProto event = new CriticalEventProto(); event.setAnr(anr); log(event); } private void log(CriticalEventProto event) { event.timestampMs = getWallTimeMillis(); mEvents.append(event); Loading @@ -160,14 +186,37 @@ public class CriticalEventLog { } /** * Returns recent critical events in text format to include in logs such as ANR files. * Returns recent critical events in text format to include in system server ANR stack trace * file. * * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. */ public String logLinesForAnrFile() { public String logLinesForSystemServerTraceFile() { return logLinesForTraceFile(ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", AID_SYSTEM); } /** * Returns recent critical events in text format to include in logs such as ANR stack trace * files. * * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. * * Some data in the returned log may be redacted for privacy. For example, a log for a data * app will not include specific crash information for a different data app. See * {@link LogSanitizer} for more information. * * @param traceProcessClassEnum {@link android.server.ServerProtoEnums} value for the process * the ANR trace file is for. * @param traceProcessName name of the process the ANR trace file is for. * @param traceUid uid of the process the ANR trace file is for. */ public String logLinesForTraceFile(int traceProcessClassEnum, String traceProcessName, int traceUid) { CriticalEventLogProto outputLogProto = getOutputLogProto(traceProcessClassEnum, traceProcessName, traceUid); return new StringBuilder() .append("--- CriticalEventLog ---\n") .append(MessageNanoPrinter.print(getRecentEvents())) .append(MessageNanoPrinter.print(outputLogProto)) .append('\n').toString(); } Loading @@ -177,12 +226,20 @@ public class CriticalEventLog { * Includes all events in the ring buffer with age less than or equal to {@code mWindowMs}. */ @VisibleForTesting protected CriticalEventLogProto getRecentEvents() { protected CriticalEventLogProto getOutputLogProto(int traceProcessClassEnum, String traceProcessName, int traceUid) { CriticalEventLogProto log = new CriticalEventLogProto(); log.timestampMs = getWallTimeMillis(); log.windowMs = mWindowMs; log.capacity = mEvents.capacity(); log.events = recentEventsWithMinTimestamp(log.timestampMs - mWindowMs); CriticalEventProto[] events = recentEventsWithMinTimestamp(log.timestampMs - mWindowMs); LogSanitizer sanitizer = new LogSanitizer(traceProcessClassEnum, traceProcessName, traceUid); for (int i = 0; i < events.length; i++) { events[i] = sanitizer.process(events[i]); } log.events = events; return log; } Loading Loading @@ -325,4 +382,68 @@ public class CriticalEventLog { } } } /** * Redacts private data app fields from the critical event protos. * * When a critical event log is requested, this class is used to redact specific information * so that the trace file for a data app does not leak private information about other data * apps. */ private static class LogSanitizer { /** * The {@link CriticalEventProto.ProcessClass} of the process the output trace file is for. */ int mTraceProcessClassEnum; /** The name of the process that the output trace file is for. */ String mTraceProcessName; /** The uid of the process that the output trace file is for. */ int mTraceUid; LogSanitizer(int traceProcessClassEnum, String traceProcessName, int traceUid) { mTraceProcessClassEnum = traceProcessClassEnum; mTraceProcessName = traceProcessName; mTraceUid = traceUid; } /** * Redacts information from a critical event proto where necessary. * * This function does not mutate its input. If redaction happens, it returns a new proto. * Otherwise, it returns the original proto. */ CriticalEventProto process(CriticalEventProto event) { if (event.hasAnr()) { AppNotResponding anr = event.getAnr(); if (shouldSanitize(anr.processClass, anr.process, anr.uid)) { return sanitizeAnr(event); } } return event; } private boolean shouldSanitize(int processClassEnum, String processName, int uid) { boolean sameApp = processName != null && processName.equals(mTraceProcessName) && mTraceUid == uid; // Only sanitize when both the ANR event and trace file are for different data apps. return processClassEnum == CriticalEventProto.DATA_APP && mTraceProcessClassEnum == CriticalEventProto.DATA_APP && !sameApp; } private static CriticalEventProto sanitizeAnr(CriticalEventProto base) { CriticalEventProto sanitized = new CriticalEventProto(); sanitized.timestampMs = base.timestampMs; AppNotResponding anr = new AppNotResponding(); sanitized.setAnr(anr); // Do not set subject and process. anr.processClass = base.getAnr().processClass; anr.uid = base.getAnr().uid; anr.pid = base.getAnr().pid; return sanitized; } } }
services/core/java/com/android/server/wm/AnrController.java +1 −1 Original line number Diff line number Diff line Loading @@ -213,7 +213,7 @@ class AnrController { } } String criticalEvents = CriticalEventLog.getInstance().logLinesForAnrFile(); String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); final File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, null /* processCpuTracker */, null /* lastPids */, nativePids, null /* logExceptionCreatingFile */, "Pre-dump", criticalEvents); Loading