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/stringprintf.h>
38 #include <cutils/properties.h>
40 #include "private/android_filesystem_config.h"
42 #define LOG_TAG "dumpstate"
43 #include <cutils/log.h>
45 #include "dumpstate.h"
47 #include "ziparchive/zip_writer.h"
49 #include "mincrypt/sha256.h"
51 using android::base::StringPrintf;
53 /* read before root is shed */
54 static char cmdline_buf[16384] = "(unknown)";
55 static const char *dump_traces_path = NULL;
57 // TODO: variables below should be part of dumpstate object
58 static unsigned long id;
59 static char build_type[PROPERTY_VALUE_MAX];
61 static std::unique_ptr<ZipWriter> zip_writer;
62 static std::set<std::string> mount_points;
64 int control_socket_fd = -1;
65 /* suffix of the bugreport files - it's typically the date (when invoked with -d),
66 * although it could be changed by the user using a system property */
67 static std::string suffix;
69 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
70 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
72 #define RAFT_DIR "/data/misc/raft"
73 #define RECOVERY_DIR "/cache/recovery"
74 #define RECOVERY_DATA_DIR "/data/misc/recovery"
75 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
76 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
77 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
78 #define TOMBSTONE_DIR "/data/tombstones"
79 #define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
80 /* Can accomodate a tombstone number up to 9999. */
81 #define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
82 #define NUM_TOMBSTONES 10
83 #define WLUTIL "/vendor/xbin/wlutil"
86 char name[TOMBSTONE_MAX_LEN];
90 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
92 const std::string ZIP_ROOT_DIR = "FS";
93 std::string bugreport_dir;
96 * List of supported zip format versions.
98 * See bugreport-format.txt for more info.
100 static std::string VERSION_DEFAULT = "1.0";
102 bool is_user_build() {
103 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
106 /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
107 * otherwise gets just those modified in the last half an hour. */
108 static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
109 time_t thirty_minutes_ago = now - 60*30;
110 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
111 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
112 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
113 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
115 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
116 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
125 // for_each_pid() callback to get mount info about a process.
126 void do_mountinfo(int pid, const char *name) {
129 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
131 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
132 char linkname[PATH_MAX];
133 ssize_t r = readlink(path, linkname, PATH_MAX);
135 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
140 if (mount_points.find(linkname) == mount_points.end()) {
141 // First time this mount point was found: add it
142 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
143 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
144 mount_points.insert(linkname);
146 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
151 void add_mountinfo() {
152 if (!zip_writer) return;
153 const char *title = "MOUNT INFO";
154 mount_points.clear();
155 DurationReporter duration_reporter(title, NULL);
156 for_each_pid(do_mountinfo, NULL);
157 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
160 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
166 d = opendir(driverpath);
171 while ((de = readdir(d))) {
172 if (de->d_type != DT_LNK) {
175 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
176 dump_file(title, path);
182 static void dump_systrace() {
184 MYLOGD("Not dumping systrace because zip_writer is not set\n");
187 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
188 if (systrace_path.empty()) {
189 MYLOGE("Not dumping systrace because path is empty\n");
192 const char* path = "/sys/kernel/debug/tracing/tracing_on";
194 if (read_file_as_long(path, &is_tracing)) {
195 return; // error already logged
197 if (is_tracing <= 0) {
198 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
202 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
203 systrace_path.c_str());
204 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
205 systrace_path.c_str(), NULL)) {
206 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
207 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
208 // we should call strace to stop itself, but there is no such option yet (just a
209 // --async_stop, which stops and dump
210 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
211 // MYLOGE("could not stop systrace ");
214 if (!add_zip_entry("systrace.txt", systrace_path)) {
215 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
217 if (remove(systrace_path.c_str())) {
218 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
223 static void dump_raft() {
224 if (is_user_build()) {
228 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
229 if (raft_log_path.empty()) {
230 MYLOGD("raft_log_path is empty\n");
235 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
236 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
241 // Write compressed and encoded raft logs to stdout if not zip_writer.
242 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
246 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
247 "-o", raft_log_path.c_str(), NULL);
248 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
249 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
251 if (remove(raft_log_path.c_str())) {
252 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
257 static bool skip_not_stat(const char *path) {
258 static const char stat[] = "/stat";
259 size_t len = strlen(path);
260 if (path[len - 1] == '/') { /* Directory? */
263 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
266 static bool skip_none(const char *path) {
270 static const char mmcblk0[] = "/sys/block/mmcblk0/";
271 unsigned long worst_write_perf = 20000; /* in KB/s */
275 // Name units description
276 // ---- ----- -----------
277 // read I/Os requests number of read I/Os processed
278 #define __STAT_READ_IOS 0
279 // read merges requests number of read I/Os merged with in-queue I/O
280 #define __STAT_READ_MERGES 1
281 // read sectors sectors number of sectors read
282 #define __STAT_READ_SECTORS 2
283 // read ticks milliseconds total wait time for read requests
284 #define __STAT_READ_TICKS 3
285 // write I/Os requests number of write I/Os processed
286 #define __STAT_WRITE_IOS 4
287 // write merges requests number of write I/Os merged with in-queue I/O
288 #define __STAT_WRITE_MERGES 5
289 // write sectors sectors number of sectors written
290 #define __STAT_WRITE_SECTORS 6
291 // write ticks milliseconds total wait time for write requests
292 #define __STAT_WRITE_TICKS 7
293 // in_flight requests number of I/Os currently in flight
294 #define __STAT_IN_FLIGHT 8
295 // io_ticks milliseconds total time this block device has been active
296 #define __STAT_IO_TICKS 9
297 // time_in_queue milliseconds total wait time for all requests
298 #define __STAT_IN_QUEUE 10
299 #define __STAT_NUMBER_FIELD 11
301 // read I/Os, write I/Os
302 // =====================
304 // These values increment when an I/O request completes.
306 // read merges, write merges
307 // =========================
309 // These values increment when an I/O request is merged with an
310 // already-queued I/O request.
312 // read sectors, write sectors
313 // ===========================
315 // These values count the number of sectors read from or written to this
316 // block device. The "sectors" in question are the standard UNIX 512-byte
317 // sectors, not any device- or filesystem-specific block size. The
318 // counters are incremented when the I/O completes.
319 #define SECTOR_SIZE 512
321 // read ticks, write ticks
322 // =======================
324 // These values count the number of milliseconds that I/O requests have
325 // waited on this block device. If there are multiple I/O requests waiting,
326 // these values will increase at a rate greater than 1000/second; for
327 // example, if 60 read requests wait for an average of 30 ms, the read_ticks
328 // field will increase by 60*30 = 1800.
333 // This value counts the number of I/O requests that have been issued to
334 // the device driver but have not yet completed. It does not include I/O
335 // requests that are in the queue but not yet issued to the device driver.
340 // This value counts the number of milliseconds during which the device has
341 // had I/O requests queued.
346 // This value counts the number of milliseconds that I/O requests have waited
347 // on this block device. If there are multiple I/O requests waiting, this
348 // value will increase as the product of the number of milliseconds times the
349 // number of requests waiting (see "read ticks" above for an example).
353 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
354 unsigned long long fields[__STAT_NUMBER_FIELD];
356 char *cp, *buffer = NULL;
358 FILE *fp = fdopen(fd, "rb");
359 getline(&buffer, &i, fp);
365 while ((i > 0) && (buffer[i - 1] == '\n')) {
373 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
374 fields[i] = strtoull(cp, &cp, 10);
375 if (fields[i] != 0) {
379 if (z) { /* never accessed */
384 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
385 path += sizeof(mmcblk0) - 1;
388 printf("%s: %s\n", path, buffer);
391 if (fields[__STAT_IO_TICKS]) {
392 unsigned long read_perf = 0;
393 unsigned long read_ios = 0;
394 if (fields[__STAT_READ_TICKS]) {
395 unsigned long long divisor = fields[__STAT_READ_TICKS]
396 * fields[__STAT_IO_TICKS];
397 read_perf = ((unsigned long long)SECTOR_SIZE
398 * fields[__STAT_READ_SECTORS]
399 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
401 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
402 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
406 unsigned long write_perf = 0;
407 unsigned long write_ios = 0;
408 if (fields[__STAT_WRITE_TICKS]) {
409 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
410 * fields[__STAT_IO_TICKS];
411 write_perf = ((unsigned long long)SECTOR_SIZE
412 * fields[__STAT_WRITE_SECTORS]
413 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
415 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
416 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
420 unsigned queue = (fields[__STAT_IN_QUEUE]
421 + (fields[__STAT_IO_TICKS] >> 1))
422 / fields[__STAT_IO_TICKS];
424 if (!write_perf && !write_ios) {
425 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
426 path, read_perf, read_ios, queue);
428 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
429 path, read_perf, read_ios, write_perf, write_ios, queue);
432 /* bugreport timeout factor adjustment */
433 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
434 worst_write_perf = write_perf;
440 /* Copied policy from system/core/logd/LogBuffer.cpp */
442 #define LOG_BUFFER_SIZE (256 * 1024)
443 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
444 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
446 static bool valid_size(unsigned long value) {
447 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
451 long pages = sysconf(_SC_PHYS_PAGES);
456 long pagesize = sysconf(_SC_PAGESIZE);
458 pagesize = PAGE_SIZE;
461 // maximum memory impact a somewhat arbitrary ~3%
462 pages = (pages + 31) / 32;
463 unsigned long maximum = pages * pagesize;
465 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
469 return value <= maximum;
472 static unsigned long property_get_size(const char *key) {
474 char *cp, property[PROPERTY_VALUE_MAX];
476 property_get(key, property, "");
477 value = strtoul(property, &cp, 10);
495 if (!valid_size(value)) {
503 static unsigned long logcat_timeout(const char *name) {
504 static const char global_tuneable[] = "persist.logd.size"; // Settings App
505 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
506 char key[PROP_NAME_MAX];
507 unsigned long property_size, default_size;
509 default_size = property_get_size(global_tuneable);
511 default_size = property_get_size(global_default);
514 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
515 property_size = property_get_size(key);
517 if (!property_size) {
518 snprintf(key, sizeof(key), "%s.%s", global_default, name);
519 property_size = property_get_size(key);
522 if (!property_size) {
523 property_size = default_size;
526 if (!property_size) {
527 property_size = LOG_BUFFER_SIZE;
530 /* Engineering margin is ten-fold our guess */
531 return 10 * (property_size + worst_write_perf) / worst_write_perf;
534 /* End copy from system/core/logd/LogBuffer.cpp */
536 /* dumps the current system state to stdout */
537 static void print_header(std::string version) {
538 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
539 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
540 char network[PROPERTY_VALUE_MAX], date[80];
542 property_get("ro.build.display.id", build, "(unknown)");
543 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
544 property_get("ro.build.type", build_type, "(unknown)");
545 property_get("gsm.version.baseband", radio, "(unknown)");
546 property_get("ro.bootloader", bootloader, "(unknown)");
547 property_get("gsm.operator.alpha", network, "(unknown)");
548 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
550 printf("========================================================\n");
551 printf("== dumpstate: %s\n", date);
552 printf("========================================================\n");
555 printf("Build: %s\n", build);
556 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
557 printf("Bootloader: %s\n", bootloader);
558 printf("Radio: %s\n", radio);
559 printf("Network: %s\n", network);
562 dump_file(NULL, "/proc/version");
563 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
564 printf("Bugreport format version: %s\n", version.c_str());
565 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
569 // List of file extensions that can cause a zip file attachment to be rejected by some email
570 // service providers.
571 static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
572 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
573 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
574 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
577 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
579 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
583 std::string valid_name = entry_name;
585 // Rename extension if necessary.
586 size_t idx = entry_name.rfind(".");
587 if (idx != std::string::npos) {
588 std::string extension = entry_name.substr(idx);
589 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
590 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
591 valid_name = entry_name + ".renamed";
592 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
596 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
597 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
598 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
599 ZipWriter::kCompress, get_mtime(fd, now));
601 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
602 ZipWriter::ErrorCodeString(err));
606 std::vector<uint8_t> buffer(65536);
608 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
609 if (bytes_read == 0) {
611 } else if (bytes_read == -1) {
612 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
615 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
617 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
622 err = zip_writer->FinishEntry();
624 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
631 bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
632 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
633 if (fd.get() == -1) {
634 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
638 return add_zip_entry_from_fd(entry_name, fd.get());
641 /* adds a file to the existing zipped bugreport */
642 static int _add_file_from_fd(const char *title, const char *path, int fd) {
643 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
646 // TODO: move to util.cpp
647 void add_dir(const char *dir, bool recursive) {
649 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
652 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
653 DurationReporter duration_reporter(dir, NULL);
654 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
657 /* adds a text entry entry to the existing zip file. */
658 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
660 MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str());
663 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
664 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
666 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
667 ZipWriter::ErrorCodeString(err));
671 err = zip_writer->WriteBytes(content.c_str(), content.length());
673 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
674 ZipWriter::ErrorCodeString(err));
678 err = zip_writer->FinishEntry();
680 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
687 static void dump_iptables() {
688 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
689 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
690 run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
692 run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
693 run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
694 run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
695 run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
698 static void dumpstate(const std::string& screenshot_path, const std::string& version) {
699 DurationReporter duration_reporter("DUMPSTATE");
700 unsigned long timeout;
702 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
703 run_command("UPTIME", 10, "uptime", NULL);
704 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
705 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
706 dump_file("MEMORY INFO", "/proc/meminfo");
707 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
708 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
709 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
710 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
711 dump_file("SLAB INFO", "/proc/slabinfo");
712 dump_file("ZONEINFO", "/proc/zoneinfo");
713 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
714 dump_file("BUDDYINFO", "/proc/buddyinfo");
715 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
717 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
718 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
719 dump_file("KERNEL SYNC", "/d/sync");
721 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
722 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
724 run_command("PRINTENV", 10, "printenv", NULL);
725 run_command("NETSTAT", 10, "netstat", "-n", NULL);
726 run_command("LSMOD", 10, "lsmod", NULL);
730 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
731 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
732 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
733 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
735 if (!screenshot_path.empty()) {
736 MYLOGI("taking late screenshot\n");
737 take_screenshot(screenshot_path);
738 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
741 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
743 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
744 if (timeout < 20000) {
747 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
751 timeout = logcat_timeout("events");
752 if (timeout < 20000) {
755 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
760 timeout = logcat_timeout("radio");
761 if (timeout < 20000) {
764 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
770 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
772 /* show the traces we collected in main(), if that was done */
773 if (dump_traces_path != NULL) {
774 dump_file("VM TRACES JUST NOW", dump_traces_path);
777 /* only show ANR traces if they're less than 15 minutes old */
779 char anr_traces_path[PATH_MAX];
780 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
781 if (!anr_traces_path[0]) {
782 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
784 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
785 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
787 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
789 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
793 /* slow traces for slow operations */
794 if (anr_traces_path[0] != 0) {
795 int tail = strlen(anr_traces_path)-1;
796 while (tail > 0 && anr_traces_path[tail] != '/') {
801 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
802 if (stat(anr_traces_path, &st)) {
803 // No traces file at this index, done with the files.
806 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
812 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
813 if (tombstone_data[i].fd != -1) {
814 const char *name = tombstone_data[i].name;
815 int fd = tombstone_data[i].fd;
818 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
819 MYLOGE("Unable to add tombstone %s to zip file\n", name);
822 dump_file_from_fd("TOMBSTONE", name, fd);
825 tombstone_data[i].fd = -1;
829 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
832 dump_file("NETWORK DEV INFO", "/proc/net/dev");
833 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
834 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
835 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
836 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
838 if (!stat(PSTORE_LAST_KMSG, &st)) {
839 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
840 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
841 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
842 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
844 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
845 dump_file("LAST KMSG", "/proc/last_kmsg");
848 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
849 run_command("LAST LOGCAT", 10, "logcat", "-L",
856 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
858 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
860 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
861 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
863 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
864 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
868 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
869 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
870 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
871 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
874 run_command("ND OFFLOAD TABLE", 5,
875 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
877 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
878 SU_PATH, "root", WLUTIL, "counters", NULL);
880 run_command("ND OFFLOAD STATUS (1)", 5,
881 SU_PATH, "root", WLUTIL, "nd_status", NULL);
884 dump_file("INTERRUPTS (1)", "/proc/interrupts");
886 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
889 run_command("DUMP WIFI STATUS", 20,
890 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
892 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
893 SU_PATH, "root", WLUTIL, "counters", NULL);
895 run_command("ND OFFLOAD STATUS (2)", 5,
896 SU_PATH, "root", WLUTIL, "nd_status", NULL);
898 dump_file("INTERRUPTS (2)", "/proc/interrupts");
902 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
903 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
905 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
907 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
909 printf("------ BACKLIGHTS ------\n");
910 printf("LCD brightness=");
911 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
912 printf("Button brightness=");
913 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
914 printf("Keyboard brightness=");
915 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
917 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
918 printf("LCD driver registers:\n");
919 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
922 /* Binder state is expensive to look at as it uses a lot of memory. */
923 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
924 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
925 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
926 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
927 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
929 printf("========================================================\n");
930 printf("== Board\n");
931 printf("========================================================\n");
936 /* Migrate the ril_dumpstate to a dumpstate_board()? */
937 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
938 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
939 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
940 if (is_user_build()) {
941 // su does not exist on user builds, so try running without it.
942 // This way any implementations of vril-dump that do not require
943 // root can run on user builds.
944 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
947 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
948 SU_PATH, "root", "vril-dump", NULL);
952 printf("========================================================\n");
953 printf("== Android Framework Services\n");
954 printf("========================================================\n");
956 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
958 printf("========================================================\n");
959 printf("== Checkins\n");
960 printf("========================================================\n");
962 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
963 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
964 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
965 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
966 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
967 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
969 printf("========================================================\n");
970 printf("== Running Application Activities\n");
971 printf("========================================================\n");
973 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
975 printf("========================================================\n");
976 printf("== Running Application Services\n");
977 printf("========================================================\n");
979 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
981 printf("========================================================\n");
982 printf("== Running Application Providers\n");
983 printf("========================================================\n");
985 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
988 printf("========================================================\n");
989 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
990 getpid(), progress, weight_total, WEIGHT_TOTAL);
991 printf("========================================================\n");
992 printf("== dumpstate: done\n");
993 printf("========================================================\n");
996 static void usage() {
998 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
999 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1000 " -h: display this help message\n"
1001 " -b: play sound file instead of vibrate, at beginning of job\n"
1002 " -e: play sound file instead of vibrate, at end of job\n"
1003 " -o: write to file (instead of stdout)\n"
1004 " -d: append date to filename (requires -o)\n"
1005 " -p: capture screenshot to filename.png (requires -o)\n"
1006 " -z: generate zipped file (requires -o)\n"
1007 " -s: write output to control socket (for init)\n"
1008 " -S: write file location to control socket (for init; requires -o and -z)"
1009 " -q: disable vibrate\n"
1010 " -B: send broadcast when finished (requires -o)\n"
1011 " -P: send broadcast when started and update system properties on "
1012 "progress (requires -o and -B)\n"
1013 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1014 "shouldn't be used with -P)\n"
1015 " -V: sets the bugreport format version (valid values: %s)\n",
1016 VERSION_DEFAULT.c_str());
1019 static void sigpipe_handler(int n) {
1020 // don't complain to stderr or stdout
1021 _exit(EXIT_FAILURE);
1024 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1027 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1029 if (!add_zip_entry(bugreport_name, bugreport_path)) {
1030 MYLOGE("Failed to add text entry to .zip file\n");
1033 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1034 MYLOGE("Failed to add main_entry.txt to .zip file\n");
1038 int32_t err = zip_writer->Finish();
1040 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1044 if (is_user_build()) {
1045 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1046 if (remove(bugreport_path.c_str())) {
1047 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1050 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1056 static std::string SHA256_file_hash(std::string filepath) {
1057 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1059 if (fd.get() == -1) {
1060 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1067 std::vector<uint8_t> buffer(65536);
1069 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1070 if (bytes_read == 0) {
1072 } else if (bytes_read == -1) {
1073 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1077 SHA256_update(&ctx, buffer.data(), bytes_read);
1080 uint8_t hash[SHA256_DIGEST_SIZE];
1081 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1082 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1083 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1084 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1086 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1087 return std::string(hash_buffer);
1090 int main(int argc, char *argv[]) {
1091 struct sigaction sigact;
1092 int do_add_date = 0;
1093 int do_zip_file = 0;
1095 char* use_outfile = 0;
1097 int use_control_socket = 0;
1099 int do_broadcast = 0;
1100 int do_early_screenshot = 0;
1101 int is_remote_mode = 0;
1102 std::string version = VERSION_DEFAULT;
1108 /* gets the sequential id */
1109 char last_id[PROPERTY_VALUE_MAX];
1110 property_get("dumpstate.last_id", last_id, "0");
1111 id = strtoul(last_id, NULL, 10) + 1;
1112 snprintf(last_id, sizeof(last_id), "%lu", id);
1113 property_set("dumpstate.last_id", last_id);
1114 MYLOGI("dumpstate id: %lu\n", id);
1116 /* clear SIGPIPE handler */
1117 memset(&sigact, 0, sizeof(sigact));
1118 sigact.sa_handler = sigpipe_handler;
1119 sigaction(SIGPIPE, &sigact, NULL);
1121 /* set as high priority, and protect from OOM killer */
1122 setpriority(PRIO_PROCESS, 0, -20);
1124 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1126 fputs("-1000", oom_adj);
1129 /* fallback to kernels <= 2.6.35 */
1130 oom_adj = fopen("/proc/self/oom_adj", "we");
1132 fputs("-17", oom_adj);
1137 /* parse arguments */
1139 format_args(argc, const_cast<const char **>(argv), &args);
1140 MYLOGD("Dumpstate command line: %s\n", args.c_str());
1142 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1144 case 'd': do_add_date = 1; break;
1145 case 'z': do_zip_file = 1; break;
1146 case 'o': use_outfile = optarg; break;
1147 case 's': use_socket = 1; break;
1148 case 'S': use_control_socket = 1; break;
1149 case 'v': break; // compatibility no-op
1150 case 'q': do_vibrate = 0; break;
1151 case 'p': do_fb = 1; break;
1152 case 'P': do_update_progress = 1; break;
1153 case 'R': is_remote_mode = 1; break;
1154 case 'B': do_broadcast = 1; break;
1155 case 'V': version = optarg; break;
1156 case '?': printf("\n");
1163 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1168 if (use_control_socket && !do_zip_file) {
1173 if (do_update_progress && !do_broadcast) {
1178 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1183 if (version != VERSION_DEFAULT) {
1188 MYLOGI("bugreport format version: %s\n", version.c_str());
1190 do_early_screenshot = do_update_progress;
1192 // If we are going to use a socket, do it as early as possible
1193 // to avoid timeouts from bugreport.
1195 redirect_to_socket(stdout, "dumpstate");
1198 if (use_control_socket) {
1199 MYLOGD("Opening control socket\n");
1200 control_socket_fd = open_socket("dumpstate");
1201 do_update_progress = 1;
1204 /* full path of the temporary file containing the bugreport */
1205 std::string tmp_path;
1207 /* full path of the file containing the dumpstate logs*/
1208 std::string log_path;
1210 /* full path of the systrace file, when enabled */
1211 std::string systrace_path;
1213 /* full path of the temporary file containing the screenshot (when requested) */
1214 std::string screenshot_path;
1216 /* base name (without suffix or extensions) of the bugreport files */
1217 std::string base_name;
1219 /* pointer to the actual path, be it zip or text */
1222 /* pointer to the zipped file */
1223 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1225 /* redirect output if needed */
1226 bool is_redirecting = !use_socket && use_outfile;
1228 if (is_redirecting) {
1229 bugreport_dir = dirname(use_outfile);
1230 base_name = basename(use_outfile);
1233 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1238 char build_id[PROPERTY_VALUE_MAX];
1239 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1240 base_name = base_name + "-" + build_id;
1242 // TODO: if dumpstate was an object, the paths could be internal variables and then
1243 // we could have a function to calculate the derived values, such as:
1244 // screenshot_path = GetPath(".png");
1245 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1247 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1248 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1249 + std::to_string(getpid()) + ".txt";
1251 MYLOGD("Bugreport dir: %s\n"
1255 "Temporary path: %s\n"
1256 "Screenshot path: %s\n",
1257 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1258 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1261 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1262 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1263 create_parent_dirs(path.c_str());
1264 zip_file.reset(fopen(path.c_str(), "wb"));
1266 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1269 zip_writer.reset(new ZipWriter(zip_file.get()));
1271 add_text_zip_entry("version.txt", version);
1274 if (do_update_progress) {
1277 std::vector<std::string> am_args = {
1278 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1279 "--es", "android.intent.extra.NAME", suffix,
1280 "--ei", "android.intent.extra.ID", std::to_string(id),
1281 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1282 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1285 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1287 if (use_control_socket) {
1288 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1293 /* read /proc/cmdline before dropping root */
1294 FILE *cmdline = fopen("/proc/cmdline", "re");
1296 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1300 /* open the vibrator before dropping root */
1301 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1303 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1305 vibrate(vibrator.get(), 150);
1309 if (do_fb && do_early_screenshot) {
1310 if (screenshot_path.empty()) {
1311 // should not have happened
1312 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1314 MYLOGI("taking early screenshot\n");
1315 take_screenshot(screenshot_path);
1316 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1317 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1318 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1319 screenshot_path.c_str(), strerror(errno));
1325 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1326 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1330 if (is_redirecting) {
1331 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1332 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1333 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1334 log_path.c_str(), strerror(errno));
1336 /* TODO: rather than generating a text file now and zipping it later,
1337 it would be more efficient to redirect stdout to the zip entry
1338 directly, but the libziparchive doesn't support that option yet. */
1339 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1340 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1341 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1342 tmp_path.c_str(), strerror(errno));
1345 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1346 // In particular, DurationReport objects should be created passing 'title, NULL', so their
1347 // duration is logged into MYLOG instead.
1348 print_header(version);
1350 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1353 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1356 // Invoking the following dumpsys calls before dump_traces() to try and
1357 // keep the system stats as close to its initial state as possible.
1358 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1359 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1361 /* collect stack traces from Dalvik and native processes (needs root) */
1362 dump_traces_path = dump_traces();
1364 /* Run some operations that require root. */
1365 get_tombstone_fds(tombstone_data);
1366 add_dir(RECOVERY_DIR, true);
1367 add_dir(RECOVERY_DATA_DIR, true);
1368 add_dir(LOGPERSIST_DATA_DIR, false);
1369 if (!is_user_build()) {
1370 add_dir(PROFILE_DATA_DIR_CUR, true);
1371 add_dir(PROFILE_DATA_DIR_REF, true);
1376 // Capture any IPSec policies in play. No keys are exposed here.
1377 run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
1379 // Run ss as root so we can see socket marks.
1380 run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1382 if (!drop_root_user()) {
1386 dumpstate(do_early_screenshot ? "": screenshot_path, version);
1388 /* close output if needed */
1389 if (is_redirecting) {
1393 /* rename or zip the (now complete) .tmp file to its final location */
1396 /* check if user changed the suffix using system properties */
1397 char key[PROPERTY_KEY_MAX];
1398 char value[PROPERTY_VALUE_MAX];
1399 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1400 property_get(key, value, "");
1401 bool change_suffix= false;
1403 /* must whitelist which characters are allowed, otherwise it could cross directories */
1404 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1405 if (std::regex_match(value, valid_regex)) {
1406 change_suffix = true;
1408 MYLOGE("invalid suffix provided by user: %s\n", value);
1411 if (change_suffix) {
1412 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1414 if (!screenshot_path.empty()) {
1415 std::string new_screenshot_path =
1416 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1417 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1418 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1419 new_screenshot_path.c_str(), strerror(errno));
1421 screenshot_path = new_screenshot_path;
1426 bool do_text_file = true;
1428 std::string entry_name = base_name + "-" + suffix + ".txt";
1429 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1430 if (!finish_zip_file(entry_name, tmp_path, now)) {
1431 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1432 do_text_file = true;
1434 do_text_file = false;
1435 // Since zip file is already created, it needs to be renamed.
1436 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1437 if (path != new_path) {
1438 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1439 if (rename(path.c_str(), new_path.c_str())) {
1440 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1441 new_path.c_str(), strerror(errno));
1449 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1450 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1451 if (rename(tmp_path.c_str(), path.c_str())) {
1452 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1456 if (use_control_socket) {
1458 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1459 "for more details\n", log_path.c_str());
1461 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1466 /* vibrate a few but shortly times to let user know it's finished */
1468 for (int i = 0; i < 3; i++) {
1469 vibrate(vibrator.get(), 75);
1470 usleep((75 + 50) * 1000);
1474 /* tell activity manager we're done */
1476 if (!path.empty()) {
1477 MYLOGI("Final bugreport path: %s\n", path.c_str());
1479 std::vector<std::string> am_args = {
1480 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1481 "--ei", "android.intent.extra.ID", std::to_string(id),
1482 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1483 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1484 "--es", "android.intent.extra.BUGREPORT", path,
1485 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1489 am_args.push_back("--es");
1490 am_args.push_back("android.intent.extra.SCREENSHOT");
1491 am_args.push_back(screenshot_path);
1493 if (is_remote_mode) {
1494 am_args.push_back("--es");
1495 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1496 am_args.push_back(SHA256_file_hash(path));
1497 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1499 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1502 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1506 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1509 if (is_redirecting) {
1513 if (use_control_socket && control_socket_fd != -1) {
1514 MYLOGD("Closing control socket\n");
1515 close(control_socket_fd);