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