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