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();
RunCommand(const std::string & title,const std::vector<std::string> & fullCommand,const CommandOptions & options=CommandOptions::DEFAULT)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 }
RunDumpsys(const std::string & title,const std::vector<std::string> & dumpsysArgs,const CommandOptions & options=Dumpstate::DEFAULT_DUMPSYS,long dumpsysTimeoutMs=0)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 }
DumpFile(const std::string & title,const std::string & path)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  */
GetDumpFds(const std::string & dir_path,const std::string & file_prefix,bool limit_by_mtime,bool limit_by_count=true)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 
AddDumps(const std::vector<DumpData>::const_iterator start,const std::vector<DumpData>::const_iterator end,const char * type_name,const bool add_to_zip)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.
do_mountinfo(int pid,const char * name)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 
add_mountinfo()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 
dump_dev_files(const char * title,const char * driverpath,const char * filename)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.
dump_anrd_trace()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 
dump_systrace()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 
dump_raft()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 
skip_not_stat(const char * path)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 
skip_none(const char * path)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 
dump_stat_from_fd(const char * title __unused,const char * path,int fd)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 */
logcat_timeout(const std::vector<std::string> & 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 
PrintHeader() const689 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 
AddZipEntryFromFd(const std::string & entry_name,int fd,std::chrono::milliseconds timeout=0ms)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 
AddZipEntry(const std::string & entry_name,const std::string & entry_path)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 */
_add_file_from_fd(const char * title,const char * path,int fd)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 
AddDir(const std::string & dir,bool recursive)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 
AddTextZipEntry(const std::string & entry_name,const std::string & content)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 
DoKmsg()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 
DoKernelLogcat()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 
DoLogcat()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 
DumpIpTablesAsRoot()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 
AddGlobalAnrTraceFile(const bool add_to_zip,const std::string & anr_traces_file,const std::string & anr_traces_dir)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 
AddAnrTraceDir(const bool add_to_zip,const std::string & anr_traces_dir)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 
AddAnrTraceFiles()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 
DumpBlockStatFiles()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 
DumpPacketStats()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 
DumpIpAddrAndRules()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 
RunDumpsysTextByPriority(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)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 
RunDumpsysText(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)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. */
RunDumpsysTextNormalPriority(const std::string & title,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)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 
RunDumpsysProto(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)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.
RunDumpsysCritical()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.
RunDumpsysHigh()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.
RunDumpsysNormal()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 
DumpHals()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 
dumpstate()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
DumpstateRadioCommon()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
DumpstateTelephonyOnly()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
DumpstateWifiOnly()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 
DumpstateBoard()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 
ShowUsageAndExit(int exitCode=1)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 
ExitOnInvalidArgs()1701 static void ExitOnInvalidArgs() {
1702     fprintf(stderr, "invalid combination of args\n");
1703     ShowUsageAndExit();
1704 }
1705 
register_sig_handler()1706 static void register_sig_handler() {
1707     signal(SIGPIPE, SIG_IGN);
1708 }
1709 
FinishZipFile()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 
SHA256_file_hash(const std::string & filepath)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 
SendBroadcast(const std::string & action,const std::vector<std::string> & args)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 
Vibrate(int duration_ms)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. */
run_main(int argc,char * argv[])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