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 if (!screenshot_path.empty()) {
949 MYLOGI("taking late screenshot\n");
950 take_screenshot(screenshot_path);
951 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
954 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
956 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
957 if (timeout < 20000) {
960 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
964 timeout = logcat_timeout("events");
965 if (timeout < 20000) {
968 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
973 timeout = logcat_timeout("radio");
974 if (timeout < 20000) {
977 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
983 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
985 /* show the traces we collected in main(), if that was done */
986 if (dump_traces_path != NULL) {
987 dump_file("VM TRACES JUST NOW", dump_traces_path);
990 /* only show ANR traces if they're less than 15 minutes old */
992 char anr_traces_path[PATH_MAX];
993 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
994 if (!anr_traces_path[0]) {
995 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
997 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
998 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
1000 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
1002 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
1006 /* slow traces for slow operations */
1007 if (anr_traces_path[0] != 0) {
1008 int tail = strlen(anr_traces_path)-1;
1009 while (tail > 0 && anr_traces_path[tail] != '/') {
1014 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
1015 if (stat(anr_traces_path, &st)) {
1016 // No traces file at this index, done with the files.
1019 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
1025 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
1026 if (tombstone_data[i].fd != -1) {
1027 const char *name = tombstone_data[i].name;
1028 int fd = tombstone_data[i].fd;
1031 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
1032 MYLOGE("Unable to add tombstone %s to zip file\n", name);
1035 dump_file_from_fd("TOMBSTONE", name, fd);
1038 tombstone_data[i].fd = -1;
1042 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1045 dump_file("NETWORK DEV INFO", "/proc/net/dev");
1046 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1047 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1048 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1049 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1051 if (!stat(PSTORE_LAST_KMSG, &st)) {
1052 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
1053 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
1054 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
1055 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
1057 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
1058 dump_file("LAST KMSG", "/proc/last_kmsg");
1061 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
1062 run_command("LAST LOGCAT", 10, "logcat", "-L",
1069 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1071 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
1073 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
1074 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
1076 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
1077 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
1079 dump_route_tables();
1081 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1082 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
1083 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
1084 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
1086 #ifdef FWDUMP_bcmdhd
1087 run_command("ND OFFLOAD TABLE", 5,
1088 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
1090 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
1091 SU_PATH, "root", WLUTIL, "counters", NULL);
1093 run_command("ND OFFLOAD STATUS (1)", 5,
1094 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1097 dump_file("INTERRUPTS (1)", "/proc/interrupts");
1099 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
1101 #ifdef FWDUMP_bcmdhd
1102 run_command("DUMP WIFI STATUS", 20,
1103 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
1105 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
1106 SU_PATH, "root", WLUTIL, "counters", NULL);
1108 run_command("ND OFFLOAD STATUS (2)", 5,
1109 SU_PATH, "root", WLUTIL, "nd_status", NULL);
1111 dump_file("INTERRUPTS (2)", "/proc/interrupts");
1115 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1116 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1118 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
1120 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1122 printf("------ BACKLIGHTS ------\n");
1123 printf("LCD brightness=");
1124 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1125 printf("Button brightness=");
1126 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1127 printf("Keyboard brightness=");
1128 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1129 printf("ALS mode=");
1130 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1131 printf("LCD driver registers:\n");
1132 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1135 /* Binder state is expensive to look at as it uses a lot of memory. */
1136 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1137 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1138 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1139 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1140 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1142 printf("========================================================\n");
1143 printf("== Board\n");
1144 printf("========================================================\n");
1149 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1150 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1151 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1152 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
1153 if (is_user_build()) {
1154 // su does not exist on user builds, so try running without it.
1155 // This way any implementations of vril-dump that do not require
1156 // root can run on user builds.
1157 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1160 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1161 SU_PATH, "root", "vril-dump", NULL);
1165 printf("========================================================\n");
1166 printf("== Android Framework Services\n");
1167 printf("========================================================\n");
1169 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
1171 printf("========================================================\n");
1172 printf("== Checkins\n");
1173 printf("========================================================\n");
1175 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1176 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1177 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1178 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1179 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1180 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
1182 printf("========================================================\n");
1183 printf("== Running Application Activities\n");
1184 printf("========================================================\n");
1186 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
1188 printf("========================================================\n");
1189 printf("== Running Application Services\n");
1190 printf("========================================================\n");
1192 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
1194 printf("========================================================\n");
1195 printf("== Running Application Providers\n");
1196 printf("========================================================\n");
1198 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
1200 // dump_modem_logs adds the modem logs if available to the bugreport.
1201 // Do this at the end to allow for sufficient time for the modem logs to be
1205 printf("========================================================\n");
1206 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1207 getpid(), progress, weight_total, WEIGHT_TOTAL);
1208 printf("========================================================\n");
1209 printf("== dumpstate: done\n");
1210 printf("========================================================\n");
1213 static void usage() {
1215 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1216 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1217 " -h: display this help message\n"
1218 " -b: play sound file instead of vibrate, at beginning of job\n"
1219 " -e: play sound file instead of vibrate, at end of job\n"
1220 " -o: write to file (instead of stdout)\n"
1221 " -d: append date to filename (requires -o)\n"
1222 " -p: capture screenshot to filename.png (requires -o)\n"
1223 " -z: generate zipped file (requires -o)\n"
1224 " -s: write output to control socket (for init)\n"
1225 " -S: write file location to control socket (for init; requires -o and -z)"
1226 " -q: disable vibrate\n"
1227 " -B: send broadcast when finished (requires -o)\n"
1228 " -P: send broadcast when started and update system properties on "
1229 "progress (requires -o and -B)\n"
1230 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1231 "shouldn't be used with -P)\n"
1232 " -V: sets the bugreport format version (valid values: %s)\n",
1233 VERSION_DEFAULT.c_str());
1236 static void sigpipe_handler(int n) {
1237 // don't complain to stderr or stdout
1238 _exit(EXIT_FAILURE);
1241 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1244 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1246 if (!add_zip_entry(bugreport_name, bugreport_path)) {
1247 MYLOGE("Failed to add text entry to .zip file\n");
1250 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1251 MYLOGE("Failed to add main_entry.txt to .zip file\n");
1255 int32_t err = zip_writer->Finish();
1257 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1261 if (is_user_build()) {
1262 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1263 if (remove(bugreport_path.c_str())) {
1264 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1267 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1273 static std::string SHA256_file_hash(std::string filepath) {
1274 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1276 if (fd.get() == -1) {
1277 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1284 std::vector<uint8_t> buffer(65536);
1286 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1287 if (bytes_read == 0) {
1289 } else if (bytes_read == -1) {
1290 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1294 SHA256_update(&ctx, buffer.data(), bytes_read);
1297 uint8_t hash[SHA256_DIGEST_SIZE];
1298 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1299 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1300 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1301 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1303 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1304 return std::string(hash_buffer);
1307 int main(int argc, char *argv[]) {
1308 struct sigaction sigact;
1309 int do_add_date = 0;
1310 int do_zip_file = 0;
1312 char* use_outfile = 0;
1314 int use_control_socket = 0;
1316 int do_broadcast = 0;
1317 int do_early_screenshot = 0;
1318 int is_remote_mode = 0;
1319 std::string version = VERSION_DEFAULT;
1325 /* gets the sequential id */
1326 char last_id[PROPERTY_VALUE_MAX];
1327 property_get("dumpstate.last_id", last_id, "0");
1328 id = strtoul(last_id, NULL, 10) + 1;
1329 snprintf(last_id, sizeof(last_id), "%lu", id);
1330 property_set("dumpstate.last_id", last_id);
1331 MYLOGI("dumpstate id: %lu\n", id);
1333 /* clear SIGPIPE handler */
1334 memset(&sigact, 0, sizeof(sigact));
1335 sigact.sa_handler = sigpipe_handler;
1336 sigaction(SIGPIPE, &sigact, NULL);
1338 /* set as high priority, and protect from OOM killer */
1339 setpriority(PRIO_PROCESS, 0, -20);
1341 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1343 fputs("-1000", oom_adj);
1346 /* fallback to kernels <= 2.6.35 */
1347 oom_adj = fopen("/proc/self/oom_adj", "we");
1349 fputs("-17", oom_adj);
1354 /* parse arguments */
1356 format_args(argc, const_cast<const char **>(argv), &args);
1357 MYLOGD("Dumpstate command line: %s\n", args.c_str());
1359 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1361 case 'd': do_add_date = 1; break;
1362 case 'z': do_zip_file = 1; break;
1363 case 'o': use_outfile = optarg; break;
1364 case 's': use_socket = 1; break;
1365 case 'S': use_control_socket = 1; break;
1366 case 'v': break; // compatibility no-op
1367 case 'q': do_vibrate = 0; break;
1368 case 'p': do_fb = 1; break;
1369 case 'P': do_update_progress = 1; break;
1370 case 'R': is_remote_mode = 1; break;
1371 case 'B': do_broadcast = 1; break;
1372 case 'V': version = optarg; break;
1373 case '?': printf("\n");
1380 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1385 if (use_control_socket && !do_zip_file) {
1390 if (do_update_progress && !do_broadcast) {
1395 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1400 if (version != VERSION_DEFAULT) {
1405 MYLOGI("bugreport format version: %s\n", version.c_str());
1407 do_early_screenshot = do_update_progress;
1409 // If we are going to use a socket, do it as early as possible
1410 // to avoid timeouts from bugreport.
1412 redirect_to_socket(stdout, "dumpstate");
1415 if (use_control_socket) {
1416 MYLOGD("Opening control socket\n");
1417 control_socket_fd = open_socket("dumpstate");
1418 do_update_progress = 1;
1421 /* full path of the temporary file containing the bugreport */
1422 std::string tmp_path;
1424 /* full path of the file containing the dumpstate logs*/
1425 std::string log_path;
1427 /* full path of the systrace file, when enabled */
1428 std::string systrace_path;
1430 /* full path of the temporary file containing the screenshot (when requested) */
1431 std::string screenshot_path;
1433 /* base name (without suffix or extensions) of the bugreport files */
1434 std::string base_name;
1436 /* pointer to the actual path, be it zip or text */
1439 /* pointer to the zipped file */
1440 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1442 /* redirect output if needed */
1443 bool is_redirecting = !use_socket && use_outfile;
1445 if (is_redirecting) {
1446 bugreport_dir = dirname(use_outfile);
1447 base_name = basename(use_outfile);
1450 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1455 char build_id[PROPERTY_VALUE_MAX];
1456 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1457 base_name = base_name + "-" + build_id;
1459 // TODO: if dumpstate was an object, the paths could be internal variables and then
1460 // we could have a function to calculate the derived values, such as:
1461 // screenshot_path = GetPath(".png");
1462 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1464 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1465 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1466 + std::to_string(getpid()) + ".txt";
1468 MYLOGD("Bugreport dir: %s\n"
1472 "Temporary path: %s\n"
1473 "Screenshot path: %s\n",
1474 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1475 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1478 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1479 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1480 create_parent_dirs(path.c_str());
1481 zip_file.reset(fopen(path.c_str(), "wb"));
1483 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1486 zip_writer.reset(new ZipWriter(zip_file.get()));
1488 add_text_zip_entry("version.txt", version);
1491 if (do_update_progress) {
1494 std::vector<std::string> am_args = {
1495 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1496 "--es", "android.intent.extra.NAME", suffix,
1497 "--ei", "android.intent.extra.ID", std::to_string(id),
1498 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1499 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1502 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1504 if (use_control_socket) {
1505 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1510 /* read /proc/cmdline before dropping root */
1511 FILE *cmdline = fopen("/proc/cmdline", "re");
1513 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1517 /* open the vibrator before dropping root */
1518 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1520 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1522 vibrate(vibrator.get(), 150);
1526 if (do_fb && do_early_screenshot) {
1527 if (screenshot_path.empty()) {
1528 // should not have happened
1529 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1531 MYLOGI("taking early screenshot\n");
1532 take_screenshot(screenshot_path);
1533 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1534 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1535 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1536 screenshot_path.c_str(), strerror(errno));
1542 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1543 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1547 if (is_redirecting) {
1548 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1549 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1550 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1551 log_path.c_str(), strerror(errno));
1553 /* TODO: rather than generating a text file now and zipping it later,
1554 it would be more efficient to redirect stdout to the zip entry
1555 directly, but the libziparchive doesn't support that option yet. */
1556 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1557 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1558 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1559 tmp_path.c_str(), strerror(errno));
1562 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1563 // In particular, DurationReport objects should be created passing 'title, NULL', so their
1564 // duration is logged into MYLOG instead.
1565 print_header(version);
1567 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1568 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1570 if (!dump_anrd_trace()) {
1574 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1577 // Invoking the following dumpsys calls before dump_traces() to try and
1578 // keep the system stats as close to its initial state as possible.
1579 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1580 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1582 /* collect stack traces from Dalvik and native processes (needs root) */
1583 dump_traces_path = dump_traces();
1585 /* Run some operations that require root. */
1586 get_tombstone_fds(tombstone_data);
1587 add_dir(RECOVERY_DIR, true);
1588 add_dir(RECOVERY_DATA_DIR, true);
1589 add_dir(LOGPERSIST_DATA_DIR, false);
1590 if (!is_user_build()) {
1591 add_dir(PROFILE_DATA_DIR_CUR, true);
1592 add_dir(PROFILE_DATA_DIR_REF, true);
1597 // Capture any IPSec policies in play. No keys are exposed here.
1598 run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
1600 // Run ss as root so we can see socket marks.
1601 run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1603 if (!drop_root_user()) {
1607 dumpstate(do_early_screenshot ? "": screenshot_path, version);
1609 /* close output if needed */
1610 if (is_redirecting) {
1614 /* rename or zip the (now complete) .tmp file to its final location */
1617 /* check if user changed the suffix using system properties */
1618 char key[PROPERTY_KEY_MAX];
1619 char value[PROPERTY_VALUE_MAX];
1620 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1621 property_get(key, value, "");
1622 bool change_suffix= false;
1624 /* must whitelist which characters are allowed, otherwise it could cross directories */
1625 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1626 if (std::regex_match(value, valid_regex)) {
1627 change_suffix = true;
1629 MYLOGE("invalid suffix provided by user: %s\n", value);
1632 if (change_suffix) {
1633 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1635 if (!screenshot_path.empty()) {
1636 std::string new_screenshot_path =
1637 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1638 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1639 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1640 new_screenshot_path.c_str(), strerror(errno));
1642 screenshot_path = new_screenshot_path;
1647 bool do_text_file = true;
1649 std::string entry_name = base_name + "-" + suffix + ".txt";
1650 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1651 if (!finish_zip_file(entry_name, tmp_path, now)) {
1652 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1653 do_text_file = true;
1655 do_text_file = false;
1656 // Since zip file is already created, it needs to be renamed.
1657 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1658 if (path != new_path) {
1659 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1660 if (rename(path.c_str(), new_path.c_str())) {
1661 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1662 new_path.c_str(), strerror(errno));
1670 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1671 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1672 if (rename(tmp_path.c_str(), path.c_str())) {
1673 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1677 if (use_control_socket) {
1679 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1680 "for more details\n", log_path.c_str());
1682 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1687 /* vibrate a few but shortly times to let user know it's finished */
1689 for (int i = 0; i < 3; i++) {
1690 vibrate(vibrator.get(), 75);
1691 usleep((75 + 50) * 1000);
1695 /* tell activity manager we're done */
1697 if (!path.empty()) {
1698 MYLOGI("Final bugreport path: %s\n", path.c_str());
1700 std::vector<std::string> am_args = {
1701 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1702 "--ei", "android.intent.extra.ID", std::to_string(id),
1703 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1704 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1705 "--es", "android.intent.extra.BUGREPORT", path,
1706 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1710 am_args.push_back("--es");
1711 am_args.push_back("android.intent.extra.SCREENSHOT");
1712 am_args.push_back(screenshot_path);
1714 if (is_remote_mode) {
1715 am_args.push_back("--es");
1716 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1717 am_args.push_back(SHA256_file_hash(path));
1718 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1720 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1723 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1727 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1730 if (is_redirecting) {
1734 if (use_control_socket && control_socket_fd != -1) {
1735 MYLOGD("Closing control socket\n");
1736 close(control_socket_fd);