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