summaryrefslogtreecommitdiffstats
path: root/cmds/dumpstate/dumpstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/dumpstate/dumpstate.c')
-rw-r--r--cmds/dumpstate/dumpstate.c192
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");