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