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