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

Commit a455d194 authored by Dan Egnor's avatar Dan Egnor
Browse files

Record some logcat output with crashes, ANRs, etc..

Shelling out to logcat from the system server makes me queasy,
so this is turned off by default -- it must be enabled individually
for each error type (system_app_anr, etc) via a secure settings
value (which I plan to poke into from gservices for internal use).

Even when enabled, it happens in a side thread, unless the system
server is about to die anyway (system server restart).

Change-Id: Id6d88bcd78d3625f0364a5fe9c771046601a5a14
parent e25bf5dc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -2900,6 +2900,15 @@ public final class Settings {
         */
        public static final String DROPBOX_TAG_PREFIX =
                "dropbox:";
        /**
         * Lines of logcat to include with system crash/ANR/etc. reports,
         * as a prefix of the dropbox tag of the report type.
         * For example, "logcat_for_system_server_anr" controls the lines
         * of logcat captured with system server ANR reports.  0 to disable.
         * @hide
         */
        public static final String ERROR_LOGCAT_PREFIX =
                "logcat_for_";


        /**
+103 −57
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
@@ -8960,24 +8961,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
     * @param crashInfo giving an application stack trace, null if absent
     */
    public void addErrorToDropBox(String eventType,
            ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
            String subject, String report, File logFile,
            ApplicationErrorReport.CrashInfo crashInfo) {
            ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject,
            final String report, final File logFile,
            final ApplicationErrorReport.CrashInfo crashInfo) {
        // NOTE -- this must never acquire the ActivityManagerService lock,
        // otherwise the watchdog may be prevented from resetting the system.
        String dropboxTag;
        String prefix;
        if (process == null || process.pid == MY_PID) {
            dropboxTag = "system_server_" + eventType;
            prefix = "system_server_";
        } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
            dropboxTag = "system_app_" + eventType;
            prefix = "system_app_";
        } else {
            dropboxTag = "data_app_" + eventType;
            prefix = "data_app_";
        }
        DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
        if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
            StringBuilder sb = new StringBuilder(1024);
        final String dropboxTag = prefix + eventType;
        final DropBoxManager dbox = (DropBoxManager)
                mContext.getSystemService(Context.DROPBOX_SERVICE);
        // Exit early if the dropbox isn't configured to accept this report type.
        if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
        final StringBuilder sb = new StringBuilder(1024);
        if (process == null || process.pid == MY_PID) {
            sb.append("Process: system_server\n");
        } else {
@@ -9017,6 +9023,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
        }
        sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
        sb.append("\n");
        // Do the rest in a worker thread to avoid blocking the caller on I/O
        // (After this point, we shouldn't access AMS internal data structures.)
        Thread worker = new Thread("Error dump: " + dropboxTag) {
            @Override
            public void run() {
                if (report != null) {
                    sb.append(report);
                }
@@ -9030,8 +9042,42 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                if (crashInfo != null && crashInfo.stackTrace != null) {
                    sb.append(crashInfo.stackTrace);
                }
                String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag;
                int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0);
                if (lines > 0) {
                    sb.append("\n");
                    // Merge several logcat streams, and take the last N lines
                    InputStreamReader input = null;
                    try {
                        java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
                                "-v", "time", "-b", "events", "-b", "system", "-b", "main",
                                "-t", String.valueOf(lines)).redirectErrorStream(true).start();
                        try { logcat.getOutputStream().close(); } catch (IOException e) {}
                        try { logcat.getErrorStream().close(); } catch (IOException e) {}
                        input = new InputStreamReader(logcat.getInputStream());
                        int num;
                        char[] buf = new char[8192];
                        while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
                    } catch (IOException e) {
                        Slog.e(TAG, "Error running logcat", e);
                    } finally {
                        if (input != null) try { input.close(); } catch (IOException e) {}
                    }
                }
                dbox.addText(dropboxTag, sb.toString());
            }
        };
        if (process == null || process.pid == MY_PID) {
            worker.run();  // We may be about to die -- need to run this synchronously
        } else {
            worker.start();
        }
    }
    /**