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