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