2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 #include <sys/prctl.h>
31 #include <sys/resource.h>
37 #include <android-base/file.h>
38 #include <android-base/stringprintf.h>
39 #include <android-base/strings.h>
40 #include <cutils/properties.h>
42 #include "private/android_filesystem_config.h"
44 #define LOG_TAG "dumpstate"
45 #include <cutils/log.h>
47 #include "dumpstate.h"
49 #include "ziparchive/zip_writer.h"
51 #include "mincrypt/sha256.h"
53 using android::base::StringPrintf;
55 /* read before root is shed */
56 static char cmdline_buf[16384] = "(unknown)";
57 static const char *dump_traces_path = NULL;
59 // TODO: variables below should be part of dumpstate object
60 static unsigned long id;
61 static char build_type[PROPERTY_VALUE_MAX];
63 static std::unique_ptr<ZipWriter> zip_writer;
64 static std::set<std::string> mount_points;
66 int control_socket_fd = -1;
67 /* suffix of the bugreport files - it's typically the date (when invoked with -d),
68 * although it could be changed by the user using a system property */
69 static std::string suffix;
71 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
72 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
74 #define RAFT_DIR "/data/misc/raft"
75 #define RECOVERY_DIR "/cache/recovery"
76 #define RECOVERY_DATA_DIR "/data/misc/recovery"
77 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
78 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
79 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
80 #define TOMBSTONE_DIR "/data/tombstones"
81 #define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
82 /* Can accomodate a tombstone number up to 9999. */
83 #define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
84 #define NUM_TOMBSTONES 10
85 #define WLUTIL "/vendor/xbin/wlutil"
88 char name[TOMBSTONE_MAX_LEN];
92 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
94 const std::string ZIP_ROOT_DIR = "FS";
95 std::string bugreport_dir;
98 * List of supported zip format versions.
100 * See bugreport-format.txt for more info.
102 static std::string VERSION_DEFAULT = "1.0";
104 bool is_user_build() {
105 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
108 /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
109 * otherwise gets just those modified in the last half an hour. */
110 static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
111 time_t thirty_minutes_ago = now - 60*30;
112 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
113 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
114 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
115 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
117 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
118 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
127 // for_each_pid() callback to get mount info about a process.
128 void do_mountinfo(int pid, const char *name) {
131 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
133 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
134 char linkname[PATH_MAX];
135 ssize_t r = readlink(path, linkname, PATH_MAX);
137 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
142 if (mount_points.find(linkname) == mount_points.end()) {
143 // First time this mount point was found: add it
144 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
145 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
146 mount_points.insert(linkname);
148 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
153 void add_mountinfo() {
154 if (!is_zipping()) return;
155 const char *title = "MOUNT INFO";
156 mount_points.clear();
157 DurationReporter duration_reporter(title, NULL);
158 for_each_pid(do_mountinfo, NULL);
159 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
162 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
168 d = opendir(driverpath);
173 while ((de = readdir(d))) {
174 if (de->d_type != DT_LNK) {
177 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
178 dump_file(title, path);
184 // return pid of a userspace process. If not found or error, return 0.
185 static unsigned int pid_of_process(const char* ps_name) {
191 if (!(proc_dir = opendir("/proc"))) {
192 MYLOGE("Can't open /proc\n");
196 while ((ps = readdir(proc_dir))) {
197 if (!(pid = atoi(ps->d_name))) {
200 android::base::ReadFileToString("/proc/"
201 + std::string(ps->d_name) + "/cmdline", &cmdline);
202 if (cmdline.find(ps_name) == std::string::npos) {
213 // dump anrd's trace and add to the zip file.
214 // 1. check if anrd is running on this device.
215 // 2. send a SIGUSR1 to its pid which will dump anrd's trace.
216 // 3. wait until the trace generation completes and add to the zip file.
217 static bool dump_anrd_trace() {
219 char buf[50], path[PATH_MAX];
220 struct dirent *trace;
224 long max_ctime = 0, old_mtime;
225 long long cur_size = 0;
226 const char *trace_path = "/data/misc/anrd/";
229 MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
233 // find anrd's pid if it is running.
234 pid = pid_of_process("/system/xbin/anrd");
237 if (stat(trace_path, &st) == 0) {
238 old_mtime = st.st_mtime;
240 MYLOGE("Failed to find: %s\n", trace_path);
244 // send SIGUSR1 to the anrd to generate a trace.
245 sprintf(buf, "%u", pid);
246 if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
247 MYLOGE("anrd signal timed out. Please manually collect trace\n");
251 while (retry-- > 0 && old_mtime == st.st_mtime) {
253 stat(trace_path, &st);
256 if (retry < 0 && old_mtime == st.st_mtime) {
257 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
261 // identify the trace file by its creation time.
262 if (!(trace_dir = opendir(trace_path))) {
263 MYLOGE("Can't open trace file under %s\n", trace_path);
265 while ((trace = readdir(trace_dir))) {
266 if (strcmp(trace->d_name, ".") == 0
267 || strcmp(trace->d_name, "..") == 0) {
270 sprintf(path, "%s%s", trace_path, trace->d_name);
271 if (stat(path, &st) == 0) {
272 if (st.st_ctime > max_ctime) {
273 max_ctime = st.st_ctime;
274 sprintf(buf, "%s", trace->d_name);
280 // Wait until the dump completes by checking the size of the trace.
282 sprintf(path, "%s%s", trace_path, buf);
285 if (stat(path, &st) == 0) {
286 if (st.st_size == cur_size) {
288 } else if (st.st_size > cur_size) {
289 cur_size = st.st_size;
294 MYLOGE("Cant stat() %s anymore\n", path);
298 // Add to the zip file.
299 if (!add_zip_entry("anrd_trace.txt", path)) {
300 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
303 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
308 MYLOGE("Can't stats any trace file under %s\n", trace_path);
314 static void dump_systrace() {
316 MYLOGD("Not dumping systrace because dumpstate is not zipping\n");
319 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
320 if (systrace_path.empty()) {
321 MYLOGE("Not dumping systrace because path is empty\n");
324 const char* path = "/sys/kernel/debug/tracing/tracing_on";
326 if (read_file_as_long(path, &is_tracing)) {
327 return; // error already logged
329 if (is_tracing <= 0) {
330 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
334 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
335 systrace_path.c_str());
336 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
337 systrace_path.c_str(), NULL)) {
338 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
339 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
340 // we should call strace to stop itself, but there is no such option yet (just a
341 // --async_stop, which stops and dump
342 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
343 // MYLOGE("could not stop systrace ");
346 if (!add_zip_entry("systrace.txt", systrace_path)) {
347 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
349 if (remove(systrace_path.c_str())) {
350 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
355 static void dump_raft() {
356 if (is_user_build()) {
360 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
361 if (raft_log_path.empty()) {
362 MYLOGD("raft_log_path is empty\n");
367 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
368 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
373 // Write compressed and encoded raft logs to stdout if not zip_writer.
374 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
378 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
379 "-o", raft_log_path.c_str(), NULL);
380 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
381 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
383 if (remove(raft_log_path.c_str())) {
384 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
390 * Finds the last modified file in the directory dir whose name starts with file_prefix
391 * Function returns empty string when it does not find a file
393 static std::string get_last_modified_file_matching_prefix(const std::string& dir,
394 const std::string& file_prefix) {
395 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
397 MYLOGD("Error %d opening %s\n", errno, dir.c_str());
401 // Find the newest file matching the file_prefix in dir
403 time_t last_modified = 0;
404 std::string last_modified_file = "";
407 while ((de = readdir(d.get()))) {
408 std::string file = std::string(de->d_name);
409 if (!file_prefix.empty()) {
410 if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
412 file = dir + "/" + file;
413 int ret = stat(file.c_str(), &s);
415 if ((ret == 0) && (s.st_mtime > last_modified)) {
416 last_modified_file = file;
417 last_modified = s.st_mtime;
421 return last_modified_file;
424 void dump_modem_logs() {
425 DurationReporter duration_reporter("dump_modem_logs");
426 if (is_user_build()) {
431 MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
435 char property[PROPERTY_VALUE_MAX];
436 property_get("ro.radio.log_prefix", property, "");
437 std::string file_prefix = std::string(property);
438 if(file_prefix.empty()) {
439 MYLOGD("No modem log : file_prefix is empty\n");
443 MYLOGD("dump_modem_logs: directory is %s and file_prefix is %s\n",
444 bugreport_dir.c_str(), file_prefix.c_str());
446 std::string modem_log_file =
447 get_last_modified_file_matching_prefix(bugreport_dir, file_prefix);
450 if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
451 MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
455 std::string filename = basename(modem_log_file.c_str());
456 if (!add_zip_entry(filename, modem_log_file)) {
457 MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
459 MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
463 static bool skip_not_stat(const char *path) {
464 static const char stat[] = "/stat";
465 size_t len = strlen(path);
466 if (path[len - 1] == '/') { /* Directory? */
469 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
472 static bool skip_none(const char *path) {
476 static const char mmcblk0[] = "/sys/block/mmcblk0/";
477 unsigned long worst_write_perf = 20000; /* in KB/s */
481 // Name units description
482 // ---- ----- -----------
483 // read I/Os requests number of read I/Os processed
484 #define __STAT_READ_IOS 0
485 // read merges requests number of read I/Os merged with in-queue I/O
486 #define __STAT_READ_MERGES 1
487 // read sectors sectors number of sectors read
488 #define __STAT_READ_SECTORS 2
489 // read ticks milliseconds total wait time for read requests
490 #define __STAT_READ_TICKS 3
491 // write I/Os requests number of write I/Os processed
492 #define __STAT_WRITE_IOS 4
493 // write merges requests number of write I/Os merged with in-queue I/O
494 #define __STAT_WRITE_MERGES 5
495 // write sectors sectors number of sectors written
496 #define __STAT_WRITE_SECTORS 6
497 // write ticks milliseconds total wait time for write requests
498 #define __STAT_WRITE_TICKS 7
499 // in_flight requests number of I/Os currently in flight
500 #define __STAT_IN_FLIGHT 8
501 // io_ticks milliseconds total time this block device has been active
502 #define __STAT_IO_TICKS 9
503 // time_in_queue milliseconds total wait time for all requests
504 #define __STAT_IN_QUEUE 10
505 #define __STAT_NUMBER_FIELD 11
507 // read I/Os, write I/Os
508 // =====================
510 // These values increment when an I/O request completes.
512 // read merges, write merges
513 // =========================
515 // These values increment when an I/O request is merged with an
516 // already-queued I/O request.
518 // read sectors, write sectors
519 // ===========================
521 // These values count the number of sectors read from or written to this
522 // block device. The "sectors" in question are the standard UNIX 512-byte
523 // sectors, not any device- or filesystem-specific block size. The
524 // counters are incremented when the I/O completes.
525 #define SECTOR_SIZE 512
527 // read ticks, write ticks
528 // =======================
530 // These values count the number of milliseconds that I/O requests have
531 // waited on this block device. If there are multiple I/O requests waiting,
532 // these values will increase at a rate greater than 1000/second; for
533 // example, if 60 read requests wait for an average of 30 ms, the read_ticks
534 // field will increase by 60*30 = 1800.
539 // This value counts the number of I/O requests that have been issued to
540 // the device driver but have not yet completed. It does not include I/O
541 // requests that are in the queue but not yet issued to the device driver.
546 // This value counts the number of milliseconds during which the device has
547 // had I/O requests queued.
552 // This value counts the number of milliseconds that I/O requests have waited
553 // on this block device. If there are multiple I/O requests waiting, this
554 // value will increase as the product of the number of milliseconds times the
555 // number of requests waiting (see "read ticks" above for an example).
559 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
560 unsigned long long fields[__STAT_NUMBER_FIELD];
562 char *cp, *buffer = NULL;
564 FILE *fp = fdopen(fd, "rb");
565 getline(&buffer, &i, fp);
571 while ((i > 0) && (buffer[i - 1] == '\n')) {
579 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
580 fields[i] = strtoull(cp, &cp, 10);
581 if (fields[i] != 0) {
585 if (z) { /* never accessed */
590 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
591 path += sizeof(mmcblk0) - 1;
594 printf("%s: %s\n", path, buffer);
597 if (fields[__STAT_IO_TICKS]) {
598 unsigned long read_perf = 0;
599 unsigned long read_ios = 0;
600 if (fields[__STAT_READ_TICKS]) {
601 unsigned long long divisor = fields[__STAT_READ_TICKS]
602 * fields[__STAT_IO_TICKS];
603 read_perf = ((unsigned long long)SECTOR_SIZE
604 * fields[__STAT_READ_SECTORS]
605 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
607 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
608 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
612 unsigned long write_perf = 0;
613 unsigned long write_ios = 0;
614 if (fields[__STAT_WRITE_TICKS]) {
615 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
616 * fields[__STAT_IO_TICKS];
617 write_perf = ((unsigned long long)SECTOR_SIZE
618 * fields[__STAT_WRITE_SECTORS]
619 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
621 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
622 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
626 unsigned queue = (fields[__STAT_IN_QUEUE]
627 + (fields[__STAT_IO_TICKS] >> 1))
628 / fields[__STAT_IO_TICKS];
630 if (!write_perf && !write_ios) {
631 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
632 path, read_perf, read_ios, queue);
634 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
635 path, read_perf, read_ios, write_perf, write_ios, queue);
638 /* bugreport timeout factor adjustment */
639 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
640 worst_write_perf = write_perf;
646 /* Copied policy from system/core/logd/LogBuffer.cpp */
648 #define LOG_BUFFER_SIZE (256 * 1024)
649 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
650 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
652 static bool valid_size(unsigned long value) {
653 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
657 long pages = sysconf(_SC_PHYS_PAGES);
662 long pagesize = sysconf(_SC_PAGESIZE);
664 pagesize = PAGE_SIZE;
667 // maximum memory impact a somewhat arbitrary ~3%
668 pages = (pages + 31) / 32;
669 unsigned long maximum = pages * pagesize;
671 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
675 return value <= maximum;
678 static unsigned long property_get_size(const char *key) {
680 char *cp, property[PROPERTY_VALUE_MAX];
682 property_get(key, property, "");
683 value = strtoul(property, &cp, 10);
701 if (!valid_size(value)) {
709 static unsigned long logcat_timeout(const char *name) {
710 static const char global_tuneable[] = "persist.logd.size"; // Settings App
711 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
712 char key[PROP_NAME_MAX];
713 unsigned long property_size, default_size;
715 default_size = property_get_size(global_tuneable);
717 default_size = property_get_size(global_default);
720 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
721 property_size = property_get_size(key);
723 if (!property_size) {
724 snprintf(key, sizeof(key), "%s.%s", global_default, name);
725 property_size = property_get_size(key);
728 if (!property_size) {
729 property_size = default_size;
732 if (!property_size) {
733 property_size = LOG_BUFFER_SIZE;
736 /* Engineering margin is ten-fold our guess */
737 return 10 * (property_size + worst_write_perf) / worst_write_perf;
740 /* End copy from system/core/logd/LogBuffer.cpp */
742 /* dumps the current system state to stdout */
743 static void print_header(std::string version) {
744 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
745 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
746 char network[PROPERTY_VALUE_MAX], date[80];
748 property_get("ro.build.display.id", build, "(unknown)");
749 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
750 property_get("ro.build.type", build_type, "(unknown)");
751 property_get("gsm.version.baseband", radio, "(unknown)");
752 property_get("ro.bootloader", bootloader, "(unknown)");
753 property_get("gsm.operator.alpha", network, "(unknown)");
754 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
756 printf("========================================================\n");
757 printf("== dumpstate: %s\n", date);
758 printf("========================================================\n");
761 printf("Build: %s\n", build);
762 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
763 printf("Bootloader: %s\n", bootloader);
764 printf("Radio: %s\n", radio);
765 printf("Network: %s\n", network);
768 dump_file(NULL, "/proc/version");
769 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
770 printf("Bugreport format version: %s\n", version.c_str());
771 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
775 // List of file extensions that can cause a zip file attachment to be rejected by some email
776 // service providers.
777 static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
778 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
779 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
780 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
783 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
785 MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
789 std::string valid_name = entry_name;
791 // Rename extension if necessary.
792 size_t idx = entry_name.rfind(".");
793 if (idx != std::string::npos) {
794 std::string extension = entry_name.substr(idx);
795 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
796 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
797 valid_name = entry_name + ".renamed";
798 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
802 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
803 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
804 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
805 ZipWriter::kCompress, get_mtime(fd, now));
807 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
808 ZipWriter::ErrorCodeString(err));
812 std::vector<uint8_t> buffer(65536);
814 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
815 if (bytes_read == 0) {
817 } else if (bytes_read == -1) {
818 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
821 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
823 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
828 err = zip_writer->FinishEntry();
830 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
837 bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
838 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
839 if (fd.get() == -1) {
840 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
844 return add_zip_entry_from_fd(entry_name, fd.get());
847 /* adds a file to the existing zipped bugreport */
848 static int _add_file_from_fd(const char *title, const char *path, int fd) {
849 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
852 // TODO: move to util.cpp
853 void add_dir(const char *dir, bool recursive) {
855 MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
858 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
859 DurationReporter duration_reporter(dir, NULL);
860 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
864 return zip_writer != nullptr;
867 /* adds a text entry entry to the existing zip file. */
868 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
870 MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
873 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
874 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
876 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
877 ZipWriter::ErrorCodeString(err));
881 err = zip_writer->WriteBytes(content.c_str(), content.length());
883 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
884 ZipWriter::ErrorCodeString(err));
888 err = zip_writer->FinishEntry();
890 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
897 static void dump_iptables() {
898 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
899 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
900 run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
902 run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
903 run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
904 run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
905 run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
908 static void dumpstate(const std::string& screenshot_path, const std::string& version) {
909 DurationReporter duration_reporter("DUMPSTATE");
910 unsigned long timeout;
912 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
913 run_command("UPTIME", 10, "uptime", NULL);
914 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
915 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
916 dump_file("MEMORY INFO", "/proc/meminfo");
917 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
918 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
919 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
920 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
921 dump_file("SLAB INFO", "/proc/slabinfo");
922 dump_file("ZONEINFO", "/proc/zoneinfo");
923 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
924 dump_file("BUDDYINFO", "/proc/buddyinfo");
925 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
927 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
928 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
929 dump_file("KERNEL SYNC", "/d/sync");
931 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
932 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
934 run_command("PRINTENV", 10, "printenv", NULL);
935 run_command("NETSTAT", 10, "netstat", "-n", NULL);
936 run_command("LSMOD", 10, "lsmod", NULL);
940 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
941 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
942 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
943 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
945 if (!screenshot_path.empty()) {
946 MYLOGI("taking late screenshot\n");
947 take_screenshot(screenshot_path);
948 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
951 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
953 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
954 if (timeout < 20000) {
957 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
961 timeout = logcat_timeout("events");
962 if (timeout < 20000) {
965 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
970 timeout = logcat_timeout("radio");
971 if (timeout < 20000) {
974 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
980 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
982 /* show the traces we collected in main(), if that was done */
983 if (dump_traces_path != NULL) {
984 dump_file("VM TRACES JUST NOW", dump_traces_path);
987 /* only show ANR traces if they're less than 15 minutes old */
989 char anr_traces_path[PATH_MAX];
990 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
991 if (!anr_traces_path[0]) {
992 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
994 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
995 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
997 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
999 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
1003 /* slow traces for slow operations */
1004 if (anr_traces_path[0] != 0) {
1005 int tail = strlen(anr_traces_path)-1;
1006 while (tail > 0 && anr_traces_path[tail] != '/') {
1011 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
1012 if (stat(anr_traces_path, &st)) {
1013 // No traces file at this index, done with the files.
1016 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
1022 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
1023 if (tombstone_data[i].fd != -1) {
1024 const char *name = tombstone_data[i].name;
1025 int fd = tombstone_data[i].fd;
1028 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
1029 MYLOGE("Unable to add tombstone %s to zip file\n", name);
1032 dump_file_from_fd("TOMBSTONE", name, fd);
1035 tombstone_data[i].fd = -1;
1039 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1042 dump_file("NETWORK DEV INFO", "/proc/net/dev");
1043 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1044 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1045 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1046 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1048 if (!stat(PSTORE_LAST_KMSG, &st)) {
1049 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
1050 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
1051 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
1052 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
1054 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
1055 dump_file("LAST KMSG", "/proc/last_kmsg");
1058 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
1059 run_command("LAST LOGCAT", 10, "logcat", "-L",
1066 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1068 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
1070 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
1071 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
1073 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
1074 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
1076 dump_route_tables();
1078 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1079 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
1080 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
1081 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
1083 #ifdef FWDUMP_bcmdhd
1084 run_command("ND OFFLOAD TABLE", 5,
1085 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
1087 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
1088 SU_PATH, "root", WLUTIL, "counters", NULL);
1090 run_command("ND OFFLOAD STATUS (1)", 5,
1091 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1094 dump_file("INTERRUPTS (1)", "/proc/interrupts");
1096 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
1098 #ifdef FWDUMP_bcmdhd
1099 run_command("DUMP WIFI STATUS", 20,
1100 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
1102 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
1103 SU_PATH, "root", WLUTIL, "counters", NULL);
1105 run_command("ND OFFLOAD STATUS (2)", 5,
1106 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1108 dump_file("INTERRUPTS (2)", "/proc/interrupts");
1112 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1113 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1115 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
1117 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1119 printf("------ BACKLIGHTS ------\n");
1120 printf("LCD brightness=");
1121 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1122 printf("Button brightness=");
1123 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1124 printf("Keyboard brightness=");
1125 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1126 printf("ALS mode=");
1127 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1128 printf("LCD driver registers:\n");
1129 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1132 /* Binder state is expensive to look at as it uses a lot of memory. */
1133 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1134 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1135 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1136 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1137 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1139 printf("========================================================\n");
1140 printf("== Board\n");
1141 printf("========================================================\n");
1146 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1147 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1148 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1149 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
1150 if (is_user_build()) {
1151 // su does not exist on user builds, so try running without it.
1152 // This way any implementations of vril-dump that do not require
1153 // root can run on user builds.
1154 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1157 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1158 SU_PATH, "root", "vril-dump", NULL);
1162 printf("========================================================\n");
1163 printf("== Android Framework Services\n");
1164 printf("========================================================\n");
1166 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
1168 printf("========================================================\n");
1169 printf("== Checkins\n");
1170 printf("========================================================\n");
1172 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1173 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1174 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1175 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1176 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1177 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
1179 printf("========================================================\n");
1180 printf("== Running Application Activities\n");
1181 printf("========================================================\n");
1183 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
1185 printf("========================================================\n");
1186 printf("== Running Application Services\n");
1187 printf("========================================================\n");
1189 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
1191 printf("========================================================\n");
1192 printf("== Running Application Providers\n");
1193 printf("========================================================\n");
1195 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
1197 // dump_modem_logs adds the modem logs if available to the bugreport.
1198 // Do this at the end to allow for sufficient time for the modem logs to be
1202 printf("========================================================\n");
1203 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1204 getpid(), progress, weight_total, WEIGHT_TOTAL);
1205 printf("========================================================\n");
1206 printf("== dumpstate: done\n");
1207 printf("========================================================\n");
1210 static void usage() {
1212 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1213 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1214 " -h: display this help message\n"
1215 " -b: play sound file instead of vibrate, at beginning of job\n"
1216 " -e: play sound file instead of vibrate, at end of job\n"
1217 " -o: write to file (instead of stdout)\n"
1218 " -d: append date to filename (requires -o)\n"
1219 " -p: capture screenshot to filename.png (requires -o)\n"
1220 " -z: generate zipped file (requires -o)\n"
1221 " -s: write output to control socket (for init)\n"
1222 " -S: write file location to control socket (for init; requires -o and -z)"
1223 " -q: disable vibrate\n"
1224 " -B: send broadcast when finished (requires -o)\n"
1225 " -P: send broadcast when started and update system properties on "
1226 "progress (requires -o and -B)\n"
1227 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1228 "shouldn't be used with -P)\n"
1229 " -V: sets the bugreport format version (valid values: %s)\n",
1230 VERSION_DEFAULT.c_str());
1233 static void sigpipe_handler(int n) {
1234 // don't complain to stderr or stdout
1235 _exit(EXIT_FAILURE);
1238 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1241 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1243 if (!add_zip_entry(bugreport_name, bugreport_path)) {
1244 MYLOGE("Failed to add text entry to .zip file\n");
1247 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1248 MYLOGE("Failed to add main_entry.txt to .zip file\n");
1252 int32_t err = zip_writer->Finish();
1254 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1258 if (is_user_build()) {
1259 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1260 if (remove(bugreport_path.c_str())) {
1261 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1264 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1270 static std::string SHA256_file_hash(std::string filepath) {
1271 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1273 if (fd.get() == -1) {
1274 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1281 std::vector<uint8_t> buffer(65536);
1283 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1284 if (bytes_read == 0) {
1286 } else if (bytes_read == -1) {
1287 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1291 SHA256_update(&ctx, buffer.data(), bytes_read);
1294 uint8_t hash[SHA256_DIGEST_SIZE];
1295 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1296 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1297 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1298 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1300 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1301 return std::string(hash_buffer);
1304 int main(int argc, char *argv[]) {
1305 struct sigaction sigact;
1306 int do_add_date = 0;
1307 int do_zip_file = 0;
1309 char* use_outfile = 0;
1311 int use_control_socket = 0;
1313 int do_broadcast = 0;
1314 int do_early_screenshot = 0;
1315 int is_remote_mode = 0;
1316 std::string version = VERSION_DEFAULT;
1322 /* gets the sequential id */
1323 char last_id[PROPERTY_VALUE_MAX];
1324 property_get("dumpstate.last_id", last_id, "0");
1325 id = strtoul(last_id, NULL, 10) + 1;
1326 snprintf(last_id, sizeof(last_id), "%lu", id);
1327 property_set("dumpstate.last_id", last_id);
1328 MYLOGI("dumpstate id: %lu\n", id);
1330 /* clear SIGPIPE handler */
1331 memset(&sigact, 0, sizeof(sigact));
1332 sigact.sa_handler = sigpipe_handler;
1333 sigaction(SIGPIPE, &sigact, NULL);
1335 /* set as high priority, and protect from OOM killer */
1336 setpriority(PRIO_PROCESS, 0, -20);
1338 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1340 fputs("-1000", oom_adj);
1343 /* fallback to kernels <= 2.6.35 */
1344 oom_adj = fopen("/proc/self/oom_adj", "we");
1346 fputs("-17", oom_adj);
1351 /* parse arguments */
1353 format_args(argc, const_cast<const char **>(argv), &args);
1354 MYLOGD("Dumpstate command line: %s\n", args.c_str());
1356 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1358 case 'd': do_add_date = 1; break;
1359 case 'z': do_zip_file = 1; break;
1360 case 'o': use_outfile = optarg; break;
1361 case 's': use_socket = 1; break;
1362 case 'S': use_control_socket = 1; break;
1363 case 'v': break; // compatibility no-op
1364 case 'q': do_vibrate = 0; break;
1365 case 'p': do_fb = 1; break;
1366 case 'P': do_update_progress = 1; break;
1367 case 'R': is_remote_mode = 1; break;
1368 case 'B': do_broadcast = 1; break;
1369 case 'V': version = optarg; break;
1370 case '?': printf("\n");
1377 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1382 if (use_control_socket && !do_zip_file) {
1387 if (do_update_progress && !do_broadcast) {
1392 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1397 if (version != VERSION_DEFAULT) {
1402 MYLOGI("bugreport format version: %s\n", version.c_str());
1404 do_early_screenshot = do_update_progress;
1406 // If we are going to use a socket, do it as early as possible
1407 // to avoid timeouts from bugreport.
1409 redirect_to_socket(stdout, "dumpstate");
1412 if (use_control_socket) {
1413 MYLOGD("Opening control socket\n");
1414 control_socket_fd = open_socket("dumpstate");
1415 do_update_progress = 1;
1418 /* full path of the temporary file containing the bugreport */
1419 std::string tmp_path;
1421 /* full path of the file containing the dumpstate logs*/
1422 std::string log_path;
1424 /* full path of the systrace file, when enabled */
1425 std::string systrace_path;
1427 /* full path of the temporary file containing the screenshot (when requested) */
1428 std::string screenshot_path;
1430 /* base name (without suffix or extensions) of the bugreport files */
1431 std::string base_name;
1433 /* pointer to the actual path, be it zip or text */
1436 /* pointer to the zipped file */
1437 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1439 /* redirect output if needed */
1440 bool is_redirecting = !use_socket && use_outfile;
1442 if (is_redirecting) {
1443 bugreport_dir = dirname(use_outfile);
1444 base_name = basename(use_outfile);
1447 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1452 char build_id[PROPERTY_VALUE_MAX];
1453 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1454 base_name = base_name + "-" + build_id;
1456 // TODO: if dumpstate was an object, the paths could be internal variables and then
1457 // we could have a function to calculate the derived values, such as:
1458 // screenshot_path = GetPath(".png");
1459 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1461 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1462 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1463 + std::to_string(getpid()) + ".txt";
1465 MYLOGD("Bugreport dir: %s\n"
1469 "Temporary path: %s\n"
1470 "Screenshot path: %s\n",
1471 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1472 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1475 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1476 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1477 create_parent_dirs(path.c_str());
1478 zip_file.reset(fopen(path.c_str(), "wb"));
1480 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1483 zip_writer.reset(new ZipWriter(zip_file.get()));
1485 add_text_zip_entry("version.txt", version);
1488 if (do_update_progress) {
1491 std::vector<std::string> am_args = {
1492 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1493 "--es", "android.intent.extra.NAME", suffix,
1494 "--ei", "android.intent.extra.ID", std::to_string(id),
1495 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1496 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1499 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1501 if (use_control_socket) {
1502 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1507 /* read /proc/cmdline before dropping root */
1508 FILE *cmdline = fopen("/proc/cmdline", "re");
1510 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1514 /* open the vibrator before dropping root */
1515 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1517 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1519 vibrate(vibrator.get(), 150);
1523 if (do_fb && do_early_screenshot) {
1524 if (screenshot_path.empty()) {
1525 // should not have happened
1526 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1528 MYLOGI("taking early screenshot\n");
1529 take_screenshot(screenshot_path);
1530 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1531 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1532 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1533 screenshot_path.c_str(), strerror(errno));
1539 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1540 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1544 if (is_redirecting) {
1545 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1546 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1547 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1548 log_path.c_str(), strerror(errno));
1550 /* TODO: rather than generating a text file now and zipping it later,
1551 it would be more efficient to redirect stdout to the zip entry
1552 directly, but the libziparchive doesn't support that option yet. */
1553 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1554 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1555 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1556 tmp_path.c_str(), strerror(errno));
1559 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1560 // In particular, DurationReport objects should be created passing 'title, NULL', so their
1561 // duration is logged into MYLOG instead.
1562 print_header(version);
1564 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1565 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1567 if (!dump_anrd_trace()) {
1571 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1574 // Invoking the following dumpsys calls before dump_traces() to try and
1575 // keep the system stats as close to its initial state as possible.
1576 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1577 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1579 /* collect stack traces from Dalvik and native processes (needs root) */
1580 dump_traces_path = dump_traces();
1582 /* Run some operations that require root. */
1583 get_tombstone_fds(tombstone_data);
1584 add_dir(RECOVERY_DIR, true);
1585 add_dir(RECOVERY_DATA_DIR, true);
1586 add_dir(LOGPERSIST_DATA_DIR, false);
1587 if (!is_user_build()) {
1588 add_dir(PROFILE_DATA_DIR_CUR, true);
1589 add_dir(PROFILE_DATA_DIR_REF, true);
1594 // Capture any IPSec policies in play. No keys are exposed here.
1595 run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
1597 // Run ss as root so we can see socket marks.
1598 run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1600 if (!drop_root_user()) {
1604 dumpstate(do_early_screenshot ? "": screenshot_path, version);
1606 /* close output if needed */
1607 if (is_redirecting) {
1611 /* rename or zip the (now complete) .tmp file to its final location */
1614 /* check if user changed the suffix using system properties */
1615 char key[PROPERTY_KEY_MAX];
1616 char value[PROPERTY_VALUE_MAX];
1617 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1618 property_get(key, value, "");
1619 bool change_suffix= false;
1621 /* must whitelist which characters are allowed, otherwise it could cross directories */
1622 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1623 if (std::regex_match(value, valid_regex)) {
1624 change_suffix = true;
1626 MYLOGE("invalid suffix provided by user: %s\n", value);
1629 if (change_suffix) {
1630 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1632 if (!screenshot_path.empty()) {
1633 std::string new_screenshot_path =
1634 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1635 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1636 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1637 new_screenshot_path.c_str(), strerror(errno));
1639 screenshot_path = new_screenshot_path;
1644 bool do_text_file = true;
1646 std::string entry_name = base_name + "-" + suffix + ".txt";
1647 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1648 if (!finish_zip_file(entry_name, tmp_path, now)) {
1649 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1650 do_text_file = true;
1652 do_text_file = false;
1653 // Since zip file is already created, it needs to be renamed.
1654 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1655 if (path != new_path) {
1656 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1657 if (rename(path.c_str(), new_path.c_str())) {
1658 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1659 new_path.c_str(), strerror(errno));
1667 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1668 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1669 if (rename(tmp_path.c_str(), path.c_str())) {
1670 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1674 if (use_control_socket) {
1676 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1677 "for more details\n", log_path.c_str());
1679 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1684 /* vibrate a few but shortly times to let user know it's finished */
1686 for (int i = 0; i < 3; i++) {
1687 vibrate(vibrator.get(), 75);
1688 usleep((75 + 50) * 1000);
1692 /* tell activity manager we're done */
1694 if (!path.empty()) {
1695 MYLOGI("Final bugreport path: %s\n", path.c_str());
1697 std::vector<std::string> am_args = {
1698 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1699 "--ei", "android.intent.extra.ID", std::to_string(id),
1700 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1701 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1702 "--es", "android.intent.extra.BUGREPORT", path,
1703 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1707 am_args.push_back("--es");
1708 am_args.push_back("android.intent.extra.SCREENSHOT");
1709 am_args.push_back(screenshot_path);
1711 if (is_remote_mode) {
1712 am_args.push_back("--es");
1713 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1714 am_args.push_back(SHA256_file_hash(path));
1715 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1717 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1720 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1724 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1727 if (is_redirecting) {
1731 if (use_control_socket && control_socket_fd != -1) {
1732 MYLOGD("Closing control socket\n");
1733 close(control_socket_fd);