Loading proto/src/criticalevents/critical_event_log.proto +43 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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; Loading services/core/java/com/android/server/am/ActivityManagerService.java +15 −5 Original line number Diff line number Diff line Loading @@ -8049,11 +8049,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 Loading @@ -8063,9 +8068,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, Loading @@ -8092,6 +8095,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); Loading services/core/java/com/android/server/criticalevents/CriticalEventLog.java +96 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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; } Loading @@ -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; } } Loading services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java +191 −28 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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", Loading @@ -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[]{ Loading Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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()); Loading @@ -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; } Loading Loading
proto/src/criticalevents/critical_event_log.proto +43 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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; Loading
services/core/java/com/android/server/am/ActivityManagerService.java +15 −5 Original line number Diff line number Diff line Loading @@ -8049,11 +8049,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 Loading @@ -8063,9 +8068,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, Loading @@ -8092,6 +8095,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); Loading
services/core/java/com/android/server/criticalevents/CriticalEventLog.java +96 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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; } Loading @@ -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; } } Loading
services/tests/servicestests/src/com/android/server/criticalevents/CriticalEventLogTest.java +191 −28 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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", Loading @@ -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[]{ Loading Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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()); Loading @@ -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; } Loading