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