diff options
-rw-r--r-- | debuggerd/debuggerd.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index 97a6b9e..91d9dda 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -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; } |