Loading cmds/dumpstate/bugreport-format.md +4 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,10 @@ files upon the end user’s request: - `title.txt`: whose value is a single-line summary of the problem. - `description.txt`: whose value is a multi-line, detailed description of the problem. ## Android O versions On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made: - The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`). ## Intermediate versions During development, the versions will be suffixed with _-devX_ or _-devX-EXPERIMENTAL_FEATURE_, where _X_ is a number that increases as the Loading cmds/dumpstate/dumpstate.cpp +87 −41 Original line number Diff line number Diff line Loading @@ -827,6 +827,87 @@ static void dump_iptables() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } static void AddAnrTraceFiles() { bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR; std::string dump_traces_dir; /* show the traces we collected in main(), if that was done */ if (dump_traces_path != nullptr) { if (add_to_zip) { dump_traces_dir = dirname(dump_traces_path); MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str()); ds.AddDir(dump_traces_dir, true); } else { MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n", dump_traces_path); ds.DumpFile("VM TRACES JUST NOW", dump_traces_path); } } std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); std::string anr_traces_dir = dirname(anr_traces_path.c_str()); // Make sure directory is not added twice. // TODO: this is an overzealous check because it's relying on dump_traces_path - which is // generated by dump_traces() - and anr_traces_path - which is retrieved from a system // property - but in reality they're the same path (although the former could be nullptr). // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should // be revisited. bool already_dumped = anr_traces_dir == dump_traces_dir; MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n", dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped); if (anr_traces_path.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { int fd = TEMP_FAILURE_RETRY( open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(), strerror(errno)); } else { if (add_to_zip) { if (!already_dumped) { MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n", anr_traces_dir.c_str()); ds.AddDir(anr_traces_dir, true); already_dumped = true; } } else { MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n", anr_traces_path.c_str()); dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd); } } } if (add_to_zip && already_dumped) { MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str()); return; } /* slow traces for slow operations */ struct stat st; if (!anr_traces_path.empty()) { int tail = anr_traces_path.size() - 1; while (tail > 0 && anr_traces_path.at(tail) != '/') { tail--; } int i = 0; while (1) { anr_traces_path = anr_traces_path.substr(0, tail + 1) + android::base::StringPrintf("slow%02d.txt", i); if (stat(anr_traces_path.c_str(), &st)) { // No traces file at this index, done with the files. break; } ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str()); i++; } } } static void dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); unsigned long timeout; Loading Loading @@ -904,44 +985,7 @@ static void dumpstate() { RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { DumpFile("VM TRACES JUST NOW", dump_traces_path); } /* only show ANR traces if they're less than 15 minutes old */ struct stat st; std::string anrTracesPath = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (anrTracesPath.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { int fd = TEMP_FAILURE_RETRY( open(anrTracesPath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anrTracesPath.c_str(), strerror(errno)); } else { dump_file_from_fd("VM TRACES AT LAST ANR", anrTracesPath.c_str(), fd); } } /* slow traces for slow operations */ if (!anrTracesPath.empty()) { int tail = anrTracesPath.size() - 1; while (tail > 0 && anrTracesPath.at(tail) != '/') { tail--; } int i = 0; while (1) { anrTracesPath = anrTracesPath.substr(0, tail + 1) + android::base::StringPrintf("slow%02d.txt", i); if (stat(anrTracesPath.c_str(), &st)) { // No traces file at this index, done with the files. break; } DumpFile("VM TRACES WHEN SLOW", anrTracesPath.c_str()); i++; } } AddAnrTraceFiles(); int dumped = 0; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { Loading Loading @@ -970,6 +1014,7 @@ static void dumpstate() { DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats"); struct stat st; if (!stat(PSTORE_LAST_KMSG, &st)) { /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ DumpFile("LAST KMSG", PSTORE_LAST_KMSG); Loading Loading @@ -1368,9 +1413,10 @@ int main(int argc, char *argv[]) { ds.version_ = VERSION_CURRENT; } if (ds.version_ != VERSION_CURRENT) { MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s')\n", ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str()); if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) { MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n", ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), VERSION_SPLIT_ANR.c_str()); exit(1); } Loading cmds/dumpstate/dumpstate.h +6 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,12 @@ static const int WEIGHT_TOTAL = 6500; */ static std::string VERSION_CURRENT = "1.0"; /* * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version * will be bumped to 2.0-dev-1. */ static std::string VERSION_SPLIT_ANR = "2.0-dev-1"; /* * "Alias" for the current version. */ Loading cmds/dumpstate/utils.cpp +22 −20 Original line number Diff line number Diff line Loading @@ -17,24 +17,25 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <libgen.h> #include <limits.h> #include <poll.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string> #include <string.h> #include <sys/capability.h> #include <sys/inotify.h> #include <sys/klog.h> #include <sys/prctl.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> #include <sys/klog.h> #include <time.h> #include <unistd.h> #include <string> #include <vector> #include <sys/prctl.h> #define LOG_TAG "dumpstate" Loading Loading @@ -1137,32 +1138,31 @@ static bool should_dump_native_traces(const char* path) { /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { DurationReporter duration_reporter("DUMP TRACES", nullptr); if (IsDryRun()) return nullptr; DurationReporter duration_reporter("DUMP TRACES"); const char* result = nullptr; std::string tracesPath = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (tracesPath.empty()) return nullptr; std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (traces_path.empty()) return nullptr; /* move the old traces.txt (if any) out of the way temporarily */ std::string anrTracesPath = tracesPath + ".anr"; if (rename(tracesPath.c_str(), anrTracesPath.c_str()) && errno != ENOENT) { MYLOGE("rename(%s, %s): %s\n", tracesPath.c_str(), anrTracesPath.c_str(), strerror(errno)); std::string anrtraces_path = traces_path + ".anr"; if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) { MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), anrtraces_path.c_str(), strerror(errno)); return nullptr; // Can't rename old traces.txt -- no permission? -- leave it alone instead } /* create a new, empty traces.txt file to receive stack dumps */ int fd = TEMP_FAILURE_RETRY(open(tracesPath.c_str(), int fd = TEMP_FAILURE_RETRY(open(traces_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 0666)); /* -rw-rw-rw- */ if (fd < 0) { MYLOGE("%s: %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno)); return nullptr; } int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { MYLOGE("fchmod on %s failed: %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno)); close(fd); return nullptr; } Loading @@ -1185,9 +1185,9 @@ const char *dump_traces() { goto error_close_fd; } wfd = inotify_add_watch(ifd, tracesPath.c_str(), IN_CLOSE_WRITE); wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE); if (wfd < 0) { MYLOGE("inotify_add_watch(%s): %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno)); goto error_close_ifd; } Loading Loading @@ -1271,15 +1271,17 @@ const char *dump_traces() { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } static std::string dumpTracesPath = tracesPath + ".bugreport"; if (rename(tracesPath.c_str(), dumpTracesPath.c_str())) { MYLOGE("rename(%s, %s): %s\n", tracesPath.c_str(), dumpTracesPath.c_str(), strerror(errno)); static std::string dumptraces_path = android::base::StringPrintf( "%s/bugreport-%s", dirname(traces_path.c_str()), basename(traces_path.c_str())); if (rename(traces_path.c_str(), dumptraces_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), dumptraces_path.c_str(), strerror(errno)); goto error_close_ifd; } result = dumpTracesPath.c_str(); result = dumptraces_path.c_str(); /* replace the saved [ANR] traces.txt file */ rename(anrTracesPath.c_str(), tracesPath.c_str()); rename(anrtraces_path.c_str(), traces_path.c_str()); error_close_ifd: close(ifd); Loading Loading
cmds/dumpstate/bugreport-format.md +4 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,10 @@ files upon the end user’s request: - `title.txt`: whose value is a single-line summary of the problem. - `description.txt`: whose value is a multi-line, detailed description of the problem. ## Android O versions On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made: - The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`). ## Intermediate versions During development, the versions will be suffixed with _-devX_ or _-devX-EXPERIMENTAL_FEATURE_, where _X_ is a number that increases as the Loading
cmds/dumpstate/dumpstate.cpp +87 −41 Original line number Diff line number Diff line Loading @@ -827,6 +827,87 @@ static void dump_iptables() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } static void AddAnrTraceFiles() { bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR; std::string dump_traces_dir; /* show the traces we collected in main(), if that was done */ if (dump_traces_path != nullptr) { if (add_to_zip) { dump_traces_dir = dirname(dump_traces_path); MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str()); ds.AddDir(dump_traces_dir, true); } else { MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n", dump_traces_path); ds.DumpFile("VM TRACES JUST NOW", dump_traces_path); } } std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); std::string anr_traces_dir = dirname(anr_traces_path.c_str()); // Make sure directory is not added twice. // TODO: this is an overzealous check because it's relying on dump_traces_path - which is // generated by dump_traces() - and anr_traces_path - which is retrieved from a system // property - but in reality they're the same path (although the former could be nullptr). // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should // be revisited. bool already_dumped = anr_traces_dir == dump_traces_dir; MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n", dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped); if (anr_traces_path.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { int fd = TEMP_FAILURE_RETRY( open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(), strerror(errno)); } else { if (add_to_zip) { if (!already_dumped) { MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n", anr_traces_dir.c_str()); ds.AddDir(anr_traces_dir, true); already_dumped = true; } } else { MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n", anr_traces_path.c_str()); dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd); } } } if (add_to_zip && already_dumped) { MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str()); return; } /* slow traces for slow operations */ struct stat st; if (!anr_traces_path.empty()) { int tail = anr_traces_path.size() - 1; while (tail > 0 && anr_traces_path.at(tail) != '/') { tail--; } int i = 0; while (1) { anr_traces_path = anr_traces_path.substr(0, tail + 1) + android::base::StringPrintf("slow%02d.txt", i); if (stat(anr_traces_path.c_str(), &st)) { // No traces file at this index, done with the files. break; } ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str()); i++; } } } static void dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); unsigned long timeout; Loading Loading @@ -904,44 +985,7 @@ static void dumpstate() { RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { DumpFile("VM TRACES JUST NOW", dump_traces_path); } /* only show ANR traces if they're less than 15 minutes old */ struct stat st; std::string anrTracesPath = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (anrTracesPath.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { int fd = TEMP_FAILURE_RETRY( open(anrTracesPath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anrTracesPath.c_str(), strerror(errno)); } else { dump_file_from_fd("VM TRACES AT LAST ANR", anrTracesPath.c_str(), fd); } } /* slow traces for slow operations */ if (!anrTracesPath.empty()) { int tail = anrTracesPath.size() - 1; while (tail > 0 && anrTracesPath.at(tail) != '/') { tail--; } int i = 0; while (1) { anrTracesPath = anrTracesPath.substr(0, tail + 1) + android::base::StringPrintf("slow%02d.txt", i); if (stat(anrTracesPath.c_str(), &st)) { // No traces file at this index, done with the files. break; } DumpFile("VM TRACES WHEN SLOW", anrTracesPath.c_str()); i++; } } AddAnrTraceFiles(); int dumped = 0; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { Loading Loading @@ -970,6 +1014,7 @@ static void dumpstate() { DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats"); struct stat st; if (!stat(PSTORE_LAST_KMSG, &st)) { /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ DumpFile("LAST KMSG", PSTORE_LAST_KMSG); Loading Loading @@ -1368,9 +1413,10 @@ int main(int argc, char *argv[]) { ds.version_ = VERSION_CURRENT; } if (ds.version_ != VERSION_CURRENT) { MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s')\n", ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str()); if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) { MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n", ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), VERSION_SPLIT_ANR.c_str()); exit(1); } Loading
cmds/dumpstate/dumpstate.h +6 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,12 @@ static const int WEIGHT_TOTAL = 6500; */ static std::string VERSION_CURRENT = "1.0"; /* * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version * will be bumped to 2.0-dev-1. */ static std::string VERSION_SPLIT_ANR = "2.0-dev-1"; /* * "Alias" for the current version. */ Loading
cmds/dumpstate/utils.cpp +22 −20 Original line number Diff line number Diff line Loading @@ -17,24 +17,25 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <libgen.h> #include <limits.h> #include <poll.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string> #include <string.h> #include <sys/capability.h> #include <sys/inotify.h> #include <sys/klog.h> #include <sys/prctl.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> #include <sys/klog.h> #include <time.h> #include <unistd.h> #include <string> #include <vector> #include <sys/prctl.h> #define LOG_TAG "dumpstate" Loading Loading @@ -1137,32 +1138,31 @@ static bool should_dump_native_traces(const char* path) { /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { DurationReporter duration_reporter("DUMP TRACES", nullptr); if (IsDryRun()) return nullptr; DurationReporter duration_reporter("DUMP TRACES"); const char* result = nullptr; std::string tracesPath = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (tracesPath.empty()) return nullptr; std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (traces_path.empty()) return nullptr; /* move the old traces.txt (if any) out of the way temporarily */ std::string anrTracesPath = tracesPath + ".anr"; if (rename(tracesPath.c_str(), anrTracesPath.c_str()) && errno != ENOENT) { MYLOGE("rename(%s, %s): %s\n", tracesPath.c_str(), anrTracesPath.c_str(), strerror(errno)); std::string anrtraces_path = traces_path + ".anr"; if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) { MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), anrtraces_path.c_str(), strerror(errno)); return nullptr; // Can't rename old traces.txt -- no permission? -- leave it alone instead } /* create a new, empty traces.txt file to receive stack dumps */ int fd = TEMP_FAILURE_RETRY(open(tracesPath.c_str(), int fd = TEMP_FAILURE_RETRY(open(traces_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 0666)); /* -rw-rw-rw- */ if (fd < 0) { MYLOGE("%s: %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno)); return nullptr; } int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { MYLOGE("fchmod on %s failed: %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno)); close(fd); return nullptr; } Loading @@ -1185,9 +1185,9 @@ const char *dump_traces() { goto error_close_fd; } wfd = inotify_add_watch(ifd, tracesPath.c_str(), IN_CLOSE_WRITE); wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE); if (wfd < 0) { MYLOGE("inotify_add_watch(%s): %s\n", tracesPath.c_str(), strerror(errno)); MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno)); goto error_close_ifd; } Loading Loading @@ -1271,15 +1271,17 @@ const char *dump_traces() { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } static std::string dumpTracesPath = tracesPath + ".bugreport"; if (rename(tracesPath.c_str(), dumpTracesPath.c_str())) { MYLOGE("rename(%s, %s): %s\n", tracesPath.c_str(), dumpTracesPath.c_str(), strerror(errno)); static std::string dumptraces_path = android::base::StringPrintf( "%s/bugreport-%s", dirname(traces_path.c_str()), basename(traces_path.c_str())); if (rename(traces_path.c_str(), dumptraces_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), dumptraces_path.c_str(), strerror(errno)); goto error_close_ifd; } result = dumpTracesPath.c_str(); result = dumptraces_path.c_str(); /* replace the saved [ANR] traces.txt file */ rename(anrTracesPath.c_str(), tracesPath.c_str()); rename(anrtraces_path.c_str(), traces_path.c_str()); error_close_ifd: close(ifd); Loading