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