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