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