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