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