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

Commit f26c6567 authored by Andy McFadden's avatar Andy McFadden Committed by Android Git Automerger
Browse files

am 76feaf37: Merge "Append log data to tombstones"

* commit '76feaf37':
  Append log data to tombstones
parents 08df672a 76feaf37
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@

#include <cutils/sockets.h>
#include <cutils/logd.h>
#include <cutils/logger.h>
#include <cutils/properties.h>

#include <linux/input.h>
@@ -413,6 +414,101 @@ static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid)
    return need_cleanup != 0;
}

/*
 * Reads the contents of the specified log device, filters out the entries
 * that don't match the specified pid, and writes them to the tombstone file.
 */
static void dump_log_file(int tfd, unsigned pid, const char* filename)
{
    int logfd = open(filename, O_RDONLY | O_NONBLOCK);
    if (logfd < 0) {
        XLOG("Unable to open %s: %s\n", filename, strerror(errno));
        return;
    }
    _LOG(tfd, true, "--------- log %s\n", filename);

    union {
        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
        struct logger_entry entry;
    } log_entry;

    while (true) {
        ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
        if (actual < 0) {
            if (errno == EINTR) {
                /* interrupted by signal, retry */
                continue;
            } else if (errno == EAGAIN) {
                /* non-blocking EOF; we're done */
                break;
            } else {
                _LOG(tfd, true, "Error while reading log: %s\n",
                    strerror(errno));
                break;
            }
        } else if (actual == 0) {
            _LOG(tfd, true, "Got zero bytes while reading log: %s\n",
                strerror(errno));
            break;
        }

        /*
         * NOTE: if you XLOG something here, this will spin forever,
         * because you will be writing as fast as you're reading.  Any
         * high-frequency debug diagnostics should just be written to
         * the tombstone file.
         */

        struct logger_entry* entry = &log_entry.entry;

        if (entry->pid != (int32_t) pid) {
            /* wrong pid, ignore */
            continue;
        }

        /*
         * Msg format is: <priority:1><tag:N>\0<message:N>\0
         *
         * We want to display it in the same format as "logcat -v threadtime"
         * (although in this case the pid is redundant).
         *
         * TODO: scan for line breaks ('\n') and display each text line
         * on a separate line, prefixed with the header, like logcat does.
         */
        static const char* kPrioChars = "!.VDIWEFS";
        unsigned char prio = entry->msg[0];
        const char* tag = entry->msg + 1;
        const char* msg = tag + strlen(tag) + 1;

        log_entry.entry.msg[entry->len] = '\0';

        char timeBuf[32];
        time_t sec = (time_t) entry->sec;
        struct tm tmBuf;
        struct tm* ptm;
        ptm = localtime_r(&sec, &tmBuf);
        strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);

        _LOG(tfd, true, "%s.%03ld %5d %5d %c %-8s: %s\n",
            timeBuf, entry->nsec / 1000000,
            entry->pid, entry->tid,
            (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?'),
            tag, msg);
    }

    close(logfd);
}

/*
 * Dumps the logs generated by the specified pid to the tombstone, from both
 * "system" and "main" log devices.  Ideally we'd interleave the output.
 */
static void dump_logs(int tfd, unsigned pid)
{
    dump_log_file(tfd, pid, "/dev/log/system");
    dump_log_file(tfd, pid, "/dev/log/main");
}

/* Return true if some thread is not detached cleanly */
static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
                              int signal)
@@ -437,6 +533,13 @@ static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
        need_cleanup = dump_sibling_thread_report(fd, pid, tid);
    }

    /* don't copy log to tombstone unless this is a dev device */
    char value[PROPERTY_VALUE_MAX];
    property_get("ro.debuggable", value, "0");
    if (value[0] == '1') {
        dump_logs(fd, pid);
    }

    close(fd);
    return need_cleanup;
}