diff options
Diffstat (limited to 'cmds/dumpstate/dumpstate.c')
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 192 |
1 files changed, 185 insertions, 7 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index a33dcf3..ef8db06 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -18,6 +18,7 @@ #include <errno.h> #include <fcntl.h> #include <limits.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -99,8 +100,170 @@ static void dump_dev_files(const char *title, const char *driverpath, const char closedir(d); } +static bool skip_not_stat(const char *path) { + static const char stat[] = "/stat"; + size_t len = strlen(path); + if (path[len - 1] == '/') { /* Directory? */ + return false; + } + return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ +} + +static const char mmcblk0[] = "/sys/block/mmcblk0/"; +unsigned long worst_write_perf = 20000; /* in KB/s */ + +static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) { + unsigned long fields[11], read_perf, write_perf; + bool z; + char *cp, *buffer = NULL; + size_t i = 0; + FILE *fp = fdopen(fd, "rb"); + getline(&buffer, &i, fp); + fclose(fp); + if (!buffer) { + return -errno; + } + i = strlen(buffer); + while ((i > 0) && (buffer[i - 1] == '\n')) { + buffer[--i] = '\0'; + } + if (!*buffer) { + free(buffer); + return 0; + } + z = true; + for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) { + fields[i] = strtol(cp, &cp, 0); + if (fields[i] != 0) { + z = false; + } + } + if (z) { /* never accessed */ + free(buffer); + return 0; + } + + if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) { + path += sizeof(mmcblk0) - 1; + } + + printf("%s: %s\n", path, buffer); + free(buffer); + + read_perf = 0; + if (fields[3]) { + read_perf = 512 * fields[2] / fields[3]; + } + write_perf = 0; + if (fields[7]) { + write_perf = 512 * fields[6] / fields[7]; + } + printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf); + if ((write_perf > 1) && (write_perf < worst_write_perf)) { + worst_write_perf = write_perf; + } + return 0; +} + +/* Copied policy from system/core/logd/LogBuffer.cpp */ + +#define LOG_BUFFER_SIZE (256 * 1024) +#define LOG_BUFFER_MIN_SIZE (64 * 1024UL) +#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) + +static bool valid_size(unsigned long value) { + if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { + return false; + } + + long pages = sysconf(_SC_PHYS_PAGES); + if (pages < 1) { + return true; + } + + long pagesize = sysconf(_SC_PAGESIZE); + if (pagesize <= 1) { + pagesize = PAGE_SIZE; + } + + // maximum memory impact a somewhat arbitrary ~3% + pages = (pages + 31) / 32; + unsigned long maximum = pages * pagesize; + + if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { + return true; + } + + return value <= maximum; +} + +static unsigned long property_get_size(const char *key) { + unsigned long value; + char *cp, property[PROPERTY_VALUE_MAX]; + + property_get(key, property, ""); + value = strtoul(property, &cp, 10); + + switch(*cp) { + case 'm': + case 'M': + value *= 1024; + /* FALLTHRU */ + case 'k': + case 'K': + value *= 1024; + /* FALLTHRU */ + case '\0': + break; + + default: + value = 0; + } + + if (!valid_size(value)) { + value = 0; + } + + return value; +} + +/* timeout in ms */ +static unsigned long logcat_timeout(char *name) { + static const char global_tuneable[] = "persist.logd.size"; // Settings App + static const char global_default[] = "ro.logd.size"; // BoardConfig.mk + char key[PROP_NAME_MAX]; + unsigned long property_size, default_size; + + default_size = property_get_size(global_tuneable); + if (!default_size) { + default_size = property_get_size(global_default); + } + + snprintf(key, sizeof(key), "%s.%s", global_tuneable, name); + property_size = property_get_size(key); + + if (!property_size) { + snprintf(key, sizeof(key), "%s.%s", global_default, name); + property_size = property_get_size(key); + } + + if (!property_size) { + property_size = default_size; + } + + if (!property_size) { + property_size = LOG_BUFFER_SIZE; + } + + /* Engineering margin is ten-fold our guess */ + return 10 * (property_size + worst_write_perf) / worst_write_perf; +} + +/* End copy from system/core/logd/LogBuffer.cpp */ + /* dumps the current system state to stdout */ static void dumpstate() { + unsigned long timeout; time_t now = time(NULL); char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; @@ -133,7 +296,7 @@ static void dumpstate() { dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); - dump_file("MMC PERF", "/sys/block/mmcblk0/stat"); + dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); run_command("PROCRANK", 20, "procrank", NULL); @@ -149,7 +312,6 @@ static void dumpstate() { dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources"); dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); dump_file("KERNEL SYNC", "/d/sync"); - dump_file("KERNEL BLUEDROID", "/d/bluedroid"); run_command("PROCESSES", 10, "ps", "-P", NULL); run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); @@ -169,9 +331,24 @@ static void dumpstate() { } // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); - run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL); - 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); + // calculate timeout + timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL); + timeout = logcat_timeout("events"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); + timeout = logcat_timeout("radio"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); + + run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { @@ -242,8 +419,6 @@ static void dumpstate() { run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime", "-b", "all", "-d", "*:v", NULL); - for_each_userid(do_dump_settings, NULL); - /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ run_command("NETWORK INTERFACES", 10, "ip", "link", NULL); @@ -259,6 +434,8 @@ static void dumpstate() { run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL); run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL); + run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL); + run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL); run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL); run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL); @@ -362,6 +539,7 @@ static void dumpstate() { run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL); run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL); run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL); + run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL); printf("========================================================\n"); printf("== Running Application Activities\n"); |