Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7167d660 authored by Ben Miles's avatar Ben Miles Committed by Android (Google) Code Review
Browse files

Merge "Log java crashes & native crashes in critical event log"

parents 476aa0b3 dfec95bc
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -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;
+15 −5
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -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);
+96 −4
Original line number Diff line number Diff line
@@ -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;
        }
    }
+191 −28
Original line number Diff line number Diff line
@@ -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;
    }