diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/dumpstate/Android.mk | 2 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 349 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.h | 3 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.rc | 8 | ||||
-rw-r--r-- | cmds/dumpstate/utils.cpp | 9 |
5 files changed, 234 insertions, 137 deletions
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index daeebc41e6..a3522596c0 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -10,7 +10,7 @@ LOCAL_SRC_FILES := dumpstate.cpp utils.cpp LOCAL_MODULE := dumpstate -LOCAL_SHARED_LIBRARIES := libcutils libdebuggerd_client liblog libselinux libbase libhardware_legacy +LOCAL_SHARED_LIBRARIES := libcutils libdebuggerd_client liblog libselinux libbase # ZipArchive support, the order matters here to get all symbols. LOCAL_STATIC_LIBRARIES := libziparchive libz libcrypto_static LOCAL_HAL_STATIC_LIBRARIES := libdumpstate diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 93f17fe144..a0f9b09992 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -23,7 +23,6 @@ #include <memory> #include <regex> #include <set> -#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -36,11 +35,11 @@ #include <sys/wait.h> #include <unistd.h> +#include <android-base/file.h> #include <android-base/stringprintf.h> +#include <android-base/strings.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> @@ -83,7 +82,6 @@ static std::string suffix; #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]; @@ -152,7 +150,7 @@ void do_mountinfo(int pid, const char *name) { } void add_mountinfo() { - if (!zip_writer) return; + if (!is_zipping()) return; const char *title = "MOUNT INFO"; mount_points.clear(); DurationReporter duration_reporter(title, NULL); @@ -313,8 +311,8 @@ static bool dump_anrd_trace() { } static void dump_systrace() { - if (!zip_writer) { - MYLOGD("Not dumping systrace because zip_writer is not set\n"); + if (!is_zipping()) { + MYLOGD("Not dumping systrace because dumpstate is not zipping\n"); return; } std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt"; @@ -370,7 +368,7 @@ static void dump_raft() { return; } - if (!zip_writer) { + if (!is_zipping()) { // Write compressed and encoded raft logs to stdout if not zip_writer. run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL); return; @@ -387,6 +385,83 @@ static void dump_raft() { } } +/** + * Finds the last modified file in the directory dir whose name starts with file_prefix + * Function returns empty string when it does not find a file + */ +static std::string get_last_modified_file_matching_prefix(const std::string& dir, + const std::string& file_prefix) { + std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir); + if (d == nullptr) { + MYLOGD("Error %d opening %s\n", errno, dir.c_str()); + return ""; + } + + // Find the newest file matching the file_prefix in dir + struct dirent *de; + time_t last_modified = 0; + std::string last_modified_file = ""; + struct stat s; + + while ((de = readdir(d.get()))) { + std::string file = std::string(de->d_name); + if (!file_prefix.empty()) { + if (!android::base::StartsWith(file, file_prefix.c_str())) continue; + } + file = dir + "/" + file; + int ret = stat(file.c_str(), &s); + + if ((ret == 0) && (s.st_mtime > last_modified)) { + last_modified_file = file; + last_modified = s.st_mtime; + } + } + + return last_modified_file; +} + +void dump_modem_logs() { + DurationReporter duration_reporter("dump_modem_logs"); + if (is_user_build()) { + return; + } + + if (!is_zipping()) { + MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n"); + return; + } + + char property[PROPERTY_VALUE_MAX]; + property_get("ro.radio.log_prefix", property, ""); + std::string file_prefix = std::string(property); + if(file_prefix.empty()) { + MYLOGD("No modem log : file_prefix is empty\n"); + return; + } + + MYLOGD("dump_modem_logs: directory is %s and file_prefix is %s\n", + bugreport_dir.c_str(), file_prefix.c_str()); + + std::string modem_log_file = + get_last_modified_file_matching_prefix(bugreport_dir, file_prefix); + + struct stat s; + if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) { + MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str()); + return; + } + + std::string filename = basename(modem_log_file.c_str()); + if (!add_zip_entry(filename, modem_log_file)) { + MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str()); + } else { + MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str()); + if (remove(modem_log_file.c_str())) { + MYLOGE("Error removing modem log %s\n", modem_log_file.c_str()); + } + } +} + static bool skip_not_stat(const char *path) { static const char stat[] = "/stat"; size_t len = strlen(path); @@ -620,8 +695,8 @@ static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = { }; 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", + if (!is_zipping()) { + MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n", entry_name.c_str()); return false; } @@ -691,8 +766,8 @@ static int _add_file_from_fd(const char *title, const char *path, int fd) { // 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); + if (!is_zipping()) { + MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir); return; } MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive); @@ -700,10 +775,14 @@ void add_dir(const char *dir, bool recursive) { dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd); } +bool is_zipping() { + return zip_writer != nullptr; +} + /* adds a text entry entry to the existing zip file. */ static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) { - if (!zip_writer) { - MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str()); + if (!is_zipping()) { + MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str()); return false; } MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); @@ -741,9 +820,63 @@ static void dump_iptables() { run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL); } +static void do_kmsg() { + struct stat st; + if (!stat(PSTORE_LAST_KMSG, &st)) { + /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ + dump_file("LAST KMSG", PSTORE_LAST_KMSG); + } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) { + dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG); + } else { + /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */ + dump_file("LAST KMSG", "/proc/last_kmsg"); + } +} + +static void do_logcat() { + unsigned long timeout; + // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); + // 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", + "-v", "printable", + "-d", + "*:v", NULL); + timeout = logcat_timeout("events"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", + "-v", "threadtime", + "-v", "printable", + "-d", + "*:v", NULL); + timeout = logcat_timeout("radio"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", + "-v", "threadtime", + "-v", "printable", + "-d", + "*:v", NULL); + + run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); + + /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ + run_command("LAST LOGCAT", 10, "logcat", "-L", + "-b", "all", + "-v", "threadtime", + "-v", "printable", + "-d", + "*:v", NULL); +} + static void dumpstate(const std::string& screenshot_path, const std::string& version) { DurationReporter duration_reporter("DUMPSTATE"); - unsigned long timeout; dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); @@ -789,36 +922,7 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); } - // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); - // 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", - "-v", "printable", - "-d", - "*:v", NULL); - timeout = logcat_timeout("events"); - if (timeout < 20000) { - timeout = 20000; - } - run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", - "-v", "threadtime", - "-v", "printable", - "-d", - "*:v", NULL); - timeout = logcat_timeout("radio"); - if (timeout < 20000) { - timeout = 20000; - } - run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", - "-v", "threadtime", - "-v", "printable", - "-d", - "*:v", NULL); - - run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); + do_logcat(); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { @@ -886,23 +990,7 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats"); - if (!stat(PSTORE_LAST_KMSG, &st)) { - /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ - dump_file("LAST KMSG", PSTORE_LAST_KMSG); - } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) { - dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG); - } else { - /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */ - dump_file("LAST KMSG", "/proc/last_kmsg"); - } - - /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ - run_command("LAST LOGCAT", 10, "logcat", "-L", - "-b", "all", - "-v", "threadtime", - "-v", "printable", - "-d", - "*:v", NULL); + do_kmsg(); /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ @@ -1035,6 +1123,10 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL); + // dump_modem_logs adds the modem logs if available to the bugreport. + // Do this at the end to allow for sufficient time for the modem logs to be + // collected. + dump_modem_logs(); printf("========================================================\n"); printf("== Final progress (pid %d): %d/%d (originally %d)\n", @@ -1046,14 +1138,15 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver static void usage() { fprintf(stderr, - "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] " - "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" + "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-t]" + "[-z] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" " -o: write to file (instead of stdout)\n" " -d: append date to filename (requires -o)\n" " -p: capture screenshot to filename.png (requires -o)\n" + " -t: only captures telephony sections\n" " -z: generate zipped file (requires -o)\n" " -s: write output to control socket (for init)\n" " -S: write file location to control socket (for init; requires -o and -z)" @@ -1067,31 +1160,11 @@ static void usage() { VERSION_DEFAULT.c_str()); } -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(); +static void sigpipe_handler(int n) { + // don't complain to stderr or stdout _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. */ @@ -1160,6 +1233,7 @@ 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; @@ -1170,20 +1244,14 @@ int main(int argc, char *argv[]) { int do_broadcast = 0; int do_early_screenshot = 0; int is_remote_mode = 0; + bool telephony_only = false; + std::string version = VERSION_DEFAULT; now = time(NULL); 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"); @@ -1192,6 +1260,11 @@ 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); @@ -1213,9 +1286,10 @@ int main(int argc, char *argv[]) { format_args(argc, const_cast<const char **>(argv), &args); MYLOGD("Dumpstate command line: %s\n", args.c_str()); int c; - while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) { + while ((c = getopt(argc, argv, "dho:svqzptPBRSV:")) != -1) { switch (c) { case 'd': do_add_date = 1; break; + case 't': telephony_only = true; break; case 'z': do_zip_file = 1; break; case 'o': use_outfile = optarg; break; case 's': use_socket = 1; break; @@ -1312,6 +1386,9 @@ int main(int argc, char *argv[]) { char build_id[PROPERTY_VALUE_MAX]; property_get("ro.build.id", build_id, "UNKNOWN_BUILD"); base_name = base_name + "-" + build_id; + if (telephony_only) { + base_name = base_name + "-telephony"; + } if (do_fb) { // TODO: if dumpstate was an object, the paths could be internal variables and then // we could have a function to calculate the derived values, such as: @@ -1421,48 +1498,60 @@ int main(int argc, char *argv[]) { // duration is logged into MYLOG instead. print_header(version); - // Dumps systrace right away, otherwise it will be filled with unnecessary events. - // 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. - run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL); - run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL); + if (telephony_only) { + dump_iptables(); + if (!drop_root_user()) { + return -1; + } + do_dmesg(); + do_logcat(); + do_kmsg(); + dumpstate_board(); + dump_modem_logs(); + } else { + // Dumps systrace right away, otherwise it will be filled with unnecessary events. + // First try to dump anrd trace if the daemon is running. Otherwise, dump + // the raw trace. + if (!dump_anrd_trace()) { + dump_systrace(); + } - /* collect stack traces from Dalvik and native processes (needs root) */ - dump_traces_path = dump_traces(); + // 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. + run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL); + run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL); + + /* collect stack traces from Dalvik and native processes (needs root) */ + dump_traces_path = dump_traces(); + + /* Run some operations that require root. */ + get_tombstone_fds(tombstone_data); + 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(); - /* Run some operations that require root. */ - get_tombstone_fds(tombstone_data); - 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); - // 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); - // 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; + } - if (!drop_root_user()) { - return -1; + dumpstate(do_early_screenshot ? "": screenshot_path, version); } - dumpstate(do_early_screenshot ? "": screenshot_path, version); - /* close output if needed */ if (is_redirecting) { fclose(stdout); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 5ed9023899..0b6aaab7ac 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -87,6 +87,9 @@ extern std::string bugreport_dir; /* root dir for all files copied as-is into the bugreport. */ extern const std::string ZIP_ROOT_DIR; +/* Checkes whether dumpstate is generating a zipped bugreport. */ +bool is_zipping(); + /* adds a new entry to the existing zip file. */ bool add_zip_entry(const std::string& entry_name, const std::string& entry_path); diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc index 3448e91088..336db9fcd1 100644 --- a/cmds/dumpstate/dumpstate.rc +++ b/cmds/dumpstate/dumpstate.rc @@ -46,3 +46,11 @@ service bugreportwear /system/bin/dumpstate -d -B -P -p -z \ class main disabled oneshot + +# bugreportelefony is a lightweight version of bugreport that only includes a few, urgent +# sections used to report telephony bugs. +service bugreportelefony /system/bin/dumpstate -t -d -B -z \ + -o /data/user_de/0/com.android.shell/files/bugreports/bugreport + class main + disabled + oneshot diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp index bbe48be1ce..6ec636e029 100644 --- a/cmds/dumpstate/utils.cpp +++ b/cmds/dumpstate/utils.cpp @@ -829,8 +829,7 @@ bool drop_root_user() { } gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, - AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC, AID_WAKELOCK, - AID_BLUETOOTH }; + AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC, AID_BLUETOOTH }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); return false; @@ -851,10 +850,8 @@ bool drop_root_user() { capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; - capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = - (CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_BLOCK_SUSPEND)); - capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = - (CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_BLOCK_SUSPEND)); + capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); + capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); capdata[0].inheritable = 0; capdata[1].inheritable = 0; |