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