Log java crashes & native crashes in critical event log

Change-Id: I9efe1ff6c98dec47edbc95974d0959c343c7474f
Test: atest CriticalEventLogTest
Bug: 200263868
This commit is contained in:
Ben Miles
2021-11-09 11:17:49 +00:00
parent 75251249f2
commit dfec95bc84
4 changed files with 347 additions and 39 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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() {
public void logJavaCrash() {
mCriticalEventLog.incTimeSeconds(1);
mCriticalEventLog.logAnr("Subject 1", ServerProtoEnums.SYSTEM_SERVER, "AID_SYSTEM",
SYSTEM_SERVER_UID, 0);
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.incTimeSeconds(1);
mCriticalEventLog.logAnr("Subject 4", ServerProtoEnums.DATA_APP, "com.foo",
DATA_APP_UID_2, 3);
mCriticalEventLog.incTimeSeconds(1);
mCriticalEventLog.logAnr("Subject 5", ServerProtoEnums.DATA_APP, "com.bar",
DATA_APP_UID_3, 4);
mCriticalEventLog.logJavaCrash("com.android.MyClass", 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[]{
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.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;
}