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