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