Refactored run_command functions.
Back in the day, dumpstate.c had a simple run_command() function. Then on
Android N, dumpstate.c became dumpstate.cpp and that function multiplied into:
- run_command()
- run_command_as_shell()
- run_command_always()
Not only these 3 commands were pretty much copy-and-pasted, but they
didn't take advantage of C++ features (such as std::vector and
std::string).
This CL refactor them into a single runCommand() function that takes an
optional CommandOptions argument to set its behavior. Examples:
// Run as shell
runCommand("DUMPSYS MEMINFO", {"meminfo", "-a"},
CommandOptions::WithTimeout(90).DropRoot().Build());
// Run always, as shell
runCommand(nullptr, am, CommandOptions::WithTimeout(20).Build());
The legacy run_command() is still available since it's used by
device-specific dumpstate_board() implementations, but it will
eventually go away as well.
This change also:
- Refactored run_dumpsys() into runDumpsys().
- Added a .clang-format file (initially equals to dumpsys's).
- Renamed the variable names on those commands according to the style guide.
BUG: 26379932
Test: manual
Change-Id: Ie045eb2fb825e68088d231129044c59e61450d99
diff --git a/cmds/dumpstate/.clang-format b/cmds/dumpstate/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/cmds/dumpstate/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6d90b97..7d73b0f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -247,7 +247,8 @@
// send SIGUSR1 to the anrd to generate a trace.
sprintf(buf, "%u", pid);
- if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
+ if (runCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
+ CommandOptions::WithTimeout(1).Build())) {
MYLOGE("anrd signal timed out. Please manually collect trace\n");
return false;
}
@@ -337,15 +338,15 @@
MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
systrace_path.c_str());
- if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
- systrace_path.c_str(), NULL)) {
+ if (runCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
+ CommandOptions::WithTimeout(120).Build())) {
MYLOGE("systrace timed out, its zip entry will be incomplete\n");
- // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
- // we should call strace to stop itself, but there is no such option yet (just a
- // --async_stop, which stops and dump
- // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
- // MYLOGE("could not stop systrace ");
- // }
+ // TODO: run_command tries to kill the process, but atrace doesn't die
+ // peacefully; ideally, we should call strace to stop itself, but there is no such option
+ // yet (just a --async_stop, which stops and dump
+ // if (runCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
+ // MYLOGE("could not stop systrace ");
+ // }
}
if (!add_zip_entry("systrace.txt", systrace_path)) {
MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
@@ -373,14 +374,14 @@
return;
}
+ CommandOptions options = CommandOptions::WithTimeout(600).Build();
if (!zip_writer) {
// Write compressed and encoded raft logs to stdout if not zip_writer.
- run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
+ runCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
return;
}
- run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
- "-o", raft_log_path.c_str(), NULL);
+ runCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_log_path}, options);
if (!add_zip_entry("raft_log.txt", raft_log_path)) {
MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
} else {
@@ -403,49 +404,6 @@
return false;
}
-static void _run_dumpsys(const std::string& title, RootMode root_mode, int timeout_seconds,
- const std::vector<std::string>& args) {
- DurationReporter duration_reporter(title.c_str());
-
- std::string timeout_string = std::to_string(timeout_seconds);
-
- const char *dumpsys_args[MAX_ARGS_ARRAY_SIZE] =
- { "/system/bin/dumpsys", "-t", timeout_string.c_str()};
-
- int index = 3; // 'dumpsys' '-t' 'TIMEOUT'
- for (const std::string& arg : args) {
- if (index > MAX_ARGS_ARRAY_SIZE - 2) {
- MYLOGE("Too many arguments for '%s': %d\n", title.c_str(), (int) args.size());
- return;
- }
- dumpsys_args[index++] = arg.c_str();
- }
- // Always terminate with nullptr.
- dumpsys_args[index] = nullptr;
-
- std::string args_string;
- format_args(index, dumpsys_args, &args_string);
- printf("------ %s (%s) ------\n", title.c_str(), args_string.c_str());
- fflush(stdout);
-
- if (is_dry_run()) {
- update_progress(timeout_seconds);
- return;
- }
-
- run_command_always(title.c_str(), root_mode, NORMAL_STDOUT, timeout_seconds, dumpsys_args);
-}
-
-static void run_dumpsys(const std::string& title, int timeout_seconds,
- const std::vector<std::string>& args) {
- _run_dumpsys(title, DONT_DROP_ROOT, timeout_seconds, args);
-}
-
-static void run_dumpsys_as_shell(const std::string& title, int timeout_seconds,
- const std::vector<std::string>& args) {
- _run_dumpsys(title, DROP_ROOT, timeout_seconds, args);
-}
-
static const char mmcblk0[] = "/sys/block/mmcblk0/";
unsigned long worst_write_perf = 20000; /* in KB/s */
@@ -741,7 +699,7 @@
dump_file(NULL, "/proc/version");
printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
printf("Bugreport format version: %s\n", version.c_str());
- printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
+ printf("Dumpstate info: id=%lu pid=%d dry_run=%d\n", id, getpid(), dry_run);
printf("\n");
}
@@ -865,14 +823,14 @@
}
static void dump_iptables() {
- run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
- run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
- run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
+ runCommand("IPTABLES", {"iptables", "-L", "-nvx"});
+ runCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
+ runCommand("IPTABLE NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
/* no ip6 nat */
- run_command("IPTABLE MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
- run_command("IP6TABLE MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
- run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
- run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
+ runCommand("IPTABLE MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
+ runCommand("IP6TABLE MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
+ runCommand("IPTABLE RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
+ runCommand("IP6TABLE RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}
static void dumpstate(const std::string& screenshot_path, const std::string& version) {
@@ -880,13 +838,13 @@
unsigned long timeout;
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
- run_command("UPTIME", 10, "uptime", NULL);
+ runCommand("UPTIME", {"uptime"});
dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
dump_file("MEMORY INFO", "/proc/meminfo");
- run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
- "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
- run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
+ runCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
+ "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
+ runCommand("PROCRANK", {"procrank"}, CommandOptions::AS_ROOT_20);
dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo");
dump_file("SLAB INFO", "/proc/slabinfo");
@@ -899,22 +857,22 @@
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
- run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
- "-O", "pri,nice,rtprio,sched,pcy", NULL);
- run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
+ runCommand("PROCESSES AND THREADS",
+ {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
+ runCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT_10);
- run_command("PRINTENV", 10, "printenv", NULL);
- run_command("NETSTAT", 10, "netstat", "-n", NULL);
+ runCommand("PRINTENV", {"printenv"});
+ runCommand("NETSTAT", {"netstat", "-n"});
struct stat s;
if (stat("/proc/modules", &s) != 0) {
MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
} else {
- run_command("LSMOD", 10, "lsmod", NULL);
+ runCommand("LSMOD", {"lsmod"});
}
do_dmesg();
- run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+ runCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT_10);
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
@@ -931,30 +889,24 @@
if (timeout < 20000) {
timeout = 20000;
}
- run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
- "-v", "printable",
- "-d",
- "*:v", NULL);
+ runCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ CommandOptions::WithTimeout(timeout / 1000).Build());
timeout = logcat_timeout("events");
if (timeout < 20000) {
timeout = 20000;
}
- run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
- "-v", "threadtime",
- "-v", "printable",
- "-d",
- "*:v", NULL);
+ runCommand("EVENT LOG",
+ {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ CommandOptions::WithTimeout(timeout / 1000).Build());
timeout = logcat_timeout("radio");
if (timeout < 20000) {
timeout = 20000;
}
- run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
- "-v", "threadtime",
- "-v", "printable",
- "-d",
- "*:v", NULL);
+ runCommand("RADIO LOG",
+ {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ CommandOptions::WithTimeout(timeout / 1000).Build());
- run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
+ runCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
@@ -1033,65 +985,57 @@
}
/* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
- run_command("LAST LOGCAT", 10, "logcat", "-L",
- "-b", "all",
- "-v", "threadtime",
- "-v", "printable",
- "-d",
- "*:v", NULL);
+ runCommand("LAST LOGCAT",
+ {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
/* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
- run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
+ runCommand("NETWORK INTERFACES", {"ip", "link"});
- run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
- run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
+ runCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+ runCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
- run_command("IP RULES", 10, "ip", "rule", "show", NULL);
- run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
+ runCommand("IP RULES", {"ip", "rule", "show"});
+ runCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
dump_route_tables();
- run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
- run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
- run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
- run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
+ runCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
+ runCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
+ runCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
+ runCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
+ CommandOptions::WithTimeout(20).Build());
#ifdef FWDUMP_bcmdhd
- run_command("ND OFFLOAD TABLE", 5,
- SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
+ runCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT_5);
- run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
- SU_PATH, "root", WLUTIL, "counters", NULL);
+ runCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, CommandOptions::AS_ROOT_20);
- run_command("ND OFFLOAD STATUS (1)", 5,
- SU_PATH, "root", WLUTIL, "nd_status", NULL);
+ runCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
#endif
dump_file("INTERRUPTS (1)", "/proc/interrupts");
- run_dumpsys("NETWORK DIAGNOSTICS", 10, {"connectivity", "--diag"});
+ runDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+ CommandOptions::WithTimeout(10).Build());
#ifdef FWDUMP_bcmdhd
- run_command("DUMP WIFI STATUS", 20,
- SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
+ runCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, CommandOptions::AS_ROOT_20);
- run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
- SU_PATH, "root", WLUTIL, "counters", NULL);
+ runCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, CommandOptions::AS_ROOT_20);
- run_command("ND OFFLOAD STATUS (2)", 5,
- SU_PATH, "root", WLUTIL, "nd_status", NULL);
+ runCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
#endif
dump_file("INTERRUPTS (2)", "/proc/interrupts");
print_properties();
- run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
- run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
+ runCommand("VOLD DUMP", {"vdc", "dump"});
+ runCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
- run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
+ runCommand("FILESYSTEMS & FREE SPACE", {"df"});
- run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
+ runCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
printf("------ BACKLIGHTS ------\n");
printf("LCD brightness=");
@@ -1124,53 +1068,51 @@
char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
- if (is_user_build()) {
- // su does not exist on user builds, so try running without it.
- // This way any implementations of vril-dump that do not require
- // root can run on user builds.
- run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
- "vril-dump", NULL);
- } else {
- run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
- SU_PATH, "root", "vril-dump", NULL);
+ // su does not exist on user builds, so try running without it.
+ // This way any implementations of vril-dump that do not require
+ // root can run on user builds.
+ CommandOptions::CommandOptionsBuilder options =
+ CommandOptions::WithTimeout(atoi(ril_dumpstate_timeout));
+ if (!is_user_build()) {
+ options.AsRoot();
}
+ runCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
}
printf("========================================================\n");
printf("== Android Framework Services\n");
printf("========================================================\n");
- run_dumpsys("DUMPSYS", 60, {"--skip", "meminfo", "cpuinfo"});
+ runDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(60).Build());
printf("========================================================\n");
printf("== Checkins\n");
printf("========================================================\n");
- run_dumpsys("CHECKIN BATTERYSTATS", 30, {"batterystats", "-c"});
- run_dumpsys("CHECKIN MEMINFO", 30, {"meminfo", "--checkin"});
- run_dumpsys("CHECKIN NETSTATS", 30, {"netstats", "--checkin"});
- run_dumpsys("CHECKIN PROCSTATS", 30, {"procstats", "-c"});
- run_dumpsys("CHECKIN USAGESTATS", 30, {"usagestats", "-c"});
- run_dumpsys("CHECKIN PACKAGE", 30, {"package", "--checkin"});
+ runDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+ 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");
- run_dumpsys("APP ACTIVITIES", 30, {"activity", "all"});
+ runDumpsys("APP ACTIVITIES", {"activity", "all"});
printf("========================================================\n");
printf("== Running Application Services\n");
printf("========================================================\n");
- run_dumpsys("APP SERVICES", 30, {"activity", "service", "all"});
+ runDumpsys("APP SERVICES", {"activity", "service", "all"});
printf("========================================================\n");
printf("== Running Application Providers\n");
printf("========================================================\n");
- run_dumpsys("APP PROVIDERS", 30, {"activity", "provider", "all"});
-
+ runDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (originally %d)\n",
@@ -1315,6 +1257,13 @@
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
+ std::string args;
+ for (int i = 0; i < argc; i++) {
+ args += argv[i];
+ args += " ";
+ }
+ MYLOGD("Dumpstate command line: %s\n", args.c_str());
+
/* gets the sequential id */
char last_id[PROPERTY_VALUE_MAX];
property_get("dumpstate.last_id", last_id, "0");
@@ -1345,9 +1294,6 @@
}
/* parse arguments */
- std::string args;
- format_args(argc, const_cast<const char **>(argv), &args);
- MYLOGD("Dumpstate command line: %s\n", args.c_str());
int c;
while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
switch (c) {
@@ -1569,8 +1515,10 @@
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
- run_dumpsys_as_shell("DUMPSYS MEMINFO", 90, {"meminfo", "-a"});
- run_dumpsys_as_shell("DUMPSYS CPUINFO", 10, {"cpuinfo", "-a"});
+ runDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
+ CommandOptions::WithTimeout(90).DropRoot().Build());
+ runDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
+ CommandOptions::WithTimeout(10).DropRoot().Build());
/* collect stack traces from Dalvik and native processes (needs root) */
dump_traces_path = dump_traces();
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 11b0c3e..978abb8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -33,19 +33,151 @@
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
+
+#include <string>
#include <vector>
#define SU_PATH "/system/xbin/su"
// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
// std::vector<std::string>
+// TODO: remove once not used
#define MAX_ARGS_ARRAY_SIZE 1000
-
+// TODO: remove once moved to HAL
#ifdef __cplusplus
extern "C" {
#endif
+/*
+ * Defines the Linux user that should be executing a command.
+ */
+enum RootMode {
+ /* Explicitly change the `uid` and `gid` to be `shell`.*/
+ DROP_ROOT,
+ /* Don't change the `uid` and `gid`. */
+ DONT_DROP_ROOT,
+ /* Prefix the command with `/PATH/TO/su root`. Won't work non user builds. */
+ SU_ROOT
+};
+
+/*
+ * Defines what should happen with the `stdout` stream of a command.
+ */
+enum StdoutMode {
+ /* Don't change `stdout`. */
+ NORMAL_STDOUT,
+ /* Redirect `stdout` to `stderr`. */
+ REDIRECT_TO_STDERR
+};
+
+/*
+ * Helper class used to report how long it takes for a section to finish.
+ *
+ * Typical usage:
+ *
+ * DurationReporter duration_reporter(title);
+ *
+ */
+class DurationReporter {
+ public:
+ DurationReporter(const char* title);
+ DurationReporter(const char* title, FILE* out);
+
+ ~DurationReporter();
+
+ static uint64_t nanotime();
+
+ private:
+ // TODO: use std::string for title, once dump_files() and other places that pass a char* are
+ // refactored as well.
+ const char* mTitle;
+ FILE* mOut;
+ uint64_t mStarted;
+};
+
+/*
+ * Value object used to set command options.
+ *
+ * Typically constructed using a builder with chained setters. Examples:
+ *
+ * CommandOptions::WithTimeout(20).AsRoot().Build();
+ * CommandOptions::WithTimeout(10).Always().RedirectStderr().Build();
+ *
+ * Although the builder could be used to dynamically set values. Example:
+ *
+ * CommandOptions::CommandOptionsBuilder options =
+ * CommandOptions::WithTimeout(10);
+ * if (!is_user_build()) {
+ * options.AsRoot();
+ * }
+ * runCommand("command", {"args"}, options.Build());
+ */
+class CommandOptions {
+ private:
+ class CommandOptionsValues {
+ private:
+ CommandOptionsValues(long timeout);
+
+ long mTimeout;
+ bool mAlways;
+ RootMode mRootMode;
+ StdoutMode mStdoutMode;
+ std::string mLoggingMessage;
+
+ friend class CommandOptions;
+ friend class CommandOptionsBuilder;
+ };
+
+ CommandOptions(const CommandOptionsValues& values);
+
+ const CommandOptionsValues mValues;
+
+ public:
+ class CommandOptionsBuilder {
+ public:
+ /* Sets the command to always run, even on `dry-run` mode. */
+ CommandOptionsBuilder& Always();
+ /* Sets the command's RootMode as `SU_ROOT` */
+ CommandOptionsBuilder& AsRoot();
+ /* Sets the command's RootMode as `DROP_ROOT` */
+ CommandOptionsBuilder& DropRoot();
+ /* Sets the command's StdoutMode `REDIRECT_TO_STDERR` */
+ CommandOptionsBuilder& RedirectStderr();
+ /* When not empty, logs a message before executing the command.
+ * Must contain a `%s`, which will be replaced by the full command line, and end on `\n`. */
+ CommandOptionsBuilder& Log(const std::string& message);
+ /* Builds the command options. */
+ CommandOptions Build();
+
+ private:
+ CommandOptionsBuilder(long timeout);
+ CommandOptionsValues mValues;
+ friend class CommandOptions;
+ };
+
+ /** Gets the command timeout, in seconds. */
+ long Timeout() const;
+ /* Checks whether the command should always be run, even on dry-run mode. */
+ bool Always() const;
+ /** Gets the RootMode of the command. */
+ RootMode RootMode() const;
+ /** Gets the StdoutMode of the command. */
+ StdoutMode StdoutMode() const;
+ /** Gets the logging message header, it any. */
+ std::string LoggingMessage() const;
+
+ /** Creates a builder with the requied timeout. */
+ static CommandOptionsBuilder WithTimeout(long timeout);
+
+ // Common options.
+ static CommandOptions DEFAULT;
+ static CommandOptions DEFAULT_DUMPSYS;
+ static CommandOptions AS_ROOT_5;
+ static CommandOptions AS_ROOT_10;
+ static CommandOptions AS_ROOT_20;
+};
+
typedef void (for_each_pid_func)(int, const char *);
typedef void (for_each_tid_func)(int, int, const char *);
@@ -110,21 +242,35 @@
bool (*skip)(const char *path),
int (*dump_from_fd)(const char *title, const char *path, int fd));
-// TODO: need to refactor all those run_command variations; there shold be just one, receiving an
-// optional CommandOptions objects with values such as run_always, drop_root, etc...
-
-/* forks a command and waits for it to finish -- terminate args with NULL */
-int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...);
+/* forks a command and waits for it to finish -- terminate args with NULL
+ * DEPRECATED: will be removed once device-specific implementations use
+ * runCommand */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
-enum RootMode { DROP_ROOT, DONT_DROP_ROOT };
-enum StdoutMode { NORMAL_STDOUT, REDIRECT_TO_STDERR };
+/*
+ * Forks a command, waits for it to finish, and returns its status.
+ *
+ * |title| description of the command printed on `stdout` (or `nullptr` to skip
+ * description).
+ * |full_command| array containing the command (first entry) and its arguments.
+ * Must contain at least one element.
+ * |options| optional argument defining the command's behavior.
+ */
+// TODO: use std::string for title once other char* title references are refactored.
+int runCommand(const char* title, const std::vector<std::string>& fullCommand,
+ const CommandOptions& options = CommandOptions::DEFAULT);
-/* forks a command and waits for it to finish
- first element of args is the command, and last must be NULL.
- command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
-int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
- int timeout_seconds, const char *args[]);
+/*
+ * Runs `dumpsys` with the given arguments, automatically setting its timeout
+ * (`-t` argument)
+ * according to the command options.
+ *
+ * |title| description of the command printed on `stdout`.
+ * |dumpsys_args| `dumpsys` arguments (except `-t`).
+ * |options| optional argument defining the command's behavior.
+ */
+void runDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
+ const CommandOptions& options = CommandOptions::DEFAULT_DUMPSYS);
/* switch to non-root user and group */
bool drop_root_user();
@@ -213,29 +359,6 @@
*/
bool is_dry_run();
-/*
- * Helper class used to report how long it takes for a section to finish.
- *
- * Typical usage:
- *
- * DurationReporter duration_reporter(title);
- *
- */
-class DurationReporter {
-public:
- explicit DurationReporter(const char *title);
- DurationReporter(const char *title, FILE* out);
-
- ~DurationReporter();
-
- static uint64_t nanotime();
-
-private:
- const char* title_;
- FILE* out_;
- uint64_t started_;
-};
-
#ifdef __cplusplus
}
#endif
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 3e4d343..5c59bae 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -69,25 +69,99 @@
NULL,
};
+CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
+CommandOptions CommandOptions::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
+CommandOptions CommandOptions::AS_ROOT_5 = CommandOptions::WithTimeout(5).AsRoot().Build();
+CommandOptions CommandOptions::AS_ROOT_10 = CommandOptions::WithTimeout(10).AsRoot().Build();
+CommandOptions CommandOptions::AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
+
+CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(long timeout) : mValues(timeout) {
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() {
+ mValues.mAlways = true;
+ return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
+ mValues.mRootMode = SU_ROOT;
+ return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() {
+ mValues.mRootMode = DROP_ROOT;
+ return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::RedirectStderr() {
+ mValues.mStdoutMode = REDIRECT_TO_STDERR;
+ return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Log(
+ const std::string& message) {
+ mValues.mLoggingMessage = message;
+ return *this;
+}
+
+CommandOptions CommandOptions::CommandOptionsBuilder::Build() {
+ return CommandOptions(mValues);
+}
+
+CommandOptions::CommandOptionsValues::CommandOptionsValues(long timeout)
+ : mTimeout(timeout),
+ mAlways(false),
+ mRootMode(DONT_DROP_ROOT),
+ mStdoutMode(NORMAL_STDOUT),
+ mLoggingMessage("") {
+}
+
+CommandOptions::CommandOptions(const CommandOptionsValues& values) : mValues(values) {
+}
+
+long CommandOptions::Timeout() const {
+ return mValues.mTimeout;
+}
+
+bool CommandOptions::Always() const {
+ return mValues.mAlways;
+}
+
+RootMode CommandOptions::RootMode() const {
+ return mValues.mRootMode;
+}
+
+StdoutMode CommandOptions::StdoutMode() const {
+ return mValues.mStdoutMode;
+}
+
+std::string CommandOptions::LoggingMessage() const {
+ return mValues.mLoggingMessage;
+}
+
+CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(long timeout) {
+ return CommandOptions::CommandOptionsBuilder(timeout);
+}
+
DurationReporter::DurationReporter(const char *title) : DurationReporter(title, stdout) {}
DurationReporter::DurationReporter(const char *title, FILE *out) {
- title_ = title;
- if (title) {
- started_ = DurationReporter::nanotime();
+ mTitle = title;
+ if (title != nullptr) {
+ mStarted = DurationReporter::nanotime();
}
- out_ = out;
+ mOut = out;
}
DurationReporter::~DurationReporter() {
- if (title_) {
- uint64_t elapsed = DurationReporter::nanotime() - started_;
+ if (mTitle != nullptr) {
+ uint64_t elapsed = DurationReporter::nanotime() - mStarted;
// Use "Yoda grammar" to make it easier to grep|sort sections.
- if (out_) {
- fprintf(out_, "------ %.3fs was the duration of '%s' ------\n",
- (float) elapsed / NANOS_PER_SEC, title_);
+ if (mOut != nullptr) {
+ fprintf(mOut, "------ %.3fs was the duration of '%s' ------\n",
+ (float)elapsed / NANOS_PER_SEC, mTitle);
} else {
- MYLOGD("Duration of '%s': %.3fs\n", title_, (float) elapsed / NANOS_PER_SEC);
+ MYLOGD("Duration of '%s': %.3fs\n", mTitle, (float)elapsed / NANOS_PER_SEC);
}
}
}
@@ -408,7 +482,7 @@
snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
snprintf(arg, sizeof(arg), "%d", pid);
- run_command(title, 10, SU_PATH, "root", "showmap", "-q", arg, NULL);
+ runCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT_10);
}
static int _dump_file_from_fd(const char *title, const char *path, int fd) {
@@ -648,103 +722,82 @@
return true;
}
-// TODO: refactor all those commands that convert args
-void format_args(const char* command, const char *args[], std::string *string);
-
-int run_command(const char *title, int timeout_seconds, const char *command, ...) {
- DurationReporter duration_reporter(title);
- fflush(stdout);
-
- const char *args[MAX_ARGS_ARRAY_SIZE] = {command};
+int run_command(const char* title, int timeout_seconds, const char* command, ...) {
+ std::vector<std::string> fullCommand = {command};
size_t arg;
va_list ap;
va_start(ap, command);
- if (title) printf("------ %s (%s", title, command);
- bool null_terminated = false;
- for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
- args[arg] = va_arg(ap, const char *);
- if (args[arg] == nullptr) {
- null_terminated = true;
+ for (arg = 0; arg < MAX_ARGS_ARRAY_SIZE; ++arg) {
+ const char* ptr = va_arg(ap, const char*);
+ if (ptr == nullptr) {
break;
}
- // TODO: null_terminated check is not really working; line below would crash dumpstate if
- // nullptr is missing
- if (title) printf(" %s", args[arg]);
- }
- if (title) printf(") ------\n");
- fflush(stdout);
- if (!null_terminated) {
- // Fail now, otherwise execvp() call on run_command_always() might hang.
- std::string cmd;
- format_args(command, args, &cmd);
- MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
- va_end(ap);
- return -1;
- }
-
- int status = 0;
- if (is_dry_run()) {
- update_progress(timeout_seconds);
- } else {
- status = run_command_always(title, DONT_DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
+ fullCommand.push_back(ptr);
}
va_end(ap);
- return status;
+
+ return runCommand(title, fullCommand, CommandOptions::WithTimeout(timeout_seconds).Build());
}
-int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) {
- DurationReporter duration_reporter(title);
- fflush(stdout);
+int runCommand(const char* title, const std::vector<std::string>& fullCommand,
+ const CommandOptions& options) {
+ if (fullCommand.empty()) {
+ MYLOGE("No arguments on command '%s'\n", title);
+ return -1;
+ }
+ DurationReporter durationReporter(title);
- const char *args[MAX_ARGS_ARRAY_SIZE] = {command};
- size_t arg;
- va_list ap;
- va_start(ap, command);
- if (title) printf("------ %s (%s", title, command);
- bool null_terminated = false;
- for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
- args[arg] = va_arg(ap, const char *);
- if (args[arg] == nullptr) {
- null_terminated = true;
- break;
+ int size = fullCommand.size() + 1; // null terminated
+ if (options.RootMode() == SU_ROOT) {
+ size += 2; // "su" "root"
+ }
+
+ const char* args[size];
+
+ printf("------");
+ if (title) printf(" %s", title);
+ printf(" (");
+
+ std::string commandString;
+ int i = 0;
+ if (options.RootMode() == SU_ROOT) {
+ args[0] = SU_PATH;
+ commandString += SU_PATH;
+ args[1] = "root";
+ commandString += " root ";
+ }
+ for (auto arg = fullCommand.begin(); arg < fullCommand.end(); arg++) {
+ args[i++] = arg->c_str();
+ commandString += arg->c_str();
+ if (arg != fullCommand.end() - 1) {
+ commandString += " ";
}
- // TODO: null_terminated check is not really working; line below would crash dumpstate if
- // nullptr is missing
- if (title) printf(" %s", args[arg]);
}
- if (title) printf(") ------\n");
+ args[i] = nullptr;
+ const char* path = args[0];
+ const char* command = commandString.c_str();
+ printf("%s)\n", command);
+
fflush(stdout);
- if (!null_terminated) {
- // Fail now, otherwise execvp() call on run_command_always() might hang.
- std::string cmd;
- format_args(command, args, &cmd);
- MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
- va_end(ap);
- return -1;
+
+ const std::string& loggingMessage = options.LoggingMessage();
+ if (!loggingMessage.empty()) {
+ MYLOGI(loggingMessage.c_str(), commandString.c_str());
}
- int status = 0;
- if (is_dry_run()) {
- update_progress(timeout_seconds);
- } else {
- status = run_command_always(title, DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
+ if (is_dry_run() && !options.Always()) {
+ update_progress(options.Timeout());
+ return 0;
}
- va_end(ap);
- return status;
-}
-/* forks a command and waits for it to finish */
-int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
- int timeout_seconds, const char *args[]) {
- bool silent = (stdout_mode == REDIRECT_TO_STDERR);
- // TODO: need to check if args is null-terminated, otherwise execvp will crash dumpstate
+ bool silent = (options.StdoutMode() == REDIRECT_TO_STDERR);
- /* 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, where its weight
- * should be much higher proportionally to its timeout. */
- int weight = timeout_seconds;
+ /* 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,
+ * where its weight should be much higher proportionally to its timeout.
+ * Ideally, it should use a options.EstimatedDuration() instead...*/
+ int weight = options.Timeout();
- const char *command = args[0];
uint64_t start = DurationReporter::nanotime();
pid_t pid = fork();
@@ -757,9 +810,9 @@
/* handle child case */
if (pid == 0) {
- if (root_mode == DROP_ROOT && !drop_root_user()) {
- if (!silent) printf("*** fail todrop root before running %s: %s\n", command,
- strerror(errno));
+ if (options.RootMode() == DROP_ROOT && !drop_root_user()) {
+ if (!silent)
+ printf("*** failed to drop root before running %s: %s\n", command, strerror(errno));
MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
return -1;
}
@@ -778,49 +831,45 @@
sigact.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sigact, NULL);
- execvp(command, (char**) args);
- // execvp's result will be handled after waitpid_with_timeout() below, but if it failed,
- // it's safer to exit dumpstate.
- MYLOGD("execvp on command '%s' failed (error: %s)", command, strerror(errno));
+ execvp(path, (char**)args);
+ // execvp's result will be handled after waitpid_with_timeout() below, but
+ // if it failed, it's safer to exit dumpstate.
+ MYLOGD("execvp on command '%s' failed (error: %s)\n", command, strerror(errno));
fflush(stdout);
- // Must call _exit (instead of exit), otherwise it will corrupt the zip file.
+ // Must call _exit (instead of exit), otherwise it will corrupt the zip
+ // file.
_exit(EXIT_FAILURE);
}
/* handle parent case */
int status;
- bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
+ bool ret = waitpid_with_timeout(pid, options.Timeout(), &status);
uint64_t elapsed = DurationReporter::nanotime() - start;
- std::string cmd; // used to log command and its args
if (!ret) {
if (errno == ETIMEDOUT) {
- format_args(command, args, &cmd);
- if (!silent) printf("*** command '%s' timed out after %.3fs (killing pid %d)\n",
- cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
- MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
- (float) elapsed / NANOS_PER_SEC, pid);
+ if (!silent)
+ printf("*** command '%s' timed out after %.3fs (killing pid %d)\n", command,
+ (float)elapsed / NANOS_PER_SEC, pid);
+ MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", command,
+ (float)elapsed / NANOS_PER_SEC, pid);
} else {
- format_args(command, args, &cmd);
- if (!silent) printf("*** command '%s': Error after %.4fs (killing pid %d)\n",
- cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
- MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
- (float) elapsed / NANOS_PER_SEC, pid);
+ if (!silent)
+ printf("*** command '%s': Error after %.4fs (killing pid %d)\n", command,
+ (float)elapsed / NANOS_PER_SEC, pid);
+ MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", command,
+ (float)elapsed / NANOS_PER_SEC, pid);
}
kill(pid, SIGTERM);
if (!waitpid_with_timeout(pid, 5, NULL)) {
kill(pid, SIGKILL);
if (!waitpid_with_timeout(pid, 5, NULL)) {
- if (!silent) printf("could not kill command '%s' (pid %d) even with SIGKILL.\n",
- command, pid);
+ if (!silent)
+ printf("could not kill command '%s' (pid %d) even with SIGKILL.\n", command,
+ pid);
MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
}
}
return -1;
- } else if (status) {
- format_args(command, args, &cmd);
- if (!silent) printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
- MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
- return -2;
}
if (WIFSIGNALED(status)) {
@@ -837,6 +886,14 @@
return status;
}
+void runDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
+ const CommandOptions& options) {
+ std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-t",
+ std::to_string(options.Timeout())};
+ dumpsys.insert(dumpsys.end(), dumpsysArgs.begin(), dumpsysArgs.end());
+ runCommand(title.c_str(), dumpsys, options);
+}
+
bool drop_root_user() {
if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
MYLOGD("drop_root_user(): already running as Shell");
@@ -884,26 +941,16 @@
}
void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
- if (args.size() > 1000) {
- MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
- return;
- }
- const char *am_args[MAX_ARGS_ARRAY_SIZE] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
- action.c_str() };
- size_t am_index = 5; // Starts at the index of last initial value above.
- for (const std::string& arg : args) {
- if (am_index > MAX_ARGS_ARRAY_SIZE - 2) {
- MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
- return;
- }
- am_args[++am_index] = arg.c_str();
- }
- // Always terminate with nullptr.
- am_args[am_index + 1] = nullptr;
- std::string args_string;
- format_args(am_index + 1, am_args, &args_string);
- MYLOGD("send_broadcast command: %s\n", args_string.c_str());
- run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args);
+ std::vector<std::string> am = {"/system/bin/am", "broadcast", "--user", "0", "-a", action};
+
+ am.insert(am.end(), args.begin(), args.end());
+
+ runCommand(nullptr, am, CommandOptions::WithTimeout(20)
+ .Log("Sending broadcast: '%s'\n")
+ .Always()
+ .DropRoot()
+ .RedirectStderr()
+ .Build());
}
size_t num_props = 0;
@@ -1202,8 +1249,8 @@
// need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
// Add a fixed max limit so this doesn't go awry.
for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
- run_command("ROUTE TABLE IPv4", 10, "ip", "-4", "route", "show", "table", table, NULL);
- run_command("ROUTE TABLE IPv6", 10, "ip", "-6", "route", "show", "table", table, NULL);
+ runCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
+ runCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
}
fclose(fp);
}
@@ -1261,8 +1308,8 @@
}
void take_screenshot(const std::string& path) {
- const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
- run_command_always(NULL, DONT_DROP_ROOT, REDIRECT_TO_STDERR, 10, args);
+ runCommand(nullptr, {"/system/bin/screencap", "-p", path},
+ CommandOptions::WithTimeout(10).Always().RedirectStderr().Build());
}
void vibrate(FILE* vibrator, int ms) {
@@ -1399,30 +1446,3 @@
printf("\n");
}
-
-// TODO: refactor all those commands that convert args
-void format_args(int argc, const char *argv[], std::string *args) {
- LOG_ALWAYS_FATAL_IF(args == nullptr);
- for (int i = 0; i < argc; i++) {
- args->append(argv[i]);
- if (i < argc -1) {
- args->append(" ");
- }
- }
-}
-void format_args(const char* command, const char *args[], std::string *string) {
- LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr);
- string->append(command);
- if (args[1] == nullptr) return;
- string->append(" ");
-
- for (int arg = 1; arg <= MAX_ARGS_ARRAY_SIZE; ++arg) {
- if (args[arg] == nullptr) return;
- string->append(args[arg]);
- if (args[arg+1] != nullptr) {
- string->append(" ");
- }
- }
- // TODO: not really working: if NULL is missing, it will crash dumpstate.
- MYLOGE("internal error: missing NULL entry on %s", string->c_str());
-}