summaryrefslogtreecommitdiff
path: root/cmds/dumpstate/dumpstate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/dumpstate/dumpstate.cpp')
-rw-r--r--cmds/dumpstate/dumpstate.cpp877
1 files changed, 299 insertions, 578 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2d11b908c2..581d3ded89 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/mount.h>
#include <sys/poll.h>
#include <sys/prctl.h>
#include <sys/resource.h>
@@ -79,7 +78,6 @@
#include <hardware_legacy/power.h>
#include <hidl/ServiceManagement.h>
#include <log/log.h>
-#include <log/log_read.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -96,7 +94,6 @@ using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
using ::android::hardware::dumpstate::V1_1::toString;
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
-using ::std::placeholders::_1;
// TODO: remove once moved to namespace
using android::defaultServiceManager;
@@ -115,9 +112,7 @@ using android::base::StringPrintf;
using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::DumpPool;
using android::os::dumpstate::PropertiesHelper;
-using android::os::dumpstate::TaskQueue;
// Keep in sync with
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -130,8 +125,8 @@ static const int32_t WEIGHT_FILE = 5;
static Dumpstate& ds = Dumpstate::GetInstance();
static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
const CommandOptions& options = CommandOptions::DEFAULT,
- bool verbose_duration = false, int out_fd = STDOUT_FILENO) {
- return ds.RunCommand(title, full_command, options, verbose_duration, out_fd);
+ bool verbose_duration = false) {
+ return ds.RunCommand(title, full_command, options, verbose_duration);
}
// Reasonable value for max stats.
@@ -175,8 +170,6 @@ void add_mountinfo();
#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
#define LINKERCONFIG_DIR "/linkerconfig"
#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
-#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
-#define CGROUPFS_DIR "/sys/fs/cgroup"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -202,35 +195,8 @@ static const std::string ANR_FILE_PREFIX = "anr_";
func_ptr(__VA_ARGS__); \
RETURN_IF_USER_DENIED_CONSENT();
-// Runs func_ptr, and logs a duration report after it's finished.
-#define RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, ...) \
- { \
- DurationReporter duration_reporter_in_macro(log_title); \
- func_ptr(__VA_ARGS__); \
- }
-
-// Similar with RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK, an additional duration report
-// is output after a slow function is finished.
-#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(log_title, func_ptr, ...) \
- RETURN_IF_USER_DENIED_CONSENT(); \
- RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \
- RETURN_IF_USER_DENIED_CONSENT();
-
-#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
- RETURN_IF_USER_DENIED_CONSENT(); \
- pool_ptr->waitForTask(task_name); \
- RETURN_IF_USER_DENIED_CONSENT();
-
static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
-// Names of parallel tasks, they are used for the DumpPool to identify the dump
-// task and the log title of the duration report.
-static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
-static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
-static const std::string DUMP_HALS_TASK = "DUMP HALS";
-static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
-static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
-
namespace android {
namespace os {
namespace {
@@ -339,12 +305,8 @@ static bool CopyFileToFile(const std::string& input_file, const std::string& out
static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
- long dumpsysTimeoutMs = 0, int out_fd = STDOUT_FILENO) {
- return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs, out_fd);
-}
-static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
- int out_fd) {
- return ds.RunDumpsys(title, dumpsysArgs, Dumpstate::DEFAULT_DUMPSYS, 0, out_fd);
+ long dumpsysTimeoutMs = 0) {
+ return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
}
static int DumpFile(const std::string& title, const std::string& path) {
return ds.DumpFile(title, path);
@@ -699,31 +661,18 @@ static int dump_stat_from_fd(const char *title __unused, const char *path, int f
static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
-// Returns the actual readable size of the given buffer or -1 on error.
-static long logcat_buffer_readable_size(const std::string& buffer) {
- std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
- android_logger_list_alloc(0, 0, 0), &android_logger_list_free};
- auto logger = android_logger_open(logger_list.get(), android_name_to_log_id(buffer.c_str()));
-
- return android_logger_get_log_readable_size(logger);
-}
-
-// Returns timeout in ms to read a list of buffers.
+/* timeout in ms to read a list of buffers */
static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
unsigned long timeout_ms = 0;
for (const auto& buffer : buffers) {
- long readable_size = logcat_buffer_readable_size(buffer);
- if (readable_size > 0) {
- // Engineering margin is ten-fold our guess.
- timeout_ms += 10 * (readable_size + worst_write_perf) / worst_write_perf;
- }
+ log_id_t id = android_name_to_log_id(buffer.c_str());
+ unsigned long property_size = __android_logger_get_buffer_size(id);
+ /* Engineering margin is ten-fold our guess */
+ timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
}
return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
}
-// Opens a socket and returns its file descriptor.
-static int open_socket(const char* service);
-
Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
}
@@ -794,9 +743,6 @@ void Dumpstate::PrintHeader() const {
if (module_metadata_version != 0) {
printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
}
- printf("SDK extension versions [r=%s s=%s]\n",
- android::base::GetProperty("build.version.extensions.r", "-").c_str(),
- android::base::GetProperty("build.version.extensions.s", "-").c_str());
printf("Kernel: ");
DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
@@ -805,9 +751,8 @@ void Dumpstate::PrintHeader() const {
RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
CommandOptions::WithTimeout(1).Always().Build());
printf("Bugreport format version: %s\n", version_.c_str());
- printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
- id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
- options_->args.c_str(), options_->bugreport_mode.c_str());
+ printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
+ PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
printf("\n");
}
@@ -1037,6 +982,7 @@ static void DumpIncidentReport() {
MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
return;
}
+ DurationReporter duration_reporter("INCIDENT REPORT");
const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
@@ -1051,29 +997,9 @@ static void DumpIncidentReport() {
// Use a different name from "incident.proto"
// /proto/incident.proto is reserved for incident service dump
// i.e. metadata for debugging.
- ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "incident_report" + kProtoExt,
- path);
- } else {
- unlink(path.c_str());
+ ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
}
-}
-
-static void MaybeAddSystemTraceToZip() {
- // This function copies into the .zip the system trace that was snapshotted
- // by the early call to MaybeSnapshotSystemTrace(), if any background
- // tracing was happening.
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping system trace because it's not a zipped bugreport\n");
- return;
- }
- if (!ds.has_system_trace_) {
- // No background trace was happening at the time dumpstate was invoked.
- return;
- }
- ds.AddZipEntry(
- ZIP_ROOT_DIR + SYSTEM_TRACE_SNAPSHOT,
- SYSTEM_TRACE_SNAPSHOT);
- android::os::UnlinkAndLogOnError(SYSTEM_TRACE_SNAPSHOT);
+ unlink(path.c_str());
}
static void DumpVisibleWindowViews() {
@@ -1212,6 +1138,10 @@ static void DumpBlockStatFiles() {
static void DumpPacketStats() {
DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+ DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+ DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
}
static void DumpIpAddrAndRules() {
@@ -1241,15 +1171,8 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i
if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
- if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
- service == String16("meminfo")) {
- // Use a longer timeout for meminfo, since 30s is not always enough.
- status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
- } else {
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
- }
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
@@ -1371,21 +1294,15 @@ static Dumpstate::RunStatus RunDumpsysNormal() {
/* timeout= */ 90s, /* service_timeout= */ 10s);
}
-/*
- * |out_fd| A fd to support the DumpPool to output results to a temporary file.
- * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
- * if it's not running in the parallel task.
- */
-static void DumpHals(int out_fd = STDOUT_FILENO) {
+static void DumpHals() {
if (!ds.IsZipping()) {
- RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
- CommandOptions::WithTimeout(60).AsRootIfAvailable().Build(),
- false, out_fd);
+ RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
return;
}
- RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
- CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
- false, out_fd);
+ DurationReporter duration_reporter("DUMP HALS");
+ RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
using android::hidl::manager::V1_0::IServiceManager;
using android::hardware::defaultServiceManager;
@@ -1407,7 +1324,6 @@ static void DumpHals(int out_fd = STDOUT_FILENO) {
}, '_');
const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
- bool empty = false;
{
auto fd = android::base::unique_fd(
TEMP_FAILURE_RETRY(open(path.c_str(),
@@ -1422,14 +1338,13 @@ static void DumpHals(int out_fd = STDOUT_FILENO) {
{"lshal", "debug", "-E", interface},
CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
- empty = 0 == lseek(fd, 0, SEEK_END);
- }
- if (!empty) {
- ds.EnqueueAddZipEntryAndCleanupIfNeeded("lshal-debug/" + cleanName + ".txt",
- path);
- } else {
- unlink(path.c_str());
+ bool empty = 0 == lseek(fd, 0, SEEK_END);
+ if (!empty) {
+ ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
+ }
}
+
+ unlink(path.c_str());
}
});
@@ -1501,8 +1416,6 @@ static void DumpstateLimitedOnly() {
RunDumpsys("DUMPSYS NETWORK_SERVICE_LIMITED", {"wifi", "-a"},
CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS CONNECTIVITY REQUESTS", {"connectivity", "requests"},
- CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
printf("========================================================\n");
printf("== Dropbox crashes\n");
@@ -1519,73 +1432,6 @@ static void DumpstateLimitedOnly() {
printf("========================================================\n");
}
-/*
- * |out_fd| A fd to support the DumpPool to output results to a temporary file.
- * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
- * if it's not running in the parallel task.
- */
-static void DumpCheckins(int out_fd = STDOUT_FILENO) {
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Checkins\n");
- dprintf(out_fd, "========================================================\n");
-
- RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
- RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
- RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
- RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
- RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
- RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"}, out_fd);
-}
-
-/*
- * Runs dumpsys on activity service to dump all application activities, services
- * and providers in the device.
- *
- * |out_fd| A fd to support the DumpPool to output results to a temporary file.
- * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
- * if it's not running in the parallel task.
- */
-static void DumpAppInfos(int out_fd = STDOUT_FILENO) {
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Running Application Activities\n");
- dprintf(out_fd, "========================================================\n");
-
- // The following dumpsys internally collects output from running apps, so it can take a long
- // time. So let's extend the timeout.
-
- const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
-
- RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
-
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Running Application Services (platform)\n");
- dprintf(out_fd, "========================================================\n");
-
- RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
- DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
-
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Running Application Services (non-platform)\n");
- dprintf(out_fd, "========================================================\n");
-
- RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
-
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Running Application Providers (platform)\n");
- dprintf(out_fd, "========================================================\n");
-
- RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
- DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
-
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Running Application Providers (non-platform)\n");
- dprintf(out_fd, "========================================================\n");
-
- RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
-}
-
// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
// via the consent they are shown. Ignores other errors that occur while running various
// commands. The consent checking is currently done around long running tasks, which happen to
@@ -1593,18 +1439,6 @@ static void DumpAppInfos(int out_fd = STDOUT_FILENO) {
static Dumpstate::RunStatus dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
- // Enqueue slow functions into the thread pool, if the parallel run is enabled.
- if (ds.dump_pool_) {
- // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
- // drop root user. Restarts it with two threads for the parallel run.
- ds.dump_pool_->start(/* thread_counts = */2);
-
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
- ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
- }
-
// Dump various things. Note that anything that takes "long" (i.e. several seconds) should
// check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
// in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
@@ -1636,11 +1470,7 @@ static Dumpstate::RunStatus dumpstate() {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
CommandOptions::AS_ROOT);
- if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
- } else {
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
- }
+ DumpHals();
RunCommand("PRINTENV", {"printenv"});
RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -1649,13 +1479,10 @@ static Dumpstate::RunStatus dumpstate() {
MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
} else {
RunCommand("LSMOD", {"lsmod"});
- RunCommand("MODULES INFO",
- {"sh", "-c", "cat /proc/modules | cut -d' ' -f1 | "
- " while read MOD ; do echo modinfo:$MOD ; modinfo $MOD ; "
- "done"}, CommandOptions::AS_ROOT);
}
- if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
+ if (__android_logger_property_get_bool(
+ "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
DoKernelLogcat();
} else {
do_dmesg();
@@ -1668,8 +1495,8 @@ static Dumpstate::RunStatus dumpstate() {
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
- /* Dump Nfc NCI logs */
- ds.AddDir("/data/misc/nfc/logs", true);
+ /* Dump Bluetooth HCI logs */
+ ds.AddDir("/data/misc/bluetooth/logs", true);
if (ds.options_->do_screenshot && !ds.do_early_screenshot_) {
MYLOGI("taking late screenshot\n");
@@ -1678,8 +1505,6 @@ static Dumpstate::RunStatus dumpstate() {
AddAnrTraceFiles();
- MaybeAddSystemTraceToZip();
-
// NOTE: tombstones are always added as separate entries in the zip archive
// and are not interspersed with the main report.
const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
@@ -1704,12 +1529,6 @@ static Dumpstate::RunStatus dumpstate() {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
- // The dump mechanism in connectivity is refactored due to modularization work. Connectivity can
- // only register with a default priority(NORMAL priority). Dumpstate has to call connectivity
- // dump with priority parameters to dump high priority information.
- RunDumpsys("SERVICE HIGH connectivity", {"connectivity", "--dump-priority", "HIGH"},
- CommandOptions::WithTimeout(10).Build());
-
RunCommand("SYSTEM PROPERTIES", {"getprop"});
RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
@@ -1733,11 +1552,7 @@ static Dumpstate::RunStatus dumpstate() {
ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
- if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
- } else {
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
- }
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
/* Migrate the ril_dumpstate to a device specific dumpstate? */
int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
@@ -1759,16 +1574,57 @@ static Dumpstate::RunStatus dumpstate() {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
- /* Dump Bluetooth HCI logs after getting bluetooth_manager dumpsys */
- ds.AddDir("/data/misc/bluetooth/logs", true);
+ printf("========================================================\n");
+ printf("== Checkins\n");
+ printf("========================================================\n");
- if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
- } else {
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
- }
+ RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
+
+ RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
+ RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
+ RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
+ RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
+
+ printf("========================================================\n");
+ printf("== Running Application Activities\n");
+ printf("========================================================\n");
+
+ // The following dumpsys internally collects output from running apps, so it can take a long
+ // time. So let's extend the timeout.
+
+ const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
+
+ RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
+
+ printf("========================================================\n");
+ printf("== Running Application Services (platform)\n");
+ printf("========================================================\n");
+
+ RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
+ DUMPSYS_COMPONENTS_OPTIONS);
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpAppInfos);
+ printf("========================================================\n");
+ printf("== Running Application Services (non-platform)\n");
+ printf("========================================================\n");
+
+ RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS);
+
+ printf("========================================================\n");
+ printf("== Running Application Providers (platform)\n");
+ printf("========================================================\n");
+
+ RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS);
+
+ printf("========================================================\n");
+ printf("== Running Application Providers (non-platform)\n");
+ printf("========================================================\n");
+
+ RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS);
printf("========================================================\n");
printf("== Dropbox crashes\n");
@@ -1793,15 +1649,7 @@ static Dumpstate::RunStatus dumpstate() {
// Add linker configuration directory
ds.AddDir(LINKERCONFIG_DIR, true);
- /* Dump cgroupfs */
- ds.AddDir(CGROUPFS_DIR, true);
-
- if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
- } else {
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
- DumpIncidentReport);
- }
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
return Dumpstate::RunStatus::OK;
}
@@ -1822,18 +1670,7 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
time_t logcat_ts = time(nullptr);
/* collect stack traces from Dalvik and native processes (needs root) */
- if (dump_pool_) {
- RETURN_IF_USER_DENIED_CONSENT();
- // One thread is enough since we only need to enqueue DumpTraces here.
- dump_pool_->start(/* thread_counts = */1);
-
- // DumpTraces takes long time, post it to the another thread in the
- // pool, if pool is available
- dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
- } else {
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
- &dump_traces_path);
- }
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
/* Run some operations that require root. */
ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
@@ -1867,22 +1704,15 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
// Gather shared memory buffer info if the product implements it
- RunCommand("Dmabuf dump", {"dmabuf_dump"});
- RunCommand("Dmabuf per-buffer/per-exporter/per-device stats", {"dmabuf_dump", "-b"});
+ struct stat st;
+ if (!stat("/product/bin/dmabuf_dump", &st)) {
+ RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
+ }
DumpFile("PSI cpu", "/proc/pressure/cpu");
DumpFile("PSI memory", "/proc/pressure/memory");
DumpFile("PSI io", "/proc/pressure/io");
- if (dump_pool_) {
- RETURN_IF_USER_DENIED_CONSENT();
- dump_pool_->waitForTask(DUMP_TRACES_TASK);
-
- // Current running thread in the pool is the root user also. Shutdown
- // the pool and restart later to ensure all threads in the pool could
- // drop the root user.
- dump_pool_->shutdown();
- }
if (!DropRootUser()) {
return Dumpstate::RunStatus::ERROR;
}
@@ -1894,39 +1724,31 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
return status;
}
-// Common states for telephony and wifi which are needed to be collected before
-// dumpstate drop the root user.
-static void DumpstateRadioAsRoot() {
- DumpIpTablesAsRoot();
- ds.AddDir(LOGPERSIST_DATA_DIR, false);
-}
-
// This method collects common dumpsys for telephony and wifi. Typically, wifi
// reports are fine to include all information, but telephony reports on user
// builds need to strip some content (see DumpstateTelephonyOnly).
static void DumpstateRadioCommon(bool include_sensitive_info = true) {
+ DumpIpTablesAsRoot();
+
+ ds.AddDir(LOGPERSIST_DATA_DIR, false);
+
+ if (!DropRootUser()) {
+ return;
+ }
+
// We need to be picky about some stuff for telephony reports on user builds.
if (!include_sensitive_info) {
// Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
DoRadioLogcat();
} else {
- // DumpHals takes long time, post it to the another thread in the pool,
- // if pool is available.
- if (ds.dump_pool_) {
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
- }
// Contains various system properties and process startup info.
do_dmesg();
// Logs other than the radio buffer may contain package/component names and potential PII.
DoLogcat();
// Too broad for connectivity problems.
DoKmsg();
- // DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
- if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
- } else {
- RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
- }
+ // Contains unrelated hardware info (camera, NFC, biometrics, ...).
+ DumpHals();
}
DumpPacketStats();
@@ -1950,21 +1772,6 @@ static void DumpstateTelephonyOnly(const std::string& calling_package) {
const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
- DumpstateRadioAsRoot();
- if (!DropRootUser()) {
- return;
- }
-
- // Starts thread pool after the root user is dropped, and two additional threads
- // are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
- if (ds.dump_pool_) {
- ds.dump_pool_->start(/*thread_counts =*/2);
-
- // DumpstateBoard takes long time, post it to the another thread in the pool,
- // if pool is available.
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
- }
-
DumpstateRadioCommon(include_sensitive_info);
if (include_sensitive_info) {
@@ -1981,8 +1788,6 @@ static void DumpstateTelephonyOnly(const std::string& calling_package) {
RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS", {"vcn_management"}, CommandOptions::WithTimeout(90).Build(),
- SEC_TO_MSEC(10));
if (include_sensitive_info) {
// Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
@@ -2043,29 +1848,12 @@ static void DumpstateTelephonyOnly(const std::string& calling_package) {
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
-
- if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
- } else {
- RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
- }
}
// This method collects dumpsys for wifi debugging only
static void DumpstateWifiOnly() {
DurationReporter duration_reporter("DUMPSTATE");
- DumpstateRadioAsRoot();
- if (!DropRootUser()) {
- return;
- }
-
- // Starts thread pool after the root user is dropped. Only one additional
- // thread is needed for DumpHals in the DumpstateRadioCommon.
- if (ds.dump_pool_) {
- ds.dump_pool_->start(/*thread_counts =*/1);
- }
-
DumpstateRadioCommon();
printf("========================================================\n");
@@ -2083,7 +1871,9 @@ static void DumpstateWifiOnly() {
}
Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
- const std::string temp_file_pattern = ds.bugreport_internal_dir_ + "/dumptrace_XXXXXX";
+ 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);
@@ -2190,31 +1980,17 @@ Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
return RunStatus::OK;
}
-void Dumpstate::DumpstateBoard(int out_fd) {
- dprintf(out_fd, "========================================================\n");
- dprintf(out_fd, "== Board\n");
- dprintf(out_fd, "========================================================\n");
+void Dumpstate::DumpstateBoard() {
+ DurationReporter duration_reporter("dumpstate_board()");
+ printf("========================================================\n");
+ printf("== Board\n");
+ printf("========================================================\n");
if (!IsZipping()) {
MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
return;
}
- /*
- * mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
- * set to true and unmount it after invoking dumpstateBoard_* methods.
- * This is to enable debug builds to not have debugfs mounted during runtime.
- * It will also ensure that debugfs is only accessed by the dumpstate HAL.
- */
- auto mount_debugfs =
- android::base::GetBoolProperty("ro.product.debugfs_restrictions.enabled", false);
- if (mount_debugfs) {
- RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
- AS_ROOT_20);
- RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"},
- AS_ROOT_20);
- }
-
std::vector<std::string> paths;
std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
for (int i = 0; i < NUM_OF_DUMPS; i++) {
@@ -2314,13 +2090,6 @@ void Dumpstate::DumpstateBoard(int out_fd) {
"there might be racing in content\n", killing_timeout_sec);
}
- if (mount_debugfs) {
- auto keep_debugfs_mounted =
- android::base::GetProperty("persist.dbg.keep_debugfs_mounted", "");
- if (keep_debugfs_mounted.empty())
- RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20);
- }
-
auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
for (size_t i = 0; i < paths.size(); i++) {
struct stat s;
@@ -2341,26 +2110,27 @@ void Dumpstate::DumpstateBoard(int out_fd) {
MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
continue;
}
- remover[i].Disable();
- EnqueueAddZipEntryAndCleanupIfNeeded(kDumpstateBoardFiles[i], paths[i]);
- dprintf(out_fd, "*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
+ AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
+ printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
}
}
static void ShowUsage() {
fprintf(stderr,
- "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-p] "
- "[-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
+ "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-d] [-p] "
+ "[-z] [-s] [-S] [-q] [-P] [-R] [-L] [-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 custom directory (only in limited mode)\n"
+ " -d: append date to filename\n"
" -p: capture screenshot to filename.png\n"
- " -s: write zipped file to control socket (for init)\n"
- " -S: write file location to control socket (for init)\n"
+ " -z: generate zipped file\n"
+ " -s: write output to control socket (for init)\n"
+ " -S: write file location to control socket (for init; requires -z)\n"
" -q: disable vibrate\n"
" -P: send broadcast when started and do progress updates\n"
- " -R: take bugreport in remote mode (shouldn't be used with -P)\n"
+ " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
" -w: start binder service and make it wait for a call to startBugreport\n"
" -L: output limited information that is safe for submission in feedback reports\n"
" -v: prints the dumpstate header and exit\n");
@@ -2371,11 +2141,6 @@ static void register_sig_handler() {
}
bool Dumpstate::FinishZipFile() {
- // Runs all enqueued adding zip entry and cleanup tasks before finishing the zip file.
- if (zip_entry_tasks_) {
- zip_entry_tasks_->run(/* do_cancel = */false);
- }
-
std::string entry_name = base_name_ + "-" + name_ + ".txt";
MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
tmp_path_.c_str());
@@ -2442,9 +2207,7 @@ static void SendBroadcast(const std::string& action, const std::vector<std::stri
static void Vibrate(int duration_ms) {
// clang-format off
- std::vector<std::string> args = {"cmd", "vibrator_manager", "synced", "-f", "-d", "dumpstate",
- "oneshot", std::to_string(duration_ms)};
- RunCommand("", args,
+ RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
CommandOptions::WithTimeout(10)
.Log("Vibrate: '%s'\n")
.Always()
@@ -2461,17 +2224,21 @@ static void MaybeResolveSymlink(std::string* path) {
/*
* Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
- * and adds the version file. Return false if zip_file could not be open to write.
+ * if we are writing zip files and adds the version file.
*/
-static bool PrepareToWriteToFile() {
+static void PrepareToWriteToFile() {
MaybeResolveSymlink(&ds.bugreport_internal_dir_);
std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
- char date[80];
- strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
- ds.name_ = date;
+ if (ds.options_->do_add_date) {
+ char date[80];
+ strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+ ds.name_ = date;
+ } else {
+ ds.name_ = "undated";
+ }
if (ds.options_->telephony_only) {
ds.base_name_ += "-telephony";
@@ -2498,17 +2265,18 @@ static bool PrepareToWriteToFile() {
destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
- ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
- MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
- create_parent_dirs(ds.path_.c_str());
- ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
- if (ds.zip_file == nullptr) {
- MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
- return false;
+ if (ds.options_->do_zip_file) {
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
+ MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
+ create_parent_dirs(ds.path_.c_str());
+ ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
+ if (ds.zip_file == nullptr) {
+ MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
+ } else {
+ ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
+ }
+ ds.AddTextZipEntry("version.txt", ds.version_);
}
- ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
- ds.AddTextZipEntry("version.txt", ds.version_);
- return true;
}
/*
@@ -2516,9 +2284,14 @@ static bool PrepareToWriteToFile() {
* printing zipped file status, etc.
*/
static void FinalizeFile() {
- bool do_text_file = !ds.FinishZipFile();
- if (do_text_file) {
- MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
+ bool do_text_file = true;
+ if (ds.options_->do_zip_file) {
+ if (!ds.FinishZipFile()) {
+ MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
+ do_text_file = true;
+ } else {
+ do_text_file = false;
+ }
}
std::string final_path = ds.path_;
@@ -2527,9 +2300,7 @@ static void FinalizeFile() {
android::os::CopyFileToFile(ds.path_, final_path);
}
- if (ds.options_->stream_to_socket) {
- android::os::CopyFileToFd(ds.path_, ds.control_socket_fd_);
- } else if (ds.options_->progress_updates_to_socket) {
+ if (ds.options_->use_control_socket) {
if (do_text_file) {
dprintf(ds.control_socket_fd_,
"FAIL:could not create zip file, check %s "
@@ -2573,6 +2344,7 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
+ options->do_start_service = true;
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
@@ -2584,7 +2356,9 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt
options->dumpstate_hal_mode = DumpstateMode::REMOTE;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+ options->do_start_service = true;
options->do_progress_updates = true;
+ options->do_zip_file = true;
options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
@@ -2597,6 +2371,7 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
+ options->do_zip_file = true;
options->do_screenshot = false;
options->dumpstate_hal_mode = DumpstateMode::WIFI;
break;
@@ -2607,13 +2382,13 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt
static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
MYLOGI(
- "do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
- "is_remote_mode: %d show_header_only: %d telephony_only: %d "
+ "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d "
+ "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
"wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
"limited_only: %d args: %s\n",
- options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
+ options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
options.do_screenshot, options.is_remote_mode, options.show_header_only,
- options.telephony_only, options.wifi_only,
+ options.do_start_service, options.telephony_only, options.wifi_only,
options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
}
@@ -2622,6 +2397,11 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
const android::base::unique_fd& bugreport_fd_in,
const android::base::unique_fd& screenshot_fd_in,
bool is_screenshot_requested) {
+ // In the new API world, date is always added; output is always a zip file.
+ // TODO(111441001): remove these options once they are obsolete.
+ do_add_date = true;
+ do_zip_file = true;
+
// Duplicate the fds because the passed in fds don't outlive the binder transaction.
bugreport_fd.reset(dup(bugreport_fd_in.get()));
screenshot_fd.reset(dup(screenshot_fd_in.get()));
@@ -2635,20 +2415,18 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[])
while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1) {
switch (c) {
// clang-format off
+ case 'd': do_add_date = true; break;
+ case 'z': do_zip_file = true; break;
case 'o': out_dir = optarg; break;
- case 's': stream_to_socket = true; break;
- case 'S': progress_updates_to_socket = true; break;
+ case 's': use_socket = true; break;
+ case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
case 'q': do_vibrate = false; break;
case 'p': do_screenshot = true; break;
case 'P': do_progress_updates = true; break;
case 'R': is_remote_mode = true; break;
case 'L': limited_only = true; break;
- case 'V':
- case 'd':
- case 'z':
- // compatibility no-op
- break;
+ case 'V': break; // compatibility no-op
case 'w':
// This was already processed
break;
@@ -2677,15 +2455,19 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[])
}
bool Dumpstate::DumpOptions::ValidateOptions() const {
- if (bugreport_fd.get() != -1 && stream_to_socket) {
+ if (bugreport_fd.get() != -1 && !do_zip_file) {
+ return false;
+ }
+
+ if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
return false;
}
- if ((progress_updates_to_socket || do_progress_updates) && stream_to_socket) {
+ if (use_control_socket && !do_zip_file) {
return false;
}
- if (is_remote_mode && (do_progress_updates || stream_to_socket)) {
+ if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
return false;
}
return true;
@@ -2737,15 +2519,6 @@ void Dumpstate::Cancel() {
}
tombstone_data_.clear();
anr_data_.clear();
-
- // Instead of shutdown the pool, we delete temporary files directly since
- // shutdown blocking the call.
- if (dump_pool_) {
- dump_pool_->deleteTempFiles();
- }
- if (zip_entry_tasks_) {
- zip_entry_tasks_->run(/*do_cancel =*/ true);
- }
}
/*
@@ -2760,16 +2533,17 @@ void Dumpstate::Cancel() {
* The temporary bugreport is then populated via printfs, dumping contents of files and
* output of commands to stdout.
*
- * A bunch of other files and dumps are added to the zip archive.
+ * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
+ * text file.
*
- * The temporary bugreport file and the log file also get added to the archive.
+ * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
+ * gets added to the archive.
*
* Bugreports are first generated in a local directory and later copied to the caller's fd
* or directory if supplied.
*/
Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
const std::string& calling_package) {
- DurationReporter duration_reporter("RUN INTERNAL", /* logcat_only = */true);
LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
@@ -2810,9 +2584,14 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
calling_uid, calling_package.c_str());
+ // Redirect output if needed
+ bool is_redirecting = options_->OutputToFile();
+
// TODO: temporarily set progress until it's part of the Dumpstate constructor
std::string stats_path =
- android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str());
+ is_redirecting
+ ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
+ : "";
progress_.reset(new Progress(stats_path));
if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
@@ -2824,6 +2603,15 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
register_sig_handler();
+ // TODO(b/111441001): maybe skip if already started?
+ if (options_->do_start_service) {
+ MYLOGI("Starting 'dumpstate' service\n");
+ android::status_t ret;
+ if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+ MYLOGE("Unable to start DumpstateService: %d\n", ret);
+ }
+ }
+
if (PropertiesHelper::IsDryRun()) {
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
@@ -2835,33 +2623,35 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
- if (options_->stream_to_socket || options_->progress_updates_to_socket) {
+ if (options_->use_socket) {
+ if (!redirect_to_socket(stdout, "dumpstate")) {
+ return ERROR;
+ }
+ }
+
+ if (options_->use_control_socket) {
MYLOGD("Opening control socket\n");
- control_socket_fd_ = open_socket_fn_("dumpstate");
+ control_socket_fd_ = open_socket("dumpstate");
if (control_socket_fd_ == -1) {
return ERROR;
}
- if (options_->progress_updates_to_socket) {
- options_->do_progress_updates = 1;
- }
+ options_->do_progress_updates = 1;
}
- if (!PrepareToWriteToFile()) {
- return ERROR;
- }
+ if (is_redirecting) {
+ PrepareToWriteToFile();
- // Interactive, wear & telephony modes are default to true.
- // and may enable from cli option or when using control socket
- if (options_->do_progress_updates) {
- // clang-format off
- std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP",
- };
- // clang-format on
- // Send STARTED broadcast for apps that listen to bugreport generation events
- SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
- if (options_->progress_updates_to_socket) {
- dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
+ if (options_->do_progress_updates) {
+ // clang-format off
+ std::vector<std::string> am_args = {
+ "--receiver-permission", "android.permission.DUMP",
+ };
+ // clang-format on
+ // Send STARTED broadcast for apps that listen to bugreport generation events
+ SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
+ if (options_->use_control_socket) {
+ dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
+ }
}
}
@@ -2876,83 +2666,76 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
Vibrate(150);
}
- if (zip_file != nullptr) {
+ if (options_->do_zip_file && zip_file != nullptr) {
if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
- strerror(errno));
+ strerror(errno));
}
}
int dup_stdout_fd;
int dup_stderr_fd;
- // Redirect stderr to log_path_ for debugging.
- TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
- return ERROR;
- }
- if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
- strerror(errno));
- }
+ if (is_redirecting) {
+ // Redirect stderr to log_path_ for debugging.
+ TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
+ if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+ return ERROR;
+ }
+ if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+ strerror(errno));
+ }
- // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
- // moved into zip file later, if zipping.
- TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
- // TODO: why not write to a file instead of stdout to overcome this problem?
- /* TODO: rather than generating a text file now and zipping it later,
- it would be more efficient to redirect stdout to the zip entry
- directly, but the libziparchive doesn't support that option yet. */
- if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
- return ERROR;
- }
- if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
- tmp_path_.c_str(), strerror(errno));
+ // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+ // moved into zip file later, if zipping.
+ TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+ // TODO: why not write to a file instead of stdout to overcome this problem?
+ /* TODO: rather than generating a text file now and zipping it later,
+ it would be more efficient to redirect stdout to the zip entry
+ directly, but the libziparchive doesn't support that option yet. */
+ if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+ return ERROR;
+ }
+ if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
+ tmp_path_.c_str(), strerror(errno));
+ }
}
// Don't buffer stdout
setvbuf(stdout, nullptr, _IONBF, 0);
- // Enable the parallel run if the client requests to output to a file.
- EnableParallelRunIfNeeded();
- // Using scope guard to make sure the dump pool can be shut down correctly.
- auto scope_guard_to_shutdown_pool = android::base::make_scope_guard([=]() {
- ShutdownDumpPool();
- });
-
// NOTE: there should be no stdout output until now, otherwise it would break the header.
// In particular, DurationReport objects should be created passing 'title, NULL', so their
// duration is logged into MYLOG instead.
PrintHeader();
- bool is_dumpstate_restricted = options_->telephony_only
- || options_->wifi_only
- || options_->limited_only;
- if (!is_dumpstate_restricted) {
- // Invoke critical dumpsys first to preserve system state, before doing anything else.
- RunDumpsysCritical();
- }
- MaybeTakeEarlyScreenshot();
-
- if (!is_dumpstate_restricted) {
- // Snapshot the system trace now (if running) to avoid that dumpstate's
- // own activity pushes out interesting data from the trace ring buffer.
- // The trace file is added to the zip by MaybeAddSystemTraceToZip().
- MaybeSnapshotSystemTrace();
-
- // If a winscope trace is running, snapshot it now. It will be pulled into bugreport later
- // from WMTRACE_DATA_DIR.
- MaybeSnapshotWinTrace();
- }
- onUiIntensiveBugreportDumpsFinished(calling_uid);
- MaybeCheckUserConsent(calling_uid, calling_package);
+ // TODO(b/158737089) reduce code repetition in if branches
if (options_->telephony_only) {
+ MaybeTakeEarlyScreenshot();
+ onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
+ MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateTelephonyOnly(calling_package);
+ DumpstateBoard();
} else if (options_->wifi_only) {
+ MaybeTakeEarlyScreenshot();
+ onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
+ MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateWifiOnly();
} else if (options_->limited_only) {
+ MaybeTakeEarlyScreenshot();
+ onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
+ MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateLimitedOnly();
} else {
+ // Invoke critical dumpsys first to preserve system state, before doing anything else.
+ RunDumpsysCritical();
+
+ // Take screenshot and get consent only after critical dumpsys has finished.
+ MaybeTakeEarlyScreenshot();
+ onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
+ MaybeCheckUserConsent(calling_uid, calling_package);
+
// Dump state for the default case. This also drops root.
RunStatus s = DumpstateDefaultAfterCritical();
if (s != RunStatus::OK) {
@@ -2964,10 +2747,14 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
}
/* close output if needed */
- TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
+ if (is_redirecting) {
+ TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
+ }
// Zip the (now complete) .tmp file within the internal directory.
- FinalizeFile();
+ if (options_->OutputToFile()) {
+ FinalizeFile();
+ }
// Share the final file with the caller if the user has consented or Shell is the caller.
Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -3010,9 +2797,11 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
progress_->Save();
MYLOGI("done (id %d)\n", id_);
- TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
+ if (is_redirecting) {
+ TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
+ }
- if (control_socket_fd_ != -1) {
+ if (options_->use_control_socket && control_socket_fd_ != -1) {
MYLOGD("Closing control socket\n");
close(control_socket_fd_);
}
@@ -3034,45 +2823,16 @@ void Dumpstate::MaybeTakeEarlyScreenshot() {
TakeScreenshot();
}
-void Dumpstate::MaybeSnapshotSystemTrace() {
- // If a background system trace is happening and is marked as "suitable for
- // bugreport" (i.e. bugreport_score > 0 in the trace config), this command
- // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely)
- // case that no trace is ongoing, this command is a no-op.
- // Note: this should not be enqueued as we need to freeze the trace before
- // dumpstate starts. Otherwise the trace ring buffers will contain mostly
- // the dumpstate's own activity which is irrelevant.
- int res = RunCommand(
- "SERIALIZE PERFETTO TRACE",
- {"perfetto", "--save-for-bugreport"},
- CommandOptions::WithTimeout(10)
- .DropRoot()
- .CloseAllFileDescriptorsOnExec()
- .Build());
- has_system_trace_ = res == 0;
- // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
- // file in the later stages.
-}
-
-void Dumpstate::MaybeSnapshotWinTrace() {
- // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol.
- for (const auto& service : {"window", "input_method"}) {
- RunCommand(
- // Empty name because it's not intended to be classified as a bugreport section.
- // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
- "", {"cmd", service, "tracing", "save-for-bugreport"},
- CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
- }
-}
-
-void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
+void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
+ const std::string& calling_package) {
if (calling_uid == AID_SHELL || !CalledByApi()) {
return;
}
if (listener_ != nullptr) {
// Let listener know ui intensive bugreport dumps are finished, then it can do event
// handling if required.
- listener_->onUiIntensiveBugreportDumpsFinished();
+ android::String16 package(calling_package.c_str());
+ listener_->onUiIntensiveBugreportDumpsFinished(package);
}
}
@@ -3109,45 +2869,6 @@ void Dumpstate::CleanupTmpFiles() {
android::os::UnlinkAndLogOnError(tmp_path_);
android::os::UnlinkAndLogOnError(screenshot_path_);
android::os::UnlinkAndLogOnError(path_);
- if (dump_traces_path != nullptr) {
- android::os::UnlinkAndLogOnError(dump_traces_path);
- }
-}
-
-void Dumpstate::EnableParallelRunIfNeeded() {
- if (!PropertiesHelper::IsParallelRun()) {
- return;
- }
- dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
- zip_entry_tasks_ = std::make_unique<TaskQueue>();
-}
-
-void Dumpstate::ShutdownDumpPool() {
- if (dump_pool_) {
- dump_pool_->shutdown();
- dump_pool_ = nullptr;
- }
- if (zip_entry_tasks_) {
- zip_entry_tasks_->run(/* do_cancel = */true);
- zip_entry_tasks_ = nullptr;
- }
-}
-
-void Dumpstate::EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
- const std::string& entry_path) {
- auto func_add_zip_entry_and_cleanup = [=](bool task_cancelled) {
- if (!task_cancelled) {
- AddZipEntry(entry_name, entry_path);
- }
- android::os::UnlinkAndLogOnError(entry_path);
- };
- if (zip_entry_tasks_) {
- // Enqueues AddZipEntryAndCleanup function if the parallel run is enabled.
- zip_entry_tasks_->add(func_add_zip_entry_and_cleanup, _1);
- } else {
- // Invokes AddZipEntryAndCleanup immediately
- std::invoke(func_add_zip_entry_and_cleanup, /* task_cancelled = */false);
- }
}
Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
@@ -3206,11 +2927,6 @@ Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid
// Since we do not have user consent to share the bugreport it does not get
// copied over to the calling app but remains in the internal directory from
// where the user can manually pull it.
- std::string final_path = GetPath(".zip");
- bool copy_succeeded = android::os::CopyFileToFile(path_, final_path);
- if (copy_succeeded) {
- android::os::UnlinkAndLogOnError(path_);
- }
return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
}
// Unknown result; must be a programming error.
@@ -3265,8 +2981,7 @@ Dumpstate::Dumpstate(const std::string& version)
options_(new Dumpstate::DumpOptions()),
last_reported_percent_progress_(0),
version_(version),
- now_(time(nullptr)),
- open_socket_fn_(open_socket) {
+ now_(time(nullptr)) {
}
Dumpstate& Dumpstate::GetInstance() {
@@ -3274,9 +2989,8 @@ Dumpstate& Dumpstate::GetInstance() {
return singleton_;
}
-DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose,
- int duration_fd) : title_(title), logcat_only_(logcat_only), verbose_(verbose),
- duration_fd_(duration_fd) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
+ : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
if (!title_.empty()) {
started_ = Nanotime();
}
@@ -3290,8 +3004,7 @@ DurationReporter::~DurationReporter() {
}
if (!logcat_only_) {
// Use "Yoda grammar" to make it easier to grep|sort sections.
- dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
- elapsed, title_.c_str());
+ printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
}
}
}
@@ -3877,11 +3590,10 @@ int dump_file_from_fd(const char *title, const char *path, int fd) {
}
int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options, bool verbose_duration, int out_fd) {
- DurationReporter duration_reporter(title, false /* logcat_only */,
- verbose_duration, out_fd);
+ const CommandOptions& options, bool verbose_duration) {
+ DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
- int status = RunCommandToFd(out_fd, title, full_command, options);
+ int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
/* TODO: for now we're simplifying the progress calculation by using the
* timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
@@ -3893,14 +3605,14 @@ int Dumpstate::RunCommand(const std::string& title, const std::vector<std::strin
}
void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
- const CommandOptions& options, long dumpsysTimeoutMs, int out_fd) {
+ const CommandOptions& options, long dumpsysTimeoutMs) {
long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
- RunCommand(title, dumpsys, options, false, out_fd);
+ RunCommand(title, dumpsys, options);
}
-static int open_socket(const char* service) {
+int open_socket(const char *service) {
int s = android_get_control_socket(service);
if (s < 0) {
MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
@@ -3935,6 +3647,19 @@ static int open_socket(const char* service) {
return fd;
}
+/* redirect output to a service control socket */
+bool redirect_to_socket(FILE* redirect, const char* service) {
+ int fd = open_socket(service);
+ if (fd == -1) {
+ return false;
+ }
+ fflush(redirect);
+ // TODO: handle dup2 failure
+ TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
+ close(fd);
+ return true;
+}
+
// TODO: should call is_valid_output_file and/or be merged into it.
void create_parent_dirs(const char *path) {
char *chp = const_cast<char *> (path);
@@ -4007,16 +3732,12 @@ void dump_route_tables() {
fclose(fp);
}
+// TODO: make this function thread safe if sections are generated in parallel.
void Dumpstate::UpdateProgress(int32_t delta_sec) {
if (progress_ == nullptr) {
MYLOGE("UpdateProgress: progress_ not set\n");
return;
}
- // This function updates progress related members of the dumpstate and reports
- // progress percentage to the bugreport client. Since it could be called by
- // different dump tasks at the same time if the parallel run is enabled, a
- // mutex lock is necessary here to synchronize the call.
- std::lock_guard<std::recursive_mutex> lock(mutex_);
// Always update progess so stats can be tuned...
progress_->Inc(delta_sec);