Loading cmds/dumpstate/dumpstate.cpp +75 −115 Original line number Original line Diff line number Diff line Loading @@ -56,18 +56,10 @@ static char cmdline_buf[16384] = "(unknown)"; static char cmdline_buf[16384] = "(unknown)"; static const char *dump_traces_path = NULL; static const char *dump_traces_path = NULL; // Command-line arguments as string static std::string args; // TODO: variables below should be part of dumpstate object // TODO: variables below should be part of dumpstate object static time_t now; static std::unique_ptr<ZipWriter> zip_writer; static std::unique_ptr<ZipWriter> zip_writer; static std::set<std::string> mount_points; static std::set<std::string> mount_points; void add_mountinfo(); void add_mountinfo(); /* suffix of the bugreport files - it's typically the date (when invoked with -d), * although it could be changed by the user using a system property */ static std::string suffix; static std::string extraOptions; #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" Loading Loading @@ -111,13 +103,6 @@ bool IsUserBuild() { return ds.IsUserBuild(); return ds.IsUserBuild(); } } /* * List of supported zip format versions. * * See bugreport-format.md for more info. */ static std::string VERSION_DEFAULT = "1.0"; // Relative directory (inside the zip) for all files copied as-is into the bugreport. // Relative directory (inside the zip) for all files copied as-is into the bugreport. static const std::string ZIP_ROOT_DIR = "FS"; static const std::string ZIP_ROOT_DIR = "FS"; Loading @@ -127,7 +112,7 @@ static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id"; /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones; /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones; * otherwise, gets just those modified in the last half an hour. */ * otherwise, gets just those modified in the last half an hour. */ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { time_t thirty_minutes_ago = now - 60*30; time_t thirty_minutes_ago = ds.now_ - 60 * 30; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { for (size_t i = 0; i < NUM_TOMBSTONES; i++) { snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); int fd = TEMP_FAILURE_RETRY(open(data[i].name, int fd = TEMP_FAILURE_RETRY(open(data[i].name, Loading Loading @@ -336,7 +321,7 @@ static void dump_systrace() { MYLOGD("Not dumping systrace because zip_writer is not set\n"); MYLOGD("Not dumping systrace because zip_writer is not set\n"); return; return; } } std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt"; std::string systrace_path = ds.GetPath("-systrace.txt"); if (systrace_path.empty()) { if (systrace_path.empty()) { MYLOGE("Not dumping systrace because path is empty\n"); MYLOGE("Not dumping systrace because path is empty\n"); return; return; Loading Loading @@ -377,7 +362,7 @@ static void dump_raft() { return; return; } } std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt"; std::string raft_log_path = ds.GetPath("-raft_log.txt"); if (raft_log_path.empty()) { if (raft_log_path.empty()) { MYLOGD("raft_log_path is empty\n"); MYLOGD("raft_log_path is empty\n"); return; return; Loading Loading @@ -686,8 +671,8 @@ static unsigned long logcat_timeout(const char *name) { /* End copy from system/core/logd/LogBuffer.cpp */ /* End copy from system/core/logd/LogBuffer.cpp */ /* dumps the current system state to stdout */ // TODO: move to utils.cpp void print_header(const std::string& version) { void Dumpstate::PrintHeader() { std::string build, fingerprint, radio, bootloader, network; std::string build, fingerprint, radio, bootloader, network; char date[80]; char date[80]; Loading @@ -696,7 +681,7 @@ void print_header(const std::string& version) { radio = android::base::GetProperty("gsm.version.baseband", "(unknown)"); radio = android::base::GetProperty("gsm.version.baseband", "(unknown)"); bootloader = android::base::GetProperty("ro.bootloader", "(unknown)"); bootloader = android::base::GetProperty("ro.bootloader", "(unknown)"); network = android::base::GetProperty("gsm.operator.alpha", "(unknown)"); network = android::base::GetProperty("gsm.operator.alpha", "(unknown)"); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_)); printf("========================================================\n"); printf("========================================================\n"); printf("== dumpstate: %s\n", date); printf("== dumpstate: %s\n", date); Loading @@ -713,9 +698,9 @@ void print_header(const std::string& version) { printf("Kernel: "); printf("Kernel: "); DumpFile("", "/proc/version"); DumpFile("", "/proc/version"); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("Bugreport format version: %s\n", version.c_str()); printf("Bugreport format version: %s\n", version_.c_str()); printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(), printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", id_, getpid(), ds.IsDryRun(), args.c_str(), extraOptions.c_str()); dryRun_, args_.c_str(), extraOptions_.c_str()); printf("\n"); printf("\n"); } } Loading Loading @@ -748,8 +733,8 @@ bool add_zip_entry_from_fd(const std::string& entry_name, int fd) { // Logging statement below is useful to time how long each entry takes, but it's too verbose. // Logging statement below is useful to time how long each entry takes, but it's too verbose. // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress, ZipWriter::kCompress, get_mtime(fd, now)); get_mtime(fd, ds.now_)); if (err) { if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(), MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(), ZipWriter::ErrorCodeString(err)); ZipWriter::ErrorCodeString(err)); Loading Loading @@ -815,7 +800,7 @@ static bool add_text_zip_entry(const std::string& entry_name, const std::string& return false; return false; } } MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_); if (err) { if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); ZipWriter::ErrorCodeString(err)); Loading Loading @@ -849,8 +834,7 @@ static void dump_iptables() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } } static void dumpstate(const std::string& screenshot_path, static void dumpstate() { const std::string& version __attribute__((unused))) { DurationReporter durationReporter("DUMPSTATE"); DurationReporter durationReporter("DUMPSTATE"); unsigned long timeout; unsigned long timeout; Loading Loading @@ -897,10 +881,9 @@ static void dumpstate(const std::string& screenshot_path, /* Dump Bluetooth HCI logs */ /* Dump Bluetooth HCI logs */ add_dir("/data/misc/bluetooth/logs", true); add_dir("/data/misc/bluetooth/logs", true); if (!screenshot_path.empty()) { if (!ds.doEarlyScreenshot_) { MYLOGI("taking late screenshot\n"); MYLOGI("taking late screenshot\n"); take_screenshot(screenshot_path); ds.TakeScreenshot(); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); } } // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); Loading Loading @@ -1147,7 +1130,7 @@ static void dumpstate(const std::string& screenshot_path, static void ShowUsageAndExit(int exitCode = 1) { static void ShowUsageAndExit(int exitCode = 1) { fprintf(stderr, fprintf(stderr, "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] " "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -b: play sound file instead of vibrate, at beginning of job\n" Loading Loading @@ -1203,13 +1186,13 @@ static void register_sig_handler() { temporary file. temporary file. */ */ static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, const std::string& log_path, time_t now) { const std::string& log_path) { // Final timestamp // Final timestamp char date[80]; char date[80]; time_t the_real_now_please_stand_up = time(nullptr); time_t the_real_now_please_stand_up = time(nullptr); strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up)); strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up)); MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date, MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date, the_real_now_please_stand_up - now); the_real_now_please_stand_up - ds.now_); if (!add_zip_entry(bugreport_name, bugreport_path)) { if (!add_zip_entry(bugreport_name, bugreport_path)) { MYLOGE("Failed to add text entry to .zip file\n"); MYLOGE("Failed to add text entry to .zip file\n"); Loading Loading @@ -1292,11 +1275,7 @@ int main(int argc, char *argv[]) { int use_control_socket = 0; int use_control_socket = 0; int do_fb = 0; int do_fb = 0; int do_broadcast = 0; int do_broadcast = 0; int do_early_screenshot = 0; int is_remote_mode = 0; int is_remote_mode = 0; std::string version = VERSION_DEFAULT; now = time(nullptr); MYLOGI("begin\n"); MYLOGI("begin\n"); Loading @@ -1314,14 +1293,14 @@ int main(int argc, char *argv[]) { // TODO: use helper function to convert argv into a string // TODO: use helper function to convert argv into a string for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) { args += argv[i]; ds.args_ += argv[i]; if (i < argc - 1) { if (i < argc - 1) { args += " "; ds.args_ += " "; } } } } extraOptions = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); ds.extraOptions_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); MYLOGI("Dumpstate args: %s (extra options: %s)\n", args.c_str(), extraOptions.c_str()); MYLOGI("Dumpstate args: %s (extra options: %s)\n", ds.args_.c_str(), ds.extraOptions_.c_str()); /* gets the sequential id */ /* gets the sequential id */ int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); Loading Loading @@ -1358,10 +1337,10 @@ int main(int argc, char *argv[]) { case 'v': break; // compatibility no-op case 'v': break; // compatibility no-op case 'q': do_vibrate = 0; break; case 'q': do_vibrate = 0; break; case 'p': do_fb = 1; break; case 'p': do_fb = 1; break; case 'P': ds.updateProgress_ = 1; break; case 'P': ds.updateProgress_ = true; break; case 'R': is_remote_mode = 1; break; case 'R': is_remote_mode = 1; break; case 'B': do_broadcast = 1; break; case 'B': do_broadcast = 1; break; case 'V': version = optarg; break; case 'V': ds.version_ = optarg; break; case 'h': case 'h': ShowUsageAndExit(0); ShowUsageAndExit(0); break; break; Loading @@ -1372,23 +1351,23 @@ int main(int argc, char *argv[]) { } } } } if (!extraOptions.empty()) { if (!ds.extraOptions_.empty()) { // Framework uses a system property to override some command-line args. // Framework uses a system property to override some command-line args. // Currently, it contains the type of the requested bugreport. // Currently, it contains the type of the requested bugreport. if (extraOptions == "bugreportplus") { if (ds.extraOptions_ == "bugreportplus") { MYLOGD("Running as bugreportplus: add -P, remove -p\n"); MYLOGD("Running as bugreportplus: add -P, remove -p\n"); ds.updateProgress_ = 1; ds.updateProgress_ = true; do_fb = 0; do_fb = 0; } else if (extraOptions == "bugreportremote") { } else if (ds.extraOptions_ == "bugreportremote") { MYLOGD("Running as bugreportremote: add -q -R, remove -p\n"); MYLOGD("Running as bugreportremote: add -q -R, remove -p\n"); do_vibrate = 0; do_vibrate = 0; is_remote_mode = 1; is_remote_mode = 1; do_fb = 0; do_fb = 0; } else if (extraOptions == "bugreportwear") { } else if (ds.extraOptions_ == "bugreportwear") { MYLOGD("Running as bugreportwear: add -P\n"); MYLOGD("Running as bugreportwear: add -P\n"); ds.updateProgress_ = 1; ds.updateProgress_ = true; } else { } else { MYLOGE("Unknown extra option: %s\n", extraOptions.c_str()); MYLOGE("Unknown extra option: %s\n", ds.extraOptions_.c_str()); } } // Reset the property // Reset the property android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); Loading @@ -1410,13 +1389,13 @@ int main(int argc, char *argv[]) { ExitOnInvalidArgs(); ExitOnInvalidArgs(); } } if (version != VERSION_DEFAULT) { if (ds.version_ != VERSION_DEFAULT) { ShowUsageAndExit(); ShowUsageAndExit(); } } MYLOGI("bugreport format version: %s\n", version.c_str()); MYLOGI("bugreport format version: %s\n", ds.version_.c_str()); do_early_screenshot = ds.updateProgress_; ds.doEarlyScreenshot_ = ds.updateProgress_; // If we are going to use a socket, do it as early as possible // If we are going to use a socket, do it as early as possible // to avoid timeouts from bugreport. // to avoid timeouts from bugreport. Loading @@ -1436,15 +1415,6 @@ int main(int argc, char *argv[]) { /* full path of the file containing the dumpstate logs */ /* full path of the file containing the dumpstate logs */ std::string log_path; std::string log_path; /* full path of the systrace file, when enabled */ std::string systrace_path; /* full path of the temporary file containing the screenshot (when requested) */ std::string screenshot_path; /* base name (without suffix or extensions) of the bugreport files */ std::string base_name; /* pointer to the actual path, be it zip or text */ /* pointer to the actual path, be it zip or text */ std::string path; std::string path; Loading @@ -1456,25 +1426,21 @@ int main(int argc, char *argv[]) { if (is_redirecting) { if (is_redirecting) { ds.bugreportDir_ = dirname(use_outfile); ds.bugreportDir_ = dirname(use_outfile); base_name = basename(use_outfile); ds.baseName_ = basename(use_outfile); if (do_add_date) { if (do_add_date) { char date[80]; char date[80]; strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now)); strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_)); suffix = date; ds.suffix_ = date; } else { } else { suffix = "undated"; ds.suffix_ = "undated"; } } std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD"); std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD"); base_name = base_name + "-" + buildId; ds.baseName_ = ds.baseName_ + "-" + buildId; if (do_fb) { if (do_fb) { // TODO: if dumpstate was an object, the paths could be internal variables and then ds.screenshotPath_ = ds.GetPath(".png"); // we could have a function to calculate the derived values, such as: // screenshot_path = GetPath(".png"); screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png"; } } tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp"; tmp_path = ds.GetPath(".tmp"); log_path = log_path = ds.GetPath("-dumpstate_log-" + std::to_string(getpid()) + ".txt"); ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt"; MYLOGD( MYLOGD( "Bugreport dir: %s\n" "Bugreport dir: %s\n" Loading @@ -1483,11 +1449,11 @@ int main(int argc, char *argv[]) { "Log path: %s\n" "Log path: %s\n" "Temporary path: %s\n" "Temporary path: %s\n" "Screenshot path: %s\n", "Screenshot path: %s\n", ds.bugreportDir_.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(), ds.bugreportDir_.c_str(), ds.baseName_.c_str(), ds.suffix_.c_str(), log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str()); tmp_path.c_str(), ds.screenshotPath_.c_str()); if (do_zip_file) { if (do_zip_file) { path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip"; path = ds.GetPath(".zip"); MYLOGD("Creating initial .zip file (%s)\n", path.c_str()); MYLOGD("Creating initial .zip file (%s)\n", path.c_str()); create_parent_dirs(path.c_str()); create_parent_dirs(path.c_str()); zip_file.reset(fopen(path.c_str(), "wb")); zip_file.reset(fopen(path.c_str(), "wb")); Loading @@ -1497,7 +1463,7 @@ int main(int argc, char *argv[]) { } else { } else { zip_writer.reset(new ZipWriter(zip_file.get())); zip_writer.reset(new ZipWriter(zip_file.get())); } } add_text_zip_entry("version.txt", version); add_text_zip_entry("version.txt", ds.version_); } } if (ds.updateProgress_) { if (ds.updateProgress_) { Loading @@ -1505,7 +1471,7 @@ int main(int argc, char *argv[]) { // clang-format off // clang-format off std::vector<std::string> am_args = { std::vector<std::string> am_args = { "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--es", "android.intent.extra.NAME", suffix, "--es", "android.intent.extra.NAME", ds.suffix_, "--ei", "android.intent.extra.ID", std::to_string(ds.id_), "--ei", "android.intent.extra.ID", std::to_string(ds.id_), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), Loading Loading @@ -1535,18 +1501,13 @@ int main(int argc, char *argv[]) { } } } } if (do_fb && do_early_screenshot) { if (do_fb && ds.doEarlyScreenshot_) { if (screenshot_path.empty()) { if (ds.screenshotPath_.empty()) { // should not have happened // should not have happened MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); } else { } else { MYLOGI("taking early screenshot\n"); MYLOGI("taking early screenshot\n"); take_screenshot(screenshot_path); ds.TakeScreenshot(); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of screenshot file %s: %s\n", screenshot_path.c_str(), strerror(errno)); } } } } } Loading Loading @@ -1574,7 +1535,7 @@ int main(int argc, char *argv[]) { // NOTE: there should be no stdout output until now, otherwise it would break the header. // 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 // In particular, DurationReport objects should be created passing 'title, NULL', so their // duration is logged into MYLOG instead. // duration is logged into MYLOG instead. print_header(version); ds.PrintHeader(); // Dumps systrace right away, otherwise it will be filled with unnecessary events. // Dumps systrace right away, otherwise it will be filled with unnecessary events. // First try to dump anrd trace if the daemon is running. Otherwise, dump // First try to dump anrd trace if the daemon is running. Otherwise, dump Loading Loading @@ -1619,7 +1580,7 @@ int main(int argc, char *argv[]) { return -1; return -1; } } dumpstate(do_early_screenshot ? "": screenshot_path, version); dumpstate(); /* close output if needed */ /* close output if needed */ if (is_redirecting) { if (is_redirecting) { Loading @@ -1643,31 +1604,30 @@ int main(int argc, char *argv[]) { } } } } if (change_suffix) { if (change_suffix) { MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), name.c_str()); MYLOGI("changing suffix from %s to %s\n", ds.suffix_.c_str(), name.c_str()); suffix = name; ds.suffix_ = name; if (!screenshot_path.empty()) { if (!ds.screenshotPath_.empty()) { std::string new_screenshot_path = std::string newScreenshotPath = ds.GetPath(".png"); ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png"; if (rename(ds.screenshotPath_.c_str(), newScreenshotPath.c_str())) { if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", ds.screenshotPath_.c_str(), MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(), newScreenshotPath.c_str(), strerror(errno)); new_screenshot_path.c_str(), strerror(errno)); } else { } else { screenshot_path = new_screenshot_path; ds.screenshotPath_ = newScreenshotPath; } } } } } } bool do_text_file = true; bool do_text_file = true; if (do_zip_file) { if (do_zip_file) { std::string entry_name = base_name + "-" + suffix + ".txt"; std::string entry_name = ds.baseName_ + "-" + ds.suffix_ + ".txt"; MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str()); MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str()); if (!finish_zip_file(entry_name, tmp_path, log_path, now)) { if (!finish_zip_file(entry_name, tmp_path, log_path)) { MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); do_text_file = true; do_text_file = true; } else { } else { do_text_file = false; do_text_file = false; // Since zip file is already created, it needs to be renamed. // Since zip file is already created, it needs to be renamed. std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip"; std::string new_path = ds.GetPath(".zip"); if (path != new_path) { if (path != new_path) { MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str()); MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str()); if (rename(path.c_str(), new_path.c_str())) { if (rename(path.c_str(), new_path.c_str())) { Loading @@ -1680,7 +1640,7 @@ int main(int argc, char *argv[]) { } } } } if (do_text_file) { if (do_text_file) { path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".txt"; path = ds.GetPath(".txt"); MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str()); MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str()); if (rename(tmp_path.c_str(), path.c_str())) { if (rename(tmp_path.c_str(), path.c_str())) { MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); Loading Loading @@ -1724,7 +1684,7 @@ int main(int argc, char *argv[]) { if (do_fb) { if (do_fb) { am_args.push_back("--es"); am_args.push_back("--es"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back(screenshot_path); am_args.push_back(ds.screenshotPath_); } } if (is_remote_mode) { if (is_remote_mode) { am_args.push_back("--es"); am_args.push_back("--es"); Loading cmds/dumpstate/dumpstate.h +44 −4 Original line number Original line Diff line number Diff line Loading @@ -192,6 +192,13 @@ class CommandOptions { // TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file // TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file static const int WEIGHT_TOTAL = 6500; static const int WEIGHT_TOTAL = 6500; /* * List of supported zip format versions. * * See bugreport-format.md for more info. */ static std::string VERSION_DEFAULT = "1.0"; /* /* * Main class driving a bugreport generation. * Main class driving a bugreport generation. * * Loading Loading @@ -255,6 +262,13 @@ class Dumpstate { */ */ int DumpFile(const std::string& title, const std::string& path); int DumpFile(const std::string& title, const std::string& path); /* * Takes a screenshot and save it to the given `path`. * * If `path` is empty, uses a standard path based on the bugreport name. */ void TakeScreenshot(const std::string& path = ""); // TODO: members below should be private once refactor is finished // TODO: members below should be private once refactor is finished /* /* Loading @@ -262,6 +276,12 @@ class Dumpstate { */ */ void UpdateProgress(int delta); void UpdateProgress(int delta); /* Prints the dumpstate header on `stdout`. */ void PrintHeader(); /* Gets the path of a bugreport file with the given suffix. */ std::string GetPath(const std::string& suffix); // TODO: initialize fields on constructor // TODO: initialize fields on constructor // dumpstate id - unique after each device reboot. // dumpstate id - unique after each device reboot. Loading @@ -270,6 +290,9 @@ class Dumpstate { // Whether progress updates should be published. // Whether progress updates should be published. bool updateProgress_ = false; bool updateProgress_ = false; // Whether it should take an screenshot earlier in the process. bool doEarlyScreenshot_ = false; // Currrent progress. // Currrent progress. int progress_ = 0; int progress_ = 0; Loading @@ -279,10 +302,30 @@ class Dumpstate { // When set, defines a socket file-descriptor use to report progress to bugreportz. // When set, defines a socket file-descriptor use to report progress to bugreportz. int controlSocketFd_ = -1; int controlSocketFd_ = -1; // Bugreport format version; std::string version_ = VERSION_DEFAULT; // Command-line arguments as string std::string args_; // Full path of the directory where the bugreport files will be written; // Extra options passed as system property. std::string extraOptions_; // Full path of the directory where the bugreport files will be written. std::string bugreportDir_; std::string bugreportDir_; // Full path of the temporary file containing the screenshot (when requested). std::string screenshotPath_; time_t now_; // Suffix of the bugreport files - it's typically the date (when invoked with -d), // although it could be changed by the user using a system property. std::string suffix_; // Base name (without suffix or extensions) of the bugreport files. std::string baseName_; private: private: // Used by GetInstance() only. // Used by GetInstance() only. Dumpstate(bool dryRun = false, const std::string& buildType = "user"); Dumpstate(bool dryRun = false, const std::string& buildType = "user"); Loading Loading @@ -380,9 +423,6 @@ void play_sound(const char *path); /* Implemented by libdumpstate_board to dump board-specific info */ /* Implemented by libdumpstate_board to dump board-specific info */ void dumpstate_board(); void dumpstate_board(); /* Takes a screenshot and save it to the given file */ void take_screenshot(const std::string& path); /* Vibrates for a given durating (in milliseconds). */ /* Vibrates for a given durating (in milliseconds). */ void vibrate(FILE* vibrator, int ms); void vibrate(FILE* vibrator, int ms); Loading cmds/dumpstate/utils.cpp +15 −4 Original line number Original line Diff line number Diff line Loading @@ -163,7 +163,7 @@ CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(long timeout) } } Dumpstate::Dumpstate(bool dryRun, const std::string& buildType) Dumpstate::Dumpstate(bool dryRun, const std::string& buildType) : dryRun_(dryRun), buildType_(buildType) { : now_(time(nullptr)), dryRun_(dryRun), buildType_(buildType) { } } Dumpstate& Dumpstate::GetInstance() { Dumpstate& Dumpstate::GetInstance() { Loading Loading @@ -208,6 +208,10 @@ bool Dumpstate::IsUserBuild() { return "user" == buildType_; return "user" == buildType_; } } std::string Dumpstate::GetPath(const std::string& suffix) { return bugreportDir_ + "/" + baseName_ + "-" + suffix_ + suffix; } void for_each_userid(void (*func)(int), const char *header) { void for_each_userid(void (*func)(int), const char *header) { if (IsDryRun()) return; if (IsDryRun()) return; Loading Loading @@ -1342,9 +1346,16 @@ void Dumpstate::UpdateProgress(int delta) { } } } } void take_screenshot(const std::string& path) { void Dumpstate::TakeScreenshot(const std::string& path) { RunCommand("", {"/system/bin/screencap", "-p", path}, const std::string& realPath = path.empty() ? screenshotPath_ : path; CommandOptions::WithTimeout(10).Always().RedirectStderr().Build()); int status = RunCommand("", {"/system/bin/screencap", "-p", realPath}, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); if (status == 0) { MYLOGD("Screenshot saved on %s\n", realPath.c_str()); } else { MYLOGE("Failed to take screenshot on %s\n", realPath.c_str()); } } } void vibrate(FILE* vibrator, int ms) { void vibrate(FILE* vibrator, int ms) { Loading Loading
cmds/dumpstate/dumpstate.cpp +75 −115 Original line number Original line Diff line number Diff line Loading @@ -56,18 +56,10 @@ static char cmdline_buf[16384] = "(unknown)"; static char cmdline_buf[16384] = "(unknown)"; static const char *dump_traces_path = NULL; static const char *dump_traces_path = NULL; // Command-line arguments as string static std::string args; // TODO: variables below should be part of dumpstate object // TODO: variables below should be part of dumpstate object static time_t now; static std::unique_ptr<ZipWriter> zip_writer; static std::unique_ptr<ZipWriter> zip_writer; static std::set<std::string> mount_points; static std::set<std::string> mount_points; void add_mountinfo(); void add_mountinfo(); /* suffix of the bugreport files - it's typically the date (when invoked with -d), * although it could be changed by the user using a system property */ static std::string suffix; static std::string extraOptions; #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" Loading Loading @@ -111,13 +103,6 @@ bool IsUserBuild() { return ds.IsUserBuild(); return ds.IsUserBuild(); } } /* * List of supported zip format versions. * * See bugreport-format.md for more info. */ static std::string VERSION_DEFAULT = "1.0"; // Relative directory (inside the zip) for all files copied as-is into the bugreport. // Relative directory (inside the zip) for all files copied as-is into the bugreport. static const std::string ZIP_ROOT_DIR = "FS"; static const std::string ZIP_ROOT_DIR = "FS"; Loading @@ -127,7 +112,7 @@ static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id"; /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones; /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones; * otherwise, gets just those modified in the last half an hour. */ * otherwise, gets just those modified in the last half an hour. */ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { time_t thirty_minutes_ago = now - 60*30; time_t thirty_minutes_ago = ds.now_ - 60 * 30; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { for (size_t i = 0; i < NUM_TOMBSTONES; i++) { snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); int fd = TEMP_FAILURE_RETRY(open(data[i].name, int fd = TEMP_FAILURE_RETRY(open(data[i].name, Loading Loading @@ -336,7 +321,7 @@ static void dump_systrace() { MYLOGD("Not dumping systrace because zip_writer is not set\n"); MYLOGD("Not dumping systrace because zip_writer is not set\n"); return; return; } } std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt"; std::string systrace_path = ds.GetPath("-systrace.txt"); if (systrace_path.empty()) { if (systrace_path.empty()) { MYLOGE("Not dumping systrace because path is empty\n"); MYLOGE("Not dumping systrace because path is empty\n"); return; return; Loading Loading @@ -377,7 +362,7 @@ static void dump_raft() { return; return; } } std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt"; std::string raft_log_path = ds.GetPath("-raft_log.txt"); if (raft_log_path.empty()) { if (raft_log_path.empty()) { MYLOGD("raft_log_path is empty\n"); MYLOGD("raft_log_path is empty\n"); return; return; Loading Loading @@ -686,8 +671,8 @@ static unsigned long logcat_timeout(const char *name) { /* End copy from system/core/logd/LogBuffer.cpp */ /* End copy from system/core/logd/LogBuffer.cpp */ /* dumps the current system state to stdout */ // TODO: move to utils.cpp void print_header(const std::string& version) { void Dumpstate::PrintHeader() { std::string build, fingerprint, radio, bootloader, network; std::string build, fingerprint, radio, bootloader, network; char date[80]; char date[80]; Loading @@ -696,7 +681,7 @@ void print_header(const std::string& version) { radio = android::base::GetProperty("gsm.version.baseband", "(unknown)"); radio = android::base::GetProperty("gsm.version.baseband", "(unknown)"); bootloader = android::base::GetProperty("ro.bootloader", "(unknown)"); bootloader = android::base::GetProperty("ro.bootloader", "(unknown)"); network = android::base::GetProperty("gsm.operator.alpha", "(unknown)"); network = android::base::GetProperty("gsm.operator.alpha", "(unknown)"); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_)); printf("========================================================\n"); printf("========================================================\n"); printf("== dumpstate: %s\n", date); printf("== dumpstate: %s\n", date); Loading @@ -713,9 +698,9 @@ void print_header(const std::string& version) { printf("Kernel: "); printf("Kernel: "); DumpFile("", "/proc/version"); DumpFile("", "/proc/version"); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("Bugreport format version: %s\n", version.c_str()); printf("Bugreport format version: %s\n", version_.c_str()); printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(), printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", id_, getpid(), ds.IsDryRun(), args.c_str(), extraOptions.c_str()); dryRun_, args_.c_str(), extraOptions_.c_str()); printf("\n"); printf("\n"); } } Loading Loading @@ -748,8 +733,8 @@ bool add_zip_entry_from_fd(const std::string& entry_name, int fd) { // Logging statement below is useful to time how long each entry takes, but it's too verbose. // Logging statement below is useful to time how long each entry takes, but it's too verbose. // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress, ZipWriter::kCompress, get_mtime(fd, now)); get_mtime(fd, ds.now_)); if (err) { if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(), MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(), ZipWriter::ErrorCodeString(err)); ZipWriter::ErrorCodeString(err)); Loading Loading @@ -815,7 +800,7 @@ static bool add_text_zip_entry(const std::string& entry_name, const std::string& return false; return false; } } MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_); if (err) { if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); ZipWriter::ErrorCodeString(err)); Loading Loading @@ -849,8 +834,7 @@ static void dump_iptables() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } } static void dumpstate(const std::string& screenshot_path, static void dumpstate() { const std::string& version __attribute__((unused))) { DurationReporter durationReporter("DUMPSTATE"); DurationReporter durationReporter("DUMPSTATE"); unsigned long timeout; unsigned long timeout; Loading Loading @@ -897,10 +881,9 @@ static void dumpstate(const std::string& screenshot_path, /* Dump Bluetooth HCI logs */ /* Dump Bluetooth HCI logs */ add_dir("/data/misc/bluetooth/logs", true); add_dir("/data/misc/bluetooth/logs", true); if (!screenshot_path.empty()) { if (!ds.doEarlyScreenshot_) { MYLOGI("taking late screenshot\n"); MYLOGI("taking late screenshot\n"); take_screenshot(screenshot_path); ds.TakeScreenshot(); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); } } // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); Loading Loading @@ -1147,7 +1130,7 @@ static void dumpstate(const std::string& screenshot_path, static void ShowUsageAndExit(int exitCode = 1) { static void ShowUsageAndExit(int exitCode = 1) { fprintf(stderr, fprintf(stderr, "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] " "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -b: play sound file instead of vibrate, at beginning of job\n" Loading Loading @@ -1203,13 +1186,13 @@ static void register_sig_handler() { temporary file. temporary file. */ */ static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, const std::string& log_path, time_t now) { const std::string& log_path) { // Final timestamp // Final timestamp char date[80]; char date[80]; time_t the_real_now_please_stand_up = time(nullptr); time_t the_real_now_please_stand_up = time(nullptr); strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up)); strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up)); MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date, MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date, the_real_now_please_stand_up - now); the_real_now_please_stand_up - ds.now_); if (!add_zip_entry(bugreport_name, bugreport_path)) { if (!add_zip_entry(bugreport_name, bugreport_path)) { MYLOGE("Failed to add text entry to .zip file\n"); MYLOGE("Failed to add text entry to .zip file\n"); Loading Loading @@ -1292,11 +1275,7 @@ int main(int argc, char *argv[]) { int use_control_socket = 0; int use_control_socket = 0; int do_fb = 0; int do_fb = 0; int do_broadcast = 0; int do_broadcast = 0; int do_early_screenshot = 0; int is_remote_mode = 0; int is_remote_mode = 0; std::string version = VERSION_DEFAULT; now = time(nullptr); MYLOGI("begin\n"); MYLOGI("begin\n"); Loading @@ -1314,14 +1293,14 @@ int main(int argc, char *argv[]) { // TODO: use helper function to convert argv into a string // TODO: use helper function to convert argv into a string for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) { args += argv[i]; ds.args_ += argv[i]; if (i < argc - 1) { if (i < argc - 1) { args += " "; ds.args_ += " "; } } } } extraOptions = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); ds.extraOptions_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); MYLOGI("Dumpstate args: %s (extra options: %s)\n", args.c_str(), extraOptions.c_str()); MYLOGI("Dumpstate args: %s (extra options: %s)\n", ds.args_.c_str(), ds.extraOptions_.c_str()); /* gets the sequential id */ /* gets the sequential id */ int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); Loading Loading @@ -1358,10 +1337,10 @@ int main(int argc, char *argv[]) { case 'v': break; // compatibility no-op case 'v': break; // compatibility no-op case 'q': do_vibrate = 0; break; case 'q': do_vibrate = 0; break; case 'p': do_fb = 1; break; case 'p': do_fb = 1; break; case 'P': ds.updateProgress_ = 1; break; case 'P': ds.updateProgress_ = true; break; case 'R': is_remote_mode = 1; break; case 'R': is_remote_mode = 1; break; case 'B': do_broadcast = 1; break; case 'B': do_broadcast = 1; break; case 'V': version = optarg; break; case 'V': ds.version_ = optarg; break; case 'h': case 'h': ShowUsageAndExit(0); ShowUsageAndExit(0); break; break; Loading @@ -1372,23 +1351,23 @@ int main(int argc, char *argv[]) { } } } } if (!extraOptions.empty()) { if (!ds.extraOptions_.empty()) { // Framework uses a system property to override some command-line args. // Framework uses a system property to override some command-line args. // Currently, it contains the type of the requested bugreport. // Currently, it contains the type of the requested bugreport. if (extraOptions == "bugreportplus") { if (ds.extraOptions_ == "bugreportplus") { MYLOGD("Running as bugreportplus: add -P, remove -p\n"); MYLOGD("Running as bugreportplus: add -P, remove -p\n"); ds.updateProgress_ = 1; ds.updateProgress_ = true; do_fb = 0; do_fb = 0; } else if (extraOptions == "bugreportremote") { } else if (ds.extraOptions_ == "bugreportremote") { MYLOGD("Running as bugreportremote: add -q -R, remove -p\n"); MYLOGD("Running as bugreportremote: add -q -R, remove -p\n"); do_vibrate = 0; do_vibrate = 0; is_remote_mode = 1; is_remote_mode = 1; do_fb = 0; do_fb = 0; } else if (extraOptions == "bugreportwear") { } else if (ds.extraOptions_ == "bugreportwear") { MYLOGD("Running as bugreportwear: add -P\n"); MYLOGD("Running as bugreportwear: add -P\n"); ds.updateProgress_ = 1; ds.updateProgress_ = true; } else { } else { MYLOGE("Unknown extra option: %s\n", extraOptions.c_str()); MYLOGE("Unknown extra option: %s\n", ds.extraOptions_.c_str()); } } // Reset the property // Reset the property android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); Loading @@ -1410,13 +1389,13 @@ int main(int argc, char *argv[]) { ExitOnInvalidArgs(); ExitOnInvalidArgs(); } } if (version != VERSION_DEFAULT) { if (ds.version_ != VERSION_DEFAULT) { ShowUsageAndExit(); ShowUsageAndExit(); } } MYLOGI("bugreport format version: %s\n", version.c_str()); MYLOGI("bugreport format version: %s\n", ds.version_.c_str()); do_early_screenshot = ds.updateProgress_; ds.doEarlyScreenshot_ = ds.updateProgress_; // If we are going to use a socket, do it as early as possible // If we are going to use a socket, do it as early as possible // to avoid timeouts from bugreport. // to avoid timeouts from bugreport. Loading @@ -1436,15 +1415,6 @@ int main(int argc, char *argv[]) { /* full path of the file containing the dumpstate logs */ /* full path of the file containing the dumpstate logs */ std::string log_path; std::string log_path; /* full path of the systrace file, when enabled */ std::string systrace_path; /* full path of the temporary file containing the screenshot (when requested) */ std::string screenshot_path; /* base name (without suffix or extensions) of the bugreport files */ std::string base_name; /* pointer to the actual path, be it zip or text */ /* pointer to the actual path, be it zip or text */ std::string path; std::string path; Loading @@ -1456,25 +1426,21 @@ int main(int argc, char *argv[]) { if (is_redirecting) { if (is_redirecting) { ds.bugreportDir_ = dirname(use_outfile); ds.bugreportDir_ = dirname(use_outfile); base_name = basename(use_outfile); ds.baseName_ = basename(use_outfile); if (do_add_date) { if (do_add_date) { char date[80]; char date[80]; strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now)); strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_)); suffix = date; ds.suffix_ = date; } else { } else { suffix = "undated"; ds.suffix_ = "undated"; } } std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD"); std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD"); base_name = base_name + "-" + buildId; ds.baseName_ = ds.baseName_ + "-" + buildId; if (do_fb) { if (do_fb) { // TODO: if dumpstate was an object, the paths could be internal variables and then ds.screenshotPath_ = ds.GetPath(".png"); // we could have a function to calculate the derived values, such as: // screenshot_path = GetPath(".png"); screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png"; } } tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp"; tmp_path = ds.GetPath(".tmp"); log_path = log_path = ds.GetPath("-dumpstate_log-" + std::to_string(getpid()) + ".txt"); ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt"; MYLOGD( MYLOGD( "Bugreport dir: %s\n" "Bugreport dir: %s\n" Loading @@ -1483,11 +1449,11 @@ int main(int argc, char *argv[]) { "Log path: %s\n" "Log path: %s\n" "Temporary path: %s\n" "Temporary path: %s\n" "Screenshot path: %s\n", "Screenshot path: %s\n", ds.bugreportDir_.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(), ds.bugreportDir_.c_str(), ds.baseName_.c_str(), ds.suffix_.c_str(), log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str()); tmp_path.c_str(), ds.screenshotPath_.c_str()); if (do_zip_file) { if (do_zip_file) { path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip"; path = ds.GetPath(".zip"); MYLOGD("Creating initial .zip file (%s)\n", path.c_str()); MYLOGD("Creating initial .zip file (%s)\n", path.c_str()); create_parent_dirs(path.c_str()); create_parent_dirs(path.c_str()); zip_file.reset(fopen(path.c_str(), "wb")); zip_file.reset(fopen(path.c_str(), "wb")); Loading @@ -1497,7 +1463,7 @@ int main(int argc, char *argv[]) { } else { } else { zip_writer.reset(new ZipWriter(zip_file.get())); zip_writer.reset(new ZipWriter(zip_file.get())); } } add_text_zip_entry("version.txt", version); add_text_zip_entry("version.txt", ds.version_); } } if (ds.updateProgress_) { if (ds.updateProgress_) { Loading @@ -1505,7 +1471,7 @@ int main(int argc, char *argv[]) { // clang-format off // clang-format off std::vector<std::string> am_args = { std::vector<std::string> am_args = { "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--es", "android.intent.extra.NAME", suffix, "--es", "android.intent.extra.NAME", ds.suffix_, "--ei", "android.intent.extra.ID", std::to_string(ds.id_), "--ei", "android.intent.extra.ID", std::to_string(ds.id_), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), Loading Loading @@ -1535,18 +1501,13 @@ int main(int argc, char *argv[]) { } } } } if (do_fb && do_early_screenshot) { if (do_fb && ds.doEarlyScreenshot_) { if (screenshot_path.empty()) { if (ds.screenshotPath_.empty()) { // should not have happened // should not have happened MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); } else { } else { MYLOGI("taking early screenshot\n"); MYLOGI("taking early screenshot\n"); take_screenshot(screenshot_path); ds.TakeScreenshot(); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of screenshot file %s: %s\n", screenshot_path.c_str(), strerror(errno)); } } } } } Loading Loading @@ -1574,7 +1535,7 @@ int main(int argc, char *argv[]) { // NOTE: there should be no stdout output until now, otherwise it would break the header. // 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 // In particular, DurationReport objects should be created passing 'title, NULL', so their // duration is logged into MYLOG instead. // duration is logged into MYLOG instead. print_header(version); ds.PrintHeader(); // Dumps systrace right away, otherwise it will be filled with unnecessary events. // Dumps systrace right away, otherwise it will be filled with unnecessary events. // First try to dump anrd trace if the daemon is running. Otherwise, dump // First try to dump anrd trace if the daemon is running. Otherwise, dump Loading Loading @@ -1619,7 +1580,7 @@ int main(int argc, char *argv[]) { return -1; return -1; } } dumpstate(do_early_screenshot ? "": screenshot_path, version); dumpstate(); /* close output if needed */ /* close output if needed */ if (is_redirecting) { if (is_redirecting) { Loading @@ -1643,31 +1604,30 @@ int main(int argc, char *argv[]) { } } } } if (change_suffix) { if (change_suffix) { MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), name.c_str()); MYLOGI("changing suffix from %s to %s\n", ds.suffix_.c_str(), name.c_str()); suffix = name; ds.suffix_ = name; if (!screenshot_path.empty()) { if (!ds.screenshotPath_.empty()) { std::string new_screenshot_path = std::string newScreenshotPath = ds.GetPath(".png"); ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png"; if (rename(ds.screenshotPath_.c_str(), newScreenshotPath.c_str())) { if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", ds.screenshotPath_.c_str(), MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(), newScreenshotPath.c_str(), strerror(errno)); new_screenshot_path.c_str(), strerror(errno)); } else { } else { screenshot_path = new_screenshot_path; ds.screenshotPath_ = newScreenshotPath; } } } } } } bool do_text_file = true; bool do_text_file = true; if (do_zip_file) { if (do_zip_file) { std::string entry_name = base_name + "-" + suffix + ".txt"; std::string entry_name = ds.baseName_ + "-" + ds.suffix_ + ".txt"; MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str()); MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str()); if (!finish_zip_file(entry_name, tmp_path, log_path, now)) { if (!finish_zip_file(entry_name, tmp_path, log_path)) { MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); do_text_file = true; do_text_file = true; } else { } else { do_text_file = false; do_text_file = false; // Since zip file is already created, it needs to be renamed. // Since zip file is already created, it needs to be renamed. std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip"; std::string new_path = ds.GetPath(".zip"); if (path != new_path) { if (path != new_path) { MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str()); MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str()); if (rename(path.c_str(), new_path.c_str())) { if (rename(path.c_str(), new_path.c_str())) { Loading @@ -1680,7 +1640,7 @@ int main(int argc, char *argv[]) { } } } } if (do_text_file) { if (do_text_file) { path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".txt"; path = ds.GetPath(".txt"); MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str()); MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str()); if (rename(tmp_path.c_str(), path.c_str())) { if (rename(tmp_path.c_str(), path.c_str())) { MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); Loading Loading @@ -1724,7 +1684,7 @@ int main(int argc, char *argv[]) { if (do_fb) { if (do_fb) { am_args.push_back("--es"); am_args.push_back("--es"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back(screenshot_path); am_args.push_back(ds.screenshotPath_); } } if (is_remote_mode) { if (is_remote_mode) { am_args.push_back("--es"); am_args.push_back("--es"); Loading
cmds/dumpstate/dumpstate.h +44 −4 Original line number Original line Diff line number Diff line Loading @@ -192,6 +192,13 @@ class CommandOptions { // TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file // TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file static const int WEIGHT_TOTAL = 6500; static const int WEIGHT_TOTAL = 6500; /* * List of supported zip format versions. * * See bugreport-format.md for more info. */ static std::string VERSION_DEFAULT = "1.0"; /* /* * Main class driving a bugreport generation. * Main class driving a bugreport generation. * * Loading Loading @@ -255,6 +262,13 @@ class Dumpstate { */ */ int DumpFile(const std::string& title, const std::string& path); int DumpFile(const std::string& title, const std::string& path); /* * Takes a screenshot and save it to the given `path`. * * If `path` is empty, uses a standard path based on the bugreport name. */ void TakeScreenshot(const std::string& path = ""); // TODO: members below should be private once refactor is finished // TODO: members below should be private once refactor is finished /* /* Loading @@ -262,6 +276,12 @@ class Dumpstate { */ */ void UpdateProgress(int delta); void UpdateProgress(int delta); /* Prints the dumpstate header on `stdout`. */ void PrintHeader(); /* Gets the path of a bugreport file with the given suffix. */ std::string GetPath(const std::string& suffix); // TODO: initialize fields on constructor // TODO: initialize fields on constructor // dumpstate id - unique after each device reboot. // dumpstate id - unique after each device reboot. Loading @@ -270,6 +290,9 @@ class Dumpstate { // Whether progress updates should be published. // Whether progress updates should be published. bool updateProgress_ = false; bool updateProgress_ = false; // Whether it should take an screenshot earlier in the process. bool doEarlyScreenshot_ = false; // Currrent progress. // Currrent progress. int progress_ = 0; int progress_ = 0; Loading @@ -279,10 +302,30 @@ class Dumpstate { // When set, defines a socket file-descriptor use to report progress to bugreportz. // When set, defines a socket file-descriptor use to report progress to bugreportz. int controlSocketFd_ = -1; int controlSocketFd_ = -1; // Bugreport format version; std::string version_ = VERSION_DEFAULT; // Command-line arguments as string std::string args_; // Full path of the directory where the bugreport files will be written; // Extra options passed as system property. std::string extraOptions_; // Full path of the directory where the bugreport files will be written. std::string bugreportDir_; std::string bugreportDir_; // Full path of the temporary file containing the screenshot (when requested). std::string screenshotPath_; time_t now_; // Suffix of the bugreport files - it's typically the date (when invoked with -d), // although it could be changed by the user using a system property. std::string suffix_; // Base name (without suffix or extensions) of the bugreport files. std::string baseName_; private: private: // Used by GetInstance() only. // Used by GetInstance() only. Dumpstate(bool dryRun = false, const std::string& buildType = "user"); Dumpstate(bool dryRun = false, const std::string& buildType = "user"); Loading Loading @@ -380,9 +423,6 @@ void play_sound(const char *path); /* Implemented by libdumpstate_board to dump board-specific info */ /* Implemented by libdumpstate_board to dump board-specific info */ void dumpstate_board(); void dumpstate_board(); /* Takes a screenshot and save it to the given file */ void take_screenshot(const std::string& path); /* Vibrates for a given durating (in milliseconds). */ /* Vibrates for a given durating (in milliseconds). */ void vibrate(FILE* vibrator, int ms); void vibrate(FILE* vibrator, int ms); Loading
cmds/dumpstate/utils.cpp +15 −4 Original line number Original line Diff line number Diff line Loading @@ -163,7 +163,7 @@ CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(long timeout) } } Dumpstate::Dumpstate(bool dryRun, const std::string& buildType) Dumpstate::Dumpstate(bool dryRun, const std::string& buildType) : dryRun_(dryRun), buildType_(buildType) { : now_(time(nullptr)), dryRun_(dryRun), buildType_(buildType) { } } Dumpstate& Dumpstate::GetInstance() { Dumpstate& Dumpstate::GetInstance() { Loading Loading @@ -208,6 +208,10 @@ bool Dumpstate::IsUserBuild() { return "user" == buildType_; return "user" == buildType_; } } std::string Dumpstate::GetPath(const std::string& suffix) { return bugreportDir_ + "/" + baseName_ + "-" + suffix_ + suffix; } void for_each_userid(void (*func)(int), const char *header) { void for_each_userid(void (*func)(int), const char *header) { if (IsDryRun()) return; if (IsDryRun()) return; Loading Loading @@ -1342,9 +1346,16 @@ void Dumpstate::UpdateProgress(int delta) { } } } } void take_screenshot(const std::string& path) { void Dumpstate::TakeScreenshot(const std::string& path) { RunCommand("", {"/system/bin/screencap", "-p", path}, const std::string& realPath = path.empty() ? screenshotPath_ : path; CommandOptions::WithTimeout(10).Always().RedirectStderr().Build()); int status = RunCommand("", {"/system/bin/screencap", "-p", realPath}, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); if (status == 0) { MYLOGD("Screenshot saved on %s\n", realPath.c_str()); } else { MYLOGE("Failed to take screenshot on %s\n", realPath.c_str()); } } } void vibrate(FILE* vibrator, int ms) { void vibrate(FILE* vibrator, int ms) { Loading