diff options
author | 2016-12-06 15:07:48 -0800 | |
---|---|---|
committer | 2016-12-06 15:07:48 -0800 | |
commit | ecea1bfeae1211f9a363925c172c0f23062107fb (patch) | |
tree | 99d7fc7c78f261a3ffde997e8354f8134c60bfbe /cmds/dumpstate/dumpstate.cpp | |
parent | f5c3b20f062ca646572ee6c07713eba691971c95 (diff) | |
parent | 6079aa6a8a845d8312435fe3e991bbe14588d018 (diff) |
Merge remote-tracking branch 'goog/stage-aosp-master' into HEAD
Diffstat (limited to 'cmds/dumpstate/dumpstate.cpp')
-rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 317 |
1 files changed, 283 insertions, 34 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index ad06e30673..5b01be1274 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -23,6 +23,7 @@ #include <memory> #include <regex> #include <set> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -37,7 +38,9 @@ #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> +#include <android-base/file.h> #include <cutils/properties.h> +#include <hardware_legacy/power.h> #include <private/android_filesystem_config.h> #include <private/android_logger.h> @@ -53,14 +56,14 @@ using android::base::StringPrintf; static char cmdline_buf[16384] = "(unknown)"; static const char *dump_traces_path = NULL; -// TODO: should be part of dumpstate object +// TODO: variables below should be part of dumpstate object static unsigned long id; static char build_type[PROPERTY_VALUE_MAX]; static time_t now; static std::unique_ptr<ZipWriter> zip_writer; static std::set<std::string> mount_points; void add_mountinfo(); -static int control_socket_fd; +int control_socket_fd = -1; /* suffix of the bugreport files - it's typically the date (when invoked with -d), * although it could be changed by the user using a system property */ static std::string suffix; @@ -68,16 +71,19 @@ static std::string suffix; #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" -#define RAFT_DIR "/data/misc/raft/" +#define RAFT_DIR "/data/misc/raft" #define RECOVERY_DIR "/cache/recovery" #define RECOVERY_DATA_DIR "/data/misc/recovery" #define LOGPERSIST_DATA_DIR "/data/misc/logd" +#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" +#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref" #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 #define WLUTIL "/vendor/xbin/wlutil" +#define WAKE_LOCK_NAME "dumpstate_wakelock" typedef struct { char name[TOMBSTONE_MAX_LEN]; @@ -176,6 +182,136 @@ static void dump_dev_files(const char *title, const char *driverpath, const char closedir(d); } +// return pid of a userspace process. If not found or error, return 0. +static unsigned int pid_of_process(const char* ps_name) { + DIR *proc_dir; + struct dirent *ps; + unsigned int pid; + std::string cmdline; + + if (!(proc_dir = opendir("/proc"))) { + MYLOGE("Can't open /proc\n"); + return 0; + } + + while ((ps = readdir(proc_dir))) { + if (!(pid = atoi(ps->d_name))) { + continue; + } + android::base::ReadFileToString("/proc/" + + std::string(ps->d_name) + "/cmdline", &cmdline); + if (cmdline.find(ps_name) == std::string::npos) { + continue; + } else { + closedir(proc_dir); + return pid; + } + } + closedir(proc_dir); + return 0; +} + +// dump anrd's trace and add to the zip file. +// 1. check if anrd is running on this device. +// 2. send a SIGUSR1 to its pid which will dump anrd's trace. +// 3. wait until the trace generation completes and add to the zip file. +static bool dump_anrd_trace() { + unsigned int pid; + char buf[50], path[PATH_MAX]; + struct dirent *trace; + struct stat st; + DIR *trace_dir; + int retry = 5; + long max_ctime = 0, old_mtime; + long long cur_size = 0; + const char *trace_path = "/data/misc/anrd/"; + + if (!zip_writer) { + MYLOGE("Not dumping anrd trace because zip_writer is not set\n"); + return false; + } + + // find anrd's pid if it is running. + pid = pid_of_process("/system/xbin/anrd"); + + if (pid > 0) { + if (stat(trace_path, &st) == 0) { + old_mtime = st.st_mtime; + } else { + MYLOGE("Failed to find: %s\n", trace_path); + return false; + } + + // send SIGUSR1 to the anrd to generate a trace. + sprintf(buf, "%u", pid); + if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) { + MYLOGE("anrd signal timed out. Please manually collect trace\n"); + return false; + } + + while (retry-- > 0 && old_mtime == st.st_mtime) { + sleep(1); + stat(trace_path, &st); + } + + if (retry < 0 && old_mtime == st.st_mtime) { + MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path); + return false; + } + + // identify the trace file by its creation time. + if (!(trace_dir = opendir(trace_path))) { + MYLOGE("Can't open trace file under %s\n", trace_path); + } + while ((trace = readdir(trace_dir))) { + if (strcmp(trace->d_name, ".") == 0 + || strcmp(trace->d_name, "..") == 0) { + continue; + } + sprintf(path, "%s%s", trace_path, trace->d_name); + if (stat(path, &st) == 0) { + if (st.st_ctime > max_ctime) { + max_ctime = st.st_ctime; + sprintf(buf, "%s", trace->d_name); + } + } + } + closedir(trace_dir); + + // Wait until the dump completes by checking the size of the trace. + if (max_ctime > 0) { + sprintf(path, "%s%s", trace_path, buf); + while(true) { + sleep(1); + if (stat(path, &st) == 0) { + if (st.st_size == cur_size) { + break; + } else if (st.st_size > cur_size) { + cur_size = st.st_size; + } else { + return false; + } + } else { + MYLOGE("Cant stat() %s anymore\n", path); + return false; + } + } + // Add to the zip file. + if (!add_zip_entry("anrd_trace.txt", path)) { + MYLOGE("Unable to add anrd_trace file %s to zip file\n", path); + } else { + if (remove(path)) { + MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno)); + } + return true; + } + } else { + MYLOGE("Can't stats any trace file under %s\n", trace_path); + } + } + return false; +} + static void dump_systrace() { if (!zip_writer) { MYLOGD("Not dumping systrace because zip_writer is not set\n"); @@ -217,6 +353,40 @@ static void dump_systrace() { } } +static void dump_raft() { + if (is_user_build()) { + return; + } + + std::string raft_log_path = bugreport_dir + "/raft_log.txt"; + if (raft_log_path.empty()) { + MYLOGD("raft_log_path is empty\n"); + return; + } + + struct stat s; + if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) { + MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR); + return; + } + + if (!zip_writer) { + // Write compressed and encoded raft logs to stdout if not zip_writer. + run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL); + return; + } + + run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR, + "-o", raft_log_path.c_str(), NULL); + if (!add_zip_entry("raft_log.txt", raft_log_path)) { + MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str()); + } else { + if (remove(raft_log_path.c_str())) { + MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno)); + } + } +} + static bool skip_not_stat(const char *path) { static const char stat[] = "/stat"; size_t len = strlen(path); @@ -417,7 +587,7 @@ static void print_header(std::string version) { property_get("ro.build.display.id", build, "(unknown)"); property_get("ro.build.fingerprint", fingerprint, "(unknown)"); property_get("ro.build.type", build_type, "(unknown)"); - property_get("ro.baseband", radio, "(unknown)"); + property_get("gsm.version.baseband", radio, "(unknown)"); property_get("ro.bootloader", bootloader, "(unknown)"); property_get("gsm.operator.alpha", network, "(unknown)"); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); @@ -441,18 +611,39 @@ static void print_header(std::string version) { printf("\n"); } +// List of file extensions that can cause a zip file attachment to be rejected by some email +// service providers. +static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = { + ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp", + ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct", + ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh" +}; + bool add_zip_entry_from_fd(const std::string& entry_name, int fd) { if (!zip_writer) { MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n", entry_name.c_str()); return false; } + std::string valid_name = entry_name; + + // Rename extension if necessary. + size_t idx = entry_name.rfind("."); + if (idx != std::string::npos) { + std::string extension = entry_name.substr(idx); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) { + valid_name = entry_name + ".renamed"; + MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str()); + } + } + // Logging statement below is useful to time how long each entry takes, but it's too verbose. // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); - int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), + int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress, get_mtime(fd, now)); if (err) { - MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), + MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(), ZipWriter::ErrorCodeString(err)); return false; } @@ -498,6 +689,7 @@ static int _add_file_from_fd(const char *title, const char *path, int fd) { return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1; } +// TODO: move to util.cpp void add_dir(const char *dir, bool recursive) { if (!zip_writer) { MYLOGD("Not adding dir %s because zip_writer is not set\n", dir); @@ -541,10 +733,12 @@ static bool add_text_zip_entry(const std::string& entry_name, const std::string& static void dump_iptables() { run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL); run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL); - run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL); + run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL); /* no ip6 nat */ - run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL); - run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL); + run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL); + run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL); + run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL); + run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL); } static void dumpstate(const std::string& screenshot_path, const std::string& version) { @@ -626,8 +820,6 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); - run_command("RAFT LOGS", 600, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, 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); @@ -841,7 +1033,7 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver printf("== Running Application Providers\n"); printf("========================================================\n"); - run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL); + run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL); printf("========================================================\n"); @@ -875,11 +1067,31 @@ static void usage() { VERSION_DEFAULT.c_str()); } -static void sigpipe_handler(int n) { - // don't complain to stderr or stdout +static void wake_lock_releaser() { + if (release_wake_lock(WAKE_LOCK_NAME) < 0) { + MYLOGE("Failed to release wake lock: %s \n", strerror(errno)); + } else { + MYLOGD("Wake lock released.\n"); + } +} + +static void sig_handler(int signo) { + wake_lock_releaser(); _exit(EXIT_FAILURE); } +static void register_sig_handler() { + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = sig_handler; + sigaction(SIGPIPE, &sa, NULL); // broken pipe + sigaction(SIGSEGV, &sa, NULL); // segment fault + sigaction(SIGINT, &sa, NULL); // ctrl-c + sigaction(SIGTERM, &sa, NULL); // killed + sigaction(SIGQUIT, &sa, NULL); // quit +} + /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the temporary file. */ @@ -948,7 +1160,6 @@ static std::string SHA256_file_hash(std::string filepath) { } int main(int argc, char *argv[]) { - struct sigaction sigact; int do_add_date = 0; int do_zip_file = 0; int do_vibrate = 1; @@ -965,6 +1176,14 @@ int main(int argc, char *argv[]) { MYLOGI("begin\n"); + if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) { + MYLOGE("Failed to acquire wake lock: %s \n", strerror(errno)); + } else { + MYLOGD("Wake lock acquired.\n"); + atexit(wake_lock_releaser); + register_sig_handler(); + } + /* gets the sequential id */ char last_id[PROPERTY_VALUE_MAX]; property_get("dumpstate.last_id", last_id, "0"); @@ -973,17 +1192,20 @@ int main(int argc, char *argv[]) { property_set("dumpstate.last_id", last_id); MYLOGI("dumpstate id: %lu\n", id); - /* clear SIGPIPE handler */ - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = sigpipe_handler; - sigaction(SIGPIPE, &sigact, NULL); - /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); - FILE *oom_adj = fopen("/proc/self/oom_adj", "we"); + + FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we"); if (oom_adj) { - fputs("-17", oom_adj); + fputs("-1000", oom_adj); fclose(oom_adj); + } else { + /* fallback to kernels <= 2.6.35 */ + oom_adj = fopen("/proc/self/oom_adj", "we"); + if (oom_adj) { + fputs("-17", oom_adj); + fclose(oom_adj); + } } /* parse arguments */ @@ -1050,6 +1272,7 @@ int main(int argc, char *argv[]) { if (use_control_socket) { MYLOGD("Opening control socket\n"); control_socket_fd = open_socket("dumpstate"); + do_update_progress = 1; } /* full path of the temporary file containing the bugreport */ @@ -1123,14 +1346,21 @@ int main(int argc, char *argv[]) { } if (do_update_progress) { - std::vector<std::string> am_args = { - "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", - "--es", "android.intent.extra.NAME", suffix, - "--ei", "android.intent.extra.ID", std::to_string(id), - "--ei", "android.intent.extra.PID", std::to_string(getpid()), - "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), - }; - send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args); + if (do_broadcast) { + // clang-format off + std::vector<std::string> am_args = { + "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", + "--es", "android.intent.extra.NAME", suffix, + "--ei", "android.intent.extra.ID", std::to_string(id), + "--ei", "android.intent.extra.PID", std::to_string(getpid()), + "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), + }; + // clang-format on + send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args); + } + if (use_control_socket) { + dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str()); + } } } @@ -1192,7 +1422,14 @@ int main(int argc, char *argv[]) { print_header(version); // Dumps systrace right away, otherwise it will be filled with unnecessary events. - dump_systrace(); + // First try to dump anrd trace if the daemon is running. Otherwise, dump + // the raw trace. + if (!dump_anrd_trace()) { + dump_systrace(); + } + + // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed. + dump_raft(); // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. @@ -1207,9 +1444,19 @@ int main(int argc, char *argv[]) { add_dir(RECOVERY_DIR, true); add_dir(RECOVERY_DATA_DIR, true); add_dir(LOGPERSIST_DATA_DIR, false); + if (!is_user_build()) { + add_dir(PROFILE_DATA_DIR_CUR, true); + add_dir(PROFILE_DATA_DIR_REF, true); + } add_mountinfo(); dump_iptables(); + // Capture any IPSec policies in play. No keys are exposed here. + run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr); + + // Run ss as root so we can see socket marks. + run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL); + if (!drop_root_user()) { return -1; } @@ -1306,6 +1553,7 @@ int main(int argc, char *argv[]) { if (do_broadcast) { if (!path.empty()) { MYLOGI("Final bugreport path: %s\n", path.c_str()); + // clang-format off std::vector<std::string> am_args = { "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--ei", "android.intent.extra.ID", std::to_string(id), @@ -1314,6 +1562,7 @@ int main(int argc, char *argv[]) { "--es", "android.intent.extra.BUGREPORT", path, "--es", "android.intent.extra.DUMPSTATE_LOG", log_path }; + // clang-format on if (do_fb) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.SCREENSHOT"); @@ -1339,9 +1588,9 @@ int main(int argc, char *argv[]) { fclose(stderr); } - if (use_control_socket && control_socket_fd >= 0) { - MYLOGD("Closing control socket\n"); - close(control_socket_fd); + if (use_control_socket && control_socket_fd != -1) { + MYLOGD("Closing control socket\n"); + close(control_socket_fd); } return 0; |