Loading cmds/dumpstate/dumpstate.cpp +12 −87 Original line number Diff line number Diff line Loading @@ -863,53 +863,6 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file, const std::string& anr_traces_dir) { std::string dump_traces_dir; 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); } } // 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("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n", dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped); android::base::unique_fd fd(TEMP_FAILURE_RETRY( open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK))); if (fd.get() < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.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); } } else { MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n", anr_traces_file.c_str()); dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get()); } } } static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) { MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path, anr_traces_dir.c_str()); Loading Loading @@ -952,39 +905,12 @@ static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_ static void AddAnrTraceFiles() { const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR; std::string anr_traces_file; std::string anr_traces_dir; bool is_global_trace_file = true; // First check whether the stack-trace-dir property is set. When it's set, // each ANR trace will be written to a separate file and not to a global // stack trace file. anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", ""); if (anr_traces_dir.empty()) { anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (!anr_traces_file.empty()) { anr_traces_dir = dirname(anr_traces_file.c_str()); } } else { is_global_trace_file = false; } // We have neither configured a global trace file nor a trace directory, // there will be nothing to dump. if (anr_traces_file.empty() && anr_traces_dir.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); return; } std::string anr_traces_dir = "/data/anr"; if (is_global_trace_file) { AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir); } else { AddAnrTraceDir(add_to_zip, anr_traces_dir); } /* slow traces for slow operations */ // Slow traces for slow operations. struct stat st; if (!anr_traces_dir.empty()) { int i = 0; while (true) { const std::string slow_trace_path = Loading @@ -997,7 +923,6 @@ static void AddAnrTraceFiles() { i++; } } } static void DumpBlockStatFiles() { DurationReporter duration_reporter("DUMP BLOCK STAT"); Loading cmds/dumpstate/utils.cpp +5 −172 Original line number Diff line number Diff line Loading @@ -856,26 +856,6 @@ std::set<int> get_interesting_hal_pids() { return pids; // whether it was okay or not } const char* DumpTraces(const std::string& traces_path); const char* DumpTracesTombstoned(const std::string& traces_dir); /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { DurationReporter duration_reporter("DUMP TRACES"); const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", ""); if (!traces_dir.empty()) { return DumpTracesTombstoned(traces_dir); } const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (!traces_file.empty()) { return DumpTraces(traces_file); } return nullptr; } static bool IsZygote(int pid) { static const std::string kZygotePrefix = "zygote"; Loading @@ -888,8 +868,11 @@ static bool IsZygote(int pid) { return (cmdline.find(kZygotePrefix) == 0); } const char* DumpTracesTombstoned(const std::string& traces_dir) { const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX"; // Dump Dalvik and native stack traces, return the trace file location (nullptr if none). const char* dump_traces() { DurationReporter duration_reporter("DUMP TRACES"); const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX"; const size_t buf_size = temp_file_pattern.length() + 1; std::unique_ptr<char[]> file_name_buf(new char[buf_size]); Loading Loading @@ -991,156 +974,6 @@ const char* DumpTracesTombstoned(const std::string& traces_dir) { return file_name_buf.release(); } const char* DumpTraces(const std::string& traces_path) { const char* result = NULL; /* move the old traces.txt (if any) out of the way temporarily */ 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(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 0666)); /* -rw-rw-rw- */ if (fd < 0) { 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", traces_path.c_str(), strerror(errno)); close(fd); return nullptr; } /* Variables below must be initialized before 'goto' statements */ int dalvik_found = 0; int ifd, wfd = -1; std::set<int> hal_pids = get_interesting_hal_pids(); /* walk /proc and kill -QUIT all Dalvik processes */ DIR *proc = opendir("/proc"); if (proc == NULL) { MYLOGE("/proc: %s\n", strerror(errno)); goto error_close_fd; } /* use inotify to find when processes are done dumping */ ifd = inotify_init(); if (ifd < 0) { MYLOGE("inotify_init: %s\n", strerror(errno)); goto error_close_fd; } wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE); if (wfd < 0) { MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno)); goto error_close_ifd; } struct dirent *d; while ((d = readdir(proc))) { int pid = atoi(d->d_name); if (pid <= 0) continue; char path[PATH_MAX]; char data[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/exe", pid); ssize_t len = readlink(path, data, sizeof(data) - 1); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) { /* skip zygote -- it won't dump its stack anyway */ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)); len = read(cfd, data, sizeof(data) - 1); close(cfd); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "zygote", strlen("zygote"))) { continue; } ++dalvik_found; uint64_t start = Nanotime(); if (kill(pid, SIGQUIT)) { MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); continue; } /* wait for the writable-close notification from inotify */ struct pollfd pfd = { ifd, POLLIN, 0 }; int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS); if (ret < 0) { MYLOGE("poll: %s\n", strerror(errno)); } else if (ret == 0) { MYLOGE("warning: timed out dumping pid %d\n", pid); } else { struct inotify_event ie; read(ifd, &ie, sizeof(ie)); } if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid, (float)(Nanotime() - start) / NANOS_PER_SEC); } } else if (should_dump_native_traces(data) || hal_pids.find(pid) != hal_pids.end()) { /* dump native process if appropriate */ if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { static uint16_t timeout_failures = 0; uint64_t start = Nanotime(); /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */ if (timeout_failures == 3) { dprintf(fd, "too many stack dump failures, skipping...\n"); } else if (dump_backtrace_to_file_timeout( pid, kDebuggerdNativeBacktrace, 20, fd) == -1) { dprintf(fd, "dumping failed, likely due to a timeout\n"); timeout_failures++; } else { timeout_failures = 0; } dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid, (float)(Nanotime() - start) / NANOS_PER_SEC); } } } if (dalvik_found == 0) { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } 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 = dumptraces_path.c_str(); /* replace the saved [ANR] traces.txt file */ rename(anrtraces_path.c_str(), traces_path.c_str()); error_close_ifd: close(ifd); error_close_fd: close(fd); return result; } void dump_route_tables() { DurationReporter duration_reporter("DUMP ROUTE TABLES"); if (PropertiesHelper::IsDryRun()) return; Loading Loading
cmds/dumpstate/dumpstate.cpp +12 −87 Original line number Diff line number Diff line Loading @@ -863,53 +863,6 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file, const std::string& anr_traces_dir) { std::string dump_traces_dir; 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); } } // 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("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n", dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped); android::base::unique_fd fd(TEMP_FAILURE_RETRY( open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK))); if (fd.get() < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.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); } } else { MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n", anr_traces_file.c_str()); dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get()); } } } static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) { MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path, anr_traces_dir.c_str()); Loading Loading @@ -952,39 +905,12 @@ static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_ static void AddAnrTraceFiles() { const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR; std::string anr_traces_file; std::string anr_traces_dir; bool is_global_trace_file = true; // First check whether the stack-trace-dir property is set. When it's set, // each ANR trace will be written to a separate file and not to a global // stack trace file. anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", ""); if (anr_traces_dir.empty()) { anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (!anr_traces_file.empty()) { anr_traces_dir = dirname(anr_traces_file.c_str()); } } else { is_global_trace_file = false; } // We have neither configured a global trace file nor a trace directory, // there will be nothing to dump. if (anr_traces_file.empty() && anr_traces_dir.empty()) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); return; } std::string anr_traces_dir = "/data/anr"; if (is_global_trace_file) { AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir); } else { AddAnrTraceDir(add_to_zip, anr_traces_dir); } /* slow traces for slow operations */ // Slow traces for slow operations. struct stat st; if (!anr_traces_dir.empty()) { int i = 0; while (true) { const std::string slow_trace_path = Loading @@ -997,7 +923,6 @@ static void AddAnrTraceFiles() { i++; } } } static void DumpBlockStatFiles() { DurationReporter duration_reporter("DUMP BLOCK STAT"); Loading
cmds/dumpstate/utils.cpp +5 −172 Original line number Diff line number Diff line Loading @@ -856,26 +856,6 @@ std::set<int> get_interesting_hal_pids() { return pids; // whether it was okay or not } const char* DumpTraces(const std::string& traces_path); const char* DumpTracesTombstoned(const std::string& traces_dir); /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { DurationReporter duration_reporter("DUMP TRACES"); const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", ""); if (!traces_dir.empty()) { return DumpTracesTombstoned(traces_dir); } const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); if (!traces_file.empty()) { return DumpTraces(traces_file); } return nullptr; } static bool IsZygote(int pid) { static const std::string kZygotePrefix = "zygote"; Loading @@ -888,8 +868,11 @@ static bool IsZygote(int pid) { return (cmdline.find(kZygotePrefix) == 0); } const char* DumpTracesTombstoned(const std::string& traces_dir) { const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX"; // Dump Dalvik and native stack traces, return the trace file location (nullptr if none). const char* dump_traces() { DurationReporter duration_reporter("DUMP TRACES"); const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX"; const size_t buf_size = temp_file_pattern.length() + 1; std::unique_ptr<char[]> file_name_buf(new char[buf_size]); Loading Loading @@ -991,156 +974,6 @@ const char* DumpTracesTombstoned(const std::string& traces_dir) { return file_name_buf.release(); } const char* DumpTraces(const std::string& traces_path) { const char* result = NULL; /* move the old traces.txt (if any) out of the way temporarily */ 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(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 0666)); /* -rw-rw-rw- */ if (fd < 0) { 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", traces_path.c_str(), strerror(errno)); close(fd); return nullptr; } /* Variables below must be initialized before 'goto' statements */ int dalvik_found = 0; int ifd, wfd = -1; std::set<int> hal_pids = get_interesting_hal_pids(); /* walk /proc and kill -QUIT all Dalvik processes */ DIR *proc = opendir("/proc"); if (proc == NULL) { MYLOGE("/proc: %s\n", strerror(errno)); goto error_close_fd; } /* use inotify to find when processes are done dumping */ ifd = inotify_init(); if (ifd < 0) { MYLOGE("inotify_init: %s\n", strerror(errno)); goto error_close_fd; } wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE); if (wfd < 0) { MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno)); goto error_close_ifd; } struct dirent *d; while ((d = readdir(proc))) { int pid = atoi(d->d_name); if (pid <= 0) continue; char path[PATH_MAX]; char data[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/exe", pid); ssize_t len = readlink(path, data, sizeof(data) - 1); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) { /* skip zygote -- it won't dump its stack anyway */ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)); len = read(cfd, data, sizeof(data) - 1); close(cfd); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "zygote", strlen("zygote"))) { continue; } ++dalvik_found; uint64_t start = Nanotime(); if (kill(pid, SIGQUIT)) { MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); continue; } /* wait for the writable-close notification from inotify */ struct pollfd pfd = { ifd, POLLIN, 0 }; int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS); if (ret < 0) { MYLOGE("poll: %s\n", strerror(errno)); } else if (ret == 0) { MYLOGE("warning: timed out dumping pid %d\n", pid); } else { struct inotify_event ie; read(ifd, &ie, sizeof(ie)); } if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid, (float)(Nanotime() - start) / NANOS_PER_SEC); } } else if (should_dump_native_traces(data) || hal_pids.find(pid) != hal_pids.end()) { /* dump native process if appropriate */ if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { static uint16_t timeout_failures = 0; uint64_t start = Nanotime(); /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */ if (timeout_failures == 3) { dprintf(fd, "too many stack dump failures, skipping...\n"); } else if (dump_backtrace_to_file_timeout( pid, kDebuggerdNativeBacktrace, 20, fd) == -1) { dprintf(fd, "dumping failed, likely due to a timeout\n"); timeout_failures++; } else { timeout_failures = 0; } dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid, (float)(Nanotime() - start) / NANOS_PER_SEC); } } } if (dalvik_found == 0) { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } 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 = dumptraces_path.c_str(); /* replace the saved [ANR] traces.txt file */ rename(anrtraces_path.c_str(), traces_path.c_str()); error_close_ifd: close(ifd); error_close_fd: close(fd); return result; } void dump_route_tables() { DurationReporter duration_reporter("DUMP ROUTE TABLES"); if (PropertiesHelper::IsDryRun()) return; Loading