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