dumpstate.cpp revision a4ef1f050ce4f4a9976057f1efa34a4ff5ec0ac8
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#define LOG_TAG "dumpstate"
18
19#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <libgen.h>
23#include <limits.h>
24#include <memory>
25#include <regex>
26#include <set>
27#include <stdbool.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string>
31#include <string.h>
32#include <sys/prctl.h>
33#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
37#include <unistd.h>
38
39#include <android-base/file.h>
40#include <android-base/properties.h>
41#include <android-base/stringprintf.h>
42#include <android-base/strings.h>
43#include <android-base/unique_fd.h>
44#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
45#include <cutils/native_handle.h>
46#include <cutils/properties.h>
47#include <openssl/sha.h>
48#include <private/android_filesystem_config.h>
49#include <private/android_logger.h>
50
51#include "DumpstateInternal.h"
52#include "DumpstateService.h"
53#include "dumpstate.h"
54
55using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
56
57// TODO: remove once moved to namespace
58using android::os::dumpstate::CommandOptions;
59using android::os::dumpstate::DumpFileToFd;
60using android::os::dumpstate::PropertiesHelper;
61using android::os::dumpstate::GetPidByName;
62
63/* read before root is shed */
64static char cmdline_buf[16384] = "(unknown)";
65static const char *dump_traces_path = NULL;
66
67// TODO: variables and functions below should be part of dumpstate object
68
69static std::set<std::string> mount_points;
70void add_mountinfo();
71
72#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
73#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
74
75#define RAFT_DIR "/data/misc/raft"
76#define RECOVERY_DIR "/cache/recovery"
77#define RECOVERY_DATA_DIR "/data/misc/recovery"
78#define LOGPERSIST_DATA_DIR "/data/misc/logd"
79#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
80#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
81#define TOMBSTONE_DIR "/data/tombstones"
82#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
83/* Can accomodate a tombstone number up to 9999. */
84#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
85#define NUM_TOMBSTONES  10
86#define WLUTIL "/vendor/xbin/wlutil"
87
88typedef struct {
89  char name[TOMBSTONE_MAX_LEN];
90  int fd;
91} tombstone_data_t;
92
93static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
94
95// TODO: temporary variables and functions used during C++ refactoring
96static Dumpstate& ds = Dumpstate::GetInstance();
97static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
98                      const CommandOptions& options = CommandOptions::DEFAULT) {
99    return ds.RunCommand(title, fullCommand, options);
100}
101static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
102                       const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
103                       long dumpsysTimeout = 0) {
104    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
105}
106static int DumpFile(const std::string& title, const std::string& path) {
107    return ds.DumpFile(title, path);
108}
109
110// Relative directory (inside the zip) for all files copied as-is into the bugreport.
111static const std::string ZIP_ROOT_DIR = "FS";
112
113// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
114static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
115
116static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
117static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
118static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
119
120static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
121
122/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
123 * otherwise, gets just those modified in the last half an hour. */
124static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
125    time_t thirty_minutes_ago = ds.now_ - 60 * 30;
126    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
127        snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
128        int fd = TEMP_FAILURE_RETRY(open(data[i].name,
129                                         O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
130        struct stat st;
131        if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
132            (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
133            data[i].fd = fd;
134        } else {
135            close(fd);
136            data[i].fd = -1;
137        }
138    }
139}
140
141// for_each_pid() callback to get mount info about a process.
142void do_mountinfo(int pid, const char* name __attribute__((unused))) {
143    char path[PATH_MAX];
144
145    // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
146    // are added.
147    snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
148    char linkname[PATH_MAX];
149    ssize_t r = readlink(path, linkname, PATH_MAX);
150    if (r == -1) {
151        MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
152        return;
153    }
154    linkname[r] = '\0';
155
156    if (mount_points.find(linkname) == mount_points.end()) {
157        // First time this mount point was found: add it
158        snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
159        if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
160            mount_points.insert(linkname);
161        } else {
162            MYLOGE("Unable to add mountinfo %s to zip file\n", path);
163        }
164    }
165}
166
167void add_mountinfo() {
168    if (!ds.IsZipping()) return;
169    std::string title = "MOUNT INFO";
170    mount_points.clear();
171    DurationReporter duration_reporter(title, true);
172    for_each_pid(do_mountinfo, nullptr);
173    MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
174}
175
176static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
177{
178    DIR *d;
179    struct dirent *de;
180    char path[PATH_MAX];
181
182    d = opendir(driverpath);
183    if (d == NULL) {
184        return;
185    }
186
187    while ((de = readdir(d))) {
188        if (de->d_type != DT_LNK) {
189            continue;
190        }
191        snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
192        DumpFile(title, path);
193    }
194
195    closedir(d);
196}
197
198
199
200// dump anrd's trace and add to the zip file.
201// 1. check if anrd is running on this device.
202// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
203// 3. wait until the trace generation completes and add to the zip file.
204static bool dump_anrd_trace() {
205    unsigned int pid;
206    char buf[50], path[PATH_MAX];
207    struct dirent *trace;
208    struct stat st;
209    DIR *trace_dir;
210    int retry = 5;
211    long max_ctime = 0, old_mtime;
212    long long cur_size = 0;
213    const char *trace_path = "/data/misc/anrd/";
214
215    if (!ds.IsZipping()) {
216        MYLOGE("Not dumping anrd trace because it's not a zipped bugreport\n");
217        return false;
218    }
219
220    // find anrd's pid if it is running.
221    pid = GetPidByName("/system/xbin/anrd");
222
223    if (pid > 0) {
224        if (stat(trace_path, &st) == 0) {
225            old_mtime = st.st_mtime;
226        } else {
227            MYLOGE("Failed to find: %s\n", trace_path);
228            return false;
229        }
230
231        // send SIGUSR1 to the anrd to generate a trace.
232        sprintf(buf, "%u", pid);
233        if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
234                       CommandOptions::WithTimeout(1).Build())) {
235            MYLOGE("anrd signal timed out. Please manually collect trace\n");
236            return false;
237        }
238
239        while (retry-- > 0 && old_mtime == st.st_mtime) {
240            sleep(1);
241            stat(trace_path, &st);
242        }
243
244        if (retry < 0 && old_mtime == st.st_mtime) {
245            MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
246            return false;
247        }
248
249        // identify the trace file by its creation time.
250        if (!(trace_dir = opendir(trace_path))) {
251            MYLOGE("Can't open trace file under %s\n", trace_path);
252        }
253        while ((trace = readdir(trace_dir))) {
254            if (strcmp(trace->d_name, ".") == 0
255                    || strcmp(trace->d_name, "..") == 0) {
256                continue;
257            }
258            sprintf(path, "%s%s", trace_path, trace->d_name);
259            if (stat(path, &st) == 0) {
260                if (st.st_ctime > max_ctime) {
261                    max_ctime = st.st_ctime;
262                    sprintf(buf, "%s", trace->d_name);
263                }
264            }
265        }
266        closedir(trace_dir);
267
268        // Wait until the dump completes by checking the size of the trace.
269        if (max_ctime > 0) {
270            sprintf(path, "%s%s", trace_path, buf);
271            while(true) {
272                sleep(1);
273                if (stat(path, &st) == 0) {
274                    if (st.st_size == cur_size) {
275                        break;
276                    } else if (st.st_size > cur_size) {
277                        cur_size = st.st_size;
278                    } else {
279                        return false;
280                    }
281                } else {
282                    MYLOGE("Cant stat() %s anymore\n", path);
283                    return false;
284                }
285            }
286            // Add to the zip file.
287            if (!ds.AddZipEntry("anrd_trace.txt", path)) {
288                MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
289            } else {
290                if (remove(path)) {
291                    MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
292                }
293                return true;
294            }
295        } else {
296            MYLOGE("Can't stats any trace file under %s\n", trace_path);
297        }
298    }
299    return false;
300}
301
302static void dump_systrace() {
303    if (!ds.IsZipping()) {
304        MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
305        return;
306    }
307    std::string systrace_path = ds.GetPath("-systrace.txt");
308    if (systrace_path.empty()) {
309        MYLOGE("Not dumping systrace because path is empty\n");
310        return;
311    }
312    const char* path = "/sys/kernel/debug/tracing/tracing_on";
313    long int is_tracing;
314    if (read_file_as_long(path, &is_tracing)) {
315        return; // error already logged
316    }
317    if (is_tracing <= 0) {
318        MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
319        return;
320    }
321
322    MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
323            systrace_path.c_str());
324    if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
325                   CommandOptions::WithTimeout(120).Build())) {
326        MYLOGE("systrace timed out, its zip entry will be incomplete\n");
327        // TODO: RunCommand tries to kill the process, but atrace doesn't die
328        // peacefully; ideally, we should call strace to stop itself, but there is no such option
329        // yet (just a --async_stop, which stops and dump
330        // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
331        //   MYLOGE("could not stop systrace ");
332        // }
333    }
334    if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
335        MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
336    } else {
337        if (remove(systrace_path.c_str())) {
338            MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
339        }
340    }
341}
342
343static void dump_raft() {
344    if (PropertiesHelper::IsUserBuild()) {
345        return;
346    }
347
348    std::string raft_path = ds.GetPath("-raft_log.txt");
349    if (raft_path.empty()) {
350        MYLOGD("raft_path is empty\n");
351        return;
352    }
353
354    struct stat s;
355    if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
356        MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
357        return;
358    }
359
360    CommandOptions options = CommandOptions::WithTimeout(600).Build();
361    if (!ds.IsZipping()) {
362        // Write compressed and encoded raft logs to stdout if it's not a zipped bugreport.
363        RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
364        return;
365    }
366
367    RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_path}, options);
368    if (!ds.AddZipEntry("raft_log.txt", raft_path)) {
369        MYLOGE("Unable to add raft log %s to zip file\n", raft_path.c_str());
370    } else {
371        if (remove(raft_path.c_str())) {
372            MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
373        }
374    }
375}
376
377/**
378 * Finds the last modified file in the directory dir whose name starts with file_prefix.
379 *
380 * Function returns empty string when it does not find a file
381 */
382static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
383                                                 const std::string& file_prefix) {
384    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
385    if (d == nullptr) {
386        MYLOGD("Error %d opening %s\n", errno, dir.c_str());
387        return "";
388    }
389
390    // Find the newest file matching the file_prefix in dir
391    struct dirent *de;
392    time_t last_modified_time = 0;
393    std::string last_modified_file = "";
394    struct stat s;
395
396    while ((de = readdir(d.get()))) {
397        std::string file = std::string(de->d_name);
398        if (!file_prefix.empty()) {
399            if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
400        }
401        file = dir + "/" + file;
402        int ret = stat(file.c_str(), &s);
403
404        if ((ret == 0) && (s.st_mtime > last_modified_time)) {
405            last_modified_file = file;
406            last_modified_time = s.st_mtime;
407        }
408    }
409
410    return last_modified_file;
411}
412
413static void DumpModemLogs() {
414    DurationReporter durationReporter("DUMP MODEM LOGS");
415    if (PropertiesHelper::IsUserBuild()) {
416        return;
417    }
418
419    if (!ds.IsZipping()) {
420        MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
421        return;
422    }
423
424    std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
425
426    if(file_prefix.empty()) {
427        MYLOGD("No modem log : file_prefix is empty\n");
428        return;
429    }
430
431    // TODO: b/33820081 we need to provide a right way to dump modem logs.
432    std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
433    if (radio_bugreport_dir.empty()) {
434        radio_bugreport_dir = dirname(ds.GetPath("").c_str());
435    }
436
437    MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
438           radio_bugreport_dir.c_str(), file_prefix.c_str());
439
440    std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
441
442    struct stat s;
443    if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
444        MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
445        return;
446    }
447
448    std::string filename = basename(modem_log_file.c_str());
449    if (!ds.AddZipEntry(filename, modem_log_file)) {
450        MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
451    } else {
452        MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
453        if (remove(modem_log_file.c_str())) {
454            MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
455        }
456    }
457}
458
459static bool skip_not_stat(const char *path) {
460    static const char stat[] = "/stat";
461    size_t len = strlen(path);
462    if (path[len - 1] == '/') { /* Directory? */
463        return false;
464    }
465    return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
466}
467
468static bool skip_none(const char* path __attribute__((unused))) {
469    return false;
470}
471
472static const char mmcblk0[] = "/sys/block/mmcblk0/";
473unsigned long worst_write_perf = 20000; /* in KB/s */
474
475//
476//  stat offsets
477// Name            units         description
478// ----            -----         -----------
479// read I/Os       requests      number of read I/Os processed
480#define __STAT_READ_IOS      0
481// read merges     requests      number of read I/Os merged with in-queue I/O
482#define __STAT_READ_MERGES   1
483// read sectors    sectors       number of sectors read
484#define __STAT_READ_SECTORS  2
485// read ticks      milliseconds  total wait time for read requests
486#define __STAT_READ_TICKS    3
487// write I/Os      requests      number of write I/Os processed
488#define __STAT_WRITE_IOS     4
489// write merges    requests      number of write I/Os merged with in-queue I/O
490#define __STAT_WRITE_MERGES  5
491// write sectors   sectors       number of sectors written
492#define __STAT_WRITE_SECTORS 6
493// write ticks     milliseconds  total wait time for write requests
494#define __STAT_WRITE_TICKS   7
495// in_flight       requests      number of I/Os currently in flight
496#define __STAT_IN_FLIGHT     8
497// io_ticks        milliseconds  total time this block device has been active
498#define __STAT_IO_TICKS      9
499// time_in_queue   milliseconds  total wait time for all requests
500#define __STAT_IN_QUEUE     10
501#define __STAT_NUMBER_FIELD 11
502//
503// read I/Os, write I/Os
504// =====================
505//
506// These values increment when an I/O request completes.
507//
508// read merges, write merges
509// =========================
510//
511// These values increment when an I/O request is merged with an
512// already-queued I/O request.
513//
514// read sectors, write sectors
515// ===========================
516//
517// These values count the number of sectors read from or written to this
518// block device.  The "sectors" in question are the standard UNIX 512-byte
519// sectors, not any device- or filesystem-specific block size.  The
520// counters are incremented when the I/O completes.
521#define SECTOR_SIZE 512
522//
523// read ticks, write ticks
524// =======================
525//
526// These values count the number of milliseconds that I/O requests have
527// waited on this block device.  If there are multiple I/O requests waiting,
528// these values will increase at a rate greater than 1000/second; for
529// example, if 60 read requests wait for an average of 30 ms, the read_ticks
530// field will increase by 60*30 = 1800.
531//
532// in_flight
533// =========
534//
535// This value counts the number of I/O requests that have been issued to
536// the device driver but have not yet completed.  It does not include I/O
537// requests that are in the queue but not yet issued to the device driver.
538//
539// io_ticks
540// ========
541//
542// This value counts the number of milliseconds during which the device has
543// had I/O requests queued.
544//
545// time_in_queue
546// =============
547//
548// This value counts the number of milliseconds that I/O requests have waited
549// on this block device.  If there are multiple I/O requests waiting, this
550// value will increase as the product of the number of milliseconds times the
551// number of requests waiting (see "read ticks" above for an example).
552#define S_TO_MS 1000
553//
554
555static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
556    unsigned long long fields[__STAT_NUMBER_FIELD];
557    bool z;
558    char *cp, *buffer = NULL;
559    size_t i = 0;
560    FILE *fp = fdopen(fd, "rb");
561    getline(&buffer, &i, fp);
562    fclose(fp);
563    if (!buffer) {
564        return -errno;
565    }
566    i = strlen(buffer);
567    while ((i > 0) && (buffer[i - 1] == '\n')) {
568        buffer[--i] = '\0';
569    }
570    if (!*buffer) {
571        free(buffer);
572        return 0;
573    }
574    z = true;
575    for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
576        fields[i] = strtoull(cp, &cp, 10);
577        if (fields[i] != 0) {
578            z = false;
579        }
580    }
581    if (z) { /* never accessed */
582        free(buffer);
583        return 0;
584    }
585
586    if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
587        path += sizeof(mmcblk0) - 1;
588    }
589
590    printf("%s: %s\n", path, buffer);
591    free(buffer);
592
593    if (fields[__STAT_IO_TICKS]) {
594        unsigned long read_perf = 0;
595        unsigned long read_ios = 0;
596        if (fields[__STAT_READ_TICKS]) {
597            unsigned long long divisor = fields[__STAT_READ_TICKS]
598                                       * fields[__STAT_IO_TICKS];
599            read_perf = ((unsigned long long)SECTOR_SIZE
600                           * fields[__STAT_READ_SECTORS]
601                           * fields[__STAT_IN_QUEUE] + (divisor >> 1))
602                                        / divisor;
603            read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
604                           * fields[__STAT_IN_QUEUE] + (divisor >> 1))
605                                        / divisor;
606        }
607
608        unsigned long write_perf = 0;
609        unsigned long write_ios = 0;
610        if (fields[__STAT_WRITE_TICKS]) {
611            unsigned long long divisor = fields[__STAT_WRITE_TICKS]
612                                       * fields[__STAT_IO_TICKS];
613            write_perf = ((unsigned long long)SECTOR_SIZE
614                           * fields[__STAT_WRITE_SECTORS]
615                           * fields[__STAT_IN_QUEUE] + (divisor >> 1))
616                                        / divisor;
617            write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
618                           * fields[__STAT_IN_QUEUE] + (divisor >> 1))
619                                        / divisor;
620        }
621
622        unsigned queue = (fields[__STAT_IN_QUEUE]
623                             + (fields[__STAT_IO_TICKS] >> 1))
624                                 / fields[__STAT_IO_TICKS];
625
626        if (!write_perf && !write_ios) {
627            printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
628        } else {
629            printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
630                   read_ios, write_perf, write_ios, queue);
631        }
632
633        /* bugreport timeout factor adjustment */
634        if ((write_perf > 1) && (write_perf < worst_write_perf)) {
635            worst_write_perf = write_perf;
636        }
637    }
638    return 0;
639}
640
641/* timeout in ms */
642static unsigned long logcat_timeout(const char *name) {
643    log_id_t id = android_name_to_log_id(name);
644    unsigned long property_size = __android_logger_get_buffer_size(id);
645    /* Engineering margin is ten-fold our guess */
646    return 10 * (property_size + worst_write_perf) / worst_write_perf;
647}
648
649void Dumpstate::PrintHeader() const {
650    std::string build, fingerprint, radio, bootloader, network;
651    char date[80];
652
653    build = android::base::GetProperty("ro.build.display.id", "(unknown)");
654    fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
655    radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
656    bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
657    network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
658    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
659
660    printf("========================================================\n");
661    printf("== dumpstate: %s\n", date);
662    printf("========================================================\n");
663
664    printf("\n");
665    printf("Build: %s\n", build.c_str());
666    // NOTE: fingerprint entry format is important for other tools.
667    printf("Build fingerprint: '%s'\n", fingerprint.c_str());
668    printf("Bootloader: %s\n", bootloader.c_str());
669    printf("Radio: %s\n", radio.c_str());
670    printf("Network: %s\n", network.c_str());
671
672    printf("Kernel: ");
673    DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
674    printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
675    printf("Bugreport format version: %s\n", version_.c_str());
676    printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
677           PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
678    printf("\n");
679}
680
681// List of file extensions that can cause a zip file attachment to be rejected by some email
682// service providers.
683static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
684      ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
685      ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
686      ".shb", ".sys", ".vb",  ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
687};
688
689bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
690    if (!IsZipping()) {
691        MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
692               entry_name.c_str());
693        return false;
694    }
695    std::string valid_name = entry_name;
696
697    // Rename extension if necessary.
698    size_t idx = entry_name.rfind(".");
699    if (idx != std::string::npos) {
700        std::string extension = entry_name.substr(idx);
701        std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
702        if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
703            valid_name = entry_name + ".renamed";
704            MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
705        }
706    }
707
708    // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
709    // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
710    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
711                                                  get_mtime(fd, ds.now_));
712    if (err != 0) {
713        MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
714               ZipWriter::ErrorCodeString(err));
715        return false;
716    }
717
718    std::vector<uint8_t> buffer(65536);
719    while (1) {
720        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
721        if (bytes_read == 0) {
722            break;
723        } else if (bytes_read == -1) {
724            MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
725            return false;
726        }
727        err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
728        if (err) {
729            MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
730            return false;
731        }
732    }
733
734    err = zip_writer_->FinishEntry();
735    if (err != 0) {
736        MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
737        return false;
738    }
739
740    return true;
741}
742
743bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
744    android::base::unique_fd fd(
745        TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
746    if (fd == -1) {
747        MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
748        return false;
749    }
750
751    return AddZipEntryFromFd(entry_name, fd.get());
752}
753
754/* adds a file to the existing zipped bugreport */
755static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
756    return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
757}
758
759void Dumpstate::AddDir(const std::string& dir, bool recursive) {
760    if (!IsZipping()) {
761        MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
762        return;
763    }
764    MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
765    DurationReporter duration_reporter(dir, true);
766    dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
767}
768
769bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
770    if (!IsZipping()) {
771        MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
772               entry_name.c_str());
773        return false;
774    }
775    MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
776    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
777    if (err != 0) {
778        MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
779               ZipWriter::ErrorCodeString(err));
780        return false;
781    }
782
783    err = zip_writer_->WriteBytes(content.c_str(), content.length());
784    if (err != 0) {
785        MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
786               ZipWriter::ErrorCodeString(err));
787        return false;
788    }
789
790    err = zip_writer_->FinishEntry();
791    if (err != 0) {
792        MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
793        return false;
794    }
795
796    return true;
797}
798
799static void DoKmsg() {
800    struct stat st;
801    if (!stat(PSTORE_LAST_KMSG, &st)) {
802        /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
803        DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
804    } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
805        DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
806    } else {
807        /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
808        DumpFile("LAST KMSG", "/proc/last_kmsg");
809    }
810}
811
812static void DoLogcat() {
813    unsigned long timeout;
814    // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
815    // calculate timeout
816    timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
817    if (timeout < 20000) {
818        timeout = 20000;
819    }
820    RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
821               CommandOptions::WithTimeout(timeout / 1000).Build());
822    timeout = logcat_timeout("events");
823    if (timeout < 20000) {
824        timeout = 20000;
825    }
826    RunCommand("EVENT LOG",
827               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
828               CommandOptions::WithTimeout(timeout / 1000).Build());
829    timeout = logcat_timeout("radio");
830    if (timeout < 20000) {
831        timeout = 20000;
832    }
833    RunCommand("RADIO LOG",
834               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
835               CommandOptions::WithTimeout(timeout / 1000).Build());
836
837    RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
838
839    /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
840    RunCommand("LAST LOGCAT",
841               {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
842}
843
844static void DumpIpTables() {
845    RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
846    RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
847    RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
848    /* no ip6 nat */
849    RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
850    RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
851    RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
852    RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
853}
854
855static void AddAnrTraceFiles() {
856    bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
857    std::string dump_traces_dir;
858
859    /* show the traces we collected in main(), if that was done */
860    if (dump_traces_path != nullptr) {
861        if (add_to_zip) {
862            dump_traces_dir = dirname(dump_traces_path);
863            MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
864            ds.AddDir(dump_traces_dir, true);
865        } else {
866            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
867                   dump_traces_path);
868            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
869        }
870    }
871
872    std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
873    std::string anr_traces_dir = dirname(anr_traces_path.c_str());
874
875    // Make sure directory is not added twice.
876    // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
877    // generated by dump_traces() -  and anr_traces_path - which is retrieved from a system
878    // property - but in reality they're the same path (although the former could be nullptr).
879    // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
880    // be revisited.
881    bool already_dumped = anr_traces_dir == dump_traces_dir;
882
883    MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
884           dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
885
886    if (anr_traces_path.empty()) {
887        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
888    } else {
889        int fd = TEMP_FAILURE_RETRY(
890            open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
891        if (fd < 0) {
892            printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
893                   strerror(errno));
894        } else {
895            if (add_to_zip) {
896                if (!already_dumped) {
897                    MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
898                           anr_traces_dir.c_str());
899                    ds.AddDir(anr_traces_dir, true);
900                    already_dumped = true;
901                }
902            } else {
903                MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
904                       anr_traces_path.c_str());
905                dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
906            }
907        }
908    }
909
910    if (add_to_zip && already_dumped) {
911        MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
912        return;
913    }
914
915    /* slow traces for slow operations */
916    struct stat st;
917    if (!anr_traces_path.empty()) {
918        int tail = anr_traces_path.size() - 1;
919        while (tail > 0 && anr_traces_path.at(tail) != '/') {
920            tail--;
921        }
922        int i = 0;
923        while (1) {
924            anr_traces_path = anr_traces_path.substr(0, tail + 1) +
925                              android::base::StringPrintf("slow%02d.txt", i);
926            if (stat(anr_traces_path.c_str(), &st)) {
927                // No traces file at this index, done with the files.
928                break;
929            }
930            ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
931            i++;
932        }
933    }
934}
935
936static void dumpstate() {
937    DurationReporter duration_reporter("DUMPSTATE");
938
939    dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
940    RunCommand("UPTIME", {"uptime"});
941    dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
942    dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
943    DumpFile("MEMORY INFO", "/proc/meminfo");
944    RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
945                            "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
946    RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20);
947    DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
948    DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
949    DumpFile("SLAB INFO", "/proc/slabinfo");
950    DumpFile("ZONEINFO", "/proc/zoneinfo");
951    DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
952    DumpFile("BUDDYINFO", "/proc/buddyinfo");
953    DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
954
955    DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
956    DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
957    DumpFile("KERNEL SYNC", "/d/sync");
958
959    RunCommand("PROCESSES AND THREADS",
960               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
961    RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
962
963    RunCommand("HARDWARE HALS", {"lshal"});
964
965    RunCommand("PRINTENV", {"printenv"});
966    RunCommand("NETSTAT", {"netstat", "-nW"});
967    struct stat s;
968    if (stat("/proc/modules", &s) != 0) {
969        MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
970    } else {
971        RunCommand("LSMOD", {"lsmod"});
972    }
973
974    do_dmesg();
975
976    RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
977    for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
978    for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
979    for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
980
981    /* Dump Bluetooth HCI logs */
982    ds.AddDir("/data/misc/bluetooth/logs", true);
983
984    if (!ds.do_early_screenshot_) {
985        MYLOGI("taking late screenshot\n");
986        ds.TakeScreenshot();
987    }
988
989    DoLogcat();
990
991    AddAnrTraceFiles();
992
993    int dumped = 0;
994    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
995        if (tombstone_data[i].fd != -1) {
996            const char *name = tombstone_data[i].name;
997            int fd = tombstone_data[i].fd;
998            dumped = 1;
999            if (ds.IsZipping()) {
1000                if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
1001                    MYLOGE("Unable to add tombstone %s to zip file\n", name);
1002                }
1003            } else {
1004                dump_file_from_fd("TOMBSTONE", name, fd);
1005            }
1006            close(fd);
1007            tombstone_data[i].fd = -1;
1008        }
1009    }
1010    if (!dumped) {
1011        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1012    }
1013
1014    DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1015    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1016    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1017    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1018    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1019
1020    DoKmsg();
1021
1022    /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1023
1024    RunCommand("NETWORK INTERFACES", {"ip", "link"});
1025
1026    RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1027    RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1028
1029    RunCommand("IP RULES", {"ip", "rule", "show"});
1030    RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1031
1032    dump_route_tables();
1033
1034    RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1035    RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1036    RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
1037    RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
1038               CommandOptions::WithTimeout(20).Build());
1039
1040#ifdef FWDUMP_bcmdhd
1041    RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT);
1042
1043    RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
1044
1045    RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
1046
1047#endif
1048    DumpFile("INTERRUPTS (1)", "/proc/interrupts");
1049
1050    RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1051               CommandOptions::WithTimeout(10).Build());
1052
1053#ifdef FWDUMP_bcmdhd
1054    RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, AS_ROOT_20);
1055
1056    RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
1057
1058    RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
1059#endif
1060    DumpFile("INTERRUPTS (2)", "/proc/interrupts");
1061
1062    print_properties();
1063
1064    RunCommand("VOLD DUMP", {"vdc", "dump"});
1065    RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
1066
1067    RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build());
1068
1069    RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
1070
1071    RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
1072
1073    printf("------ BACKLIGHTS ------\n");
1074    printf("LCD brightness=");
1075    DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
1076    printf("Button brightness=");
1077    DumpFile("", "/sys/class/leds/button-backlight/brightness");
1078    printf("Keyboard brightness=");
1079    DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
1080    printf("ALS mode=");
1081    DumpFile("", "/sys/class/leds/lcd-backlight/als");
1082    printf("LCD driver registers:\n");
1083    DumpFile("", "/sys/class/leds/lcd-backlight/registers");
1084    printf("\n");
1085
1086    /* Binder state is expensive to look at as it uses a lot of memory. */
1087    DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1088    DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1089    DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1090    DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1091    DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
1092
1093    ds.DumpstateBoard();
1094
1095    /* Migrate the ril_dumpstate to a device specific dumpstate? */
1096    int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1097    if (rilDumpstateTimeout > 0) {
1098        // su does not exist on user builds, so try running without it.
1099        // This way any implementations of vril-dump that do not require
1100        // root can run on user builds.
1101        CommandOptions::CommandOptionsBuilder options =
1102            CommandOptions::WithTimeout(rilDumpstateTimeout);
1103        if (!PropertiesHelper::IsUserBuild()) {
1104            options.AsRoot();
1105        }
1106        RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
1107    }
1108
1109    printf("========================================================\n");
1110    printf("== Android Framework Services\n");
1111    printf("========================================================\n");
1112
1113    RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
1114               10);
1115
1116    printf("========================================================\n");
1117    printf("== Checkins\n");
1118    printf("========================================================\n");
1119
1120    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1121    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
1122    RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1123    RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1124    RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1125    RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
1126
1127    printf("========================================================\n");
1128    printf("== Running Application Activities\n");
1129    printf("========================================================\n");
1130
1131    RunDumpsys("APP ACTIVITIES", {"activity", "all"});
1132
1133    printf("========================================================\n");
1134    printf("== Running Application Services\n");
1135    printf("========================================================\n");
1136
1137    RunDumpsys("APP SERVICES", {"activity", "service", "all"});
1138
1139    printf("========================================================\n");
1140    printf("== Running Application Providers\n");
1141    printf("========================================================\n");
1142
1143    RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
1144
1145    // DumpModemLogs adds the modem logs if available to the bugreport.
1146    // Do this at the end to allow for sufficient time for the modem logs to be
1147    // collected.
1148    DumpModemLogs();
1149
1150    printf("========================================================\n");
1151    printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1152           ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1153    printf("========================================================\n");
1154    printf("== dumpstate: done (id %d)\n", ds.id_);
1155    printf("========================================================\n");
1156}
1157
1158void Dumpstate::DumpstateBoard() {
1159    DurationReporter duration_reporter("dumpstate_board()");
1160    printf("========================================================\n");
1161    printf("== Board\n");
1162    printf("========================================================\n");
1163
1164    ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService("dumpstate"));
1165    if (dumpstate_device == nullptr) {
1166        MYLOGE("No IDumpstateDevice implementation\n");
1167        return;
1168    }
1169
1170    if (!IsZipping()) {
1171        MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
1172        return;
1173    }
1174
1175    std::string path = kDumpstateBoardPath;
1176    MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
1177
1178    int fd =
1179        TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1180                                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
1181    if (fd < 0) {
1182        MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
1183        return;
1184    }
1185
1186    native_handle_t* handle = native_handle_create(1, 0);
1187    if (handle == nullptr) {
1188        MYLOGE("Could not create native_handle\n");
1189        return;
1190    }
1191    handle->data[0] = fd;
1192
1193    // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
1194    android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
1195    if (!status.isOk()) {
1196        MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
1197        native_handle_close(handle);
1198        native_handle_delete(handle);
1199        return;
1200    }
1201
1202    AddZipEntry("dumpstate-board.txt", path);
1203    printf("*** See dumpstate-board.txt entry ***\n");
1204
1205    native_handle_close(handle);
1206    native_handle_delete(handle);
1207
1208    if (remove(path.c_str()) != 0) {
1209        MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
1210    }
1211}
1212
1213static void ShowUsageAndExit(int exitCode = 1) {
1214    fprintf(stderr,
1215            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
1216            "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1217            "  -h: display this help message\n"
1218            "  -b: play sound file instead of vibrate, at beginning of job\n"
1219            "  -e: play sound file instead of vibrate, at end of job\n"
1220            "  -o: write to file (instead of stdout)\n"
1221            "  -d: append date to filename (requires -o)\n"
1222            "  -p: capture screenshot to filename.png (requires -o)\n"
1223            "  -z: generate zipped file (requires -o)\n"
1224            "  -s: write output to control socket (for init)\n"
1225            "  -S: write file location to control socket (for init; requires -o and -z)"
1226            "  -q: disable vibrate\n"
1227            "  -B: send broadcast when finished (requires -o)\n"
1228            "  -P: send broadcast when started and update system properties on "
1229            "progress (requires -o and -B)\n"
1230            "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1231            "shouldn't be used with -P)\n"
1232            "  -v: prints the dumpstate header and exit\n");
1233    exit(exitCode);
1234}
1235
1236static void ExitOnInvalidArgs() {
1237    fprintf(stderr, "invalid combination of args\n");
1238    ShowUsageAndExit();
1239}
1240
1241static void sig_handler(int) {
1242    _exit(EXIT_FAILURE);
1243}
1244
1245static void register_sig_handler() {
1246    struct sigaction sa;
1247    sigemptyset(&sa.sa_mask);
1248    sa.sa_flags = 0;
1249    sa.sa_handler = sig_handler;
1250    sigaction(SIGPIPE, &sa, NULL); // broken pipe
1251    sigaction(SIGSEGV, &sa, NULL); // segment fault
1252    sigaction(SIGINT, &sa, NULL); // ctrl-c
1253    sigaction(SIGTERM, &sa, NULL); // killed
1254    sigaction(SIGQUIT, &sa, NULL); // quit
1255}
1256
1257bool Dumpstate::FinishZipFile() {
1258    std::string entry_name = base_name_ + "-" + name_ + ".txt";
1259    MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
1260           tmp_path_.c_str());
1261    // Final timestamp
1262    char date[80];
1263    time_t the_real_now_please_stand_up = time(nullptr);
1264    strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
1265    MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
1266           the_real_now_please_stand_up - ds.now_);
1267
1268    if (!ds.AddZipEntry(entry_name, tmp_path_)) {
1269        MYLOGE("Failed to add text entry to .zip file\n");
1270        return false;
1271    }
1272    if (!AddTextZipEntry("main_entry.txt", entry_name)) {
1273        MYLOGE("Failed to add main_entry.txt to .zip file\n");
1274        return false;
1275    }
1276
1277    // Add log file (which contains stderr output) to zip...
1278    fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
1279    if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
1280        MYLOGE("Failed to add dumpstate log to .zip file\n");
1281        return false;
1282    }
1283    // ... and re-opens it for further logging.
1284    redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
1285    fprintf(stderr, "\n");
1286
1287    int32_t err = zip_writer_->Finish();
1288    if (err != 0) {
1289        MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1290        return false;
1291    }
1292
1293    // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1294    ds.zip_file.reset(nullptr);
1295
1296    MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
1297    if (remove(tmp_path_.c_str()) != 0) {
1298        MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
1299    }
1300
1301    return true;
1302}
1303
1304static std::string SHA256_file_hash(std::string filepath) {
1305    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1306            | O_CLOEXEC | O_NOFOLLOW)));
1307    if (fd == -1) {
1308        MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1309        return NULL;
1310    }
1311
1312    SHA256_CTX ctx;
1313    SHA256_Init(&ctx);
1314
1315    std::vector<uint8_t> buffer(65536);
1316    while (1) {
1317        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1318        if (bytes_read == 0) {
1319            break;
1320        } else if (bytes_read == -1) {
1321            MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1322            return NULL;
1323        }
1324
1325        SHA256_Update(&ctx, buffer.data(), bytes_read);
1326    }
1327
1328    uint8_t hash[SHA256_DIGEST_LENGTH];
1329    SHA256_Final(hash, &ctx);
1330
1331    char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1332    for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
1333        sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1334    }
1335    hash_buffer[sizeof(hash_buffer) - 1] = 0;
1336    return std::string(hash_buffer);
1337}
1338
1339static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1340    // clang-format off
1341    std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1342                    "--receiver-foreground", "--receiver-include-background", "-a", action};
1343    // clang-format on
1344
1345    am.insert(am.end(), args.begin(), args.end());
1346
1347    RunCommand("", am,
1348               CommandOptions::WithTimeout(20)
1349                   .Log("Sending broadcast: '%s'\n")
1350                   .Always()
1351                   .DropRoot()
1352                   .RedirectStderr()
1353                   .Build());
1354}
1355
1356static void Vibrate(int duration_ms) {
1357    // clang-format off
1358    RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
1359               CommandOptions::WithTimeout(10)
1360                   .Log("Vibrate: '%s'\n")
1361                   .Always()
1362                   .Build());
1363    // clang-format on
1364}
1365
1366int main(int argc, char *argv[]) {
1367    int do_add_date = 0;
1368    int do_zip_file = 0;
1369    int do_vibrate = 1;
1370    char* use_outfile = 0;
1371    int use_socket = 0;
1372    int use_control_socket = 0;
1373    int do_fb = 0;
1374    int do_broadcast = 0;
1375    int is_remote_mode = 0;
1376    bool show_header_only = false;
1377    bool do_start_service = false;
1378    bool telephony_only = false;
1379
1380    /* set as high priority, and protect from OOM killer */
1381    setpriority(PRIO_PROCESS, 0, -20);
1382
1383    FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
1384    if (oom_adj) {
1385        fputs("-1000", oom_adj);
1386        fclose(oom_adj);
1387    } else {
1388        /* fallback to kernels <= 2.6.35 */
1389        oom_adj = fopen("/proc/self/oom_adj", "we");
1390        if (oom_adj) {
1391            fputs("-17", oom_adj);
1392            fclose(oom_adj);
1393        }
1394    }
1395
1396    /* parse arguments */
1397    int c;
1398    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1399        switch (c) {
1400            // clang-format off
1401            case 'd': do_add_date = 1;            break;
1402            case 'z': do_zip_file = 1;            break;
1403            case 'o': use_outfile = optarg;       break;
1404            case 's': use_socket = 1;             break;
1405            case 'S': use_control_socket = 1;     break;
1406            case 'v': show_header_only = true;    break;
1407            case 'q': do_vibrate = 0;             break;
1408            case 'p': do_fb = 1;                  break;
1409            case 'P': ds.update_progress_ = true; break;
1410            case 'R': is_remote_mode = 1;         break;
1411            case 'B': do_broadcast = 1;           break;
1412            case 'V':                             break; // compatibility no-op
1413            case 'h':
1414                ShowUsageAndExit(0);
1415                break;
1416            default:
1417                fprintf(stderr, "Invalid option: %c\n", c);
1418                ShowUsageAndExit();
1419                // clang-format on
1420        }
1421    }
1422
1423    // TODO: use helper function to convert argv into a string
1424    for (int i = 0; i < argc; i++) {
1425        ds.args_ += argv[i];
1426        if (i < argc - 1) {
1427            ds.args_ += " ";
1428        }
1429    }
1430
1431    ds.extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
1432    if (!ds.extra_options_.empty()) {
1433        // Framework uses a system property to override some command-line args.
1434        // Currently, it contains the type of the requested bugreport.
1435        if (ds.extra_options_ == "bugreportplus") {
1436            // Currently, the dumpstate binder is only used by Shell to update progress.
1437            do_start_service = true;
1438            ds.update_progress_ = true;
1439            do_fb = 0;
1440        } else if (ds.extra_options_ == "bugreportremote") {
1441            do_vibrate = 0;
1442            is_remote_mode = 1;
1443            do_fb = 0;
1444        } else if (ds.extra_options_ == "bugreportwear") {
1445            ds.update_progress_ = true;
1446        } else if (ds.extra_options_ == "bugreporttelephony") {
1447            telephony_only = true;
1448        } else {
1449            MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
1450        }
1451        // Reset the property
1452        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
1453    }
1454
1455    if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
1456        ExitOnInvalidArgs();
1457    }
1458
1459    if (use_control_socket && !do_zip_file) {
1460        ExitOnInvalidArgs();
1461    }
1462
1463    if (ds.update_progress_ && !do_broadcast) {
1464        ExitOnInvalidArgs();
1465    }
1466
1467    if (is_remote_mode && (ds.update_progress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
1468        ExitOnInvalidArgs();
1469    }
1470
1471    if (ds.version_ == VERSION_DEFAULT) {
1472        ds.version_ = VERSION_CURRENT;
1473    }
1474
1475    if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
1476        MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
1477               ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
1478               VERSION_SPLIT_ANR.c_str());
1479        exit(1);
1480    }
1481
1482    if (show_header_only) {
1483        ds.PrintHeader();
1484        exit(0);
1485    }
1486
1487    /* redirect output if needed */
1488    bool is_redirecting = !use_socket && use_outfile;
1489
1490    // TODO: temporarily set progress until it's part of the Dumpstate constructor
1491    std::string stats_path =
1492        is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
1493                       : "";
1494    ds.progress_.reset(new Progress(stats_path));
1495
1496    /* gets the sequential id */
1497    uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
1498    ds.id_ = ++last_id;
1499    android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
1500
1501    MYLOGI("begin\n");
1502
1503    register_sig_handler();
1504
1505    if (do_start_service) {
1506        MYLOGI("Starting 'dumpstate' service\n");
1507        android::status_t ret;
1508        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
1509            MYLOGE("Unable to start DumpstateService: %d\n", ret);
1510        }
1511    }
1512
1513    if (PropertiesHelper::IsDryRun()) {
1514        MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
1515    }
1516
1517    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
1518           ds.extra_options_.c_str());
1519
1520    MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
1521
1522    ds.do_early_screenshot_ = ds.update_progress_;
1523
1524    // If we are going to use a socket, do it as early as possible
1525    // to avoid timeouts from bugreport.
1526    if (use_socket) {
1527        redirect_to_socket(stdout, "dumpstate");
1528    }
1529
1530    if (use_control_socket) {
1531        MYLOGD("Opening control socket\n");
1532        ds.control_socket_fd_ = open_socket("dumpstate");
1533        ds.update_progress_ = 1;
1534    }
1535
1536    if (is_redirecting) {
1537        ds.bugreport_dir_ = dirname(use_outfile);
1538        std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1539        std::string device_name = android::base::GetProperty("ro.product.device", "UNKNOWN_DEVICE");
1540        ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(use_outfile),
1541                                                    device_name.c_str(), build_id.c_str());
1542        if (do_add_date) {
1543            char date[80];
1544            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
1545            ds.name_ = date;
1546        } else {
1547            ds.name_ = "undated";
1548        }
1549
1550        if (telephony_only) {
1551            ds.base_name_ += "-telephony";
1552        }
1553
1554        if (do_fb) {
1555            ds.screenshot_path_ = ds.GetPath(".png");
1556        }
1557        ds.tmp_path_ = ds.GetPath(".tmp");
1558        ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1559
1560        MYLOGD(
1561            "Bugreport dir: %s\n"
1562            "Base name: %s\n"
1563            "Suffix: %s\n"
1564            "Log path: %s\n"
1565            "Temporary path: %s\n"
1566            "Screenshot path: %s\n",
1567            ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(),
1568            ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
1569
1570        if (do_zip_file) {
1571            ds.path_ = ds.GetPath(".zip");
1572            MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
1573            create_parent_dirs(ds.path_.c_str());
1574            ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
1575            if (ds.zip_file == nullptr) {
1576                MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
1577                do_zip_file = 0;
1578            } else {
1579                ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
1580            }
1581            ds.AddTextZipEntry("version.txt", ds.version_);
1582        }
1583
1584        if (ds.update_progress_) {
1585            if (do_broadcast) {
1586                // clang-format off
1587
1588                std::vector<std::string> am_args = {
1589                     "--receiver-permission", "android.permission.DUMP",
1590                     "--es", "android.intent.extra.NAME", ds.name_,
1591                     "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
1592                     "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
1593                     "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
1594                };
1595                // clang-format on
1596                SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
1597            }
1598            if (use_control_socket) {
1599                dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
1600            }
1601        }
1602    }
1603
1604    /* read /proc/cmdline before dropping root */
1605    FILE *cmdline = fopen("/proc/cmdline", "re");
1606    if (cmdline) {
1607        fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1608        fclose(cmdline);
1609    }
1610
1611    if (do_vibrate) {
1612        Vibrate(150);
1613    }
1614
1615    if (do_fb && ds.do_early_screenshot_) {
1616        if (ds.screenshot_path_.empty()) {
1617            // should not have happened
1618            MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1619        } else {
1620            MYLOGI("taking early screenshot\n");
1621            ds.TakeScreenshot();
1622        }
1623    }
1624
1625    if (do_zip_file) {
1626        if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
1627            MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
1628                   strerror(errno));
1629        }
1630    }
1631
1632    if (is_redirecting) {
1633        redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
1634        if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
1635            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1636                   ds.log_path_.c_str(), strerror(errno));
1637        }
1638        /* TODO: rather than generating a text file now and zipping it later,
1639           it would be more efficient to redirect stdout to the zip entry
1640           directly, but the libziparchive doesn't support that option yet. */
1641        redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
1642        if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
1643            MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1644                   ds.tmp_path_.c_str(), strerror(errno));
1645        }
1646    }
1647
1648    // Don't buffer stdout
1649    setvbuf(stdout, nullptr, _IONBF, 0);
1650
1651    // NOTE: there should be no stdout output until now, otherwise it would break the header.
1652    // In particular, DurationReport objects should be created passing 'title, NULL', so their
1653    // duration is logged into MYLOG instead.
1654    ds.PrintHeader();
1655
1656    if (telephony_only) {
1657        DumpIpTables();
1658        if (!DropRootUser()) {
1659            return -1;
1660        }
1661        do_dmesg();
1662        DoLogcat();
1663        DoKmsg();
1664        ds.DumpstateBoard();
1665        DumpModemLogs();
1666    } else {
1667        // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1668        // First try to dump anrd trace if the daemon is running. Otherwise, dump
1669        // the raw trace.
1670        if (!dump_anrd_trace()) {
1671            dump_systrace();
1672        }
1673
1674        // Invoking the following dumpsys calls before dump_traces() to try and
1675        // keep the system stats as close to its initial state as possible.
1676        RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
1677                   CommandOptions::WithTimeout(90).DropRoot().Build());
1678        RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
1679                   CommandOptions::WithTimeout(10).DropRoot().Build());
1680
1681        // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1682        dump_raft();
1683
1684        /* collect stack traces from Dalvik and native processes (needs root) */
1685        dump_traces_path = dump_traces();
1686
1687        /* Run some operations that require root. */
1688        get_tombstone_fds(tombstone_data);
1689        ds.AddDir(RECOVERY_DIR, true);
1690        ds.AddDir(RECOVERY_DATA_DIR, true);
1691        ds.AddDir(LOGPERSIST_DATA_DIR, false);
1692        if (!PropertiesHelper::IsUserBuild()) {
1693            ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1694            ds.AddDir(PROFILE_DATA_DIR_REF, true);
1695        }
1696        add_mountinfo();
1697        DumpIpTables();
1698
1699        // Capture any IPSec policies in play.  No keys are exposed here.
1700        RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
1701                   CommandOptions::WithTimeout(10).Build());
1702
1703        // Run ss as root so we can see socket marks.
1704        RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
1705                   CommandOptions::WithTimeout(10).Build());
1706
1707        if (!DropRootUser()) {
1708            return -1;
1709        }
1710
1711        dumpstate();
1712    }
1713
1714    /* close output if needed */
1715    if (is_redirecting) {
1716        fclose(stdout);
1717    }
1718
1719    /* rename or zip the (now complete) .tmp file to its final location */
1720    if (use_outfile) {
1721
1722        /* check if user changed the suffix using system properties */
1723        std::string name = android::base::GetProperty(
1724            android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
1725        bool change_suffix= false;
1726        if (!name.empty()) {
1727            /* must whitelist which characters are allowed, otherwise it could cross directories */
1728            std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1729            if (std::regex_match(name.c_str(), valid_regex)) {
1730                change_suffix = true;
1731            } else {
1732                MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
1733            }
1734        }
1735        if (change_suffix) {
1736            MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
1737            ds.name_ = name;
1738            if (!ds.screenshot_path_.empty()) {
1739                std::string new_screenshot_path = ds.GetPath(".png");
1740                if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
1741                    MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
1742                           new_screenshot_path.c_str(), strerror(errno));
1743                } else {
1744                    ds.screenshot_path_ = new_screenshot_path;
1745                }
1746            }
1747        }
1748
1749        bool do_text_file = true;
1750        if (do_zip_file) {
1751            if (!ds.FinishZipFile()) {
1752                MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1753                do_text_file = true;
1754            } else {
1755                do_text_file = false;
1756                // Since zip file is already created, it needs to be renamed.
1757                std::string new_path = ds.GetPath(".zip");
1758                if (ds.path_ != new_path) {
1759                    MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
1760                    if (rename(ds.path_.c_str(), new_path.c_str())) {
1761                        MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
1762                               strerror(errno));
1763                    } else {
1764                        ds.path_ = new_path;
1765                    }
1766                }
1767            }
1768        }
1769        if (do_text_file) {
1770            ds.path_ = ds.GetPath(".txt");
1771            MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(),
1772                   ds.tmp_path_.c_str());
1773            if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
1774                MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(),
1775                       strerror(errno));
1776                ds.path_.clear();
1777            }
1778        }
1779        if (use_control_socket) {
1780            if (do_text_file) {
1781                dprintf(ds.control_socket_fd_,
1782                        "FAIL:could not create zip file, check %s "
1783                        "for more details\n",
1784                        ds.log_path_.c_str());
1785            } else {
1786                dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
1787            }
1788        }
1789    }
1790
1791    /* vibrate a few but shortly times to let user know it's finished */
1792    for (int i = 0; i < 3; i++) {
1793        Vibrate(75);
1794        usleep((75 + 50) * 1000);
1795    }
1796
1797    /* tell activity manager we're done */
1798    if (do_broadcast) {
1799        if (!ds.path_.empty()) {
1800            MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
1801            // clang-format off
1802
1803            std::vector<std::string> am_args = {
1804                 "--receiver-permission", "android.permission.DUMP",
1805                 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
1806                 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
1807                 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
1808                 "--es", "android.intent.extra.BUGREPORT", ds.path_,
1809                 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
1810            };
1811            // clang-format on
1812            if (do_fb) {
1813                am_args.push_back("--es");
1814                am_args.push_back("android.intent.extra.SCREENSHOT");
1815                am_args.push_back(ds.screenshot_path_);
1816            }
1817            if (is_remote_mode) {
1818                am_args.push_back("--es");
1819                am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1820                am_args.push_back(SHA256_file_hash(ds.path_));
1821                SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
1822                              am_args);
1823            } else {
1824                SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
1825            }
1826        } else {
1827            MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1828        }
1829    }
1830
1831    MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
1832           ds.progress_->GetInitialMax());
1833    ds.progress_->Save();
1834    MYLOGI("done (id %d)\n", ds.id_);
1835
1836    if (is_redirecting) {
1837        fclose(stderr);
1838    }
1839
1840    if (use_control_socket && ds.control_socket_fd_ != -1) {
1841        MYLOGD("Closing control socket\n");
1842        close(ds.control_socket_fd_);
1843    }
1844
1845    return 0;
1846}
1847