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 #include <dirent.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <limits.h>
22 #include <memory>
23 #include <regex>
24 #include <set>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string>
29 #include <string.h>
30 #include <sys/prctl.h>
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36
37 #include <android-base/stringprintf.h>
38 #include <cutils/properties.h>
39
40 #include "private/android_filesystem_config.h"
41
42 #define LOG_TAG "dumpstate"
43 #include <cutils/log.h>
44
45 #include "dumpstate.h"
46 #include "ScopedFd.h"
47 #include "ziparchive/zip_writer.h"
48
49 #include "mincrypt/sha256.h"
50
51 using android::base::StringPrintf;
52
53 /* read before root is shed */
54 static char cmdline_buf[16384] = "(unknown)";
55 static const char *dump_traces_path = NULL;
56
57 // TODO: variables below should be part of dumpstate object
58 static unsigned long id;
59 static char build_type[PROPERTY_VALUE_MAX];
60 static time_t now;
61 static std::unique_ptr<ZipWriter> zip_writer;
62 static std::set<std::string> mount_points;
63 void add_mountinfo();
64 int control_socket_fd = -1;
65 /* suffix of the bugreport files - it's typically the date (when invoked with -d),
66 * although it could be changed by the user using a system property */
67 static std::string suffix;
68
69 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
70 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
71
72 #define RAFT_DIR "/data/misc/raft"
73 #define RECOVERY_DIR "/cache/recovery"
74 #define RECOVERY_DATA_DIR "/data/misc/recovery"
75 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
76 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
77 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
78 #define TOMBSTONE_DIR "/data/tombstones"
79 #define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
80 /* Can accomodate a tombstone number up to 9999. */
81 #define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
82 #define NUM_TOMBSTONES 10
83 #define WLUTIL "/vendor/xbin/wlutil"
84
85 typedef struct {
86 char name[TOMBSTONE_MAX_LEN];
87 int fd;
88 } tombstone_data_t;
89
90 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
91
92 const std::string ZIP_ROOT_DIR = "FS";
93 std::string bugreport_dir;
94
95 /*
96 * List of supported zip format versions.
97 *
98 * See bugreport-format.txt for more info.
99 */
100 static std::string VERSION_DEFAULT = "1.0";
101
is_user_build()102 bool is_user_build() {
103 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
104 }
105
106 /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
107 * otherwise gets just those modified in the last half an hour. */
get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES])108 static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
109 time_t thirty_minutes_ago = now - 60*30;
110 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
111 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
112 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
113 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
114 struct stat st;
115 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
116 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
117 data[i].fd = fd;
118 } else {
119 close(fd);
120 data[i].fd = -1;
121 }
122 }
123 }
124
125 // for_each_pid() callback to get mount info about a process.
do_mountinfo(int pid,const char * name)126 void do_mountinfo(int pid, const char *name) {
127 char path[PATH_MAX];
128
129 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
130 // are added.
131 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
132 char linkname[PATH_MAX];
133 ssize_t r = readlink(path, linkname, PATH_MAX);
134 if (r == -1) {
135 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
136 return;
137 }
138 linkname[r] = '\0';
139
140 if (mount_points.find(linkname) == mount_points.end()) {
141 // First time this mount point was found: add it
142 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
143 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
144 mount_points.insert(linkname);
145 } else {
146 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
147 }
148 }
149 }
150
add_mountinfo()151 void add_mountinfo() {
152 if (!zip_writer) return;
153 const char *title = "MOUNT INFO";
154 mount_points.clear();
155 DurationReporter duration_reporter(title, NULL);
156 for_each_pid(do_mountinfo, NULL);
157 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
158 }
159
dump_dev_files(const char * title,const char * driverpath,const char * filename)160 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
161 {
162 DIR *d;
163 struct dirent *de;
164 char path[PATH_MAX];
165
166 d = opendir(driverpath);
167 if (d == NULL) {
168 return;
169 }
170
171 while ((de = readdir(d))) {
172 if (de->d_type != DT_LNK) {
173 continue;
174 }
175 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
176 dump_file(title, path);
177 }
178
179 closedir(d);
180 }
181
dump_systrace()182 static void dump_systrace() {
183 if (!zip_writer) {
184 MYLOGD("Not dumping systrace because zip_writer is not set\n");
185 return;
186 }
187 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
188 if (systrace_path.empty()) {
189 MYLOGE("Not dumping systrace because path is empty\n");
190 return;
191 }
192 const char* path = "/sys/kernel/debug/tracing/tracing_on";
193 long int is_tracing;
194 if (read_file_as_long(path, &is_tracing)) {
195 return; // error already logged
196 }
197 if (is_tracing <= 0) {
198 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
199 return;
200 }
201
202 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
203 systrace_path.c_str());
204 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
205 systrace_path.c_str(), NULL)) {
206 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
207 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
208 // we should call strace to stop itself, but there is no such option yet (just a
209 // --async_stop, which stops and dump
210 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
211 // MYLOGE("could not stop systrace ");
212 // }
213 }
214 if (!add_zip_entry("systrace.txt", systrace_path)) {
215 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
216 } else {
217 if (remove(systrace_path.c_str())) {
218 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
219 }
220 }
221 }
222
dump_raft()223 static void dump_raft() {
224 if (is_user_build()) {
225 return;
226 }
227
228 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
229 if (raft_log_path.empty()) {
230 MYLOGD("raft_log_path is empty\n");
231 return;
232 }
233
234 struct stat s;
235 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
236 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
237 return;
238 }
239
240 if (!zip_writer) {
241 // Write compressed and encoded raft logs to stdout if not zip_writer.
242 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
243 return;
244 }
245
246 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
247 "-o", raft_log_path.c_str(), NULL);
248 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
249 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
250 } else {
251 if (remove(raft_log_path.c_str())) {
252 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
253 }
254 }
255 }
256
skip_not_stat(const char * path)257 static bool skip_not_stat(const char *path) {
258 static const char stat[] = "/stat";
259 size_t len = strlen(path);
260 if (path[len - 1] == '/') { /* Directory? */
261 return false;
262 }
263 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
264 }
265
skip_none(const char * path)266 static bool skip_none(const char *path) {
267 return false;
268 }
269
270 static const char mmcblk0[] = "/sys/block/mmcblk0/";
271 unsigned long worst_write_perf = 20000; /* in KB/s */
272
273 //
274 // stat offsets
275 // Name units description
276 // ---- ----- -----------
277 // read I/Os requests number of read I/Os processed
278 #define __STAT_READ_IOS 0
279 // read merges requests number of read I/Os merged with in-queue I/O
280 #define __STAT_READ_MERGES 1
281 // read sectors sectors number of sectors read
282 #define __STAT_READ_SECTORS 2
283 // read ticks milliseconds total wait time for read requests
284 #define __STAT_READ_TICKS 3
285 // write I/Os requests number of write I/Os processed
286 #define __STAT_WRITE_IOS 4
287 // write merges requests number of write I/Os merged with in-queue I/O
288 #define __STAT_WRITE_MERGES 5
289 // write sectors sectors number of sectors written
290 #define __STAT_WRITE_SECTORS 6
291 // write ticks milliseconds total wait time for write requests
292 #define __STAT_WRITE_TICKS 7
293 // in_flight requests number of I/Os currently in flight
294 #define __STAT_IN_FLIGHT 8
295 // io_ticks milliseconds total time this block device has been active
296 #define __STAT_IO_TICKS 9
297 // time_in_queue milliseconds total wait time for all requests
298 #define __STAT_IN_QUEUE 10
299 #define __STAT_NUMBER_FIELD 11
300 //
301 // read I/Os, write I/Os
302 // =====================
303 //
304 // These values increment when an I/O request completes.
305 //
306 // read merges, write merges
307 // =========================
308 //
309 // These values increment when an I/O request is merged with an
310 // already-queued I/O request.
311 //
312 // read sectors, write sectors
313 // ===========================
314 //
315 // These values count the number of sectors read from or written to this
316 // block device. The "sectors" in question are the standard UNIX 512-byte
317 // sectors, not any device- or filesystem-specific block size. The
318 // counters are incremented when the I/O completes.
319 #define SECTOR_SIZE 512
320 //
321 // read ticks, write ticks
322 // =======================
323 //
324 // These values count the number of milliseconds that I/O requests have
325 // waited on this block device. If there are multiple I/O requests waiting,
326 // these values will increase at a rate greater than 1000/second; for
327 // example, if 60 read requests wait for an average of 30 ms, the read_ticks
328 // field will increase by 60*30 = 1800.
329 //
330 // in_flight
331 // =========
332 //
333 // This value counts the number of I/O requests that have been issued to
334 // the device driver but have not yet completed. It does not include I/O
335 // requests that are in the queue but not yet issued to the device driver.
336 //
337 // io_ticks
338 // ========
339 //
340 // This value counts the number of milliseconds during which the device has
341 // had I/O requests queued.
342 //
343 // time_in_queue
344 // =============
345 //
346 // This value counts the number of milliseconds that I/O requests have waited
347 // on this block device. If there are multiple I/O requests waiting, this
348 // value will increase as the product of the number of milliseconds times the
349 // number of requests waiting (see "read ticks" above for an example).
350 #define S_TO_MS 1000
351 //
352
dump_stat_from_fd(const char * title __unused,const char * path,int fd)353 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
354 unsigned long long fields[__STAT_NUMBER_FIELD];
355 bool z;
356 char *cp, *buffer = NULL;
357 size_t i = 0;
358 FILE *fp = fdopen(fd, "rb");
359 getline(&buffer, &i, fp);
360 fclose(fp);
361 if (!buffer) {
362 return -errno;
363 }
364 i = strlen(buffer);
365 while ((i > 0) && (buffer[i - 1] == '\n')) {
366 buffer[--i] = '\0';
367 }
368 if (!*buffer) {
369 free(buffer);
370 return 0;
371 }
372 z = true;
373 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
374 fields[i] = strtoull(cp, &cp, 10);
375 if (fields[i] != 0) {
376 z = false;
377 }
378 }
379 if (z) { /* never accessed */
380 free(buffer);
381 return 0;
382 }
383
384 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
385 path += sizeof(mmcblk0) - 1;
386 }
387
388 printf("%s: %s\n", path, buffer);
389 free(buffer);
390
391 if (fields[__STAT_IO_TICKS]) {
392 unsigned long read_perf = 0;
393 unsigned long read_ios = 0;
394 if (fields[__STAT_READ_TICKS]) {
395 unsigned long long divisor = fields[__STAT_READ_TICKS]
396 * fields[__STAT_IO_TICKS];
397 read_perf = ((unsigned long long)SECTOR_SIZE
398 * fields[__STAT_READ_SECTORS]
399 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
400 / divisor;
401 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
402 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
403 / divisor;
404 }
405
406 unsigned long write_perf = 0;
407 unsigned long write_ios = 0;
408 if (fields[__STAT_WRITE_TICKS]) {
409 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
410 * fields[__STAT_IO_TICKS];
411 write_perf = ((unsigned long long)SECTOR_SIZE
412 * fields[__STAT_WRITE_SECTORS]
413 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
414 / divisor;
415 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
416 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
417 / divisor;
418 }
419
420 unsigned queue = (fields[__STAT_IN_QUEUE]
421 + (fields[__STAT_IO_TICKS] >> 1))
422 / fields[__STAT_IO_TICKS];
423
424 if (!write_perf && !write_ios) {
425 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
426 path, read_perf, read_ios, queue);
427 } else {
428 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
429 path, read_perf, read_ios, write_perf, write_ios, queue);
430 }
431
432 /* bugreport timeout factor adjustment */
433 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
434 worst_write_perf = write_perf;
435 }
436 }
437 return 0;
438 }
439
440 /* Copied policy from system/core/logd/LogBuffer.cpp */
441
442 #define LOG_BUFFER_SIZE (256 * 1024)
443 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
444 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
445
valid_size(unsigned long value)446 static bool valid_size(unsigned long value) {
447 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
448 return false;
449 }
450
451 long pages = sysconf(_SC_PHYS_PAGES);
452 if (pages < 1) {
453 return true;
454 }
455
456 long pagesize = sysconf(_SC_PAGESIZE);
457 if (pagesize <= 1) {
458 pagesize = PAGE_SIZE;
459 }
460
461 // maximum memory impact a somewhat arbitrary ~3%
462 pages = (pages + 31) / 32;
463 unsigned long maximum = pages * pagesize;
464
465 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
466 return true;
467 }
468
469 return value <= maximum;
470 }
471
property_get_size(const char * key)472 static unsigned long property_get_size(const char *key) {
473 unsigned long value;
474 char *cp, property[PROPERTY_VALUE_MAX];
475
476 property_get(key, property, "");
477 value = strtoul(property, &cp, 10);
478
479 switch(*cp) {
480 case 'm':
481 case 'M':
482 value *= 1024;
483 /* FALLTHRU */
484 case 'k':
485 case 'K':
486 value *= 1024;
487 /* FALLTHRU */
488 case '\0':
489 break;
490
491 default:
492 value = 0;
493 }
494
495 if (!valid_size(value)) {
496 value = 0;
497 }
498
499 return value;
500 }
501
502 /* timeout in ms */
logcat_timeout(const char * name)503 static unsigned long logcat_timeout(const char *name) {
504 static const char global_tuneable[] = "persist.logd.size"; // Settings App
505 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
506 char key[PROP_NAME_MAX];
507 unsigned long property_size, default_size;
508
509 default_size = property_get_size(global_tuneable);
510 if (!default_size) {
511 default_size = property_get_size(global_default);
512 }
513
514 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
515 property_size = property_get_size(key);
516
517 if (!property_size) {
518 snprintf(key, sizeof(key), "%s.%s", global_default, name);
519 property_size = property_get_size(key);
520 }
521
522 if (!property_size) {
523 property_size = default_size;
524 }
525
526 if (!property_size) {
527 property_size = LOG_BUFFER_SIZE;
528 }
529
530 /* Engineering margin is ten-fold our guess */
531 return 10 * (property_size + worst_write_perf) / worst_write_perf;
532 }
533
534 /* End copy from system/core/logd/LogBuffer.cpp */
535
536 /* dumps the current system state to stdout */
print_header(std::string version)537 static void print_header(std::string version) {
538 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
539 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
540 char network[PROPERTY_VALUE_MAX], date[80];
541
542 property_get("ro.build.display.id", build, "(unknown)");
543 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
544 property_get("ro.build.type", build_type, "(unknown)");
545 property_get("gsm.version.baseband", radio, "(unknown)");
546 property_get("ro.bootloader", bootloader, "(unknown)");
547 property_get("gsm.operator.alpha", network, "(unknown)");
548 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
549
550 printf("========================================================\n");
551 printf("== dumpstate: %s\n", date);
552 printf("========================================================\n");
553
554 printf("\n");
555 printf("Build: %s\n", build);
556 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
557 printf("Bootloader: %s\n", bootloader);
558 printf("Radio: %s\n", radio);
559 printf("Network: %s\n", network);
560
561 printf("Kernel: ");
562 dump_file(NULL, "/proc/version");
563 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
564 printf("Bugreport format version: %s\n", version.c_str());
565 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
566 printf("\n");
567 }
568
569 // List of file extensions that can cause a zip file attachment to be rejected by some email
570 // service providers.
571 static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
572 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
573 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
574 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
575 };
576
add_zip_entry_from_fd(const std::string & entry_name,int fd)577 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
578 if (!zip_writer) {
579 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
580 entry_name.c_str());
581 return false;
582 }
583 std::string valid_name = entry_name;
584
585 // Rename extension if necessary.
586 size_t idx = entry_name.rfind(".");
587 if (idx != std::string::npos) {
588 std::string extension = entry_name.substr(idx);
589 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
590 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
591 valid_name = entry_name + ".renamed";
592 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
593 }
594 }
595
596 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
597 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
598 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
599 ZipWriter::kCompress, get_mtime(fd, now));
600 if (err) {
601 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
602 ZipWriter::ErrorCodeString(err));
603 return false;
604 }
605
606 std::vector<uint8_t> buffer(65536);
607 while (1) {
608 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
609 if (bytes_read == 0) {
610 break;
611 } else if (bytes_read == -1) {
612 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
613 return false;
614 }
615 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
616 if (err) {
617 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
618 return false;
619 }
620 }
621
622 err = zip_writer->FinishEntry();
623 if (err) {
624 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
625 return false;
626 }
627
628 return true;
629 }
630
add_zip_entry(const std::string & entry_name,const std::string & entry_path)631 bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
632 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
633 if (fd.get() == -1) {
634 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
635 return false;
636 }
637
638 return add_zip_entry_from_fd(entry_name, fd.get());
639 }
640
641 /* adds a file to the existing zipped bugreport */
_add_file_from_fd(const char * title,const char * path,int fd)642 static int _add_file_from_fd(const char *title, const char *path, int fd) {
643 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
644 }
645
646 // TODO: move to util.cpp
add_dir(const char * dir,bool recursive)647 void add_dir(const char *dir, bool recursive) {
648 if (!zip_writer) {
649 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
650 return;
651 }
652 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
653 DurationReporter duration_reporter(dir, NULL);
654 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
655 }
656
657 /* adds a text entry entry to the existing zip file. */
add_text_zip_entry(const std::string & entry_name,const std::string & content)658 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
659 if (!zip_writer) {
660 MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str());
661 return false;
662 }
663 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
664 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
665 if (err) {
666 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
667 ZipWriter::ErrorCodeString(err));
668 return false;
669 }
670
671 err = zip_writer->WriteBytes(content.c_str(), content.length());
672 if (err) {
673 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
674 ZipWriter::ErrorCodeString(err));
675 return false;
676 }
677
678 err = zip_writer->FinishEntry();
679 if (err) {
680 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
681 return false;
682 }
683
684 return true;
685 }
686
dump_iptables()687 static void dump_iptables() {
688 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
689 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
690 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
691 /* no ip6 nat */
692 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
693 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
694 }
695
dumpstate(const std::string & screenshot_path,const std::string & version)696 static void dumpstate(const std::string& screenshot_path, const std::string& version) {
697 DurationReporter duration_reporter("DUMPSTATE");
698 unsigned long timeout;
699
700 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
701 run_command("UPTIME", 10, "uptime", NULL);
702 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
703 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
704 dump_file("MEMORY INFO", "/proc/meminfo");
705 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
706 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
707 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
708 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
709 dump_file("SLAB INFO", "/proc/slabinfo");
710 dump_file("ZONEINFO", "/proc/zoneinfo");
711 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
712 dump_file("BUDDYINFO", "/proc/buddyinfo");
713 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
714
715 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
716 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
717 dump_file("KERNEL SYNC", "/d/sync");
718
719 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
720 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
721
722 run_command("PRINTENV", 10, "printenv", NULL);
723 run_command("NETSTAT", 10, "netstat", "-n", NULL);
724 run_command("LSMOD", 10, "lsmod", NULL);
725
726 do_dmesg();
727
728 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
729 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
730 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
731 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
732
733 if (!screenshot_path.empty()) {
734 MYLOGI("taking late screenshot\n");
735 take_screenshot(screenshot_path);
736 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
737 }
738
739 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
740 // calculate timeout
741 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
742 if (timeout < 20000) {
743 timeout = 20000;
744 }
745 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
746 "-v", "printable",
747 "-d",
748 "*:v", NULL);
749 timeout = logcat_timeout("events");
750 if (timeout < 20000) {
751 timeout = 20000;
752 }
753 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
754 "-v", "threadtime",
755 "-v", "printable",
756 "-d",
757 "*:v", NULL);
758 timeout = logcat_timeout("radio");
759 if (timeout < 20000) {
760 timeout = 20000;
761 }
762 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
763 "-v", "threadtime",
764 "-v", "printable",
765 "-d",
766 "*:v", NULL);
767
768 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
769
770 /* show the traces we collected in main(), if that was done */
771 if (dump_traces_path != NULL) {
772 dump_file("VM TRACES JUST NOW", dump_traces_path);
773 }
774
775 /* only show ANR traces if they're less than 15 minutes old */
776 struct stat st;
777 char anr_traces_path[PATH_MAX];
778 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
779 if (!anr_traces_path[0]) {
780 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
781 } else {
782 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
783 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
784 if (fd < 0) {
785 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
786 } else {
787 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
788 }
789 }
790
791 /* slow traces for slow operations */
792 if (anr_traces_path[0] != 0) {
793 int tail = strlen(anr_traces_path)-1;
794 while (tail > 0 && anr_traces_path[tail] != '/') {
795 tail--;
796 }
797 int i = 0;
798 while (1) {
799 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
800 if (stat(anr_traces_path, &st)) {
801 // No traces file at this index, done with the files.
802 break;
803 }
804 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
805 i++;
806 }
807 }
808
809 int dumped = 0;
810 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
811 if (tombstone_data[i].fd != -1) {
812 const char *name = tombstone_data[i].name;
813 int fd = tombstone_data[i].fd;
814 dumped = 1;
815 if (zip_writer) {
816 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
817 MYLOGE("Unable to add tombstone %s to zip file\n", name);
818 }
819 } else {
820 dump_file_from_fd("TOMBSTONE", name, fd);
821 }
822 close(fd);
823 tombstone_data[i].fd = -1;
824 }
825 }
826 if (!dumped) {
827 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
828 }
829
830 dump_file("NETWORK DEV INFO", "/proc/net/dev");
831 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
832 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
833 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
834 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
835
836 if (!stat(PSTORE_LAST_KMSG, &st)) {
837 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
838 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
839 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
840 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
841 } else {
842 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
843 dump_file("LAST KMSG", "/proc/last_kmsg");
844 }
845
846 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
847 run_command("LAST LOGCAT", 10, "logcat", "-L",
848 "-b", "all",
849 "-v", "threadtime",
850 "-v", "printable",
851 "-d",
852 "*:v", NULL);
853
854 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
855
856 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
857
858 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
859 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
860
861 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
862 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
863
864 dump_route_tables();
865
866 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
867 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
868 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
869 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
870
871 #ifdef FWDUMP_bcmdhd
872 run_command("ND OFFLOAD TABLE", 5,
873 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
874
875 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
876 SU_PATH, "root", WLUTIL, "counters", NULL);
877
878 run_command("ND OFFLOAD STATUS (1)", 5,
879 SU_PATH, "root", WLUTIL, "nd_status", NULL);
880
881 #endif
882 dump_file("INTERRUPTS (1)", "/proc/interrupts");
883
884 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
885
886 #ifdef FWDUMP_bcmdhd
887 run_command("DUMP WIFI STATUS", 20,
888 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
889
890 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
891 SU_PATH, "root", WLUTIL, "counters", NULL);
892
893 run_command("ND OFFLOAD STATUS (2)", 5,
894 SU_PATH, "root", WLUTIL, "nd_status", NULL);
895 #endif
896 dump_file("INTERRUPTS (2)", "/proc/interrupts");
897
898 print_properties();
899
900 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
901 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
902
903 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
904
905 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
906
907 printf("------ BACKLIGHTS ------\n");
908 printf("LCD brightness=");
909 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
910 printf("Button brightness=");
911 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
912 printf("Keyboard brightness=");
913 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
914 printf("ALS mode=");
915 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
916 printf("LCD driver registers:\n");
917 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
918 printf("\n");
919
920 /* Binder state is expensive to look at as it uses a lot of memory. */
921 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
922 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
923 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
924 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
925 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
926
927 printf("========================================================\n");
928 printf("== Board\n");
929 printf("========================================================\n");
930
931 dumpstate_board();
932 printf("\n");
933
934 /* Migrate the ril_dumpstate to a dumpstate_board()? */
935 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
936 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
937 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
938 if (is_user_build()) {
939 // su does not exist on user builds, so try running without it.
940 // This way any implementations of vril-dump that do not require
941 // root can run on user builds.
942 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
943 "vril-dump", NULL);
944 } else {
945 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
946 SU_PATH, "root", "vril-dump", NULL);
947 }
948 }
949
950 printf("========================================================\n");
951 printf("== Android Framework Services\n");
952 printf("========================================================\n");
953
954 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
955
956 printf("========================================================\n");
957 printf("== Checkins\n");
958 printf("========================================================\n");
959
960 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
961 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
962 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
963 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
964 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
965 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
966
967 printf("========================================================\n");
968 printf("== Running Application Activities\n");
969 printf("========================================================\n");
970
971 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
972
973 printf("========================================================\n");
974 printf("== Running Application Services\n");
975 printf("========================================================\n");
976
977 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
978
979 printf("========================================================\n");
980 printf("== Running Application Providers\n");
981 printf("========================================================\n");
982
983 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
984
985
986 printf("========================================================\n");
987 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
988 getpid(), progress, weight_total, WEIGHT_TOTAL);
989 printf("========================================================\n");
990 printf("== dumpstate: done\n");
991 printf("========================================================\n");
992 }
993
usage()994 static void usage() {
995 fprintf(stderr,
996 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
997 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
998 " -h: display this help message\n"
999 " -b: play sound file instead of vibrate, at beginning of job\n"
1000 " -e: play sound file instead of vibrate, at end of job\n"
1001 " -o: write to file (instead of stdout)\n"
1002 " -d: append date to filename (requires -o)\n"
1003 " -p: capture screenshot to filename.png (requires -o)\n"
1004 " -z: generate zipped file (requires -o)\n"
1005 " -s: write output to control socket (for init)\n"
1006 " -S: write file location to control socket (for init; requires -o and -z)"
1007 " -q: disable vibrate\n"
1008 " -B: send broadcast when finished (requires -o)\n"
1009 " -P: send broadcast when started and update system properties on "
1010 "progress (requires -o and -B)\n"
1011 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1012 "shouldn't be used with -P)\n"
1013 " -V: sets the bugreport format version (valid values: %s)\n",
1014 VERSION_DEFAULT.c_str());
1015 }
1016
sigpipe_handler(int n)1017 static void sigpipe_handler(int n) {
1018 // don't complain to stderr or stdout
1019 _exit(EXIT_FAILURE);
1020 }
1021
1022 /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1023 temporary file.
1024 */
finish_zip_file(const std::string & bugreport_name,const std::string & bugreport_path,time_t now)1025 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
1026 time_t now) {
1027 if (!add_zip_entry(bugreport_name, bugreport_path)) {
1028 MYLOGE("Failed to add text entry to .zip file\n");
1029 return false;
1030 }
1031 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
1032 MYLOGE("Failed to add main_entry.txt to .zip file\n");
1033 return false;
1034 }
1035
1036 int32_t err = zip_writer->Finish();
1037 if (err) {
1038 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
1039 return false;
1040 }
1041
1042 if (is_user_build()) {
1043 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1044 if (remove(bugreport_path.c_str())) {
1045 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1046 }
1047 } else {
1048 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1049 }
1050
1051 return true;
1052 }
1053
SHA256_file_hash(std::string filepath)1054 static std::string SHA256_file_hash(std::string filepath) {
1055 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1056 | O_NOFOLLOW)));
1057 if (fd.get() == -1) {
1058 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
1059 return NULL;
1060 }
1061
1062 SHA256_CTX ctx;
1063 SHA256_init(&ctx);
1064
1065 std::vector<uint8_t> buffer(65536);
1066 while (1) {
1067 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1068 if (bytes_read == 0) {
1069 break;
1070 } else if (bytes_read == -1) {
1071 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
1072 return NULL;
1073 }
1074
1075 SHA256_update(&ctx, buffer.data(), bytes_read);
1076 }
1077
1078 uint8_t hash[SHA256_DIGEST_SIZE];
1079 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1080 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
1081 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1082 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
1083 }
1084 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1085 return std::string(hash_buffer);
1086 }
1087
main(int argc,char * argv[])1088 int main(int argc, char *argv[]) {
1089 struct sigaction sigact;
1090 int do_add_date = 0;
1091 int do_zip_file = 0;
1092 int do_vibrate = 1;
1093 char* use_outfile = 0;
1094 int use_socket = 0;
1095 int use_control_socket = 0;
1096 int do_fb = 0;
1097 int do_broadcast = 0;
1098 int do_early_screenshot = 0;
1099 int is_remote_mode = 0;
1100 std::string version = VERSION_DEFAULT;
1101
1102 now = time(NULL);
1103
1104 MYLOGI("begin\n");
1105
1106 /* gets the sequential id */
1107 char last_id[PROPERTY_VALUE_MAX];
1108 property_get("dumpstate.last_id", last_id, "0");
1109 id = strtoul(last_id, NULL, 10) + 1;
1110 snprintf(last_id, sizeof(last_id), "%lu", id);
1111 property_set("dumpstate.last_id", last_id);
1112 MYLOGI("dumpstate id: %lu\n", id);
1113
1114 /* clear SIGPIPE handler */
1115 memset(&sigact, 0, sizeof(sigact));
1116 sigact.sa_handler = sigpipe_handler;
1117 sigaction(SIGPIPE, &sigact, NULL);
1118
1119 /* set as high priority, and protect from OOM killer */
1120 setpriority(PRIO_PROCESS, 0, -20);
1121
1122 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
1123 if (oom_adj) {
1124 fputs("-1000", oom_adj);
1125 fclose(oom_adj);
1126 } else {
1127 /* fallback to kernels <= 2.6.35 */
1128 oom_adj = fopen("/proc/self/oom_adj", "we");
1129 if (oom_adj) {
1130 fputs("-17", oom_adj);
1131 fclose(oom_adj);
1132 }
1133 }
1134
1135 /* parse arguments */
1136 std::string args;
1137 format_args(argc, const_cast<const char **>(argv), &args);
1138 MYLOGD("Dumpstate command line: %s\n", args.c_str());
1139 int c;
1140 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
1141 switch (c) {
1142 case 'd': do_add_date = 1; break;
1143 case 'z': do_zip_file = 1; break;
1144 case 'o': use_outfile = optarg; break;
1145 case 's': use_socket = 1; break;
1146 case 'S': use_control_socket = 1; break;
1147 case 'v': break; // compatibility no-op
1148 case 'q': do_vibrate = 0; break;
1149 case 'p': do_fb = 1; break;
1150 case 'P': do_update_progress = 1; break;
1151 case 'R': is_remote_mode = 1; break;
1152 case 'B': do_broadcast = 1; break;
1153 case 'V': version = optarg; break;
1154 case '?': printf("\n");
1155 case 'h':
1156 usage();
1157 exit(1);
1158 }
1159 }
1160
1161 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
1162 usage();
1163 exit(1);
1164 }
1165
1166 if (use_control_socket && !do_zip_file) {
1167 usage();
1168 exit(1);
1169 }
1170
1171 if (do_update_progress && !do_broadcast) {
1172 usage();
1173 exit(1);
1174 }
1175
1176 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1177 usage();
1178 exit(1);
1179 }
1180
1181 if (version != VERSION_DEFAULT) {
1182 usage();
1183 exit(1);
1184 }
1185
1186 MYLOGI("bugreport format version: %s\n", version.c_str());
1187
1188 do_early_screenshot = do_update_progress;
1189
1190 // If we are going to use a socket, do it as early as possible
1191 // to avoid timeouts from bugreport.
1192 if (use_socket) {
1193 redirect_to_socket(stdout, "dumpstate");
1194 }
1195
1196 if (use_control_socket) {
1197 MYLOGD("Opening control socket\n");
1198 control_socket_fd = open_socket("dumpstate");
1199 do_update_progress = 1;
1200 }
1201
1202 /* full path of the temporary file containing the bugreport */
1203 std::string tmp_path;
1204
1205 /* full path of the file containing the dumpstate logs*/
1206 std::string log_path;
1207
1208 /* full path of the systrace file, when enabled */
1209 std::string systrace_path;
1210
1211 /* full path of the temporary file containing the screenshot (when requested) */
1212 std::string screenshot_path;
1213
1214 /* base name (without suffix or extensions) of the bugreport files */
1215 std::string base_name;
1216
1217 /* pointer to the actual path, be it zip or text */
1218 std::string path;
1219
1220 /* pointer to the zipped file */
1221 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
1222
1223 /* redirect output if needed */
1224 bool is_redirecting = !use_socket && use_outfile;
1225
1226 if (is_redirecting) {
1227 bugreport_dir = dirname(use_outfile);
1228 base_name = basename(use_outfile);
1229 if (do_add_date) {
1230 char date[80];
1231 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1232 suffix = date;
1233 } else {
1234 suffix = "undated";
1235 }
1236 char build_id[PROPERTY_VALUE_MAX];
1237 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1238 base_name = base_name + "-" + build_id;
1239 if (do_fb) {
1240 // TODO: if dumpstate was an object, the paths could be internal variables and then
1241 // we could have a function to calculate the derived values, such as:
1242 // screenshot_path = GetPath(".png");
1243 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1244 }
1245 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
1246 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1247 + std::to_string(getpid()) + ".txt";
1248
1249 MYLOGD("Bugreport dir: %s\n"
1250 "Base name: %s\n"
1251 "Suffix: %s\n"
1252 "Log path: %s\n"
1253 "Temporary path: %s\n"
1254 "Screenshot path: %s\n",
1255 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1256 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
1257
1258 if (do_zip_file) {
1259 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1260 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
1261 create_parent_dirs(path.c_str());
1262 zip_file.reset(fopen(path.c_str(), "wb"));
1263 if (!zip_file) {
1264 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
1265 do_zip_file = 0;
1266 } else {
1267 zip_writer.reset(new ZipWriter(zip_file.get()));
1268 }
1269 add_text_zip_entry("version.txt", version);
1270 }
1271
1272 if (do_update_progress) {
1273 if (do_broadcast) {
1274 // clang-format off
1275 std::vector<std::string> am_args = {
1276 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1277 "--es", "android.intent.extra.NAME", suffix,
1278 "--ei", "android.intent.extra.ID", std::to_string(id),
1279 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1280 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1281 };
1282 // clang-format on
1283 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1284 }
1285 if (use_control_socket) {
1286 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1287 }
1288 }
1289 }
1290
1291 /* read /proc/cmdline before dropping root */
1292 FILE *cmdline = fopen("/proc/cmdline", "re");
1293 if (cmdline) {
1294 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1295 fclose(cmdline);
1296 }
1297
1298 /* open the vibrator before dropping root */
1299 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
1300 if (do_vibrate) {
1301 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
1302 if (vibrator) {
1303 vibrate(vibrator.get(), 150);
1304 }
1305 }
1306
1307 if (do_fb && do_early_screenshot) {
1308 if (screenshot_path.empty()) {
1309 // should not have happened
1310 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
1311 } else {
1312 MYLOGI("taking early screenshot\n");
1313 take_screenshot(screenshot_path);
1314 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
1315 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
1316 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
1317 screenshot_path.c_str(), strerror(errno));
1318 }
1319 }
1320 }
1321
1322 if (do_zip_file) {
1323 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
1324 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
1325 }
1326 }
1327
1328 if (is_redirecting) {
1329 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
1330 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1331 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1332 log_path.c_str(), strerror(errno));
1333 }
1334 /* TODO: rather than generating a text file now and zipping it later,
1335 it would be more efficient to redirect stdout to the zip entry
1336 directly, but the libziparchive doesn't support that option yet. */
1337 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
1338 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1339 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1340 tmp_path.c_str(), strerror(errno));
1341 }
1342 }
1343 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1344 // In particular, DurationReport objects should be created passing 'title, NULL', so their
1345 // duration is logged into MYLOG instead.
1346 print_header(version);
1347
1348 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1349 dump_systrace();
1350
1351 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1352 dump_raft();
1353
1354 // Invoking the following dumpsys calls before dump_traces() to try and
1355 // keep the system stats as close to its initial state as possible.
1356 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
1357 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
1358
1359 /* collect stack traces from Dalvik and native processes (needs root) */
1360 dump_traces_path = dump_traces();
1361
1362 /* Run some operations that require root. */
1363 get_tombstone_fds(tombstone_data);
1364 add_dir(RECOVERY_DIR, true);
1365 add_dir(RECOVERY_DATA_DIR, true);
1366 add_dir(LOGPERSIST_DATA_DIR, false);
1367 if (!is_user_build()) {
1368 add_dir(PROFILE_DATA_DIR_CUR, true);
1369 add_dir(PROFILE_DATA_DIR_REF, true);
1370 }
1371 add_mountinfo();
1372 dump_iptables();
1373
1374 if (!drop_root_user()) {
1375 return -1;
1376 }
1377
1378 dumpstate(do_early_screenshot ? "": screenshot_path, version);
1379
1380 /* close output if needed */
1381 if (is_redirecting) {
1382 fclose(stdout);
1383 }
1384
1385 /* rename or zip the (now complete) .tmp file to its final location */
1386 if (use_outfile) {
1387
1388 /* check if user changed the suffix using system properties */
1389 char key[PROPERTY_KEY_MAX];
1390 char value[PROPERTY_VALUE_MAX];
1391 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
1392 property_get(key, value, "");
1393 bool change_suffix= false;
1394 if (value[0]) {
1395 /* must whitelist which characters are allowed, otherwise it could cross directories */
1396 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1397 if (std::regex_match(value, valid_regex)) {
1398 change_suffix = true;
1399 } else {
1400 MYLOGE("invalid suffix provided by user: %s\n", value);
1401 }
1402 }
1403 if (change_suffix) {
1404 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
1405 suffix = value;
1406 if (!screenshot_path.empty()) {
1407 std::string new_screenshot_path =
1408 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1409 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
1410 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
1411 new_screenshot_path.c_str(), strerror(errno));
1412 } else {
1413 screenshot_path = new_screenshot_path;
1414 }
1415 }
1416 }
1417
1418 bool do_text_file = true;
1419 if (do_zip_file) {
1420 std::string entry_name = base_name + "-" + suffix + ".txt";
1421 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1422 if (!finish_zip_file(entry_name, tmp_path, now)) {
1423 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
1424 do_text_file = true;
1425 } else {
1426 do_text_file = false;
1427 // Since zip file is already created, it needs to be renamed.
1428 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1429 if (path != new_path) {
1430 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1431 if (rename(path.c_str(), new_path.c_str())) {
1432 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1433 new_path.c_str(), strerror(errno));
1434 } else {
1435 path = new_path;
1436 }
1437 }
1438 }
1439 }
1440 if (do_text_file) {
1441 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
1442 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
1443 if (rename(tmp_path.c_str(), path.c_str())) {
1444 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
1445 path.clear();
1446 }
1447 }
1448 if (use_control_socket) {
1449 if (do_text_file) {
1450 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1451 "for more details\n", log_path.c_str());
1452 } else {
1453 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1454 }
1455 }
1456 }
1457
1458 /* vibrate a few but shortly times to let user know it's finished */
1459 if (vibrator) {
1460 for (int i = 0; i < 3; i++) {
1461 vibrate(vibrator.get(), 75);
1462 usleep((75 + 50) * 1000);
1463 }
1464 }
1465
1466 /* tell activity manager we're done */
1467 if (do_broadcast) {
1468 if (!path.empty()) {
1469 MYLOGI("Final bugreport path: %s\n", path.c_str());
1470 // clang-format off
1471 std::vector<std::string> am_args = {
1472 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1473 "--ei", "android.intent.extra.ID", std::to_string(id),
1474 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1475 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
1476 "--es", "android.intent.extra.BUGREPORT", path,
1477 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
1478 };
1479 // clang-format on
1480 if (do_fb) {
1481 am_args.push_back("--es");
1482 am_args.push_back("android.intent.extra.SCREENSHOT");
1483 am_args.push_back(screenshot_path);
1484 }
1485 if (is_remote_mode) {
1486 am_args.push_back("--es");
1487 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1488 am_args.push_back(SHA256_file_hash(path));
1489 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1490 } else {
1491 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1492 }
1493 } else {
1494 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
1495 }
1496 }
1497
1498 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1499 MYLOGI("done\n");
1500
1501 if (is_redirecting) {
1502 fclose(stderr);
1503 }
1504
1505 if (use_control_socket && control_socket_fd != -1) {
1506 MYLOGD("Closing control socket\n");
1507 close(control_socket_fd);
1508 }
1509
1510 return 0;
1511 }
1512