From 1fe6107b66516b225e0843836d60a69b1b57f3c3 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 22 Jul 2014 16:08:19 -0700 Subject: [PATCH] Add dumping of tombstones to dumpstate. Dump only those tombstones modified within the last half an hour. Change-Id: I8ce836b2e19eba7a9c0c31a4f312f9a382526da7 --- cmds/dumpstate/dumpstate.c | 59 ++++++++++++++++++++++++++++++++++---- cmds/dumpstate/dumpstate.h | 7 +++-- cmds/dumpstate/utils.c | 10 +++++-- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index c6a2a0d9a..c23a9e833 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -20,13 +20,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include -#include #include @@ -43,6 +43,36 @@ static const char *dump_traces_path = NULL; static char screenshot_path[PATH_MAX] = ""; +#define TOMBSTONE_DIR "/data/tombstones" +#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_" +/* Can accomodate a tombstone number up to 9999. */ +#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4) +#define NUM_TOMBSTONES 10 + +typedef struct { + char name[TOMBSTONE_MAX_LEN]; + int fd; +} tombstone_data_t; + +static tombstone_data_t tombstone_data[NUM_TOMBSTONES]; + +/* Get the fds of any tombstone that was modified in the last half an hour. */ +static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { + time_t thirty_minutes_ago = time(NULL) - 60*30; + for (size_t i = 0; i < NUM_TOMBSTONES; i++) { + snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); + int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + struct stat st; + if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && + (time_t) st.st_mtime >= thirty_minutes_ago) { + data[i].fd = fd; + } else { + close(fd); + data[i].fd = -1; + } + } +} + /* dumps the current system state to stdout */ static void dumpstate() { time_t now = time(NULL); @@ -116,7 +146,6 @@ static void dumpstate() { run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); - /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { dump_file("VM TRACES JUST NOW", dump_traces_path); @@ -128,10 +157,13 @@ static void dumpstate() { property_get("dalvik.vm.stack-trace-file", anr_traces_path, ""); if (!anr_traces_path[0]) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); - } else if (stat(anr_traces_path, &st)) { - printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); } else { - dump_file("VM TRACES AT LAST ANR", anr_traces_path); + int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) { + printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); + } else { + dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd); + } } /* slow traces for slow operations */ @@ -152,6 +184,18 @@ static void dumpstate() { } } + int dumped = 0; + for (size_t i = 0; i < NUM_TOMBSTONES; i++) { + if (tombstone_data[i].fd != -1) { + dumped = 1; + dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd); + tombstone_data[i].fd = -1; + } + } + if (!dumped) { + printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR); + } + dump_file("NETWORK DEV INFO", "/proc/net/dev"); dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all"); dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt"); @@ -404,6 +448,9 @@ int main(int argc, char *argv[]) { return -1; } + /* Get the tombstone fds here while we are running as root. */ + get_tombstone_fds(tombstone_data); + /* switch to non-root user and group */ gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS }; diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 6906dcf9b..e75da2d0b 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -28,7 +28,10 @@ typedef void (for_each_pid_func)(int, const char *); typedef void (for_each_tid_func)(int, int, const char *); /* prints the contents of a file */ -int dump_file(const char *title, const char* path); +int dump_file(const char *title, const char *path); + +/* prints the contents of the fd */ +int dump_file_from_fd(const char *title, const char *path, int fd); /* forks a command and waits for it to finish -- terminate args with NULL */ int run_command(const char *title, int timeout_seconds, const char *command, ...); @@ -64,7 +67,7 @@ void do_dmesg(); void dump_route_tables(); /* Play a sound via Stagefright */ -void play_sound(const char* path); +void play_sound(const char *path); /* Implemented by libdumpstate_board to dump board-specific info */ void dumpstate_board(); diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index 9451417d4..56287a084 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -210,8 +210,7 @@ void do_showmap(int pid, const char *name) { } /* prints the contents of a file */ -int dump_file(const char *title, const char* path) { - char buffer[32768]; +int dump_file(const char *title, const char *path) { int fd = open(path, O_RDONLY); if (fd < 0) { int err = errno; @@ -220,6 +219,11 @@ int dump_file(const char *title, const char* path) { if (title) printf("\n"); return -1; } + return dump_file_from_fd(title, path, fd); +} + +int dump_file_from_fd(const char *title, const char *path, int fd) { + char buffer[32768]; if (title) printf("------ %s (%s", title, path); @@ -243,8 +247,8 @@ int dump_file(const char *title, const char* path) { } if (ret <= 0) break; } - close(fd); + if (!newline) printf("\n"); if (title) printf("\n"); return 0;