• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #include <dirent.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <limits.h>
22 #include <memory>
23 #include <regex>
24 #include <set>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string>
29 #include <string.h>
30 #include <sys/prctl.h>
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36 
37 #include <android-base/file.h>
38 #include <android-base/stringprintf.h>
39 #include <android-base/strings.h>
40 #include <cutils/properties.h>
41 
42 #include "private/android_filesystem_config.h"
43 
44 #define LOG_TAG "dumpstate"
45 #include <cutils/log.h>
46 
47 #include "dumpstate.h"
48 #include "ScopedFd.h"
49 #include "ziparchive/zip_writer.h"
50 
51 #include "mincrypt/sha256.h"
52 
53 using android::base::StringPrintf;
54 
55 /* read before root is shed */
56 static char cmdline_buf[16384] = "(unknown)";
57 static const char *dump_traces_path = NULL;
58 
59 // TODO: variables below should be part of dumpstate object
60 static unsigned long id;
61 static char build_type[PROPERTY_VALUE_MAX];
62 static time_t now;
63 static std::unique_ptr<ZipWriter> zip_writer;
64 static std::set<std::string> mount_points;
65 void add_mountinfo();
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;
70 
71 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
72 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
73 
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"
86 
87 typedef struct {
88   char name[TOMBSTONE_MAX_LEN];
89   int fd;
90 } tombstone_data_t;
91 
92 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
93 
94 const std::string ZIP_ROOT_DIR = "FS";
95 std::string bugreport_dir;
96 
97 /*
98  * List of supported zip format versions.
99  *
100  * See bugreport-format.txt for more info.
101  */
102 static std::string VERSION_DEFAULT = "1.0";
103 
is_user_build()104 bool is_user_build() {
105     return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
106 }
107 
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. */
get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES])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));
116         struct stat st;
117         if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
118             (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
119         data[i].fd = fd;
120         } else {
121         close(fd);
122             data[i].fd = -1;
123         }
124     }
125 }
126 
127 // for_each_pid() callback to get mount info about a process.
do_mountinfo(int pid,const char * name)128 void do_mountinfo(int pid, const char *name) {
129     char path[PATH_MAX];
130 
131     // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
132     // are added.
133     snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
134     char linkname[PATH_MAX];
135     ssize_t r = readlink(path, linkname, PATH_MAX);
136     if (r == -1) {
137         MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
138         return;
139     }
140     linkname[r] = '\0';
141 
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);
147         } else {
148             MYLOGE("Unable to add mountinfo %s to zip file\n", path);
149         }
150     }
151 }
152 
add_mountinfo()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());
160 }
161 
dump_dev_files(const char * title,const char * driverpath,const char * filename)162 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
163 {
164     DIR *d;
165     struct dirent *de;
166     char path[PATH_MAX];
167 
168     d = opendir(driverpath);
169     if (d == NULL) {
170         return;
171     }
172 
173     while ((de = readdir(d))) {
174         if (de->d_type != DT_LNK) {
175             continue;
176         }
177         snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
178         dump_file(title, path);
179     }
180 
181     closedir(d);
182 }
183 
184 // return pid of a userspace process. If not found or error, return 0.
pid_of_process(const char * ps_name)185 static unsigned int pid_of_process(const char* ps_name) {
186     DIR *proc_dir;
187     struct dirent *ps;
188     unsigned int pid;
189     std::string cmdline;
190 
191     if (!(proc_dir = opendir("/proc"))) {
192         MYLOGE("Can't open /proc\n");
193         return 0;
194     }
195 
196     while ((ps = readdir(proc_dir))) {
197         if (!(pid = atoi(ps->d_name))) {
198             continue;
199         }
200         android::base::ReadFileToString("/proc/"
201                 + std::string(ps->d_name) + "/cmdline", &cmdline);
202         if (cmdline.find(ps_name) == std::string::npos) {
203             continue;
204         } else {
205             closedir(proc_dir);
206             return pid;
207         }
208     }
209     closedir(proc_dir);
210     return 0;
211 }
212 
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.
dump_anrd_trace()217 static bool dump_anrd_trace() {
218     unsigned int pid;
219     char buf[50], path[PATH_MAX];
220     struct dirent *trace;
221     struct stat st;
222     DIR *trace_dir;
223     int retry = 5;
224     long max_ctime = 0, old_mtime;
225     long long cur_size = 0;
226     const char *trace_path = "/data/misc/anrd/";
227 
228     if (!zip_writer) {
229         MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
230         return false;
231     }
232 
233     // find anrd's pid if it is running.
234     pid = pid_of_process("/system/xbin/anrd");
235 
236     if (pid > 0) {
237         if (stat(trace_path, &st) == 0) {
238             old_mtime = st.st_mtime;
239         } else {
240             MYLOGE("Failed to find: %s\n", trace_path);
241             return false;
242         }
243 
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");
248             return false;
249         }
250 
251         while (retry-- > 0 && old_mtime == st.st_mtime) {
252             sleep(1);
253             stat(trace_path, &st);
254         }
255 
256         if (retry < 0 && old_mtime == st.st_mtime) {
257             MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
258             return false;
259         }
260 
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);
264         }
265         while ((trace = readdir(trace_dir))) {
266             if (strcmp(trace->d_name, ".") == 0
267                     || strcmp(trace->d_name, "..") == 0) {
268                 continue;
269             }
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);
275                 }
276             }
277         }
278         closedir(trace_dir);
279 
280         // Wait until the dump completes by checking the size of the trace.
281         if (max_ctime > 0) {
282             sprintf(path, "%s%s", trace_path, buf);
283             while(true) {
284                 sleep(1);
285                 if (stat(path, &st) == 0) {
286                     if (st.st_size == cur_size) {
287                         break;
288                     } else if (st.st_size > cur_size) {
289                         cur_size = st.st_size;
290                     } else {
291                         return false;
292                     }
293                 } else {
294                     MYLOGE("Cant stat() %s anymore\n", path);
295                     return false;
296                 }
297             }
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);
301             } else {
302                 if (remove(path)) {
303                     MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
304                 }
305                 return true;
306             }
307         } else {
308             MYLOGE("Can't stats any trace file under %s\n", trace_path);
309         }
310     }
311     return false;
312 }
313 
dump_systrace()314 static void dump_systrace() {
315     if (!is_zipping()) {
316         MYLOGD("Not dumping systrace because dumpstate is not zipping\n");
317         return;
318     }
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");
322         return;
323     }
324     const char* path = "/sys/kernel/debug/tracing/tracing_on";
325     long int is_tracing;
326     if (read_file_as_long(path, &is_tracing)) {
327         return; // error already logged
328     }
329     if (is_tracing <= 0) {
330         MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
331         return;
332     }
333 
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 ");
344         //        }
345     }
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());
348     } else {
349         if (remove(systrace_path.c_str())) {
350             MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
351         }
352     }
353 }
354 
dump_raft()355 static void dump_raft() {
356     if (is_user_build()) {
357         return;
358     }
359 
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");
363         return;
364     }
365 
366     struct stat s;
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);
369         return;
370     }
371 
372     if (!is_zipping()) {
373         // Write compressed and encoded raft logs to stdout if not zip_writer.
374         run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
375         return;
376     }
377 
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());
382     } else {
383         if (remove(raft_log_path.c_str())) {
384             MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
385         }
386     }
387 }
388 
389 /**
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
392  */
get_last_modified_file_matching_prefix(const std::string & dir,const std::string & file_prefix)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);
396     if (d == nullptr) {
397         MYLOGD("Error %d opening %s\n", errno, dir.c_str());
398         return "";
399     }
400 
401     // Find the newest file matching the file_prefix in dir
402     struct dirent *de;
403     time_t last_modified = 0;
404     std::string last_modified_file = "";
405     struct stat s;
406 
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;
411         }
412         file = dir + "/" + file;
413         int ret = stat(file.c_str(), &s);
414 
415         if ((ret == 0) && (s.st_mtime > last_modified)) {
416             last_modified_file = file;
417             last_modified = s.st_mtime;
418         }
419     }
420 
421     return last_modified_file;
422 }
423 
dump_modem_logs()424 void dump_modem_logs() {
425     DurationReporter duration_reporter("dump_modem_logs");
426     if (is_user_build()) {
427         return;
428     }
429 
430     if (!is_zipping()) {
431         MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
432         return;
433     }
434 
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");
440         return;
441     }
442 
443     MYLOGD("dump_modem_logs: directory is %s and file_prefix is %s\n",
444            bugreport_dir.c_str(), file_prefix.c_str());
445 
446     std::string modem_log_file =
447         get_last_modified_file_matching_prefix(bugreport_dir, file_prefix);
448 
449     struct stat s;
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());
452         return;
453     }
454 
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());
458     } else {
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());
462         }
463     }
464 }
465 
skip_not_stat(const char * path)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? */
470         return false;
471     }
472     return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
473 }
474 
skip_none(const char * path)475 static bool skip_none(const char *path) {
476     return false;
477 }
478 
479 static const char mmcblk0[] = "/sys/block/mmcblk0/";
480 unsigned long worst_write_perf = 20000; /* in KB/s */
481 
482 //
483 //  stat offsets
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
509 //
510 // read I/Os, write I/Os
511 // =====================
512 //
513 // These values increment when an I/O request completes.
514 //
515 // read merges, write merges
516 // =========================
517 //
518 // These values increment when an I/O request is merged with an
519 // already-queued I/O request.
520 //
521 // read sectors, write sectors
522 // ===========================
523 //
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
529 //
530 // read ticks, write ticks
531 // =======================
532 //
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.
538 //
539 // in_flight
540 // =========
541 //
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.
545 //
546 // io_ticks
547 // ========
548 //
549 // This value counts the number of milliseconds during which the device has
550 // had I/O requests queued.
551 //
552 // time_in_queue
553 // =============
554 //
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).
559 #define S_TO_MS 1000
560 //
561 
dump_stat_from_fd(const char * title __unused,const char * path,int fd)562 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
563     unsigned long long fields[__STAT_NUMBER_FIELD];
564     bool z;
565     char *cp, *buffer = NULL;
566     size_t i = 0;
567     FILE *fp = fdopen(fd, "rb");
568     getline(&buffer, &i, fp);
569     fclose(fp);
570     if (!buffer) {
571         return -errno;
572     }
573     i = strlen(buffer);
574     while ((i > 0) && (buffer[i - 1] == '\n')) {
575         buffer[--i] = '\0';
576     }
577     if (!*buffer) {
578         free(buffer);
579         return 0;
580     }
581     z = true;
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) {
585             z = false;
586         }
587     }
588     if (z) { /* never accessed */
589         free(buffer);
590         return 0;
591     }
592 
593     if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
594         path += sizeof(mmcblk0) - 1;
595     }
596 
597     printf("%s: %s\n", path, buffer);
598     free(buffer);
599 
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))
609                                         / divisor;
610             read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
611                            * fields[__STAT_IN_QUEUE] + (divisor >> 1))
612                                         / divisor;
613         }
614 
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))
623                                         / divisor;
624             write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
625                            * fields[__STAT_IN_QUEUE] + (divisor >> 1))
626                                         / divisor;
627         }
628 
629         unsigned queue = (fields[__STAT_IN_QUEUE]
630                              + (fields[__STAT_IO_TICKS] >> 1))
631                                  / fields[__STAT_IO_TICKS];
632 
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);
636         } else {
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);
639         }
640 
641         /* bugreport timeout factor adjustment */
642         if ((write_perf > 1) && (write_perf < worst_write_perf)) {
643             worst_write_perf = write_perf;
644         }
645     }
646     return 0;
647 }
648 
649 /* Copied policy from system/core/logd/LogBuffer.cpp */
650 
651 #define LOG_BUFFER_SIZE (256 * 1024)
652 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
653 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
654 
valid_size(unsigned long value)655 static bool valid_size(unsigned long value) {
656     if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
657         return false;
658     }
659 
660     long pages = sysconf(_SC_PHYS_PAGES);
661     if (pages < 1) {
662         return true;
663     }
664 
665     long pagesize = sysconf(_SC_PAGESIZE);
666     if (pagesize <= 1) {
667         pagesize = PAGE_SIZE;
668     }
669 
670     // maximum memory impact a somewhat arbitrary ~3%
671     pages = (pages + 31) / 32;
672     unsigned long maximum = pages * pagesize;
673 
674     if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
675         return true;
676     }
677 
678     return value <= maximum;
679 }
680 
property_get_size(const char * key)681 static unsigned long property_get_size(const char *key) {
682     unsigned long value;
683     char *cp, property[PROPERTY_VALUE_MAX];
684 
685     property_get(key, property, "");
686     value = strtoul(property, &cp, 10);
687 
688     switch(*cp) {
689     case 'm':
690     case 'M':
691         value *= 1024;
692     /* FALLTHRU */
693     case 'k':
694     case 'K':
695         value *= 1024;
696     /* FALLTHRU */
697     case '\0':
698         break;
699 
700     default:
701         value = 0;
702     }
703 
704     if (!valid_size(value)) {
705         value = 0;
706     }
707 
708     return value;
709 }
710 
711 /* timeout in ms */
logcat_timeout(const char * name)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;
717 
718     default_size = property_get_size(global_tuneable);
719     if (!default_size) {
720         default_size = property_get_size(global_default);
721     }
722 
723     snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
724     property_size = property_get_size(key);
725 
726     if (!property_size) {
727         snprintf(key, sizeof(key), "%s.%s", global_default, name);
728         property_size = property_get_size(key);
729     }
730 
731     if (!property_size) {
732         property_size = default_size;
733     }
734 
735     if (!property_size) {
736         property_size = LOG_BUFFER_SIZE;
737     }
738 
739     /* Engineering margin is ten-fold our guess */
740     return 10 * (property_size + worst_write_perf) / worst_write_perf;
741 }
742 
743 /* End copy from system/core/logd/LogBuffer.cpp */
744 
745 /* dumps the current system state to stdout */
print_header(std::string version)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];
750 
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));
758 
759     printf("========================================================\n");
760     printf("== dumpstate: %s\n", date);
761     printf("========================================================\n");
762 
763     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);
769 
770     printf("Kernel: ");
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());
775     printf("\n");
776 }
777 
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"
784 };
785 
add_zip_entry_from_fd(const std::string & entry_name,int fd)786 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
787     if (!is_zipping()) {
788         MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
789                 entry_name.c_str());
790         return false;
791     }
792     std::string valid_name = entry_name;
793 
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());
802         }
803     }
804 
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));
809     if (err) {
810         MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
811                 ZipWriter::ErrorCodeString(err));
812         return false;
813     }
814 
815     std::vector<uint8_t> buffer(65536);
816     while (1) {
817         ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
818         if (bytes_read == 0) {
819             break;
820         } else if (bytes_read == -1) {
821             MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
822             return false;
823         }
824         err = zip_writer->WriteBytes(buffer.data(), bytes_read);
825         if (err) {
826             MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
827             return false;
828         }
829     }
830 
831     err = zip_writer->FinishEntry();
832     if (err) {
833         MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
834         return false;
835     }
836 
837     return true;
838 }
839 
add_zip_entry(const std::string & entry_name,const std::string & entry_path)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));
844         return false;
845     }
846 
847     return add_zip_entry_from_fd(entry_name, fd.get());
848 }
849 
850 /* adds a file to the existing zipped bugreport */
_add_file_from_fd(const char * title,const char * path,int fd)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;
853 }
854 
855 // TODO: move to util.cpp
add_dir(const char * dir,bool recursive)856 void add_dir(const char *dir, bool recursive) {
857     if (!is_zipping()) {
858         MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
859         return;
860     }
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);
864 }
865 
is_zipping()866 bool is_zipping() {
867     return zip_writer != nullptr;
868 }
869 
870 /* adds a text entry entry to the existing zip file. */
add_text_zip_entry(const std::string & entry_name,const std::string & content)871 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
872     if (!is_zipping()) {
873         MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
874         return false;
875     }
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);
878     if (err) {
879         MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
880                 ZipWriter::ErrorCodeString(err));
881         return false;
882     }
883 
884     err = zip_writer->WriteBytes(content.c_str(), content.length());
885     if (err) {
886         MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
887                 ZipWriter::ErrorCodeString(err));
888         return false;
889     }
890 
891     err = zip_writer->FinishEntry();
892     if (err) {
893         MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
894         return false;
895     }
896 
897     return true;
898 }
899 
dump_iptables()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);
904     /* no ip6 nat */
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);
909 }
910 
do_kmsg()911 static void do_kmsg() {
912     struct stat st;
913     if (!stat(PSTORE_LAST_KMSG, &st)) {
914         /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
915         dump_file("LAST KMSG", PSTORE_LAST_KMSG);
916     } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
917         dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
918     } else {
919         /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
920         dump_file("LAST KMSG", "/proc/last_kmsg");
921     }
922 }
923 
do_logcat()924 static void do_logcat() {
925     unsigned long timeout;
926     // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
927     // calculate timeout
928     timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
929     if (timeout < 20000) {
930         timeout = 20000;
931     }
932     run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
933                                                         "-v", "printable",
934                                                         "-d",
935                                                         "*:v", NULL);
936     timeout = logcat_timeout("events");
937     if (timeout < 20000) {
938         timeout = 20000;
939     }
940     run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
941                                                        "-v", "threadtime",
942                                                        "-v", "printable",
943                                                        "-d",
944                                                        "*:v", NULL);
945     timeout = logcat_timeout("radio");
946     if (timeout < 20000) {
947         timeout = 20000;
948     }
949     run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
950                                                        "-v", "threadtime",
951                                                        "-v", "printable",
952                                                        "-d",
953                                                        "*:v", NULL);
954 
955     run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
956 
957     /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
958     run_command("LAST LOGCAT", 10, "logcat", "-L",
959                                              "-b", "all",
960                                              "-v", "threadtime",
961                                              "-v", "printable",
962                                              "-d",
963                                              "*:v", NULL);
964 }
965 
dumpstate(const std::string & screenshot_path,const std::string & version)966 static void dumpstate(const std::string& screenshot_path, const std::string& version) {
967     DurationReporter duration_reporter("DUMPSTATE");
968 
969     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
970     run_command("UPTIME", 10, "uptime", NULL);
971     dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
972     dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
973     dump_file("MEMORY INFO", "/proc/meminfo");
974     run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
975     run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
976     dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
977     dump_file("VMALLOC INFO", "/proc/vmallocinfo");
978     dump_file("SLAB INFO", "/proc/slabinfo");
979     dump_file("ZONEINFO", "/proc/zoneinfo");
980     dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
981     dump_file("BUDDYINFO", "/proc/buddyinfo");
982     dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
983 
984     dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
985     dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
986     dump_file("KERNEL SYNC", "/d/sync");
987 
988     run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
989     run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
990 
991     run_command("PRINTENV", 10, "printenv", NULL);
992     run_command("NETSTAT", 10, "netstat", "-n", NULL);
993     run_command("LSMOD", 10, "lsmod", NULL);
994 
995     do_dmesg();
996 
997     run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
998     for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
999     for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
1000     for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
1001 
1002     /* Dump Bluetooth HCI logs */
1003     add_dir("/data/misc/bluetooth/logs", true);
1004 
1005     if (!screenshot_path.empty()) {
1006         MYLOGI("taking late screenshot\n");
1007         take_screenshot(screenshot_path);
1008         MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1009     }
1010 
1011     do_logcat();
1012 
1013     /* show the traces we collected in main(), if that was done */
1014     if (dump_traces_path != NULL) {
1015         dump_file("VM TRACES JUST NOW", dump_traces_path);
1016     }
1017 
1018     /* only show ANR traces if they're less than 15 minutes old */
1019     struct stat st;
1020     char anr_traces_path[PATH_MAX];
1021     property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
1022     if (!anr_traces_path[0]) {
1023         printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
1024     } else {
1025       int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
1026                                        O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
1027       if (fd < 0) {
1028           printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
1029       } else {
1030           dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
1031       }
1032     }
1033 
1034     /* slow traces for slow operations */
1035     if (anr_traces_path[0] != 0) {
1036         int tail = strlen(anr_traces_path)-1;
1037         while (tail > 0 && anr_traces_path[tail] != '/') {
1038             tail--;
1039         }
1040         int i = 0;
1041         while (1) {
1042             sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
1043             if (stat(anr_traces_path, &st)) {
1044                 // No traces file at this index, done with the files.
1045                 break;
1046             }
1047             dump_file("VM TRACES WHEN SLOW", anr_traces_path);
1048             i++;
1049         }
1050     }
1051 
1052     int dumped = 0;
1053     for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
1054         if (tombstone_data[i].fd != -1) {
1055             const char *name = tombstone_data[i].name;
1056             int fd = tombstone_data[i].fd;
1057             dumped = 1;
1058             if (zip_writer) {
1059                 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
1060                     MYLOGE("Unable to add tombstone %s to zip file\n", name);
1061                 }
1062             } else {
1063                 dump_file_from_fd("TOMBSTONE", name, fd);
1064             }
1065             close(fd);
1066             tombstone_data[i].fd = -1;
1067         }
1068     }
1069     if (!dumped) {
1070         printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1071     }
1072 
1073     dump_file("NETWORK DEV INFO", "/proc/net/dev");
1074     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1075     dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1076     dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1077     dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1078 
1079     do_kmsg();
1080 
1081     /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1082 
1083     run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
1084 
1085     run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
1086     run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
1087 
1088     run_command("IP RULES", 10, "ip", "rule", "show", NULL);
1089     run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
1090 
1091     dump_route_tables();
1092 
1093     run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1094     run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
1095     run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
1096     run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
1097 
1098 #ifdef FWDUMP_bcmdhd
1099     run_command("ND OFFLOAD TABLE", 5,
1100             SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
1101 
1102     run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
1103             SU_PATH, "root", WLUTIL, "counters", NULL);
1104 
1105     run_command("ND OFFLOAD STATUS (1)", 5,
1106             SU_PATH, "root", WLUTIL, "nd_status", NULL);
1107 
1108 #endif
1109     dump_file("INTERRUPTS (1)", "/proc/interrupts");
1110 
1111     run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
1112 
1113 #ifdef FWDUMP_bcmdhd
1114     run_command("DUMP WIFI STATUS", 20,
1115             SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
1116 
1117     run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
1118             SU_PATH, "root", WLUTIL, "counters", NULL);
1119 
1120     run_command("ND OFFLOAD STATUS (2)", 5,
1121             SU_PATH, "root", WLUTIL, "nd_status", NULL);
1122 #endif
1123     dump_file("INTERRUPTS (2)", "/proc/interrupts");
1124 
1125     print_properties();
1126 
1127     run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1128     run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1129 
1130     run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
1131 
1132     run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1133 
1134     printf("------ BACKLIGHTS ------\n");
1135     printf("LCD brightness=");
1136     dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1137     printf("Button brightness=");
1138     dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1139     printf("Keyboard brightness=");
1140     dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1141     printf("ALS mode=");
1142     dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1143     printf("LCD driver registers:\n");
1144     dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1145     printf("\n");
1146 
1147     /* Binder state is expensive to look at as it uses a lot of memory. */
1148     dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1149     dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1150     dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1151     dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1152     dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1153 
1154     printf("========================================================\n");
1155     printf("== Board\n");
1156     printf("========================================================\n");
1157 
1158     dumpstate_board();
1159     printf("\n");
1160 
1161     /* Migrate the ril_dumpstate to a dumpstate_board()? */
1162     char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1163     property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1164     if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
1165         if (is_user_build()) {
1166             // su does not exist on user builds, so try running without it.
1167             // This way any implementations of vril-dump that do not require
1168             // root can run on user builds.
1169             run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1170                     "vril-dump", NULL);
1171         } else {
1172             run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1173                     SU_PATH, "root", "vril-dump", NULL);
1174         }
1175     }
1176 
1177     printf("========================================================\n");
1178     printf("== Android Framework Services\n");
1179     printf("========================================================\n");
1180 
1181     run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
1182 
1183     printf("========================================================\n");
1184     printf("== Checkins\n");
1185     printf("========================================================\n");
1186 
1187     run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1188     run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1189     run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1190     run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1191     run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1192     run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
1193 
1194     printf("========================================================\n");
1195     printf("== Running Application Activities\n");
1196     printf("========================================================\n");
1197 
1198     run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
1199 
1200     printf("========================================================\n");
1201     printf("== Running Application Services\n");
1202     printf("========================================================\n");
1203 
1204     run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
1205 
1206     printf("========================================================\n");
1207     printf("== Running Application Providers\n");
1208     printf("========================================================\n");
1209 
1210     run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
1211 
1212     // dump_modem_logs adds the modem logs if available to the bugreport.
1213     // Do this at the end to allow for sufficient time for the modem logs to be
1214     // collected.
1215     dump_modem_logs();
1216 
1217     printf("========================================================\n");
1218     printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1219             getpid(), progress, weight_total, WEIGHT_TOTAL);
1220     printf("========================================================\n");
1221     printf("== dumpstate: done\n");
1222     printf("========================================================\n");
1223 }
1224 
usage()1225 static void usage() {
1226   fprintf(stderr,
1227           "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-t]"
1228           "[-z] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1229           "  -h: display this help message\n"
1230           "  -b: play sound file instead of vibrate, at beginning of job\n"
1231           "  -e: play sound file instead of vibrate, at end of job\n"
1232           "  -o: write to file (instead of stdout)\n"
1233           "  -d: append date to filename (requires -o)\n"
1234           "  -p: capture screenshot to filename.png (requires -o)\n"
1235           "  -t: only captures telephony sections\n"
1236           "  -z: generate zipped file (requires -o)\n"
1237           "  -s: write output to control socket (for init)\n"
1238           "  -S: write file location to control socket (for init; requires -o and -z)"
1239           "  -q: disable vibrate\n"
1240           "  -B: send broadcast when finished (requires -o)\n"
1241           "  -P: send broadcast when started and update system properties on "
1242           "progress (requires -o and -B)\n"
1243           "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1244           "shouldn't be used with -P)\n"
1245           "  -V: sets the bugreport format version (valid values: %s)\n",
1246           VERSION_DEFAULT.c_str());
1247 }
1248 
sigpipe_handler(int n)1249 static void sigpipe_handler(int n) {
1250     // don't complain to stderr or stdout
1251     _exit(EXIT_FAILURE);
1252 }
1253 
1254 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1255    temporary file.
1256  */
finish_zip_file(const std::string & bugreport_name,const std::string & bugreport_path,time_t now)1257 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1258         time_t now) {
1259     if (!add_zip_entry(bugreport_name, bugreport_path)) {
1260         MYLOGE("Failed to add text entry to .zip file\n");
1261         return false;
1262     }
1263     if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1264         MYLOGE("Failed to add main_entry.txt to .zip file\n");
1265         return false;
1266     }
1267 
1268     int32_t err = zip_writer->Finish();
1269     if (err) {
1270         MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1271         return false;
1272     }
1273 
1274     if (is_user_build()) {
1275         MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1276         if (remove(bugreport_path.c_str())) {
1277             ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1278         }
1279     } else {
1280         MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1281     }
1282 
1283     return true;
1284 }
1285 
SHA256_file_hash(std::string filepath)1286 static std::string SHA256_file_hash(std::string filepath) {
1287     ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1288             | O_NOFOLLOW)));
1289     if (fd.get() == -1) {
1290         MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1291         return NULL;
1292     }
1293 
1294     SHA256_CTX ctx;
1295     SHA256_init(&ctx);
1296 
1297     std::vector<uint8_t> buffer(65536);
1298     while (1) {
1299         ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1300         if (bytes_read == 0) {
1301             break;
1302         } else if (bytes_read == -1) {
1303             MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1304             return NULL;
1305         }
1306 
1307         SHA256_update(&ctx, buffer.data(), bytes_read);
1308     }
1309 
1310     uint8_t hash[SHA256_DIGEST_SIZE];
1311     memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1312     char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1313     for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1314         sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1315     }
1316     hash_buffer[sizeof(hash_buffer) - 1] = 0;
1317     return std::string(hash_buffer);
1318 }
1319 
main(int argc,char * argv[])1320 int main(int argc, char *argv[]) {
1321     struct sigaction sigact;
1322     int do_add_date = 0;
1323     int do_zip_file = 0;
1324     int do_vibrate = 1;
1325     char* use_outfile = 0;
1326     int use_socket = 0;
1327     int use_control_socket = 0;
1328     int do_fb = 0;
1329     int do_broadcast = 0;
1330     int do_early_screenshot = 0;
1331     int is_remote_mode = 0;
1332     bool telephony_only = false;
1333 
1334     std::string version = VERSION_DEFAULT;
1335 
1336     now = time(NULL);
1337 
1338     MYLOGI("begin\n");
1339 
1340     /* gets the sequential id */
1341     char last_id[PROPERTY_VALUE_MAX];
1342     property_get("dumpstate.last_id", last_id, "0");
1343     id = strtoul(last_id, NULL, 10) + 1;
1344     snprintf(last_id, sizeof(last_id), "%lu", id);
1345     property_set("dumpstate.last_id", last_id);
1346     MYLOGI("dumpstate id: %lu\n", id);
1347 
1348     /* clear SIGPIPE handler */
1349     memset(&sigact, 0, sizeof(sigact));
1350     sigact.sa_handler = sigpipe_handler;
1351     sigaction(SIGPIPE, &sigact, NULL);
1352 
1353     /* set as high priority, and protect from OOM killer */
1354     setpriority(PRIO_PROCESS, 0, -20);
1355 
1356     FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1357     if (oom_adj) {
1358         fputs("-1000", oom_adj);
1359         fclose(oom_adj);
1360     } else {
1361         /* fallback to kernels <= 2.6.35 */
1362         oom_adj = fopen("/proc/self/oom_adj", "we");
1363         if (oom_adj) {
1364             fputs("-17", oom_adj);
1365             fclose(oom_adj);
1366         }
1367     }
1368 
1369     /* parse arguments */
1370     std::string args;
1371     format_args(argc, const_cast<const char **>(argv), &args);
1372     MYLOGD("Dumpstate command line: %s\n", args.c_str());
1373     int c;
1374     while ((c = getopt(argc, argv, "dho:svqzptPBRSV:")) != -1) {
1375         switch (c) {
1376             case 'd': do_add_date = 1;          break;
1377             case 't': telephony_only = true;    break;
1378             case 'z': do_zip_file = 1;          break;
1379             case 'o': use_outfile = optarg;     break;
1380             case 's': use_socket = 1;           break;
1381             case 'S': use_control_socket = 1;   break;
1382             case 'v': break;  // compatibility no-op
1383             case 'q': do_vibrate = 0;           break;
1384             case 'p': do_fb = 1;                break;
1385             case 'P': do_update_progress = 1;   break;
1386             case 'R': is_remote_mode = 1;       break;
1387             case 'B': do_broadcast = 1;         break;
1388             case 'V': version = optarg;         break;
1389             case '?': printf("\n");
1390             case 'h':
1391                 usage();
1392                 exit(1);
1393         }
1394     }
1395 
1396     if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1397         usage();
1398         exit(1);
1399     }
1400 
1401     if (use_control_socket && !do_zip_file) {
1402         usage();
1403         exit(1);
1404     }
1405 
1406     if (do_update_progress && !do_broadcast) {
1407         usage();
1408         exit(1);
1409     }
1410 
1411     if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1412         usage();
1413         exit(1);
1414     }
1415 
1416     if (version != VERSION_DEFAULT) {
1417       usage();
1418       exit(1);
1419     }
1420 
1421     MYLOGI("bugreport format version: %s\n", version.c_str());
1422 
1423     do_early_screenshot = do_update_progress;
1424 
1425     // If we are going to use a socket, do it as early as possible
1426     // to avoid timeouts from bugreport.
1427     if (use_socket) {
1428         redirect_to_socket(stdout, "dumpstate");
1429     }
1430 
1431     if (use_control_socket) {
1432         MYLOGD("Opening control socket\n");
1433         control_socket_fd = open_socket("dumpstate");
1434         do_update_progress = 1;
1435     }
1436 
1437     /* full path of the temporary file containing the bugreport */
1438     std::string tmp_path;
1439 
1440     /* full path of the file containing the dumpstate logs*/
1441     std::string log_path;
1442 
1443     /* full path of the systrace file, when enabled */
1444     std::string systrace_path;
1445 
1446     /* full path of the temporary file containing the screenshot (when requested) */
1447     std::string screenshot_path;
1448 
1449     /* base name (without suffix or extensions) of the bugreport files */
1450     std::string base_name;
1451 
1452     /* pointer to the actual path, be it zip or text */
1453     std::string path;
1454 
1455     /* pointer to the zipped file */
1456     std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1457 
1458     /* redirect output if needed */
1459     bool is_redirecting = !use_socket && use_outfile;
1460 
1461     if (is_redirecting) {
1462         bugreport_dir = dirname(use_outfile);
1463         base_name = basename(use_outfile);
1464         if (do_add_date) {
1465             char date[80];
1466             strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1467             suffix = date;
1468         } else {
1469             suffix = "undated";
1470         }
1471         char build_id[PROPERTY_VALUE_MAX];
1472         property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1473         base_name = base_name + "-" + build_id;
1474         if (telephony_only) {
1475             base_name = base_name + "-telephony";
1476         }
1477         if (do_fb) {
1478             // TODO: if dumpstate was an object, the paths could be internal variables and then
1479             // we could have a function to calculate the derived values, such as:
1480             //     screenshot_path = GetPath(".png");
1481             screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1482         }
1483         tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1484         log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1485                 + std::to_string(getpid()) + ".txt";
1486 
1487         MYLOGD("Bugreport dir: %s\n"
1488                 "Base name: %s\n"
1489                 "Suffix: %s\n"
1490                 "Log path: %s\n"
1491                 "Temporary path: %s\n"
1492                 "Screenshot path: %s\n",
1493                 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1494                 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1495 
1496         if (do_zip_file) {
1497             path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1498             MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1499             create_parent_dirs(path.c_str());
1500             zip_file.reset(fopen(path.c_str(), "wb"));
1501             if (!zip_file) {
1502                 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1503                 do_zip_file = 0;
1504             } else {
1505                 zip_writer.reset(new ZipWriter(zip_file.get()));
1506             }
1507             add_text_zip_entry("version.txt", version);
1508         }
1509 
1510         if (do_update_progress) {
1511             if (do_broadcast) {
1512                 // clang-format off
1513                 std::vector<std::string> am_args = {
1514                      "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1515                      "--es", "android.intent.extra.NAME", suffix,
1516                      "--ei", "android.intent.extra.ID", std::to_string(id),
1517                      "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1518                      "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1519                 };
1520                 // clang-format on
1521                 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1522             }
1523             if (use_control_socket) {
1524                 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1525             }
1526         }
1527     }
1528 
1529     /* read /proc/cmdline before dropping root */
1530     FILE *cmdline = fopen("/proc/cmdline", "re");
1531     if (cmdline) {
1532         fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1533         fclose(cmdline);
1534     }
1535 
1536     /* open the vibrator before dropping root */
1537     std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1538     if (do_vibrate) {
1539         vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1540         if (vibrator) {
1541             vibrate(vibrator.get(), 150);
1542         }
1543     }
1544 
1545     if (do_fb && do_early_screenshot) {
1546         if (screenshot_path.empty()) {
1547             // should not have happened
1548             MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1549         } else {
1550             MYLOGI("taking early screenshot\n");
1551             take_screenshot(screenshot_path);
1552             MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1553             if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1554                 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1555                         screenshot_path.c_str(), strerror(errno));
1556             }
1557         }
1558     }
1559 
1560     if (do_zip_file) {
1561         if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1562             MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1563         }
1564     }
1565 
1566     if (is_redirecting) {
1567         redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1568         if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1569             MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1570                     log_path.c_str(), strerror(errno));
1571         }
1572         /* TODO: rather than generating a text file now and zipping it later,
1573            it would be more efficient to redirect stdout to the zip entry
1574            directly, but the libziparchive doesn't support that option yet. */
1575         redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1576         if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1577             MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1578                     tmp_path.c_str(), strerror(errno));
1579         }
1580     }
1581     // NOTE: there should be no stdout output until now, otherwise it would break the header.
1582     // In particular, DurationReport objects should be created passing 'title, NULL', so their
1583     // duration is logged into MYLOG instead.
1584     print_header(version);
1585 
1586     if (telephony_only) {
1587         dump_iptables();
1588         if (!drop_root_user()) {
1589             return -1;
1590         }
1591         do_dmesg();
1592         do_logcat();
1593         do_kmsg();
1594         dumpstate_board();
1595         dump_modem_logs();
1596     } else {
1597         // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1598         // First try to dump anrd trace if the daemon is running. Otherwise, dump
1599         // the raw trace.
1600         if (!dump_anrd_trace()) {
1601             dump_systrace();
1602         }
1603 
1604         // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1605         dump_raft();
1606 
1607         // Invoking the following dumpsys calls before dump_traces() to try and
1608         // keep the system stats as close to its initial state as possible.
1609         run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1610         run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1611 
1612         /* collect stack traces from Dalvik and native processes (needs root) */
1613         dump_traces_path = dump_traces();
1614 
1615         /* Run some operations that require root. */
1616         get_tombstone_fds(tombstone_data);
1617         add_dir(RECOVERY_DIR, true);
1618         add_dir(RECOVERY_DATA_DIR, true);
1619         add_dir(LOGPERSIST_DATA_DIR, false);
1620         if (!is_user_build()) {
1621             add_dir(PROFILE_DATA_DIR_CUR, true);
1622             add_dir(PROFILE_DATA_DIR_REF, true);
1623         }
1624         add_mountinfo();
1625         dump_iptables();
1626 
1627         // Capture any IPSec policies in play.  No keys are exposed here.
1628         run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
1629 
1630         // Run ss as root so we can see socket marks.
1631         run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1632 
1633         if (!drop_root_user()) {
1634             return -1;
1635         }
1636 
1637         dumpstate(do_early_screenshot ? "": screenshot_path, version);
1638     }
1639 
1640     /* close output if needed */
1641     if (is_redirecting) {
1642         fclose(stdout);
1643     }
1644 
1645     /* rename or zip the (now complete) .tmp file to its final location */
1646     if (use_outfile) {
1647 
1648         /* check if user changed the suffix using system properties */
1649         char key[PROPERTY_KEY_MAX];
1650         char value[PROPERTY_VALUE_MAX];
1651         snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1652         property_get(key, value, "");
1653         bool change_suffix= false;
1654         if (value[0]) {
1655             /* must whitelist which characters are allowed, otherwise it could cross directories */
1656             std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1657             if (std::regex_match(value, valid_regex)) {
1658                 change_suffix = true;
1659             } else {
1660                 MYLOGE("invalid suffix provided by user: %s\n", value);
1661             }
1662         }
1663         if (change_suffix) {
1664             MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1665             suffix = value;
1666             if (!screenshot_path.empty()) {
1667                 std::string new_screenshot_path =
1668                         bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1669                 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1670                     MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1671                             new_screenshot_path.c_str(), strerror(errno));
1672                 } else {
1673                     screenshot_path = new_screenshot_path;
1674                 }
1675             }
1676         }
1677 
1678         bool do_text_file = true;
1679         if (do_zip_file) {
1680             std::string entry_name = base_name + "-" + suffix + ".txt";
1681             MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1682             if (!finish_zip_file(entry_name, tmp_path, now)) {
1683                 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1684                 do_text_file = true;
1685             } else {
1686                 do_text_file = false;
1687                 // Since zip file is already created, it needs to be renamed.
1688                 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1689                 if (path != new_path) {
1690                     MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1691                     if (rename(path.c_str(), new_path.c_str())) {
1692                         MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1693                                 new_path.c_str(), strerror(errno));
1694                     } else {
1695                         path = new_path;
1696                     }
1697                 }
1698             }
1699         }
1700         if (do_text_file) {
1701             path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1702             MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1703             if (rename(tmp_path.c_str(), path.c_str())) {
1704                 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1705                 path.clear();
1706             }
1707         }
1708         if (use_control_socket) {
1709             if (do_text_file) {
1710                 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1711                         "for more details\n", log_path.c_str());
1712             } else {
1713                 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1714             }
1715         }
1716     }
1717 
1718     /* vibrate a few but shortly times to let user know it's finished */
1719     if (vibrator) {
1720         for (int i = 0; i < 3; i++) {
1721             vibrate(vibrator.get(), 75);
1722             usleep((75 + 50) * 1000);
1723         }
1724     }
1725 
1726     /* tell activity manager we're done */
1727     if (do_broadcast) {
1728         if (!path.empty()) {
1729             MYLOGI("Final bugreport path: %s\n", path.c_str());
1730             // clang-format off
1731             std::vector<std::string> am_args = {
1732                  "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1733                  "--ei", "android.intent.extra.ID", std::to_string(id),
1734                  "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1735                  "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1736                  "--es", "android.intent.extra.BUGREPORT", path,
1737                  "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1738             };
1739             // clang-format on
1740             if (do_fb) {
1741                 am_args.push_back("--es");
1742                 am_args.push_back("android.intent.extra.SCREENSHOT");
1743                 am_args.push_back(screenshot_path);
1744             }
1745             if (is_remote_mode) {
1746                 am_args.push_back("--es");
1747                 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1748                 am_args.push_back(SHA256_file_hash(path));
1749                 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1750             } else {
1751                 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1752             }
1753         } else {
1754             MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1755         }
1756     }
1757 
1758     MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1759     MYLOGI("done\n");
1760 
1761     if (is_redirecting) {
1762         fclose(stderr);
1763     }
1764 
1765     if (use_control_socket && control_socket_fd != -1) {
1766       MYLOGD("Closing control socket\n");
1767       close(control_socket_fd);
1768     }
1769 
1770     return 0;
1771 }
1772