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