dumpstate: move dump_traces to Dumpstate
Prefactoring to handle user consent denial sooner.
BUG: 128270426
Test: adb shell
/data/nativetest64/dumpstate_smoke_test/dumpstate_smoke_test &&
adb shell /data/nativetest64/dumpstate_test/dumpstate_test
Change-Id: Ifbace4391d22901480e41d3125d8a89508ebd52d
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3c47767..5b43172 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -54,7 +54,9 @@
#include <android/os/IIncidentCompanion.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
+#include <debuggerd/client.h>
#include <dumpsys.h>
+#include <dumputils/dump_utils.h>
#include <hidl/ServiceManagement.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
@@ -1444,7 +1446,7 @@
RunDumpsysCritical();
/* collect stack traces from Dalvik and native processes (needs root) */
- dump_traces_path = dump_traces();
+ dump_traces_path = ds.DumpTraces();
/* Run some operations that require root. */
ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
@@ -1581,6 +1583,114 @@
printf("========================================================\n");
}
+const char* Dumpstate::DumpTraces() {
+ 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]);
+ memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
+
+ // Create a new, empty file to receive all trace dumps.
+ //
+ // TODO: This can be simplified once we remove support for the old style
+ // dumps. We can have a file descriptor passed in to dump_traces instead
+ // of creating a file, closing it and then reopening it again.
+ android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
+ if (fd < 0) {
+ MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ // Nobody should have access to this temporary file except dumpstate, but we
+ // temporarily grant 'read' to 'others' here because this file is created
+ // when tombstoned is still running as root, but dumped after dropping. This
+ // can go away once support for old style dumping has.
+ const int chmod_ret = fchmod(fd, 0666);
+ if (chmod_ret < 0) {
+ MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+ if (proc.get() == nullptr) {
+ MYLOGE("opendir /proc failed: %s\n", strerror(errno));
+ return nullptr;
+ }
+
+ // Number of times process dumping has timed out. If we encounter too many
+ // failures, we'll give up.
+ int timeout_failures = 0;
+ bool dalvik_found = false;
+
+ const std::set<int> hal_pids = get_interesting_hal_pids();
+
+ struct dirent* d;
+ while ((d = readdir(proc.get()))) {
+ int pid = atoi(d->d_name);
+ if (pid <= 0) {
+ continue;
+ }
+
+ const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+ std::string exe;
+ if (!android::base::Readlink(link_name, &exe)) {
+ continue;
+ }
+
+ bool is_java_process;
+ if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+ // Don't bother dumping backtraces for the zygote.
+ if (IsZygote(pid)) {
+ continue;
+ }
+
+ dalvik_found = true;
+ is_java_process = true;
+ } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
+ is_java_process = false;
+ } else {
+ // Probably a native process we don't care about, continue.
+ continue;
+ }
+
+ // If 3 backtrace dumps fail in a row, consider debuggerd dead.
+ if (timeout_failures == 3) {
+ dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
+ break;
+ }
+
+ const uint64_t start = Nanotime();
+ const int ret = dump_backtrace_to_file_timeout(
+ pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+ is_java_process ? 5 : 20, fd);
+
+ if (ret == -1) {
+ // For consistency, the header and footer to this message match those
+ // dumped by debuggerd in the success case.
+ dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
+ dprintf(fd, "Dump failed, likely due to a timeout.\n");
+ dprintf(fd, "---- end %d ----", pid);
+ timeout_failures++;
+ continue;
+ }
+
+ // We've successfully dumped stack traces, reset the failure count
+ // and write a summary of the elapsed time to the file and continue with the
+ // next process.
+ timeout_failures = 0;
+
+ dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
+ pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
+ }
+
+ if (!dalvik_found) {
+ MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
+ }
+
+ return file_name_buf.release();
+}
+
void Dumpstate::DumpstateBoard() {
DurationReporter duration_reporter("dumpstate_board()");
printf("========================================================\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index c326bb6..686f1c5 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -291,6 +291,9 @@
// TODO: temporary method until Dumpstate object is properly set
void SetProgress(std::unique_ptr<Progress> progress);
+ // Dumps Dalvik and native stack traces, return the trace file location (nullptr if none).
+ const char* DumpTraces();
+
void DumpstateBoard();
/*
@@ -543,9 +546,6 @@
/* create leading directories, if necessary */
void create_parent_dirs(const char *path);
-/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
-const char *dump_traces();
-
/* for each process in the system, run the specified function */
void for_each_pid(for_each_pid_func func, const char *header);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 2a5516d..802c1b1 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -50,8 +50,6 @@
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
-#include <debuggerd/client.h>
-#include <dumputils/dump_utils.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
@@ -795,115 +793,6 @@
return _redirect_to_file(redirect, path, O_APPEND);
}
-// 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]);
- memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
-
- // Create a new, empty file to receive all trace dumps.
- //
- // TODO: This can be simplified once we remove support for the old style
- // dumps. We can have a file descriptor passed in to dump_traces instead
- // of creating a file, closing it and then reopening it again.
- android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
- if (fd < 0) {
- MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
- return nullptr;
- }
-
- // Nobody should have access to this temporary file except dumpstate, but we
- // temporarily grant 'read' to 'others' here because this file is created
- // when tombstoned is still running as root, but dumped after dropping. This
- // can go away once support for old style dumping has.
- const int chmod_ret = fchmod(fd, 0666);
- if (chmod_ret < 0) {
- MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
- return nullptr;
- }
-
- std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
- if (proc.get() == nullptr) {
- MYLOGE("opendir /proc failed: %s\n", strerror(errno));
- return nullptr;
- }
-
- // Number of times process dumping has timed out. If we encounter too many
- // failures, we'll give up.
- int timeout_failures = 0;
- bool dalvik_found = false;
-
- const std::set<int> hal_pids = get_interesting_hal_pids();
-
- struct dirent* d;
- while ((d = readdir(proc.get()))) {
- int pid = atoi(d->d_name);
- if (pid <= 0) {
- continue;
- }
-
- const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
- std::string exe;
- if (!android::base::Readlink(link_name, &exe)) {
- continue;
- }
-
- bool is_java_process;
- if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
- // Don't bother dumping backtraces for the zygote.
- if (IsZygote(pid)) {
- continue;
- }
-
- dalvik_found = true;
- is_java_process = true;
- } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
- is_java_process = false;
- } else {
- // Probably a native process we don't care about, continue.
- continue;
- }
-
- // If 3 backtrace dumps fail in a row, consider debuggerd dead.
- if (timeout_failures == 3) {
- dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
- break;
- }
-
- const uint64_t start = Nanotime();
- const int ret = dump_backtrace_to_file_timeout(
- pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
- is_java_process ? 5 : 20, fd);
-
- if (ret == -1) {
- // For consistency, the header and footer to this message match those
- // dumped by debuggerd in the success case.
- dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
- dprintf(fd, "Dump failed, likely due to a timeout.\n");
- dprintf(fd, "---- end %d ----", pid);
- timeout_failures++;
- continue;
- }
-
- // We've successfully dumped stack traces, reset the failure count
- // and write a summary of the elapsed time to the file and continue with the
- // next process.
- timeout_failures = 0;
-
- dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
- pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
- }
-
- if (!dalvik_found) {
- MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
- }
-
- return file_name_buf.release();
-}
-
void dump_route_tables() {
DurationReporter duration_reporter("DUMP ROUTE TABLES");
if (PropertiesHelper::IsDryRun()) return;