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