dumpstate.cpp revision 635ca31754ae734b0c540ac5600d58ae55cd4237
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/capability.h> 31#include <sys/prctl.h> 32#include <sys/resource.h> 33#include <sys/stat.h> 34#include <sys/time.h> 35#include <sys/wait.h> 36#include <unistd.h> 37 38#include <android-base/stringprintf.h> 39#include <cutils/properties.h> 40 41#include "private/android_filesystem_config.h" 42 43#define LOG_TAG "dumpstate" 44#include <cutils/log.h> 45 46#include "dumpstate.h" 47#include "ScopedFd.h" 48#include "ziparchive/zip_writer.h" 49 50using android::base::StringPrintf; 51 52/* read before root is shed */ 53static char cmdline_buf[16384] = "(unknown)"; 54static const char *dump_traces_path = NULL; 55 56// TODO: should be part of dumpstate object 57static char build_type[PROPERTY_VALUE_MAX]; 58static time_t now; 59static std::unique_ptr<ZipWriter> zip_writer; 60static std::set<std::string> mount_points; 61void add_mountinfo(); 62static bool add_zip_entry(const std::string& entry_name, const std::string& entry_path); 63 64#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" 65 66#define RAFT_DIR "/data/misc/raft/" 67#define RECOVERY_DIR "/cache/recovery" 68#define TOMBSTONE_DIR "/data/tombstones" 69#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_" 70/* Can accomodate a tombstone number up to 9999. */ 71#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4) 72#define NUM_TOMBSTONES 10 73 74typedef struct { 75 char name[TOMBSTONE_MAX_LEN]; 76 int fd; 77} tombstone_data_t; 78 79static tombstone_data_t tombstone_data[NUM_TOMBSTONES]; 80 81// Root dir for all files copied as-is into the bugreport 82const std::string& ZIP_ROOT_DIR = "FS"; 83 84/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones, 85 * otherwise gets just those modified in the last half an hour. */ 86static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { 87 time_t thirty_minutes_ago = now - 60*30; 88 for (size_t i = 0; i < NUM_TOMBSTONES; i++) { 89 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); 90 int fd = TEMP_FAILURE_RETRY(open(data[i].name, 91 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); 92 struct stat st; 93 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && 94 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) { 95 data[i].fd = fd; 96 } else { 97 close(fd); 98 data[i].fd = -1; 99 } 100 } 101} 102 103// for_each_pid() callback to get mount info about a process. 104void do_mountinfo(int pid, const char *name) { 105 char path[PATH_MAX]; 106 107 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points 108 // are added. 109 sprintf(path, "/proc/%d/ns/mnt", pid); 110 char linkname[PATH_MAX]; 111 ssize_t r = readlink(path, linkname, PATH_MAX); 112 if (r == -1) { 113 ALOGE("Unable to read link for %s: %s\n", path, strerror(errno)); 114 return; 115 } 116 linkname[r] = '\0'; 117 118 if (mount_points.find(linkname) == mount_points.end()) { 119 // First time this mount point was found: add it 120 sprintf(path, "/proc/%d/mountinfo", pid); 121 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) { 122 mount_points.insert(linkname); 123 } else { 124 ALOGE("Unable to add mountinfo %s to zip file\n", path); 125 } 126 } 127} 128 129void add_mountinfo() { 130 if (!zip_writer) return; 131 const char *title = "MOUNT INFO"; 132 mount_points.clear(); 133 DurationReporter duration_reporter(title); 134 for_each_pid(do_mountinfo, NULL); 135 printf("%s: %d entries added to zip file\n", title, mount_points.size()); 136} 137 138static void dump_dev_files(const char *title, const char *driverpath, const char *filename) 139{ 140 DIR *d; 141 struct dirent *de; 142 char path[PATH_MAX]; 143 144 d = opendir(driverpath); 145 if (d == NULL) { 146 return; 147 } 148 149 while ((de = readdir(d))) { 150 if (de->d_type != DT_LNK) { 151 continue; 152 } 153 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename); 154 dump_file(title, path); 155 } 156 157 closedir(d); 158} 159 160static bool skip_not_stat(const char *path) { 161 static const char stat[] = "/stat"; 162 size_t len = strlen(path); 163 if (path[len - 1] == '/') { /* Directory? */ 164 return false; 165 } 166 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ 167} 168 169static bool skip_none(const char *path) { 170 return false; 171} 172 173static const char mmcblk0[] = "/sys/block/mmcblk0/"; 174unsigned long worst_write_perf = 20000; /* in KB/s */ 175 176static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) { 177 unsigned long fields[11], read_perf, write_perf; 178 bool z; 179 char *cp, *buffer = NULL; 180 size_t i = 0; 181 FILE *fp = fdopen(fd, "rb"); 182 getline(&buffer, &i, fp); 183 fclose(fp); 184 if (!buffer) { 185 return -errno; 186 } 187 i = strlen(buffer); 188 while ((i > 0) && (buffer[i - 1] == '\n')) { 189 buffer[--i] = '\0'; 190 } 191 if (!*buffer) { 192 free(buffer); 193 return 0; 194 } 195 z = true; 196 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) { 197 fields[i] = strtol(cp, &cp, 0); 198 if (fields[i] != 0) { 199 z = false; 200 } 201 } 202 if (z) { /* never accessed */ 203 free(buffer); 204 return 0; 205 } 206 207 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) { 208 path += sizeof(mmcblk0) - 1; 209 } 210 211 printf("%s: %s\n", path, buffer); 212 free(buffer); 213 214 read_perf = 0; 215 if (fields[3]) { 216 read_perf = 512 * fields[2] / fields[3]; 217 } 218 write_perf = 0; 219 if (fields[7]) { 220 write_perf = 512 * fields[6] / fields[7]; 221 } 222 printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf); 223 if ((write_perf > 1) && (write_perf < worst_write_perf)) { 224 worst_write_perf = write_perf; 225 } 226 return 0; 227} 228 229/* Copied policy from system/core/logd/LogBuffer.cpp */ 230 231#define LOG_BUFFER_SIZE (256 * 1024) 232#define LOG_BUFFER_MIN_SIZE (64 * 1024UL) 233#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) 234 235static bool valid_size(unsigned long value) { 236 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { 237 return false; 238 } 239 240 long pages = sysconf(_SC_PHYS_PAGES); 241 if (pages < 1) { 242 return true; 243 } 244 245 long pagesize = sysconf(_SC_PAGESIZE); 246 if (pagesize <= 1) { 247 pagesize = PAGE_SIZE; 248 } 249 250 // maximum memory impact a somewhat arbitrary ~3% 251 pages = (pages + 31) / 32; 252 unsigned long maximum = pages * pagesize; 253 254 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { 255 return true; 256 } 257 258 return value <= maximum; 259} 260 261static unsigned long property_get_size(const char *key) { 262 unsigned long value; 263 char *cp, property[PROPERTY_VALUE_MAX]; 264 265 property_get(key, property, ""); 266 value = strtoul(property, &cp, 10); 267 268 switch(*cp) { 269 case 'm': 270 case 'M': 271 value *= 1024; 272 /* FALLTHRU */ 273 case 'k': 274 case 'K': 275 value *= 1024; 276 /* FALLTHRU */ 277 case '\0': 278 break; 279 280 default: 281 value = 0; 282 } 283 284 if (!valid_size(value)) { 285 value = 0; 286 } 287 288 return value; 289} 290 291/* timeout in ms */ 292static unsigned long logcat_timeout(const char *name) { 293 static const char global_tuneable[] = "persist.logd.size"; // Settings App 294 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk 295 char key[PROP_NAME_MAX]; 296 unsigned long property_size, default_size; 297 298 default_size = property_get_size(global_tuneable); 299 if (!default_size) { 300 default_size = property_get_size(global_default); 301 } 302 303 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name); 304 property_size = property_get_size(key); 305 306 if (!property_size) { 307 snprintf(key, sizeof(key), "%s.%s", global_default, name); 308 property_size = property_get_size(key); 309 } 310 311 if (!property_size) { 312 property_size = default_size; 313 } 314 315 if (!property_size) { 316 property_size = LOG_BUFFER_SIZE; 317 } 318 319 /* Engineering margin is ten-fold our guess */ 320 return 10 * (property_size + worst_write_perf) / worst_write_perf; 321} 322 323/* End copy from system/core/logd/LogBuffer.cpp */ 324 325/* dumps the current system state to stdout */ 326static void print_header() { 327 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; 328 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; 329 char network[PROPERTY_VALUE_MAX], date[80]; 330 331 property_get("ro.build.display.id", build, "(unknown)"); 332 property_get("ro.build.fingerprint", fingerprint, "(unknown)"); 333 property_get("ro.build.type", build_type, "(unknown)"); 334 property_get("ro.baseband", radio, "(unknown)"); 335 property_get("ro.bootloader", bootloader, "(unknown)"); 336 property_get("gsm.operator.alpha", network, "(unknown)"); 337 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); 338 339 printf("========================================================\n"); 340 printf("== dumpstate: %s\n", date); 341 printf("========================================================\n"); 342 343 printf("\n"); 344 printf("Build: %s\n", build); 345 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */ 346 printf("Bootloader: %s\n", bootloader); 347 printf("Radio: %s\n", radio); 348 printf("Network: %s\n", network); 349 350 printf("Kernel: "); 351 dump_file(NULL, "/proc/version"); 352 printf("Command line: %s\n", strtok(cmdline_buf, "\n")); 353 printf("\n"); 354} 355 356/* adds a new entry to the existing zip file. */ 357static bool add_zip_entry_from_fd(const std::string& entry_name, int fd) { 358 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), 359 ZipWriter::kCompress, get_mtime(fd, now)); 360 if (err) { 361 ALOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); 362 return false; 363 } 364 365 while (1) { 366 std::vector<uint8_t> buffer(65536); 367 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer))); 368 if (bytes_read == 0) { 369 break; 370 } else if (bytes_read == -1) { 371 ALOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno)); 372 return false; 373 } 374 err = zip_writer->WriteBytes(buffer.data(), bytes_read); 375 if (err) { 376 ALOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err)); 377 return false; 378 } 379 } 380 381 err = zip_writer->FinishEntry(); 382 if (err) { 383 ALOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err)); 384 return false; 385 } 386 387 return true; 388} 389 390/* adds a new entry to the existing zip file. */ 391static bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) { 392 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); 393 if (fd.get() == -1) { 394 ALOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno)); 395 return false; 396 } 397 398 return add_zip_entry_from_fd(entry_name, fd.get()); 399} 400 401/* adds a file to the existing zipped bugreport */ 402static int _add_file_from_fd(const char *title, const char *path, int fd) { 403 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1; 404} 405 406/* adds all files from a directory to the zipped bugreport file */ 407void add_dir(const char *dir, bool recursive) { 408 if (!zip_writer) return; 409 DurationReporter duration_reporter(dir); 410 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd); 411} 412 413static void dumpstate(const std::string& screenshot_path) { 414 std::unique_ptr<DurationReporter> duration_reporter(new DurationReporter("DUMPSTATE")); 415 unsigned long timeout; 416 417 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); 418 run_command("UPTIME", 10, "uptime", NULL); 419 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); 420 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd"); 421 dump_file("MEMORY INFO", "/proc/meminfo"); 422 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL); 423 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL); 424 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat"); 425 dump_file("VMALLOC INFO", "/proc/vmallocinfo"); 426 dump_file("SLAB INFO", "/proc/slabinfo"); 427 dump_file("ZONEINFO", "/proc/zoneinfo"); 428 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo"); 429 dump_file("BUDDYINFO", "/proc/buddyinfo"); 430 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index"); 431 432 dump_file("KERNEL WAKELOCKS", "/proc/wakelocks"); 433 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources"); 434 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); 435 dump_file("KERNEL SYNC", "/d/sync"); 436 437 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL); 438 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL); 439 440 do_dmesg(); 441 442 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL); 443 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); 444 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); 445 446 if (!screenshot_path.empty()) { 447 ALOGI("taking late screenshot\n"); 448 take_screenshot(screenshot_path); 449 ALOGI("wrote screenshot: %s\n", screenshot_path.c_str()); 450 } 451 452 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); 453 // calculate timeout 454 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); 455 if (timeout < 20000) { 456 timeout = 20000; 457 } 458 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", 459 "-v", "printable", 460 "-d", 461 "*:v", NULL); 462 timeout = logcat_timeout("events") + logcat_timeout("security"); 463 if (timeout < 20000) { 464 timeout = 20000; 465 } 466 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", 467 "-b", "security", 468 "-v", "threadtime", 469 "-v", "printable", 470 "-d", 471 "*:v", NULL); 472 timeout = logcat_timeout("radio"); 473 if (timeout < 20000) { 474 timeout = 20000; 475 } 476 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", 477 "-v", "threadtime", 478 "-v", "printable", 479 "-d", 480 "*:v", NULL); 481 482 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); 483 484 run_command("RAFT LOGS", 600, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL); 485 486 /* show the traces we collected in main(), if that was done */ 487 if (dump_traces_path != NULL) { 488 dump_file("VM TRACES JUST NOW", dump_traces_path); 489 } 490 491 /* only show ANR traces if they're less than 15 minutes old */ 492 struct stat st; 493 char anr_traces_path[PATH_MAX]; 494 property_get("dalvik.vm.stack-trace-file", anr_traces_path, ""); 495 if (!anr_traces_path[0]) { 496 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); 497 } else { 498 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path, 499 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); 500 if (fd < 0) { 501 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); 502 } else { 503 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd); 504 } 505 } 506 507 /* slow traces for slow operations */ 508 if (anr_traces_path[0] != 0) { 509 int tail = strlen(anr_traces_path)-1; 510 while (tail > 0 && anr_traces_path[tail] != '/') { 511 tail--; 512 } 513 int i = 0; 514 while (1) { 515 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i); 516 if (stat(anr_traces_path, &st)) { 517 // No traces file at this index, done with the files. 518 break; 519 } 520 dump_file("VM TRACES WHEN SLOW", anr_traces_path); 521 i++; 522 } 523 } 524 525 int dumped = 0; 526 for (size_t i = 0; i < NUM_TOMBSTONES; i++) { 527 if (tombstone_data[i].fd != -1) { 528 const char *name = tombstone_data[i].name; 529 int fd = tombstone_data[i].fd; 530 dumped = 1; 531 if (zip_writer) { 532 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) { 533 ALOGE("Unable to add tombstone %s to zip file\n", name); 534 } 535 } else { 536 dump_file_from_fd("TOMBSTONE", name, fd); 537 } 538 close(fd); 539 tombstone_data[i].fd = -1; 540 } 541 } 542 if (!dumped) { 543 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR); 544 } 545 546 dump_file("NETWORK DEV INFO", "/proc/net/dev"); 547 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all"); 548 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt"); 549 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); 550 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats"); 551 552 if (!stat(PSTORE_LAST_KMSG, &st)) { 553 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ 554 dump_file("LAST KMSG", PSTORE_LAST_KMSG); 555 } else { 556 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */ 557 dump_file("LAST KMSG", "/proc/last_kmsg"); 558 } 559 560 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ 561 run_command("LAST LOGCAT", 10, "logcat", "-L", 562 "-b", "all", 563 "-v", "threadtime", 564 "-v", "printable", 565 "-d", 566 "*:v", NULL); 567 568 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ 569 570 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL); 571 572 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL); 573 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL); 574 575 run_command("IP RULES", 10, "ip", "rule", "show", NULL); 576 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL); 577 578 dump_route_tables(); 579 580 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL); 581 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL); 582 583 run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL); 584 run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL); 585 run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL); 586 /* no ip6 nat */ 587 run_command("IPTABLE RAW", 10, SU_PATH, "root", "iptables", "-t", "raw", "-L", "-nvx", NULL); 588 run_command("IP6TABLE RAW", 10, SU_PATH, "root", "ip6tables", "-t", "raw", "-L", "-nvx", NULL); 589 590 run_command("WIFI NETWORKS", 20, 591 SU_PATH, "root", "wpa_cli", "IFNAME=wlan0", "list_networks", NULL); 592 593#ifdef FWDUMP_bcmdhd 594 run_command("ND OFFLOAD TABLE", 5, 595 SU_PATH, "root", "wlutil", "nd_hostip", NULL); 596 597 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20, 598 SU_PATH, "root", "wlutil", "counters", NULL); 599 600 run_command("ND OFFLOAD STATUS (1)", 5, 601 SU_PATH, "root", "wlutil", "nd_status", NULL); 602 603#endif 604 dump_file("INTERRUPTS (1)", "/proc/interrupts"); 605 606 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL); 607 608#ifdef FWDUMP_bcmdhd 609 run_command("DUMP WIFI STATUS", 20, 610 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL); 611 612 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20, 613 SU_PATH, "root", "wlutil", "counters", NULL); 614 615 run_command("ND OFFLOAD STATUS (2)", 5, 616 SU_PATH, "root", "wlutil", "nd_status", NULL); 617#endif 618 dump_file("INTERRUPTS (2)", "/proc/interrupts"); 619 620 print_properties(); 621 622 run_command("VOLD DUMP", 10, "vdc", "dump", NULL); 623 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL); 624 625 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL); 626 627 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL); 628 629 printf("------ BACKLIGHTS ------\n"); 630 printf("LCD brightness="); 631 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness"); 632 printf("Button brightness="); 633 dump_file(NULL, "/sys/class/leds/button-backlight/brightness"); 634 printf("Keyboard brightness="); 635 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness"); 636 printf("ALS mode="); 637 dump_file(NULL, "/sys/class/leds/lcd-backlight/als"); 638 printf("LCD driver registers:\n"); 639 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers"); 640 printf("\n"); 641 642 /* Binder state is expensive to look at as it uses a lot of memory. */ 643 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); 644 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); 645 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); 646 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats"); 647 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state"); 648 649 printf("========================================================\n"); 650 printf("== Board\n"); 651 printf("========================================================\n"); 652 653 dumpstate_board(); 654 printf("\n"); 655 656 /* Migrate the ril_dumpstate to a dumpstate_board()? */ 657 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0}; 658 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30"); 659 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) { 660 if (0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1)) { 661 // su does not exist on user builds, so try running without it. 662 // This way any implementations of vril-dump that do not require 663 // root can run on user builds. 664 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), 665 "vril-dump", NULL); 666 } else { 667 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), 668 SU_PATH, "root", "vril-dump", NULL); 669 } 670 } 671 672 printf("========================================================\n"); 673 printf("== Android Framework Services\n"); 674 printf("========================================================\n"); 675 676 /* the full dumpsys is starting to take a long time, so we need 677 to increase its timeout. we really need to do the timeouts in 678 dumpsys itself... */ 679 run_command("DUMPSYS", 60, "dumpsys", NULL); 680 681 printf("========================================================\n"); 682 printf("== Checkins\n"); 683 printf("========================================================\n"); 684 685 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "batterystats", "-c", NULL); 686 run_command("CHECKIN MEMINFO", 30, "dumpsys", "meminfo", "--checkin", NULL); 687 run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL); 688 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL); 689 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL); 690 run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL); 691 692 printf("========================================================\n"); 693 printf("== Running Application Activities\n"); 694 printf("========================================================\n"); 695 696 run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL); 697 698 printf("========================================================\n"); 699 printf("== Running Application Services\n"); 700 printf("========================================================\n"); 701 702 run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL); 703 704 printf("========================================================\n"); 705 printf("== Running Application Providers\n"); 706 printf("========================================================\n"); 707 708 run_command("APP SERVICES", 30, "dumpsys", "activity", "provider", "all", NULL); 709 710 711 printf("========================================================\n"); 712 printf("== dumpstate: done\n"); 713 printf("========================================================\n"); 714} 715 716static void usage() { 717 fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s] [-q]\n" 718 " -o: write to file (instead of stdout)\n" 719 " -d: append date to filename (requires -o)\n" 720 " -z: generates zipped file (requires -o)\n" 721 " -p: capture screenshot to filename.png (requires -o)\n" 722 " -s: write output to control socket (for init)\n" 723 " -b: play sound file instead of vibrate, at beginning of job\n" 724 " -e: play sound file instead of vibrate, at end of job\n" 725 " -q: disable vibrate\n" 726 " -B: send broadcast when finished (requires -o)\n" 727 " -P: send broadacast when started and update system properties on progress (requires -o and -B)\n" 728 ); 729} 730 731static void sigpipe_handler(int n) { 732 // don't complain to stderr or stdout 733 _exit(EXIT_FAILURE); 734} 735 736/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the 737 temporary file. 738 */ 739static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, 740 time_t now) { 741 if (!add_zip_entry(bugreport_name, bugreport_path)) { 742 ALOGE("Failed to add text entry to .zip file\n"); 743 return false; 744 } 745 746 int32_t err = zip_writer->Finish(); 747 if (err) { 748 ALOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err)); 749 return false; 750 } 751 752 if (remove(bugreport_path.c_str())) { 753 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno)); 754 } 755 756 return true; 757} 758 759int main(int argc, char *argv[]) { 760 struct sigaction sigact; 761 int do_add_date = 0; 762 int do_zip_file = 0; 763 int do_vibrate = 1; 764 char* use_outfile = 0; 765 int use_socket = 0; 766 int do_fb = 0; 767 int do_broadcast = 0; 768 int do_early_screenshot = 0; 769 770 now = time(NULL); 771 772 if (getuid() != 0) { 773 // Old versions of the adb client would call the 774 // dumpstate command directly. Newer clients 775 // call /system/bin/bugreport instead. If we detect 776 // we're being called incorrectly, then exec the 777 // correct program. 778 return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL); 779 } 780 781 ALOGI("begin\n"); 782 783 /* clear SIGPIPE handler */ 784 memset(&sigact, 0, sizeof(sigact)); 785 sigact.sa_handler = sigpipe_handler; 786 sigaction(SIGPIPE, &sigact, NULL); 787 788 /* set as high priority, and protect from OOM killer */ 789 setpriority(PRIO_PROCESS, 0, -20); 790 FILE *oom_adj = fopen("/proc/self/oom_adj", "we"); 791 if (oom_adj) { 792 fputs("-17", oom_adj); 793 fclose(oom_adj); 794 } 795 796 /* parse arguments */ 797 int c; 798 while ((c = getopt(argc, argv, "dho:svqzpPB")) != -1) { 799 switch (c) { 800 case 'd': do_add_date = 1; break; 801 case 'z': do_zip_file = 1; break; 802 case 'o': use_outfile = optarg; break; 803 case 's': use_socket = 1; break; 804 case 'v': break; // compatibility no-op 805 case 'q': do_vibrate = 0; break; 806 case 'p': do_fb = 1; break; 807 case 'P': do_update_progress = 1; break; 808 case 'B': do_broadcast = 1; break; 809 case '?': printf("\n"); 810 case 'h': 811 usage(); 812 exit(1); 813 } 814 } 815 816 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) { 817 usage(); 818 exit(1); 819 } 820 821 if (do_update_progress && !do_broadcast) { 822 usage(); 823 exit(1); 824 } 825 826 do_early_screenshot = do_update_progress; 827 828 // If we are going to use a socket, do it as early as possible 829 // to avoid timeouts from bugreport. 830 if (use_socket) { 831 redirect_to_socket(stdout, "dumpstate"); 832 } 833 834 /* full path of the directory where the bug report files will be written */ 835 std::string bugreport_dir; 836 837 /* full path of the temporary file containing the bug report */ 838 std::string tmp_path; 839 840 /* full path of the temporary file containing the screenshot (when requested) */ 841 std::string screenshot_path; 842 843 /* base name (without suffix or extensions) of the bug report files */ 844 std::string base_name; 845 846 /* suffix of the bug report files - it's typically the date (when invoked with -d), 847 * although it could be changed by the user using a system property */ 848 std::string suffix; 849 850 /* pointer to the actual path, be it zip or text */ 851 std::string path; 852 853 /* pointer to the zipped file */ 854 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose); 855 856 /* redirect output if needed */ 857 bool is_redirecting = !use_socket && use_outfile; 858 859 if (is_redirecting) { 860 bugreport_dir = dirname(use_outfile); 861 base_name = basename(use_outfile); 862 if (do_add_date) { 863 char date[80]; 864 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now)); 865 suffix = date; 866 } else { 867 suffix = "undated"; 868 } 869 if (do_fb) { 870 // TODO: if dumpstate was an object, the paths could be internal variables and then 871 // we could have a function to calculate the derived values, such as: 872 // screenshot_path = GetPath(".png"); 873 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png"; 874 } 875 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp"; 876 877 ALOGD("Bugreport dir: %s\nBase name: %s\nSuffix: %s\nTemporary path: %s\n" 878 "Screenshot path: %s\n", bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(), 879 tmp_path.c_str(), screenshot_path.c_str()); 880 881 if (do_zip_file) { 882 ALOGD("Creating initial .zip file"); 883 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip"; 884 zip_file.reset(fopen(path.c_str(), "wb")); 885 if (!zip_file) { 886 ALOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno)); 887 do_zip_file = 0; 888 } else { 889 zip_writer.reset(new ZipWriter(zip_file.get())); 890 } 891 } 892 893 if (do_update_progress) { 894 std::vector<std::string> am_args = { 895 "--receiver-permission", "android.permission.DUMP", 896 "--es", "android.intent.extra.NAME", suffix, 897 "--ei", "android.intent.extra.PID", std::to_string(getpid()), 898 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), 899 }; 900 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args); 901 } 902 } 903 904 print_header(); 905 906 /* open the vibrator before dropping root */ 907 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose); 908 if (do_vibrate) { 909 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we")); 910 if (vibrator) { 911 vibrate(vibrator.get(), 150); 912 } 913 } 914 915 if (do_fb && do_early_screenshot) { 916 if (screenshot_path.empty()) { 917 // should not have happened 918 ALOGE("INTERNAL ERROR: skipping early screenshot because path was not set"); 919 } else { 920 ALOGI("taking early screenshot\n"); 921 take_screenshot(screenshot_path); 922 ALOGI("wrote screenshot: %s\n", screenshot_path.c_str()); 923 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) { 924 ALOGE("Unable to change ownership of screenshot file %s: %s\n", 925 screenshot_path.c_str(), strerror(errno)); 926 } 927 } 928 } 929 930 if (do_zip_file) { 931 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) { 932 ALOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno)); 933 } 934 } 935 936 /* read /proc/cmdline before dropping root */ 937 FILE *cmdline = fopen("/proc/cmdline", "re"); 938 if (cmdline) { 939 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); 940 fclose(cmdline); 941 } 942 943 /* collect stack traces from Dalvik and native processes (needs root) */ 944 dump_traces_path = dump_traces(); 945 946 /* Get the tombstone fds, recovery files, and mount info here while we are running as root. */ 947 get_tombstone_fds(tombstone_data); 948 add_dir(RECOVERY_DIR, true); 949 add_mountinfo(); 950 951 /* ensure we will keep capabilities when we drop root */ 952 if (prctl(PR_SET_KEEPCAPS, 1) < 0) { 953 ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); 954 return -1; 955 } 956 957 /* switch to non-root user and group */ 958 gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, 959 AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC }; 960 if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { 961 ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); 962 return -1; 963 } 964 if (setgid(AID_SHELL) != 0) { 965 ALOGE("Unable to setgid, aborting: %s\n", strerror(errno)); 966 return -1; 967 } 968 if (setuid(AID_SHELL) != 0) { 969 ALOGE("Unable to setuid, aborting: %s\n", strerror(errno)); 970 return -1; 971 } 972 973 struct __user_cap_header_struct capheader; 974 struct __user_cap_data_struct capdata[2]; 975 memset(&capheader, 0, sizeof(capheader)); 976 memset(&capdata, 0, sizeof(capdata)); 977 capheader.version = _LINUX_CAPABILITY_VERSION_3; 978 capheader.pid = 0; 979 980 capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); 981 capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); 982 capdata[0].inheritable = 0; 983 capdata[1].inheritable = 0; 984 985 if (capset(&capheader, &capdata[0]) < 0) { 986 ALOGE("capset failed: %s\n", strerror(errno)); 987 return -1; 988 } 989 990 if (is_redirecting) { 991 /* TODO: rather than generating a text file now and zipping it later, 992 it would be more efficient to redirect stdout to the zip entry 993 directly, but the libziparchive doesn't support that option yet. */ 994 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str())); 995 } 996 997 dumpstate(do_early_screenshot ? "": screenshot_path); 998 999 /* done */ 1000 if (vibrator) { 1001 for (int i = 0; i < 3; i++) { 1002 vibrate(vibrator.get(), 75); 1003 usleep((75 + 50) * 1000); 1004 } 1005 } 1006 1007 /* close output if needed */ 1008 if (is_redirecting) { 1009 fclose(stdout); 1010 } 1011 1012 /* rename or zip the (now complete) .tmp file to its final location */ 1013 if (use_outfile) { 1014 1015 /* check if user changed the suffix using system properties */ 1016 char key[PROPERTY_KEY_MAX]; 1017 char value[PROPERTY_VALUE_MAX]; 1018 sprintf(key, "dumpstate.%d.name", getpid()); 1019 property_get(key, value, ""); 1020 bool change_suffix= false; 1021 if (value[0]) { 1022 /* must whitelist which characters are allowed, otherwise it could cross directories */ 1023 std::regex valid_regex("^[-_a-zA-Z0-9]+$"); 1024 if (std::regex_match(value, valid_regex)) { 1025 change_suffix = true; 1026 } else { 1027 ALOGE("invalid suffix provided by user: %s", value); 1028 } 1029 } 1030 if (change_suffix) { 1031 ALOGI("changing suffix from %s to %s", suffix.c_str(), value); 1032 suffix = value; 1033 if (!screenshot_path.empty()) { 1034 std::string new_screenshot_path = 1035 bugreport_dir + "/" + base_name + "-" + suffix + ".png"; 1036 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) { 1037 ALOGE("rename(%s, %s): %s\n", screenshot_path.c_str(), 1038 new_screenshot_path.c_str(), strerror(errno)); 1039 } else { 1040 screenshot_path = new_screenshot_path; 1041 } 1042 } 1043 } 1044 1045 bool do_text_file = true; 1046 if (do_zip_file) { 1047 ALOGD("Adding text entry to .zip bugreport"); 1048 if (!finish_zip_file(base_name + "-" + suffix + ".txt", tmp_path, now)) { 1049 ALOGE("Failed to finish zip file; sending text bugreport instead\n"); 1050 do_text_file = true; 1051 } else { 1052 do_text_file = false; 1053 } 1054 } 1055 if (do_text_file) { 1056 ALOGD("Generating .txt bugreport"); 1057 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt"; 1058 if (rename(tmp_path.c_str(), path.c_str())) { 1059 ALOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); 1060 path.clear(); 1061 } 1062 } 1063 } 1064 1065 /* tell activity manager we're done */ 1066 if (do_broadcast) { 1067 if (!path.empty()) { 1068 ALOGI("Final bugreport path: %s\n", path.c_str()); 1069 std::vector<std::string> am_args = { 1070 "--receiver-permission", "android.permission.DUMP", 1071 "--ei", "android.intent.extra.PID", std::to_string(getpid()), 1072 "--es", "android.intent.extra.BUGREPORT", path 1073 }; 1074 if (do_fb) { 1075 am_args.push_back("--es"); 1076 am_args.push_back("android.intent.extra.SCREENSHOT"); 1077 am_args.push_back(screenshot_path); 1078 } 1079 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args); 1080 } else { 1081 ALOGE("Skipping finished broadcast because bugreport could not be generated\n"); 1082 } 1083 } 1084 1085 ALOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL); 1086 ALOGI("done\n"); 1087 1088 return 0; 1089} 1090