diff options
| author | 2021-11-09 11:17:49 +0000 | |
|---|---|---|
| committer | 2021-11-11 14:06:24 +0000 | |
| commit | dfec95bc84ababfe8d005fec68fc4ba7fd8295ee (patch) | |
| tree | 898389cec4436b21da713b68588bf9a5264b315b | |
| parent | 75251249f23c9a3afacda3a0b97eb705d3a2b56b (diff) | |
Log java crashes & native crashes in critical event log
Change-Id: I9efe1ff6c98dec47edbc95974d0959c343c7474f
Test: atest CriticalEventLogTest
Bug: 200263868
4 files changed, 345 insertions, 37 deletions
diff --git a/proto/src/criticalevents/critical_event_log.proto b/proto/src/criticalevents/critical_event_log.proto index 0e0343461d9e..25814eca9a85 100644 --- a/proto/src/criticalevents/critical_event_log.proto +++ b/proto/src/criticalevents/critical_event_log.proto @@ -57,6 +57,8 @@ message CriticalEventProto { Watchdog watchdog = 2; HalfWatchdog half_watchdog = 3; AppNotResponding anr = 4; + JavaCrash java_crash = 5; + NativeCrash native_crash = 6; } message Watchdog { @@ -99,6 +101,47 @@ message CriticalEventProto { optional ProcessClass process_class = 5; } + message JavaCrash { + // The crash exception class. + // Optional, may be redacted for privacy. + optional string exception_class = 1; + + // Name of the crashed process. + // Optional, may be redacted for privacy. + optional string process = 2; + + // PID of the crashed process. + // Required. + optional int32 pid = 3; + + // UID of the crashed process. + // Required. + optional int32 uid = 4; + + // Category of the crashed process (DATA_APP, SYSTEM_APP, etc). + // Required. + optional ProcessClass process_class = 5; + } + + message NativeCrash { + // Name of the crashed process. + // Optional, may be redacted for privacy. + optional string process = 1; + + // PID of the crashed process. + // Required. + optional int32 pid = 2; + + // UID of the crashed process. + // Required. + optional int32 uid = 3; + + // Category of the crashed process (DATA_APP, SYSTEM_APP, etc). + // Required. + optional ProcessClass process_class = 4; + } + + // Mirrors definition & values in {@link android.server.ServerProtoEnums}. enum ProcessClass { PROCESS_CLASS_UNKNOWN = 0; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b1a1e0d23019..191feec94829 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8018,11 +8018,16 @@ public class ActivityManagerService extends IActivityManager.Stub crashInfo.throwFileName, crashInfo.throwLineNumber); + int processClassEnum = processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER + : (r != null) ? r.getProcessClassEnum() + : ServerProtoEnums.ERROR_SOURCE_UNKNOWN; + int uid = (r != null) ? r.uid : -1; + int pid = (r != null) ? r.getPid() : -1; FrameworkStatsLog.write(FrameworkStatsLog.APP_CRASH_OCCURRED, - (r != null) ? r.uid : -1, + uid, eventType, processName, - (r != null) ? r.getPid() : -1, + pid, (r != null && r.info != null) ? r.info.packageName : "", (r != null && r.info != null) ? (r.info.isInstantApp() ? FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE @@ -8032,9 +8037,7 @@ public class ActivityManagerService extends IActivityManager.Stub ? FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND : FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND) : FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN, - processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER - : (r != null) ? r.getProcessClassEnum() - : ServerProtoEnums.ERROR_SOURCE_UNKNOWN, + processClassEnum, incrementalMetrics != null /* isIncremental */, loadingProgress, incrementalMetrics != null ? incrementalMetrics.getMillisSinceOldestPendingRead() : -1, @@ -8061,6 +8064,13 @@ public class ActivityManagerService extends IActivityManager.Stub : -1 ); + if (eventType.equals("native_crash")) { + CriticalEventLog.getInstance().logNativeCrash(processClassEnum, processName, uid, pid); + } else if (eventType.equals("crash")) { + CriticalEventLog.getInstance().logJavaCrash(crashInfo.exceptionClassName, + processClassEnum, processName, uid, pid); + } + final int relaunchReason = r == null ? RELAUNCH_REASON_NONE : r.getWindowProcessController().computeRelaunchReason(); final String relaunchReasonString = relaunchReasonToString(relaunchReason); diff --git a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java index 30b3524dfb1b..ab480e8e8852 100644 --- a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java +++ b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java @@ -29,6 +29,8 @@ 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.JavaCrash; +import com.android.server.criticalevents.nano.CriticalEventProto.NativeCrash; import com.android.server.criticalevents.nano.CriticalEventProto.Watchdog; import java.io.File; @@ -179,8 +181,56 @@ public class CriticalEventLog { log(event); } + /** + * Logs a java crash. + * + * @param exceptionClass the crash exception class. + * @param processClassEnum {@link android.server.ServerProtoEnums} value for the crashed + * process. + * @param processName name of the crashed process. + * @param uid uid of the crashed process. + * @param pid pid of the crashed process. + */ + public void logJavaCrash(String exceptionClass, int processClassEnum, String processName, + int uid, int pid) { + JavaCrash crash = new JavaCrash(); + crash.exceptionClass = exceptionClass; + crash.processClass = processClassEnum; + crash.process = processName; + crash.uid = uid; + crash.pid = pid; + CriticalEventProto event = new CriticalEventProto(); + event.setJavaCrash(crash); + log(event); + } + + /** + * Logs a native crash. + * + * @param processClassEnum {@link android.server.ServerProtoEnums} value for the crashed + * process. + * @param processName name of the crashed process. + * @param uid uid of the crashed process. + * @param pid pid of the crashed process. + */ + public void logNativeCrash(int processClassEnum, String processName, int uid, int pid) { + NativeCrash crash = new NativeCrash(); + crash.processClass = processClassEnum; + crash.process = processName; + crash.uid = uid; + crash.pid = pid; + CriticalEventProto event = new CriticalEventProto(); + event.setNativeCrash(crash); + log(event); + } + private void log(CriticalEventProto event) { event.timestampMs = getWallTimeMillis(); + appendAndSave(event); + } + + @VisibleForTesting + void appendAndSave(CriticalEventProto event) { mEvents.append(event); saveLogToFile(); } @@ -420,7 +470,18 @@ public class CriticalEventLog { if (shouldSanitize(anr.processClass, anr.process, anr.uid)) { return sanitizeAnr(event); } + } else if (event.hasJavaCrash()) { + JavaCrash crash = event.getJavaCrash(); + if (shouldSanitize(crash.processClass, crash.process, crash.uid)) { + return sanitizeJavaCrash(event); + } + } else if (event.hasNativeCrash()) { + NativeCrash crash = event.getNativeCrash(); + if (shouldSanitize(crash.processClass, crash.process, crash.uid)) { + return sanitizeNativeCrash(event); + } } + // No redaction needed. return event; } @@ -428,21 +489,52 @@ public class CriticalEventLog { boolean sameApp = processName != null && processName.equals(mTraceProcessName) && mTraceUid == uid; - // Only sanitize when both the ANR event and trace file are for different data apps. + // Only sanitize when both the critical 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; + + CriticalEventProto sanitized = sanitizeCriticalEventProto(base); + sanitized.setAnr(anr); + return sanitized; + } + + private static CriticalEventProto sanitizeJavaCrash(CriticalEventProto base) { + JavaCrash crash = new JavaCrash(); + // Do not set exceptionClass and process. + crash.processClass = base.getJavaCrash().processClass; + crash.uid = base.getJavaCrash().uid; + crash.pid = base.getJavaCrash().pid; + + CriticalEventProto sanitized = sanitizeCriticalEventProto(base); + sanitized.setJavaCrash(crash); + return sanitized; + } + + private static CriticalEventProto sanitizeNativeCrash(CriticalEventProto base) { + NativeCrash crash = new NativeCrash(); + // Do not set process. + crash.processClass = base.getNativeCrash().processClass; + crash.uid = base.getNativeCrash().uid; + crash.pid = base.getNativeCrash().pid; + + CriticalEventProto sanitized = sanitizeCriticalEventProto(base); + sanitized.setNativeCrash(crash); + return sanitized; + } + + private static CriticalEventProto sanitizeCriticalEventProto(CriticalEventProto base) { + CriticalEventProto sanitized = new CriticalEventProto(); + sanitized.timestampMs = base.timestampMs; return sanitized; } } diff --git a/services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java b/services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java index 54e75aacaf06..bf7c5870437c 100644 --- a/services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java +++ b/services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java @@ -29,6 +29,8 @@ 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.JavaCrash; +import com.android.server.criticalevents.nano.CriticalEventProto.NativeCrash; import com.android.server.criticalevents.nano.CriticalEventProto.Watchdog; import org.junit.Before; @@ -255,24 +257,39 @@ public class CriticalEventLogTest { } @Test - public void privacyRedaction_anr() { - mCriticalEventLog.incTimeSeconds(1); - mCriticalEventLog.logAnr("Subject 1", ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", - SYSTEM_SERVER_UID, 0); + public void logJavaCrash() { mCriticalEventLog.incTimeSeconds(1); - mCriticalEventLog.logAnr("Subject 2", ServerProtoEnums.SYSTEM_APP, "AID_RADIO", - SYSTEM_APP_UID, 1); - mCriticalEventLog.incTimeSeconds(1); - mCriticalEventLog.logAnr("Subject 3", ServerProtoEnums.DATA_APP, "com.foo", - DATA_APP_UID, 2); + mCriticalEventLog.logJavaCrash("com.android.MyClass", ServerProtoEnums.SYSTEM_APP, + "AID_RADIO", SYSTEM_APP_UID, 1); mCriticalEventLog.incTimeSeconds(1); - mCriticalEventLog.logAnr("Subject 4", ServerProtoEnums.DATA_APP, "com.foo", - DATA_APP_UID_2, 3); + + CriticalEventLogProto logProto = getLogOutput(); + + assertThat(logProto.timestampMs).isEqualTo(START_TIME_MS + 2000); + assertProtoArrayEquals(logProto.events, new CriticalEventProto[]{ + javaCrash(START_TIME_MS + 1000, "com.android.MyClass", ServerProtoEnums.SYSTEM_APP, + "AID_RADIO", SYSTEM_APP_UID, 1) + }); + } + + @Test + public void logNativeCrash() { mCriticalEventLog.incTimeSeconds(1); - mCriticalEventLog.logAnr("Subject 5", ServerProtoEnums.DATA_APP, "com.bar", - DATA_APP_UID_3, 4); + mCriticalEventLog.logNativeCrash(ServerProtoEnums.SYSTEM_APP, "AID_RADIO", SYSTEM_APP_UID, + 1); mCriticalEventLog.incTimeSeconds(1); + CriticalEventLogProto logProto = getLogOutput(); + + assertThat(logProto.timestampMs).isEqualTo(START_TIME_MS + 2000); + assertProtoArrayEquals(logProto.events, new CriticalEventProto[]{ + nativeCrash(START_TIME_MS + 1000, ServerProtoEnums.SYSTEM_APP, "AID_RADIO", + SYSTEM_APP_UID, 1) + }); + } + + @Test + public void privacyRedaction_anr() { CriticalEventProto systemServerAnr = anr(START_TIME_MS + 1000, "Subject 1", CriticalEventProto.SYSTEM_SERVER, "AID_SYSTEM", SYSTEM_SERVER_UID, 0); CriticalEventProto systemAppAnr = anr(START_TIME_MS + 2000, "Subject 2", @@ -289,6 +306,8 @@ public class CriticalEventLogTest { CriticalEventProto barAppAnrRedacted = anr(START_TIME_MS + 5000, "", CriticalEventProto.DATA_APP, "", DATA_APP_UID_3, 4); + addToLog(systemServerAnr, systemAppAnr, fooAppAnr, fooAppAnrUid2, barAppAnr); + assertProtoArrayEquals( getLogOutput(ServerProtoEnums.DATA_APP, "com.foo", DATA_APP_UID).events, new CriticalEventProto[]{ @@ -325,9 +344,123 @@ public class CriticalEventLogTest { } @Test - public void privacyRedaction_anr_doesNotMutateLogState() { - mCriticalEventLog.logAnr("Subject", ServerProtoEnums.DATA_APP, "com.foo", + public void privacyRedaction_javaCrash() { + CriticalEventProto systemServerCrash = javaCrash(START_TIME_MS + 1000, "Exception class 1", + CriticalEventProto.SYSTEM_SERVER, "AID_SYSTEM", + SYSTEM_SERVER_UID, 0); + CriticalEventProto systemAppCrash = javaCrash(START_TIME_MS + 2000, "Exception class 2", + CriticalEventProto.SYSTEM_APP, "AID_RADIO", SYSTEM_APP_UID, 1); + CriticalEventProto fooAppCrash = javaCrash(START_TIME_MS + 3000, "Exception class 3", + CriticalEventProto.DATA_APP, "com.foo", DATA_APP_UID, 2); + CriticalEventProto fooAppCrashUid2 = javaCrash(START_TIME_MS + 4000, "Exception class 4", + CriticalEventProto.DATA_APP, "com.foo", DATA_APP_UID_2, 3); + CriticalEventProto fooAppCrashUid2Redacted = javaCrash(START_TIME_MS + 4000, "", + CriticalEventProto.DATA_APP, "", DATA_APP_UID_2, 3); + CriticalEventProto barAppCrash = javaCrash(START_TIME_MS + 5000, "Exception class 5", + CriticalEventProto.DATA_APP, "com.bar", DATA_APP_UID_3, 4); + CriticalEventProto barAppCrashRedacted = javaCrash(START_TIME_MS + 5000, "", + CriticalEventProto.DATA_APP, "", DATA_APP_UID_3, 4); + + addToLog(systemServerCrash, systemAppCrash, fooAppCrash, fooAppCrashUid2, barAppCrash); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.DATA_APP, "com.foo", DATA_APP_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + // Redacted since the trace file and crash are for different uids. + fooAppCrashUid2Redacted, + // Redacted since the trace file and crash are for different data apps. + barAppCrashRedacted + }); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", + SYSTEM_SERVER_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + fooAppCrashUid2, + barAppCrash + }); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.SYSTEM_APP, "AID_RADIO", + SYSTEM_APP_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + fooAppCrashUid2, + barAppCrash + }); + } + + @Test + public void privacyRedaction_nativeCrash() { + CriticalEventProto systemServerCrash = nativeCrash(START_TIME_MS + 1000, + CriticalEventProto.SYSTEM_SERVER, "AID_SYSTEM", + SYSTEM_SERVER_UID, 0); + CriticalEventProto systemAppCrash = nativeCrash(START_TIME_MS + 2000, + CriticalEventProto.SYSTEM_APP, "AID_RADIO", SYSTEM_APP_UID, 1); + CriticalEventProto fooAppCrash = nativeCrash(START_TIME_MS + 3000, + CriticalEventProto.DATA_APP, "com.foo", DATA_APP_UID, 2); + CriticalEventProto fooAppCrashUid2 = nativeCrash(START_TIME_MS + 4000, + CriticalEventProto.DATA_APP, "com.foo", DATA_APP_UID_2, 3); + CriticalEventProto fooAppCrashUid2Redacted = nativeCrash(START_TIME_MS + 4000, + CriticalEventProto.DATA_APP, "", DATA_APP_UID_2, 3); + CriticalEventProto barAppCrash = nativeCrash(START_TIME_MS + 5000, + CriticalEventProto.DATA_APP, "com.bar", DATA_APP_UID_3, 4); + CriticalEventProto barAppCrashRedacted = nativeCrash(START_TIME_MS + 5000, + CriticalEventProto.DATA_APP, "", DATA_APP_UID_3, 4); + + addToLog(systemServerCrash, systemAppCrash, fooAppCrash, fooAppCrashUid2, barAppCrash); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.DATA_APP, "com.foo", DATA_APP_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + // Redacted since the trace file and crash are for different uids. + fooAppCrashUid2Redacted, + // Redacted since the trace file and crash are for different data apps. + barAppCrashRedacted + }); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", + SYSTEM_SERVER_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + fooAppCrashUid2, + barAppCrash + }); + + assertProtoArrayEquals( + getLogOutput(ServerProtoEnums.SYSTEM_APP, "AID_RADIO", + SYSTEM_APP_UID).events, + new CriticalEventProto[]{ + systemServerCrash, + systemAppCrash, + fooAppCrash, + fooAppCrashUid2, + barAppCrash + }); + } + + @Test + public void privacyRedaction_doesNotMutateLogState() { + mCriticalEventLog.logAnr("ANR Subject", ServerProtoEnums.DATA_APP, "com.foo", + 10_001, DATA_APP_UID); + mCriticalEventLog.logJavaCrash("com.foo.MyClass", ServerProtoEnums.DATA_APP, "com.foo", 10_001, DATA_APP_UID); + mCriticalEventLog.logNativeCrash(ServerProtoEnums.DATA_APP, "com.foo", 10_001, + DATA_APP_UID); CriticalEventLogProto unredactedLogBefore = getLogOutput(ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM", SYSTEM_SERVER_UID); @@ -488,6 +621,12 @@ public class CriticalEventLogTest { ServerProtoEnums.SYSTEM_SERVER); } + private void addToLog(CriticalEventProto... events) { + for (CriticalEventProto event : events) { + mCriticalEventLog.appendAndSave(event); + } + } + private CriticalEventLogProto getLogOutput() { return getLogOutput(mCriticalEventLog); } @@ -533,9 +672,29 @@ public class CriticalEventLogTest { } } + private static CriticalEventProto watchdog(long timestampMs, String subject) { + return watchdog(timestampMs, subject, "A UUID"); + } + + private static CriticalEventProto watchdog(long timestampMs, String subject, String uuid) { + CriticalEventProto event = new CriticalEventProto(); + event.timestampMs = timestampMs; + event.setWatchdog(new Watchdog()); + event.getWatchdog().subject = subject; + event.getWatchdog().uuid = uuid; + return event; + } + + private static CriticalEventProto halfWatchdog(long timestampMs, String subject) { + CriticalEventProto event = new CriticalEventProto(); + event.timestampMs = timestampMs; + event.setHalfWatchdog(new HalfWatchdog()); + event.getHalfWatchdog().subject = subject; + return event; + } + private static CriticalEventProto anr(long timestampMs, String subject, int processClass, - String processName, - int uid, int pid) { + String processName, int uid, int pid) { CriticalEventProto event = new CriticalEventProto(); event.timestampMs = timestampMs; event.setAnr(new AppNotResponding()); @@ -547,24 +706,28 @@ public class CriticalEventLogTest { return event; } - private CriticalEventProto watchdog(long timestampMs, String subject) { - return watchdog(timestampMs, subject, "A UUID"); - } - - private CriticalEventProto watchdog(long timestampMs, String subject, String uuid) { + private static CriticalEventProto javaCrash(long timestampMs, String exceptionClass, + int processClass, String processName, int uid, int pid) { CriticalEventProto event = new CriticalEventProto(); event.timestampMs = timestampMs; - event.setWatchdog(new Watchdog()); - event.getWatchdog().subject = subject; - event.getWatchdog().uuid = uuid; + event.setJavaCrash(new JavaCrash()); + event.getJavaCrash().exceptionClass = exceptionClass; + event.getJavaCrash().processClass = processClass; + event.getJavaCrash().process = processName; + event.getJavaCrash().uid = uid; + event.getJavaCrash().pid = pid; return event; } - private CriticalEventProto halfWatchdog(long timestampMs, String subject) { + private static CriticalEventProto nativeCrash(long timestampMs, int processClass, + String processName, int uid, int pid) { CriticalEventProto event = new CriticalEventProto(); event.timestampMs = timestampMs; - event.setHalfWatchdog(new HalfWatchdog()); - event.getHalfWatchdog().subject = subject; + event.setNativeCrash(new NativeCrash()); + event.getNativeCrash().processClass = processClass; + event.getNativeCrash().process = processName; + event.getNativeCrash().uid = uid; + event.getNativeCrash().pid = pid; return event; } |