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