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());
460 if (remove(modem_log_file.c_str())) {
461 MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
466 static bool skip_not_stat(const char *path) {
467 static const char stat[] = "/stat";
468 size_t len = strlen(path);
469 if (path[len - 1] == '/') { /* Directory? */
472 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
475 static bool skip_none(const char *path) {
479 static const char mmcblk0[] = "/sys/block/mmcblk0/";
480 unsigned long worst_write_perf = 20000; /* in KB/s */
484 // Name units description
485 // ---- ----- -----------
486 // read I/Os requests number of read I/Os processed
487 #define __STAT_READ_IOS 0
488 // read merges requests number of read I/Os merged with in-queue I/O
489 #define __STAT_READ_MERGES 1
490 // read sectors sectors number of sectors read
491 #define __STAT_READ_SECTORS 2
492 // read ticks milliseconds total wait time for read requests
493 #define __STAT_READ_TICKS 3
494 // write I/Os requests number of write I/Os processed
495 #define __STAT_WRITE_IOS 4
496 // write merges requests number of write I/Os merged with in-queue I/O
497 #define __STAT_WRITE_MERGES 5
498 // write sectors sectors number of sectors written
499 #define __STAT_WRITE_SECTORS 6
500 // write ticks milliseconds total wait time for write requests
501 #define __STAT_WRITE_TICKS 7
502 // in_flight requests number of I/Os currently in flight
503 #define __STAT_IN_FLIGHT 8
504 // io_ticks milliseconds total time this block device has been active
505 #define __STAT_IO_TICKS 9
506 // time_in_queue milliseconds total wait time for all requests
507 #define __STAT_IN_QUEUE 10
508 #define __STAT_NUMBER_FIELD 11
510 // read I/Os, write I/Os
511 // =====================
513 // These values increment when an I/O request completes.
515 // read merges, write merges
516 // =========================
518 // These values increment when an I/O request is merged with an
519 // already-queued I/O request.
521 // read sectors, write sectors
522 // ===========================
524 // These values count the number of sectors read from or written to this
525 // block device. The "sectors" in question are the standard UNIX 512-byte
526 // sectors, not any device- or filesystem-specific block size. The
527 // counters are incremented when the I/O completes.
528 #define SECTOR_SIZE 512
530 // read ticks, write ticks
531 // =======================
533 // These values count the number of milliseconds that I/O requests have
534 // waited on this block device. If there are multiple I/O requests waiting,
535 // these values will increase at a rate greater than 1000/second; for
536 // example, if 60 read requests wait for an average of 30 ms, the read_ticks
537 // field will increase by 60*30 = 1800.
542 // This value counts the number of I/O requests that have been issued to
543 // the device driver but have not yet completed. It does not include I/O
544 // requests that are in the queue but not yet issued to the device driver.
549 // This value counts the number of milliseconds during which the device has
550 // had I/O requests queued.
555 // This value counts the number of milliseconds that I/O requests have waited
556 // on this block device. If there are multiple I/O requests waiting, this
557 // value will increase as the product of the number of milliseconds times the
558 // number of requests waiting (see "read ticks" above for an example).
562 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
563 unsigned long long fields[__STAT_NUMBER_FIELD];
565 char *cp, *buffer = NULL;
567 FILE *fp = fdopen(fd, "rb");
568 getline(&buffer, &i, fp);
574 while ((i > 0) && (buffer[i - 1] == '\n')) {
582 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
583 fields[i] = strtoull(cp, &cp, 10);
584 if (fields[i] != 0) {
588 if (z) { /* never accessed */
593 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
594 path += sizeof(mmcblk0) - 1;
597 printf("%s: %s\n", path, buffer);
600 if (fields[__STAT_IO_TICKS]) {
601 unsigned long read_perf = 0;
602 unsigned long read_ios = 0;
603 if (fields[__STAT_READ_TICKS]) {
604 unsigned long long divisor = fields[__STAT_READ_TICKS]
605 * fields[__STAT_IO_TICKS];
606 read_perf = ((unsigned long long)SECTOR_SIZE
607 * fields[__STAT_READ_SECTORS]
608 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
610 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
611 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
615 unsigned long write_perf = 0;
616 unsigned long write_ios = 0;
617 if (fields[__STAT_WRITE_TICKS]) {
618 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
619 * fields[__STAT_IO_TICKS];
620 write_perf = ((unsigned long long)SECTOR_SIZE
621 * fields[__STAT_WRITE_SECTORS]
622 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
624 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
625 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
629 unsigned queue = (fields[__STAT_IN_QUEUE]
630 + (fields[__STAT_IO_TICKS] >> 1))
631 / fields[__STAT_IO_TICKS];
633 if (!write_perf && !write_ios) {
634 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
635 path, read_perf, read_ios, queue);
637 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
638 path, read_perf, read_ios, write_perf, write_ios, queue);
641 /* bugreport timeout factor adjustment */
642 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
643 worst_write_perf = write_perf;
649 /* Copied policy from system/core/logd/LogBuffer.cpp */
651 #define LOG_BUFFER_SIZE (256 * 1024)
652 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
653 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
655 static bool valid_size(unsigned long value) {
656 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
660 long pages = sysconf(_SC_PHYS_PAGES);
665 long pagesize = sysconf(_SC_PAGESIZE);
667 pagesize = PAGE_SIZE;
670 // maximum memory impact a somewhat arbitrary ~3%
671 pages = (pages + 31) / 32;
672 unsigned long maximum = pages * pagesize;
674 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
678 return value <= maximum;
681 static unsigned long property_get_size(const char *key) {
683 char *cp, property[PROPERTY_VALUE_MAX];
685 property_get(key, property, "");
686 value = strtoul(property, &cp, 10);
704 if (!valid_size(value)) {
712 static unsigned long logcat_timeout(const char *name) {
713 static const char global_tuneable[] = "persist.logd.size"; // Settings App
714 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
715 char key[PROP_NAME_MAX];
716 unsigned long property_size, default_size;
718 default_size = property_get_size(global_tuneable);
720 default_size = property_get_size(global_default);
723 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
724 property_size = property_get_size(key);
726 if (!property_size) {
727 snprintf(key, sizeof(key), "%s.%s", global_default, name);
728 property_size = property_get_size(key);
731 if (!property_size) {
732 property_size = default_size;
735 if (!property_size) {
736 property_size = LOG_BUFFER_SIZE;
739 /* Engineering margin is ten-fold our guess */
740 return 10 * (property_size + worst_write_perf) / worst_write_perf;
743 /* End copy from system/core/logd/LogBuffer.cpp */
745 /* dumps the current system state to stdout */
746 static void print_header(std::string version) {
747 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
748 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
749 char network[PROPERTY_VALUE_MAX], date[80];
751 property_get("ro.build.display.id", build, "(unknown)");
752 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
753 property_get("ro.build.type", build_type, "(unknown)");
754 property_get("gsm.version.baseband", radio, "(unknown)");
755 property_get("ro.bootloader", bootloader, "(unknown)");
756 property_get("gsm.operator.alpha", network, "(unknown)");
757 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
759 printf("========================================================\n");
760 printf("== dumpstate: %s\n", date);
761 printf("========================================================\n");
764 printf("Build: %s\n", build);
765 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
766 printf("Bootloader: %s\n", bootloader);
767 printf("Radio: %s\n", radio);
768 printf("Network: %s\n", network);
771 dump_file(NULL, "/proc/version");
772 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
773 printf("Bugreport format version: %s\n", version.c_str());
774 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
778 // List of file extensions that can cause a zip file attachment to be rejected by some email
779 // service providers.
780 static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
781 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
782 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
783 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
786 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
788 MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
792 std::string valid_name = entry_name;
794 // Rename extension if necessary.
795 size_t idx = entry_name.rfind(".");
796 if (idx != std::string::npos) {
797 std::string extension = entry_name.substr(idx);
798 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
799 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
800 valid_name = entry_name + ".renamed";
801 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
805 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
806 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
807 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
808 ZipWriter::kCompress, get_mtime(fd, now));
810 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
811 ZipWriter::ErrorCodeString(err));
815 std::vector<uint8_t> buffer(65536);
817 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
818 if (bytes_read == 0) {
820 } else if (bytes_read == -1) {
821 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
824 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
826 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
831 err = zip_writer->FinishEntry();
833 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
840 bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
841 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
842 if (fd.get() == -1) {
843 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
847 return add_zip_entry_from_fd(entry_name, fd.get());
850 /* adds a file to the existing zipped bugreport */
851 static int _add_file_from_fd(const char *title, const char *path, int fd) {
852 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
855 // TODO: move to util.cpp
856 void add_dir(const char *dir, bool recursive) {
858 MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
861 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
862 DurationReporter duration_reporter(dir, NULL);
863 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
867 return zip_writer != nullptr;
870 /* adds a text entry entry to the existing zip file. */
871 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
873 MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
876 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
877 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
879 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
880 ZipWriter::ErrorCodeString(err));
884 err = zip_writer->WriteBytes(content.c_str(), content.length());
886 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
887 ZipWriter::ErrorCodeString(err));
891 err = zip_writer->FinishEntry();
893 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
900 static void dump_iptables() {
901 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
902 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
903 run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
905 run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
906 run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
907 run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
908 run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
911 static void dumpstate(const std::string& screenshot_path, const std::string& version) {
912 DurationReporter duration_reporter("DUMPSTATE");
913 unsigned long timeout;
915 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
916 run_command("UPTIME", 10, "uptime", NULL);
917 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
918 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
919 dump_file("MEMORY INFO", "/proc/meminfo");
920 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
921 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
922 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
923 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
924 dump_file("SLAB INFO", "/proc/slabinfo");
925 dump_file("ZONEINFO", "/proc/zoneinfo");
926 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
927 dump_file("BUDDYINFO", "/proc/buddyinfo");
928 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
930 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
931 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
932 dump_file("KERNEL SYNC", "/d/sync");
934 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
935 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
937 run_command("PRINTENV", 10, "printenv", NULL);
938 run_command("NETSTAT", 10, "netstat", "-n", NULL);
939 run_command("LSMOD", 10, "lsmod", NULL);
943 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
944 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
945 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
946 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
948 /* Dump Bluetooth HCI logs */
949 add_dir("/data/misc/bluetooth/logs", true);
951 if (!screenshot_path.empty()) {
952 MYLOGI("taking late screenshot\n");
953 take_screenshot(screenshot_path);
954 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
957 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
959 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
960 if (timeout < 20000) {
963 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
967 timeout = logcat_timeout("events");
968 if (timeout < 20000) {
971 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
976 timeout = logcat_timeout("radio");
977 if (timeout < 20000) {
980 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
986 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
988 /* show the traces we collected in main(), if that was done */
989 if (dump_traces_path != NULL) {
990 dump_file("VM TRACES JUST NOW", dump_traces_path);
993 /* only show ANR traces if they're less than 15 minutes old */
995 char anr_traces_path[PATH_MAX];
996 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
997 if (!anr_traces_path[0]) {
998 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
1000 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
1001 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
1003 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
1005 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
1009 /* slow traces for slow operations */
1010 if (anr_traces_path[0] != 0) {
1011 int tail = strlen(anr_traces_path)-1;
1012 while (tail > 0 && anr_traces_path[tail] != '/') {
1017 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
1018 if (stat(anr_traces_path, &st)) {
1019 // No traces file at this index, done with the files.
1022 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
1028 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
1029 if (tombstone_data[i].fd != -1) {
1030 const char *name = tombstone_data[i].name;
1031 int fd = tombstone_data[i].fd;
1034 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
1035 MYLOGE("Unable to add tombstone %s to zip file\n", name);
1038 dump_file_from_fd("TOMBSTONE", name, fd);
1041 tombstone_data[i].fd = -1;
1045 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1048 dump_file("NETWORK DEV INFO", "/proc/net/dev");
1049 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1050 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1051 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1052 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1054 if (!stat(PSTORE_LAST_KMSG, &st)) {
1055 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
1056 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
1057 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
1058 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
1060 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
1061 dump_file("LAST KMSG", "/proc/last_kmsg");
1064 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
1065 run_command("LAST LOGCAT", 10, "logcat", "-L",
1072 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1074 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
1076 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
1077 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
1079 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
1080 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
1082 dump_route_tables();
1084 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1085 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
1086 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
1087 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
1089 #ifdef FWDUMP_bcmdhd
1090 run_command("ND OFFLOAD TABLE", 5,
1091 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
1093 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
1094 SU_PATH, "root", WLUTIL, "counters", NULL);
1096 run_command("ND OFFLOAD STATUS (1)", 5,
1097 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1100 dump_file("INTERRUPTS (1)", "/proc/interrupts");
1102 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
1104 #ifdef FWDUMP_bcmdhd
1105 run_command("DUMP WIFI STATUS", 20,
1106 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
1108 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
1109 SU_PATH, "root", WLUTIL, "counters", NULL);
1111 run_command("ND OFFLOAD STATUS (2)", 5,
1112 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1114 dump_file("INTERRUPTS (2)", "/proc/interrupts");
1118 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1119 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1121 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
1123 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1125 printf("------ BACKLIGHTS ------\n");
1126 printf("LCD brightness=");
1127 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1128 printf("Button brightness=");
1129 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1130 printf("Keyboard brightness=");
1131 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1132 printf("ALS mode=");
1133 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1134 printf("LCD driver registers:\n");
1135 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1138 /* Binder state is expensive to look at as it uses a lot of memory. */
1139 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1140 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1141 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1142 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1143 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1145 printf("========================================================\n");
1146 printf("== Board\n");
1147 printf("========================================================\n");
1152 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1153 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1154 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1155 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
1156 if (is_user_build()) {
1157 // su does not exist on user builds, so try running without it.
1158 // This way any implementations of vril-dump that do not require
1159 // root can run on user builds.
1160 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1163 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1164 SU_PATH, "root", "vril-dump", NULL);
1168 printf("========================================================\n");
1169 printf("== Android Framework Services\n");
1170 printf("========================================================\n");
1172 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
1174 printf("========================================================\n");
1175 printf("== Checkins\n");
1176 printf("========================================================\n");
1178 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1179 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1180 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1181 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1182 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1183 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
1185 printf("========================================================\n");
1186 printf("== Running Application Activities\n");
1187 printf("========================================================\n");
1189 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
1191 printf("========================================================\n");
1192 printf("== Running Application Services\n");
1193 printf("========================================================\n");
1195 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
1197 printf("========================================================\n");
1198 printf("== Running Application Providers\n");
1199 printf("========================================================\n");
1201 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
1203 // dump_modem_logs adds the modem logs if available to the bugreport.
1204 // Do this at the end to allow for sufficient time for the modem logs to be
1208 printf("========================================================\n");
1209 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1210 getpid(), progress, weight_total, WEIGHT_TOTAL);
1211 printf("========================================================\n");
1212 printf("== dumpstate: done\n");
1213 printf("========================================================\n");
1216 static void usage() {
1218 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1219 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1220 " -h: display this help message\n"
1221 " -b: play sound file instead of vibrate, at beginning of job\n"
1222 " -e: play sound file instead of vibrate, at end of job\n"
1223 " -o: write to file (instead of stdout)\n"
1224 " -d: append date to filename (requires -o)\n"
1225 " -p: capture screenshot to filename.png (requires -o)\n"
1226 " -z: generate zipped file (requires -o)\n"
1227 " -s: write output to control socket (for init)\n"
1228 " -S: write file location to control socket (for init; requires -o and -z)"
1229 " -q: disable vibrate\n"
1230 " -B: send broadcast when finished (requires -o)\n"
1231 " -P: send broadcast when started and update system properties on "
1232 "progress (requires -o and -B)\n"
1233 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1234 "shouldn't be used with -P)\n"
1235 " -V: sets the bugreport format version (valid values: %s)\n",
1236 VERSION_DEFAULT.c_str());
1239 static void sigpipe_handler(int n) {
1240 // don't complain to stderr or stdout
1241 _exit(EXIT_FAILURE);
1244 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1247 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1249 if (!add_zip_entry(bugreport_name, bugreport_path)) {
1250 MYLOGE("Failed to add text entry to .zip file\n");
1253 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1254 MYLOGE("Failed to add main_entry.txt to .zip file\n");
1258 int32_t err = zip_writer->Finish();
1260 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1264 if (is_user_build()) {
1265 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1266 if (remove(bugreport_path.c_str())) {
1267 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1270 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1276 static std::string SHA256_file_hash(std::string filepath) {
1277 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1279 if (fd.get() == -1) {
1280 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1287 std::vector<uint8_t> buffer(65536);
1289 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1290 if (bytes_read == 0) {
1292 } else if (bytes_read == -1) {
1293 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1297 SHA256_update(&ctx, buffer.data(), bytes_read);
1300 uint8_t hash[SHA256_DIGEST_SIZE];
1301 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1302 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1303 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1304 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1306 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1307 return std::string(hash_buffer);
1310 int main(int argc, char *argv[]) {
1311 struct sigaction sigact;
1312 int do_add_date = 0;
1313 int do_zip_file = 0;
1315 char* use_outfile = 0;
1317 int use_control_socket = 0;
1319 int do_broadcast = 0;
1320 int do_early_screenshot = 0;
1321 int is_remote_mode = 0;
1322 std::string version = VERSION_DEFAULT;
1328 /* gets the sequential id */
1329 char last_id[PROPERTY_VALUE_MAX];
1330 property_get("dumpstate.last_id", last_id, "0");
1331 id = strtoul(last_id, NULL, 10) + 1;
1332 snprintf(last_id, sizeof(last_id), "%lu", id);
1333 property_set("dumpstate.last_id", last_id);
1334 MYLOGI("dumpstate id: %lu\n", id);
1336 /* clear SIGPIPE handler */
1337 memset(&sigact, 0, sizeof(sigact));
1338 sigact.sa_handler = sigpipe_handler;
1339 sigaction(SIGPIPE, &sigact, NULL);
1341 /* set as high priority, and protect from OOM killer */
1342 setpriority(PRIO_PROCESS, 0, -20);
1344 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1346 fputs("-1000", oom_adj);
1349 /* fallback to kernels <= 2.6.35 */
1350 oom_adj = fopen("/proc/self/oom_adj", "we");
1352 fputs("-17", oom_adj);
1357 /* parse arguments */
1359 format_args(argc, const_cast<const char **>(argv), &args);
1360 MYLOGD("Dumpstate command line: %s\n", args.c_str());
1362 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1364 case 'd': do_add_date = 1; break;
1365 case 'z': do_zip_file = 1; break;
1366 case 'o': use_outfile = optarg; break;
1367 case 's': use_socket = 1; break;
1368 case 'S': use_control_socket = 1; break;
1369 case 'v': break; // compatibility no-op
1370 case 'q': do_vibrate = 0; break;
1371 case 'p': do_fb = 1; break;
1372 case 'P': do_update_progress = 1; break;
1373 case 'R': is_remote_mode = 1; break;
1374 case 'B': do_broadcast = 1; break;
1375 case 'V': version = optarg; break;
1376 case '?': printf("\n");
1383 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1388 if (use_control_socket && !do_zip_file) {
1393 if (do_update_progress && !do_broadcast) {
1398 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1403 if (version != VERSION_DEFAULT) {
1408 MYLOGI("bugreport format version: %s\n", version.c_str());
1410 do_early_screenshot = do_update_progress;
1412 // If we are going to use a socket, do it as early as possible
1413 // to avoid timeouts from bugreport.
1415 redirect_to_socket(stdout, "dumpstate");
1418 if (use_control_socket) {
1419 MYLOGD("Opening control socket\n");
1420 control_socket_fd = open_socket("dumpstate");
1421 do_update_progress = 1;
1424 /* full path of the temporary file containing the bugreport */
1425 std::string tmp_path;
1427 /* full path of the file containing the dumpstate logs*/
1428 std::string log_path;
1430 /* full path of the systrace file, when enabled */
1431 std::string systrace_path;
1433 /* full path of the temporary file containing the screenshot (when requested) */
1434 std::string screenshot_path;
1436 /* base name (without suffix or extensions) of the bugreport files */
1437 std::string base_name;
1439 /* pointer to the actual path, be it zip or text */
1442 /* pointer to the zipped file */
1443 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1445 /* redirect output if needed */
1446 bool is_redirecting = !use_socket && use_outfile;
1448 if (is_redirecting) {
1449 bugreport_dir = dirname(use_outfile);
1450 base_name = basename(use_outfile);
1453 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1458 char build_id[PROPERTY_VALUE_MAX];
1459 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1460 base_name = base_name + "-" + build_id;
1462 // TODO: if dumpstate was an object, the paths could be internal variables and then
1463 // we could have a function to calculate the derived values, such as:
1464 // screenshot_path = GetPath(".png");
1465 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1467 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1468 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1469 + std::to_string(getpid()) + ".txt";
1471 MYLOGD("Bugreport dir: %s\n"
1475 "Temporary path: %s\n"
1476 "Screenshot path: %s\n",
1477 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1478 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1481 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1482 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1483 create_parent_dirs(path.c_str());
1484 zip_file.reset(fopen(path.c_str(), "wb"));
1486 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1489 zip_writer.reset(new ZipWriter(zip_file.get()));
1491 add_text_zip_entry("version.txt", version);
1494 if (do_update_progress) {
1497 std::vector<std::string> am_args = {
1498 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1499 "--es", "android.intent.extra.NAME", suffix,
1500 "--ei", "android.intent.extra.ID", std::to_string(id),
1501 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1502 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1505 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1507 if (use_control_socket) {
1508 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1513 /* read /proc/cmdline before dropping root */
1514 FILE *cmdline = fopen("/proc/cmdline", "re");
1516 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1520 /* open the vibrator before dropping root */
1521 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1523 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1525 vibrate(vibrator.get(), 150);
1529 if (do_fb && do_early_screenshot) {
1530 if (screenshot_path.empty()) {
1531 // should not have happened
1532 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1534 MYLOGI("taking early screenshot\n");
1535 take_screenshot(screenshot_path);
1536 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1537 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1538 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1539 screenshot_path.c_str(), strerror(errno));
1545 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1546 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1550 if (is_redirecting) {
1551 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1552 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1553 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1554 log_path.c_str(), strerror(errno));
1556 /* TODO: rather than generating a text file now and zipping it later,
1557 it would be more efficient to redirect stdout to the zip entry
1558 directly, but the libziparchive doesn't support that option yet. */
1559 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1560 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1561 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1562 tmp_path.c_str(), strerror(errno));
1565 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1566 // In particular, DurationReport objects should be created passing 'title, NULL', so their
1567 // duration is logged into MYLOG instead.
1568 print_header(version);
1570 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1571 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1573 if (!dump_anrd_trace()) {
1577 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1580 // Invoking the following dumpsys calls before dump_traces() to try and
1581 // keep the system stats as close to its initial state as possible.
1582 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1583 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1585 /* collect stack traces from Dalvik and native processes (needs root) */
1586 dump_traces_path = dump_traces();
1588 /* Run some operations that require root. */
1589 get_tombstone_fds(tombstone_data);
1590 add_dir(RECOVERY_DIR, true);
1591 add_dir(RECOVERY_DATA_DIR, true);
1592 add_dir(LOGPERSIST_DATA_DIR, false);
1593 if (!is_user_build()) {
1594 add_dir(PROFILE_DATA_DIR_CUR, true);
1595 add_dir(PROFILE_DATA_DIR_REF, true);
1600 // Capture any IPSec policies in play. No keys are exposed here.
1601 run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
1603 // Run ss as root so we can see socket marks.
1604 run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1606 if (!drop_root_user()) {
1610 dumpstate(do_early_screenshot ? "": screenshot_path, version);
1612 /* close output if needed */
1613 if (is_redirecting) {
1617 /* rename or zip the (now complete) .tmp file to its final location */
1620 /* check if user changed the suffix using system properties */
1621 char key[PROPERTY_KEY_MAX];
1622 char value[PROPERTY_VALUE_MAX];
1623 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1624 property_get(key, value, "");
1625 bool change_suffix= false;
1627 /* must whitelist which characters are allowed, otherwise it could cross directories */
1628 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1629 if (std::regex_match(value, valid_regex)) {
1630 change_suffix = true;
1632 MYLOGE("invalid suffix provided by user: %s\n", value);
1635 if (change_suffix) {
1636 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1638 if (!screenshot_path.empty()) {
1639 std::string new_screenshot_path =
1640 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1641 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1642 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1643 new_screenshot_path.c_str(), strerror(errno));
1645 screenshot_path = new_screenshot_path;
1650 bool do_text_file = true;
1652 std::string entry_name = base_name + "-" + suffix + ".txt";
1653 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1654 if (!finish_zip_file(entry_name, tmp_path, now)) {
1655 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1656 do_text_file = true;
1658 do_text_file = false;
1659 // Since zip file is already created, it needs to be renamed.
1660 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1661 if (path != new_path) {
1662 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1663 if (rename(path.c_str(), new_path.c_str())) {
1664 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1665 new_path.c_str(), strerror(errno));
1673 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1674 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1675 if (rename(tmp_path.c_str(), path.c_str())) {
1676 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1680 if (use_control_socket) {
1682 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1683 "for more details\n", log_path.c_str());
1685 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1690 /* vibrate a few but shortly times to let user know it's finished */
1692 for (int i = 0; i < 3; i++) {
1693 vibrate(vibrator.get(), 75);
1694 usleep((75 + 50) * 1000);
1698 /* tell activity manager we're done */
1700 if (!path.empty()) {
1701 MYLOGI("Final bugreport path: %s\n", path.c_str());
1703 std::vector<std::string> am_args = {
1704 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1705 "--ei", "android.intent.extra.ID", std::to_string(id),
1706 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1707 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1708 "--es", "android.intent.extra.BUGREPORT", path,
1709 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1713 am_args.push_back("--es");
1714 am_args.push_back("android.intent.extra.SCREENSHOT");
1715 am_args.push_back(screenshot_path);
1717 if (is_remote_mode) {
1718 am_args.push_back("--es");
1719 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1720 am_args.push_back(SHA256_file_hash(path));
1721 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1723 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1726 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1730 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1733 if (is_redirecting) {
1737 if (use_control_socket && control_socket_fd != -1) {
1738 MYLOGD("Closing control socket\n");
1739 close(control_socket_fd);