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 <inttypes.h>
23 #include <libgen.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <poll.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/poll.h>
32 #include <sys/prctl.h>
33 #include <sys/resource.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <sys/wait.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <sys/capability.h>
41 #include <sys/inotify.h>
42 #include <sys/klog.h>
43 #include <time.h>
44 #include <unistd.h>
45
46 #include <chrono>
47 #include <cmath>
48 #include <fstream>
49 #include <functional>
50 #include <future>
51 #include <memory>
52 #include <numeric>
53 #include <regex>
54 #include <set>
55 #include <string>
56 #include <utility>
57 #include <vector>
58
59 #include <android-base/file.h>
60 #include <android-base/properties.h>
61 #include <android-base/scopeguard.h>
62 #include <android-base/stringprintf.h>
63 #include <android-base/strings.h>
64 #include <android-base/unique_fd.h>
65 #include <android/content/pm/IPackageManagerNative.h>
66 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
67 #include <android/hidl/manager/1.0/IServiceManager.h>
68 #include <android/os/IIncidentCompanion.h>
69 #include <binder/IServiceManager.h>
70 #include <cutils/native_handle.h>
71 #include <cutils/properties.h>
72 #include <cutils/sockets.h>
73 #include <debuggerd/client.h>
74 #include <dumpsys.h>
75 #include <dumputils/dump_utils.h>
76 #include <hardware_legacy/power.h>
77 #include <hidl/ServiceManagement.h>
78 #include <log/log.h>
79 #include <openssl/sha.h>
80 #include <private/android_filesystem_config.h>
81 #include <private/android_logger.h>
82 #include <serviceutils/PriorityDumper.h>
83 #include <utils/StrongPointer.h>
84 #include "DumpstateInternal.h"
85 #include "DumpstateService.h"
86 #include "dumpstate.h"
87
88 using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
89 using ::std::literals::chrono_literals::operator""ms;
90 using ::std::literals::chrono_literals::operator""s;
91
92 // TODO: remove once moved to namespace
93 using android::defaultServiceManager;
94 using android::Dumpsys;
95 using android::INVALID_OPERATION;
96 using android::IServiceManager;
97 using android::OK;
98 using android::sp;
99 using android::status_t;
100 using android::String16;
101 using android::String8;
102 using android::TIMED_OUT;
103 using android::UNKNOWN_ERROR;
104 using android::Vector;
105 using android::base::StringPrintf;
106 using android::os::IDumpstateListener;
107 using android::os::dumpstate::CommandOptions;
108 using android::os::dumpstate::DumpFileToFd;
109 using android::os::dumpstate::PropertiesHelper;
110
111 // Keep in sync with
112 // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113 static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115 /* Most simple commands have 10 as timeout, so 5 is a good estimate */
116 static const int32_t WEIGHT_FILE = 5;
117
118 // TODO: temporary variables and functions used during C++ refactoring
119 static Dumpstate& ds = Dumpstate::GetInstance();
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options=CommandOptions::DEFAULT,bool verbose_duration=false)120 static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
124 }
125
126 // Reasonable value for max stats.
127 static const int STATS_MAX_N_RUNS = 1000;
128 static const long STATS_MAX_AVERAGE = 100000;
129
130 CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
132 typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
134 /* read before root is shed */
135 static char cmdline_buf[16384] = "(unknown)";
136 static const char *dump_traces_path = nullptr;
137 static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
138 // Because telephony reports are significantly faster to collect (< 10 seconds vs. > 2 minutes),
139 // it's often the case that they time out far too quickly for consent with such a hefty dialog for
140 // the user to read. For telephony reports only, we increase the default timeout to 2 minutes to
141 // roughly match full reports' durations.
142 static const uint64_t TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS = 2 * 60 * 1000;
143
144 // TODO: variables and functions below should be part of dumpstate object
145
146 static std::set<std::string> mount_points;
147 void add_mountinfo();
148
149 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
150 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
151 #define BLK_DEV_SYS_DIR "/sys/block"
152
153 #define RECOVERY_DIR "/cache/recovery"
154 #define RECOVERY_DATA_DIR "/data/misc/recovery"
155 #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
156 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
157 #define PREREBOOT_DATA_DIR "/data/misc/prereboot"
158 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
159 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
160 #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
161 #define WLUTIL "/vendor/xbin/wlutil"
162 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
163 #define OTA_METADATA_DIR "/metadata/ota"
164 #define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
165 #define LINKERCONFIG_DIR "/linkerconfig"
166 #define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
167
168 // TODO(narayan): Since this information has to be kept in sync
169 // with tombstoned, we should just put it in a common header.
170 //
171 // File: system/core/debuggerd/tombstoned/tombstoned.cpp
172 static const std::string TOMBSTONE_DIR = "/data/tombstones/";
173 static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
174 static const std::string ANR_DIR = "/data/anr/";
175 static const std::string ANR_FILE_PREFIX = "anr_";
176
177 // TODO: temporary variables and functions used during C++ refactoring
178
179 #define RETURN_IF_USER_DENIED_CONSENT() \
180 if (ds.IsUserConsentDenied()) { \
181 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
182 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
183 }
184
185 // Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
186 // if consent is found to be denied.
187 #define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
188 RETURN_IF_USER_DENIED_CONSENT(); \
189 func_ptr(__VA_ARGS__); \
190 RETURN_IF_USER_DENIED_CONSENT();
191
192 static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
193
194 namespace android {
195 namespace os {
196 namespace {
197
Open(std::string path,int flags,mode_t mode=0)198 static int Open(std::string path, int flags, mode_t mode = 0) {
199 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
200 if (fd == -1) {
201 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
202 }
203 return fd;
204 }
205
206
OpenForRead(std::string path)207 static int OpenForRead(std::string path) {
208 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
209 }
210
CopyFile(int in_fd,int out_fd)211 bool CopyFile(int in_fd, int out_fd) {
212 char buf[4096];
213 ssize_t byte_count;
214 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
215 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
216 return false;
217 }
218 }
219 return (byte_count != -1);
220 }
221
CopyFileToFd(const std::string & input_file,int out_fd)222 static bool CopyFileToFd(const std::string& input_file, int out_fd) {
223 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
224
225 // Obtain a handle to the source file.
226 android::base::unique_fd in_fd(OpenForRead(input_file));
227 if (out_fd != -1 && in_fd.get() != -1) {
228 if (CopyFile(in_fd.get(), out_fd)) {
229 return true;
230 }
231 MYLOGE("Failed to copy file: %s\n", strerror(errno));
232 }
233 return false;
234 }
235
UnlinkAndLogOnError(const std::string & file)236 static bool UnlinkAndLogOnError(const std::string& file) {
237 if (unlink(file.c_str())) {
238 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
239 return false;
240 }
241 return true;
242 }
243
IsFileEmpty(const std::string & file_path)244 static bool IsFileEmpty(const std::string& file_path) {
245 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
246 if(file.bad()) {
247 MYLOGE("Cannot open file: %s\n", file_path.c_str());
248 return true;
249 }
250 return file.tellg() <= 0;
251 }
252
GetModuleMetadataVersion()253 int64_t GetModuleMetadataVersion() {
254 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
255 if (binder == nullptr) {
256 MYLOGE("Failed to retrieve package_native service");
257 return 0L;
258 }
259 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
260 std::string package_name;
261 auto status = package_service->getModuleMetadataPackageName(&package_name);
262 if (!status.isOk()) {
263 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
264 return 0L;
265 }
266 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
267 int64_t version_code;
268 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
269 &version_code);
270 if (!status.isOk()) {
271 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
272 return 0L;
273 }
274 return version_code;
275 }
276
277 } // namespace
278 } // namespace os
279 } // namespace android
280
RunDumpsys(const std::string & title,const std::vector<std::string> & dumpsysArgs,const CommandOptions & options=Dumpstate::DEFAULT_DUMPSYS,long dumpsysTimeoutMs=0)281 static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
282 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
283 long dumpsysTimeoutMs = 0) {
284 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
285 }
DumpFile(const std::string & title,const std::string & path)286 static int DumpFile(const std::string& title, const std::string& path) {
287 return ds.DumpFile(title, path);
288 }
289
290 // Relative directory (inside the zip) for all files copied as-is into the bugreport.
291 static const std::string ZIP_ROOT_DIR = "FS";
292
293 static const std::string kProtoPath = "proto/";
294 static const std::string kProtoExt = ".proto";
295 static const std::string kDumpstateBoardFiles[] = {
296 "dumpstate_board.txt",
297 "dumpstate_board.bin"
298 };
299 static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
300
301 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
302 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
303 static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
304 static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
305 static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
306
307 static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
308
309 /*
310 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
311 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
312 * is set, the vector only contains files that were written in the last 30 minutes.
313 */
GetDumpFds(const std::string & dir_path,const std::string & file_prefix,bool limit_by_mtime)314 static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
315 const std::string& file_prefix,
316 bool limit_by_mtime) {
317 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
318
319 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
320
321 if (dump_dir == nullptr) {
322 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
323 return std::vector<DumpData>();
324 }
325
326 std::vector<DumpData> dump_data;
327 struct dirent* entry = nullptr;
328 while ((entry = readdir(dump_dir.get()))) {
329 if (entry->d_type != DT_REG) {
330 continue;
331 }
332
333 const std::string base_name(entry->d_name);
334 if (base_name.find(file_prefix) != 0) {
335 continue;
336 }
337
338 const std::string abs_path = dir_path + base_name;
339 android::base::unique_fd fd(
340 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
341 if (fd == -1) {
342 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
343 break;
344 }
345
346 struct stat st = {};
347 if (fstat(fd, &st) == -1) {
348 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
349 continue;
350 }
351
352 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
353 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
354 continue;
355 }
356
357 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
358 }
359
360 return dump_data;
361 }
362
AddDumps(const std::vector<DumpData>::const_iterator start,const std::vector<DumpData>::const_iterator end,const char * type_name,const bool add_to_zip)363 static bool AddDumps(const std::vector<DumpData>::const_iterator start,
364 const std::vector<DumpData>::const_iterator end,
365 const char* type_name, const bool add_to_zip) {
366 bool dumped = false;
367 for (auto it = start; it != end; ++it) {
368 const std::string& name = it->name;
369 const int fd = it->fd;
370 dumped = true;
371
372 // Seek to the beginning of the file before dumping any data. A given
373 // DumpData entry might be dumped multiple times in the report.
374 //
375 // For example, the most recent ANR entry is dumped to the body of the
376 // main entry and it also shows up as a separate entry in the bugreport
377 // ZIP file.
378 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
379 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
380 strerror(errno));
381 }
382
383 if (ds.IsZipping() && add_to_zip) {
384 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
385 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
386 }
387 } else {
388 dump_file_from_fd(type_name, name.c_str(), fd);
389 }
390 }
391
392 return dumped;
393 }
394
395 // for_each_pid() callback to get mount info about a process.
do_mountinfo(int pid,const char * name)396 void do_mountinfo(int pid, const char* name __attribute__((unused))) {
397 char path[PATH_MAX];
398
399 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
400 // are added.
401 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
402 char linkname[PATH_MAX];
403 ssize_t r = readlink(path, linkname, PATH_MAX);
404 if (r == -1) {
405 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
406 return;
407 }
408 linkname[r] = '\0';
409
410 if (mount_points.find(linkname) == mount_points.end()) {
411 // First time this mount point was found: add it
412 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
413 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
414 mount_points.insert(linkname);
415 } else {
416 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
417 }
418 }
419 }
420
add_mountinfo()421 void add_mountinfo() {
422 if (!ds.IsZipping()) return;
423 std::string title = "MOUNT INFO";
424 mount_points.clear();
425 DurationReporter duration_reporter(title, true);
426 for_each_pid(do_mountinfo, nullptr);
427 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
428 }
429
dump_dev_files(const char * title,const char * driverpath,const char * filename)430 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
431 {
432 DIR *d;
433 struct dirent *de;
434 char path[PATH_MAX];
435
436 d = opendir(driverpath);
437 if (d == nullptr) {
438 return;
439 }
440
441 while ((de = readdir(d))) {
442 if (de->d_type != DT_LNK) {
443 continue;
444 }
445 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
446 DumpFile(title, path);
447 }
448
449 closedir(d);
450 }
451
skip_not_stat(const char * path)452 static bool skip_not_stat(const char *path) {
453 static const char stat[] = "/stat";
454 size_t len = strlen(path);
455 if (path[len - 1] == '/') { /* Directory? */
456 return false;
457 }
458 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
459 }
460
skip_none(const char * path)461 static bool skip_none(const char* path __attribute__((unused))) {
462 return false;
463 }
464
465 unsigned long worst_write_perf = 20000; /* in KB/s */
466
467 //
468 // stat offsets
469 // Name units description
470 // ---- ----- -----------
471 // read I/Os requests number of read I/Os processed
472 #define __STAT_READ_IOS 0
473 // read merges requests number of read I/Os merged with in-queue I/O
474 #define __STAT_READ_MERGES 1
475 // read sectors sectors number of sectors read
476 #define __STAT_READ_SECTORS 2
477 // read ticks milliseconds total wait time for read requests
478 #define __STAT_READ_TICKS 3
479 // write I/Os requests number of write I/Os processed
480 #define __STAT_WRITE_IOS 4
481 // write merges requests number of write I/Os merged with in-queue I/O
482 #define __STAT_WRITE_MERGES 5
483 // write sectors sectors number of sectors written
484 #define __STAT_WRITE_SECTORS 6
485 // write ticks milliseconds total wait time for write requests
486 #define __STAT_WRITE_TICKS 7
487 // in_flight requests number of I/Os currently in flight
488 #define __STAT_IN_FLIGHT 8
489 // io_ticks milliseconds total time this block device has been active
490 #define __STAT_IO_TICKS 9
491 // time_in_queue milliseconds total wait time for all requests
492 #define __STAT_IN_QUEUE 10
493 #define __STAT_NUMBER_FIELD 11
494 //
495 // read I/Os, write I/Os
496 // =====================
497 //
498 // These values increment when an I/O request completes.
499 //
500 // read merges, write merges
501 // =========================
502 //
503 // These values increment when an I/O request is merged with an
504 // already-queued I/O request.
505 //
506 // read sectors, write sectors
507 // ===========================
508 //
509 // These values count the number of sectors read from or written to this
510 // block device. The "sectors" in question are the standard UNIX 512-byte
511 // sectors, not any device- or filesystem-specific block size. The
512 // counters are incremented when the I/O completes.
513 #define SECTOR_SIZE 512
514 //
515 // read ticks, write ticks
516 // =======================
517 //
518 // These values count the number of milliseconds that I/O requests have
519 // waited on this block device. If there are multiple I/O requests waiting,
520 // these values will increase at a rate greater than 1000/second; for
521 // example, if 60 read requests wait for an average of 30 ms, the read_ticks
522 // field will increase by 60*30 = 1800.
523 //
524 // in_flight
525 // =========
526 //
527 // This value counts the number of I/O requests that have been issued to
528 // the device driver but have not yet completed. It does not include I/O
529 // requests that are in the queue but not yet issued to the device driver.
530 //
531 // io_ticks
532 // ========
533 //
534 // This value counts the number of milliseconds during which the device has
535 // had I/O requests queued.
536 //
537 // time_in_queue
538 // =============
539 //
540 // This value counts the number of milliseconds that I/O requests have waited
541 // on this block device. If there are multiple I/O requests waiting, this
542 // value will increase as the product of the number of milliseconds times the
543 // number of requests waiting (see "read ticks" above for an example).
544 #define S_TO_MS 1000
545 //
546
dump_stat_from_fd(const char * title __unused,const char * path,int fd)547 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
548 unsigned long long fields[__STAT_NUMBER_FIELD];
549 bool z;
550 char *cp, *buffer = nullptr;
551 size_t i = 0;
552 FILE *fp = fdopen(dup(fd), "rb");
553 getline(&buffer, &i, fp);
554 fclose(fp);
555 if (!buffer) {
556 return -errno;
557 }
558 i = strlen(buffer);
559 while ((i > 0) && (buffer[i - 1] == '\n')) {
560 buffer[--i] = '\0';
561 }
562 if (!*buffer) {
563 free(buffer);
564 return 0;
565 }
566 z = true;
567 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
568 fields[i] = strtoull(cp, &cp, 10);
569 if (fields[i] != 0) {
570 z = false;
571 }
572 }
573 if (z) { /* never accessed */
574 free(buffer);
575 return 0;
576 }
577
578 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
579 path += sizeof(BLK_DEV_SYS_DIR) - 1;
580 }
581
582 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
583 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
584 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
585 free(buffer);
586
587 if (fields[__STAT_IO_TICKS]) {
588 unsigned long read_perf = 0;
589 unsigned long read_ios = 0;
590 if (fields[__STAT_READ_TICKS]) {
591 unsigned long long divisor = fields[__STAT_READ_TICKS]
592 * fields[__STAT_IO_TICKS];
593 read_perf = ((unsigned long long)SECTOR_SIZE
594 * fields[__STAT_READ_SECTORS]
595 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
596 / divisor;
597 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
598 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
599 / divisor;
600 }
601
602 unsigned long write_perf = 0;
603 unsigned long write_ios = 0;
604 if (fields[__STAT_WRITE_TICKS]) {
605 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
606 * fields[__STAT_IO_TICKS];
607 write_perf = ((unsigned long long)SECTOR_SIZE
608 * fields[__STAT_WRITE_SECTORS]
609 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
610 / divisor;
611 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
612 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
613 / divisor;
614 }
615
616 unsigned queue = (fields[__STAT_IN_QUEUE]
617 + (fields[__STAT_IO_TICKS] >> 1))
618 / fields[__STAT_IO_TICKS];
619
620 if (!write_perf && !write_ios) {
621 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
622 } else {
623 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
624 read_ios, write_perf, write_ios, queue);
625 }
626
627 /* bugreport timeout factor adjustment */
628 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
629 worst_write_perf = write_perf;
630 }
631 }
632 return 0;
633 }
634
635 static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
636
637 /* timeout in ms to read a list of buffers */
logcat_timeout(const std::vector<std::string> & buffers)638 static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
639 unsigned long timeout_ms = 0;
640 for (const auto& buffer : buffers) {
641 log_id_t id = android_name_to_log_id(buffer.c_str());
642 unsigned long property_size = __android_logger_get_buffer_size(id);
643 /* Engineering margin is ten-fold our guess */
644 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
645 }
646 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
647 }
648
ConsentCallback()649 Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
650 }
651
onReportApproved()652 android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
653 std::lock_guard<std::mutex> lock(lock_);
654 result_ = APPROVED;
655 MYLOGD("User approved consent to share bugreport\n");
656 return android::binder::Status::ok();
657 }
658
onReportDenied()659 android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
660 std::lock_guard<std::mutex> lock(lock_);
661 result_ = DENIED;
662 MYLOGW("User denied consent to share bugreport\n");
663 return android::binder::Status::ok();
664 }
665
getResult()666 UserConsentResult Dumpstate::ConsentCallback::getResult() {
667 std::lock_guard<std::mutex> lock(lock_);
668 return result_;
669 }
670
getElapsedTimeMs() const671 uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
672 return (Nanotime() - start_time_) / NANOS_PER_MILLI;
673 }
674
PrintHeader() const675 void Dumpstate::PrintHeader() const {
676 std::string build, fingerprint, radio, bootloader, network;
677 char date[80];
678
679 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
680 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
681 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
682 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
683 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
684 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
685
686 printf("========================================================\n");
687 printf("== dumpstate: %s\n", date);
688 printf("========================================================\n");
689
690 printf("\n");
691 printf("Build: %s\n", build.c_str());
692 // NOTE: fingerprint entry format is important for other tools.
693 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
694 printf("Bootloader: %s\n", bootloader.c_str());
695 printf("Radio: %s\n", radio.c_str());
696 printf("Network: %s\n", network.c_str());
697 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
698 if (module_metadata_version != 0) {
699 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
700 }
701
702 printf("Kernel: ");
703 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
704 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
705 printf("Uptime: ");
706 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
707 CommandOptions::WithTimeout(1).Always().Build());
708 printf("Bugreport format version: %s\n", version_.c_str());
709 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
710 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
711 printf("\n");
712 }
713
714 // List of file extensions that can cause a zip file attachment to be rejected by some email
715 // service providers.
716 static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
717 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
718 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
719 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
720 };
721
AddZipEntryFromFd(const std::string & entry_name,int fd,std::chrono::milliseconds timeout=0ms)722 status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
723 std::chrono::milliseconds timeout = 0ms) {
724 if (!IsZipping()) {
725 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
726 entry_name.c_str());
727 return INVALID_OPERATION;
728 }
729 std::string valid_name = entry_name;
730
731 // Rename extension if necessary.
732 size_t idx = entry_name.rfind('.');
733 if (idx != std::string::npos) {
734 std::string extension = entry_name.substr(idx);
735 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
736 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
737 valid_name = entry_name + ".renamed";
738 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
739 }
740 }
741
742 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
743 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
744 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
745 get_mtime(fd, ds.now_));
746 if (err != 0) {
747 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
748 ZipWriter::ErrorCodeString(err));
749 return UNKNOWN_ERROR;
750 }
751 bool finished_entry = false;
752 auto finish_entry = [this, &finished_entry] {
753 if (!finished_entry) {
754 // This should only be called when we're going to return an earlier error,
755 // which would've been logged. This may imply the file is already corrupt
756 // and any further logging from FinishEntry is more likely to mislead than
757 // not.
758 this->zip_writer_->FinishEntry();
759 }
760 };
761 auto scope_guard = android::base::make_scope_guard(finish_entry);
762 auto start = std::chrono::steady_clock::now();
763 auto end = start + timeout;
764 struct pollfd pfd = {fd, POLLIN};
765
766 std::vector<uint8_t> buffer(65536);
767 while (1) {
768 if (timeout.count() > 0) {
769 // lambda to recalculate the timeout.
770 auto time_left_ms = [end]() {
771 auto now = std::chrono::steady_clock::now();
772 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
773 return std::max(diff.count(), 0LL);
774 };
775
776 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
777 if (rc < 0) {
778 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
779 entry_name.c_str(), strerror(errno));
780 return -errno;
781 } else if (rc == 0) {
782 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
783 entry_name.c_str(), strerror(errno), timeout.count());
784 return TIMED_OUT;
785 }
786 }
787
788 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
789 if (bytes_read == 0) {
790 break;
791 } else if (bytes_read == -1) {
792 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
793 return -errno;
794 }
795 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
796 if (err) {
797 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
798 return UNKNOWN_ERROR;
799 }
800 }
801
802 err = zip_writer_->FinishEntry();
803 finished_entry = true;
804 if (err != 0) {
805 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
806 return UNKNOWN_ERROR;
807 }
808
809 return OK;
810 }
811
AddZipEntry(const std::string & entry_name,const std::string & entry_path)812 bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
813 android::base::unique_fd fd(
814 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
815 if (fd == -1) {
816 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
817 return false;
818 }
819
820 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
821 }
822
823 /* adds a file to the existing zipped bugreport */
_add_file_from_fd(const char * title,const char * path,int fd)824 static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
825 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
826 }
827
AddDir(const std::string & dir,bool recursive)828 void Dumpstate::AddDir(const std::string& dir, bool recursive) {
829 if (!IsZipping()) {
830 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
831 return;
832 }
833 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
834 DurationReporter duration_reporter(dir, true);
835 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
836 }
837
AddTextZipEntry(const std::string & entry_name,const std::string & content)838 bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
839 if (!IsZipping()) {
840 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
841 entry_name.c_str());
842 return false;
843 }
844 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
845 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
846 if (err != 0) {
847 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
848 ZipWriter::ErrorCodeString(err));
849 return false;
850 }
851
852 err = zip_writer_->WriteBytes(content.c_str(), content.length());
853 if (err != 0) {
854 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
855 ZipWriter::ErrorCodeString(err));
856 return false;
857 }
858
859 err = zip_writer_->FinishEntry();
860 if (err != 0) {
861 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
862 return false;
863 }
864
865 return true;
866 }
867
DoKmsg()868 static void DoKmsg() {
869 struct stat st;
870 if (!stat(PSTORE_LAST_KMSG, &st)) {
871 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
872 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
873 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
874 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
875 } else {
876 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
877 DumpFile("LAST KMSG", "/proc/last_kmsg");
878 }
879 }
880
DoKernelLogcat()881 static void DoKernelLogcat() {
882 unsigned long timeout_ms = logcat_timeout({"kernel"});
883 RunCommand(
884 "KERNEL LOG",
885 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
886 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
887 }
888
DoSystemLogcat(time_t since)889 static void DoSystemLogcat(time_t since) {
890 char since_str[80];
891 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
892
893 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
894 RunCommand("SYSTEM LOG",
895 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
896 since_str},
897 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
898 }
899
DoRadioLogcat()900 static void DoRadioLogcat() {
901 unsigned long timeout_ms = logcat_timeout({"radio"});
902 RunCommand(
903 "RADIO LOG",
904 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
905 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
906 }
907
DoLogcat()908 static void DoLogcat() {
909 unsigned long timeout_ms;
910 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
911 // calculate timeout
912 timeout_ms = logcat_timeout({"main", "system", "crash"});
913 RunCommand("SYSTEM LOG",
914 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
915 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
916 timeout_ms = logcat_timeout({"events"});
917 RunCommand(
918 "EVENT LOG",
919 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
920 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
921 timeout_ms = logcat_timeout({"stats"});
922 RunCommand(
923 "STATS LOG",
924 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
925 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
926 DoRadioLogcat();
927
928 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
929
930 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
931 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
932 "-v", "uid", "-d", "*:v"});
933 }
934
DumpIncidentReport()935 static void DumpIncidentReport() {
936 if (!ds.IsZipping()) {
937 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
938 return;
939 }
940 DurationReporter duration_reporter("INCIDENT REPORT");
941 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
942 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
943 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
944 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
945 if (fd < 0) {
946 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
947 return;
948 }
949 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
950 bool empty = 0 == lseek(fd, 0, SEEK_END);
951 if (!empty) {
952 // Use a different name from "incident.proto"
953 // /proto/incident.proto is reserved for incident service dump
954 // i.e. metadata for debugging.
955 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
956 }
957 unlink(path.c_str());
958 }
959
DumpIpTablesAsRoot()960 static void DumpIpTablesAsRoot() {
961 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
962 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
963 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
964 /* no ip6 nat */
965 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
966 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
967 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
968 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
969 }
970
DumpDynamicPartitionInfo()971 static void DumpDynamicPartitionInfo() {
972 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
973 return;
974 }
975
976 RunCommand("LPDUMP", {"lpdump", "--all"});
977 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
978 }
979
AddAnrTraceDir(const bool add_to_zip,const std::string & anr_traces_dir)980 static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
981 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
982 anr_traces_dir.c_str());
983
984 // If we're here, dump_traces_path will always be a temporary file
985 // (created with mkostemp or similar) that contains dumps taken earlier
986 // on in the process.
987 if (dump_traces_path != nullptr) {
988 if (add_to_zip) {
989 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
990 } else {
991 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
992 dump_traces_path);
993 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
994 }
995
996 const int ret = unlink(dump_traces_path);
997 if (ret == -1) {
998 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
999 strerror(errno));
1000 }
1001 }
1002
1003 // Add a specific message for the first ANR Dump.
1004 if (ds.anr_data_.size() > 0) {
1005 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
1006 "VM TRACES AT LAST ANR", add_to_zip);
1007
1008 // The "last" ANR will always be included as separate entry in the zip file. In addition,
1009 // it will be present in the body of the main entry if |add_to_zip| == false.
1010 //
1011 // Historical ANRs are always included as separate entries in the bugreport zip file.
1012 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
1013 "HISTORICAL ANR", true /* add_to_zip */);
1014 } else {
1015 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1016 }
1017 }
1018
AddAnrTraceFiles()1019 static void AddAnrTraceFiles() {
1020 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1021
1022 std::string anr_traces_dir = "/data/anr";
1023
1024 AddAnrTraceDir(add_to_zip, anr_traces_dir);
1025
1026 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1027
1028 // Slow traces for slow operations.
1029 struct stat st;
1030 int i = 0;
1031 while (true) {
1032 const std::string slow_trace_path =
1033 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1034 if (stat(slow_trace_path.c_str(), &st)) {
1035 // No traces file at this index, done with the files.
1036 break;
1037 }
1038 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1039 i++;
1040 }
1041 }
1042
DumpBlockStatFiles()1043 static void DumpBlockStatFiles() {
1044 DurationReporter duration_reporter("DUMP BLOCK STAT");
1045
1046 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1047
1048 if (dirptr == nullptr) {
1049 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1050 return;
1051 }
1052
1053 printf("------ DUMP BLOCK STAT ------\n\n");
1054 while (struct dirent *d = readdir(dirptr.get())) {
1055 if ((d->d_name[0] == '.')
1056 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1057 || (d->d_name[1] == '\0'))) {
1058 continue;
1059 }
1060 const std::string new_path =
1061 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1062 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1063 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1064 printf("\n");
1065 }
1066 return;
1067 }
1068
DumpPacketStats()1069 static void DumpPacketStats() {
1070 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1071 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1072 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1073 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1074 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1075 }
1076
DumpIpAddrAndRules()1077 static void DumpIpAddrAndRules() {
1078 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1079 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1080 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1081 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1082 RunCommand("IP RULES", {"ip", "rule", "show"});
1083 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1084 }
1085
RunDumpsysTextByPriority(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)1086 static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1087 std::chrono::milliseconds timeout,
1088 std::chrono::milliseconds service_timeout) {
1089 auto start = std::chrono::steady_clock::now();
1090 sp<android::IServiceManager> sm = defaultServiceManager();
1091 Dumpsys dumpsys(sm.get());
1092 Vector<String16> args;
1093 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
1094 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1095 for (const String16& service : services) {
1096 RETURN_IF_USER_DENIED_CONSENT();
1097 std::string path(title);
1098 path.append(" - ").append(String8(service).c_str());
1099 size_t bytes_written = 0;
1100 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
1101 if (status == OK) {
1102 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1103 std::chrono::duration<double> elapsed_seconds;
1104 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1105 /* as_proto = */ false, elapsed_seconds, bytes_written);
1106 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1107 bool dump_complete = (status == OK);
1108 dumpsys.stopDumpThread(dump_complete);
1109 }
1110
1111 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1112 std::chrono::steady_clock::now() - start);
1113 if (elapsed_duration > timeout) {
1114 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1115 elapsed_duration.count());
1116 break;
1117 }
1118 }
1119 return Dumpstate::RunStatus::OK;
1120 }
1121
RunDumpsysText(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)1122 static void RunDumpsysText(const std::string& title, int priority,
1123 std::chrono::milliseconds timeout,
1124 std::chrono::milliseconds service_timeout) {
1125 DurationReporter duration_reporter(title);
1126 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1127 fsync(STDOUT_FILENO);
1128 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1129 }
1130
1131 /* Dump all services registered with Normal or Default priority. */
RunDumpsysTextNormalPriority(const std::string & title,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)1132 static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1133 std::chrono::milliseconds timeout,
1134 std::chrono::milliseconds service_timeout) {
1135 DurationReporter duration_reporter(title);
1136 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1137 fsync(STDOUT_FILENO);
1138 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1139 service_timeout);
1140
1141 RETURN_IF_USER_DENIED_CONSENT();
1142
1143 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1144 service_timeout);
1145 }
1146
RunDumpsysProto(const std::string & title,int priority,std::chrono::milliseconds timeout,std::chrono::milliseconds service_timeout)1147 static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1148 std::chrono::milliseconds timeout,
1149 std::chrono::milliseconds service_timeout) {
1150 if (!ds.IsZipping()) {
1151 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
1152 return Dumpstate::RunStatus::OK;
1153 }
1154 sp<android::IServiceManager> sm = defaultServiceManager();
1155 Dumpsys dumpsys(sm.get());
1156 Vector<String16> args;
1157 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1158 DurationReporter duration_reporter(title);
1159
1160 auto start = std::chrono::steady_clock::now();
1161 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1162 for (const String16& service : services) {
1163 RETURN_IF_USER_DENIED_CONSENT();
1164 std::string path(kProtoPath);
1165 path.append(String8(service).c_str());
1166 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1167 path.append("_CRITICAL");
1168 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1169 path.append("_HIGH");
1170 }
1171 path.append(kProtoExt);
1172 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
1173 if (status == OK) {
1174 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1175 bool dumpTerminated = (status == OK);
1176 dumpsys.stopDumpThread(dumpTerminated);
1177 }
1178 ZipWriter::FileEntry file_entry;
1179 ds.zip_writer_->GetLastEntry(&file_entry);
1180
1181 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1182 std::chrono::steady_clock::now() - start);
1183 if (elapsed_duration > timeout) {
1184 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1185 elapsed_duration.count());
1186 break;
1187 }
1188 }
1189 return Dumpstate::RunStatus::OK;
1190 }
1191
1192 // Runs dumpsys on services that must dump first and will take less than 100ms to dump.
RunDumpsysCritical()1193 static Dumpstate::RunStatus RunDumpsysCritical() {
1194 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1195 /* timeout= */ 5s, /* service_timeout= */ 500ms);
1196
1197 RETURN_IF_USER_DENIED_CONSENT();
1198
1199 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1200 /* timeout= */ 5s, /* service_timeout= */ 500ms);
1201 }
1202
1203 // Runs dumpsys on services that must dump first but can take up to 250ms to dump.
RunDumpsysHigh()1204 static Dumpstate::RunStatus RunDumpsysHigh() {
1205 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1206 // high priority. Reduce timeout once they are able to dump in a shorter time or
1207 // moved to a parallel task.
1208 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1209 /* timeout= */ 90s, /* service_timeout= */ 30s);
1210
1211 RETURN_IF_USER_DENIED_CONSENT();
1212
1213 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1214 /* timeout= */ 5s, /* service_timeout= */ 1s);
1215 }
1216
1217 // Runs dumpsys on services that must dump but can take up to 10s to dump.
RunDumpsysNormal()1218 static Dumpstate::RunStatus RunDumpsysNormal() {
1219 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
1220
1221 RETURN_IF_USER_DENIED_CONSENT();
1222
1223 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1224 /* timeout= */ 90s, /* service_timeout= */ 10s);
1225 }
1226
DumpHals()1227 static void DumpHals() {
1228 if (!ds.IsZipping()) {
1229 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1230 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1231 return;
1232 }
1233 DurationReporter duration_reporter("DUMP HALS");
1234 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
1235 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1236
1237 using android::hidl::manager::V1_0::IServiceManager;
1238 using android::hardware::defaultServiceManager;
1239
1240 sp<IServiceManager> sm = defaultServiceManager();
1241 if (sm == nullptr) {
1242 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1243 return;
1244 }
1245
1246 auto ret = sm->list([&](const auto& interfaces) {
1247 for (const std::string& interface : interfaces) {
1248 std::string cleanName = interface;
1249 std::replace_if(cleanName.begin(),
1250 cleanName.end(),
1251 [](char c) {
1252 return !isalnum(c) &&
1253 std::string("@-_:.").find(c) == std::string::npos;
1254 }, '_');
1255 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
1256
1257 {
1258 auto fd = android::base::unique_fd(
1259 TEMP_FAILURE_RETRY(open(path.c_str(),
1260 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1261 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1262 if (fd < 0) {
1263 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1264 continue;
1265 }
1266 RunCommandToFd(fd,
1267 "",
1268 {"lshal", "debug", "-E", interface},
1269 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1270
1271 bool empty = 0 == lseek(fd, 0, SEEK_END);
1272 if (!empty) {
1273 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1274 }
1275 }
1276
1277 unlink(path.c_str());
1278 }
1279 });
1280
1281 if (!ret.isOk()) {
1282 MYLOGE("Could not list hals from hwservicemanager.\n");
1283 }
1284 }
1285
DumpExternalFragmentationInfo()1286 static void DumpExternalFragmentationInfo() {
1287 struct stat st;
1288 if (stat("/proc/buddyinfo", &st) != 0) {
1289 MYLOGE("Unable to dump external fragmentation info\n");
1290 return;
1291 }
1292
1293 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1294 std::ifstream ifs("/proc/buddyinfo");
1295 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1296 for (std::string line; std::getline(ifs, line);) {
1297 std::smatch match_results;
1298 if (std::regex_match(line, match_results, unusable_index_regex)) {
1299 std::stringstream free_pages(std::string{match_results[3]});
1300 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1301 std::istream_iterator<int>());
1302
1303 int total_free_pages = 0;
1304 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1305 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1306 }
1307
1308 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1309 match_results[2].str().c_str());
1310
1311 int usable_free_pages = total_free_pages;
1312 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1313 auto unusable_index = (total_free_pages - usable_free_pages) /
1314 static_cast<double>(total_free_pages);
1315 printf(" %5.3f", unusable_index);
1316 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1317 }
1318
1319 printf("\n");
1320 }
1321 }
1322 printf("\n");
1323 }
1324
1325 // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1326 // via the consent they are shown. Ignores other errors that occur while running various
1327 // commands. The consent checking is currently done around long running tasks, which happen to
1328 // be distributed fairly evenly throughout the function.
dumpstate()1329 static Dumpstate::RunStatus dumpstate() {
1330 DurationReporter duration_reporter("DUMPSTATE");
1331
1332 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1333 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1334 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
1335 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
1336 RunCommand("UPTIME", {"uptime"});
1337 DumpBlockStatFiles();
1338 DumpFile("MEMORY INFO", "/proc/meminfo");
1339 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
1340 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
1341
1342 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1343
1344 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1345 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1346 DumpFile("SLAB INFO", "/proc/slabinfo");
1347 DumpFile("ZONEINFO", "/proc/zoneinfo");
1348 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1349 DumpFile("BUDDYINFO", "/proc/buddyinfo");
1350 DumpExternalFragmentationInfo();
1351
1352 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1353 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
1354
1355 RunCommand("PROCESSES AND THREADS",
1356 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
1357
1358 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1359 CommandOptions::AS_ROOT);
1360
1361 DumpHals();
1362
1363 RunCommand("PRINTENV", {"printenv"});
1364 RunCommand("NETSTAT", {"netstat", "-nW"});
1365 struct stat s;
1366 if (stat("/proc/modules", &s) != 0) {
1367 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1368 } else {
1369 RunCommand("LSMOD", {"lsmod"});
1370 }
1371
1372 if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
1373 DoKernelLogcat();
1374 } else {
1375 do_dmesg();
1376 }
1377
1378 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
1379
1380 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1381
1382 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
1383 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
1384
1385 /* Dump Bluetooth HCI logs */
1386 ds.AddDir("/data/misc/bluetooth/logs", true);
1387
1388 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
1389 MYLOGI("taking late screenshot\n");
1390 ds.TakeScreenshot();
1391 }
1392
1393 AddAnrTraceFiles();
1394
1395 // NOTE: tombstones are always added as separate entries in the zip archive
1396 // and are not interspersed with the main report.
1397 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
1398 "TOMBSTONE", true /* add_to_zip */);
1399 if (!tombstones_dumped) {
1400 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
1401 }
1402
1403 DumpPacketStats();
1404
1405 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1406
1407 DoKmsg();
1408
1409 DumpIpAddrAndRules();
1410
1411 dump_route_tables();
1412
1413 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1414 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1415 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
1416
1417 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
1418
1419 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1420
1421 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
1422
1423 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
1424
1425 /* Binder state is expensive to look at as it uses a lot of memory. */
1426 std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ?
1427 "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs";
1428
1429 DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log");
1430 DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log");
1431 DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions");
1432 DumpFile("BINDER STATS", binder_logs_dir + "/stats");
1433 DumpFile("BINDER STATE", binder_logs_dir + "/state");
1434
1435 /* Add window and surface trace files. */
1436 if (!PropertiesHelper::IsUserBuild()) {
1437 ds.AddDir(WMTRACE_DATA_DIR, false);
1438 }
1439
1440 ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
1441
1442 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
1443
1444 /* Migrate the ril_dumpstate to a device specific dumpstate? */
1445 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1446 if (rilDumpstateTimeout > 0) {
1447 // su does not exist on user builds, so try running without it.
1448 // This way any implementations of vril-dump that do not require
1449 // root can run on user builds.
1450 CommandOptions::CommandOptionsBuilder options =
1451 CommandOptions::WithTimeout(rilDumpstateTimeout);
1452 if (!PropertiesHelper::IsUserBuild()) {
1453 options.AsRoot();
1454 }
1455 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
1456 }
1457
1458 printf("========================================================\n");
1459 printf("== Android Framework Services\n");
1460 printf("========================================================\n");
1461
1462 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
1463
1464 printf("========================================================\n");
1465 printf("== Checkins\n");
1466 printf("========================================================\n");
1467
1468 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1469
1470 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1471
1472 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1473 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1474 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1475 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
1476
1477 printf("========================================================\n");
1478 printf("== Running Application Activities\n");
1479 printf("========================================================\n");
1480
1481 // The following dumpsys internally collects output from running apps, so it can take a long
1482 // time. So let's extend the timeout.
1483
1484 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1485
1486 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
1487
1488 printf("========================================================\n");
1489 printf("== Running Application Services (platform)\n");
1490 printf("========================================================\n");
1491
1492 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
1493 DUMPSYS_COMPONENTS_OPTIONS);
1494
1495 printf("========================================================\n");
1496 printf("== Running Application Services (non-platform)\n");
1497 printf("========================================================\n");
1498
1499 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1500 DUMPSYS_COMPONENTS_OPTIONS);
1501
1502 printf("========================================================\n");
1503 printf("== Running Application Providers (platform)\n");
1504 printf("========================================================\n");
1505
1506 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1507 DUMPSYS_COMPONENTS_OPTIONS);
1508
1509 printf("========================================================\n");
1510 printf("== Running Application Providers (non-platform)\n");
1511 printf("========================================================\n");
1512
1513 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1514 DUMPSYS_COMPONENTS_OPTIONS);
1515
1516 printf("========================================================\n");
1517 printf("== Dropbox crashes\n");
1518 printf("========================================================\n");
1519
1520 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1521 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1522
1523 printf("========================================================\n");
1524 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1525 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1526 printf("========================================================\n");
1527 printf("== dumpstate: done (id %d)\n", ds.id_);
1528 printf("========================================================\n");
1529
1530 printf("========================================================\n");
1531 printf("== Obtaining statsd metadata\n");
1532 printf("========================================================\n");
1533 // This differs from the usual dumpsys stats, which is the stats report data.
1534 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
1535
1536 // Add linker configuration directory
1537 ds.AddDir(LINKERCONFIG_DIR, true);
1538
1539 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1540
1541 return Dumpstate::RunStatus::OK;
1542 }
1543
1544 /*
1545 * Dumps state for the default case; drops root after it's no longer necessary.
1546 *
1547 * Returns RunStatus::OK if everything went fine.
1548 * Returns RunStatus::ERROR if there was an error.
1549 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1550 * with the caller.
1551 */
DumpstateDefault()1552 static Dumpstate::RunStatus DumpstateDefault() {
1553 // Invoking the following dumpsys calls before DumpTraces() to try and
1554 // keep the system stats as close to its initial state as possible.
1555 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
1556
1557 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1558 // buffer.
1559 DoLogcat();
1560 // Capture timestamp after first logcat to use in next logcat
1561 time_t logcat_ts = time(nullptr);
1562
1563 /* collect stack traces from Dalvik and native processes (needs root) */
1564 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
1565
1566 /* Run some operations that require root. */
1567 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1568 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1569
1570 ds.AddDir(RECOVERY_DIR, true);
1571 ds.AddDir(RECOVERY_DATA_DIR, true);
1572 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1573 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1574 if (!PropertiesHelper::IsUserBuild()) {
1575 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1576 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1577 ds.AddZipEntry(ZIP_ROOT_DIR + PACKAGE_DEX_USE_LIST, PACKAGE_DEX_USE_LIST);
1578 }
1579 ds.AddDir(PREREBOOT_DATA_DIR, false);
1580 add_mountinfo();
1581 DumpIpTablesAsRoot();
1582 DumpDynamicPartitionInfo();
1583 ds.AddDir(OTA_METADATA_DIR, true);
1584
1585 // Capture any IPSec policies in play. No keys are exposed here.
1586 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1587
1588 // Dump IPsec stats. No keys are exposed here.
1589 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1590
1591 // Run ss as root so we can see socket marks.
1592 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1593
1594 // Run iotop as root to show top 100 IO threads
1595 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1596
1597 // Gather shared memory buffer info if the product implements it
1598 struct stat st;
1599 if (!stat("/product/bin/dmabuf_dump", &st)) {
1600 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1601 }
1602
1603 DumpFile("PSI cpu", "/proc/pressure/cpu");
1604 DumpFile("PSI memory", "/proc/pressure/memory");
1605 DumpFile("PSI io", "/proc/pressure/io");
1606
1607 if (!DropRootUser()) {
1608 return Dumpstate::RunStatus::ERROR;
1609 }
1610
1611 RETURN_IF_USER_DENIED_CONSENT();
1612 Dumpstate::RunStatus status = dumpstate();
1613 // Capture logcat since the last time we did it.
1614 DoSystemLogcat(logcat_ts);
1615 return status;
1616 }
1617
1618 // This method collects common dumpsys for telephony and wifi. Typically, wifi
1619 // reports are fine to include all information, but telephony reports on user
1620 // builds need to strip some content (see DumpstateTelephonyOnly).
DumpstateRadioCommon(bool include_sensitive_info=true)1621 static void DumpstateRadioCommon(bool include_sensitive_info = true) {
1622 DumpIpTablesAsRoot();
1623
1624 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1625
1626 if (!DropRootUser()) {
1627 return;
1628 }
1629
1630 // We need to be picky about some stuff for telephony reports on user builds.
1631 if (!include_sensitive_info) {
1632 // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
1633 DoRadioLogcat();
1634 } else {
1635 // Contains various system properties and process startup info.
1636 do_dmesg();
1637 // Logs other than the radio buffer may contain package/component names and potential PII.
1638 DoLogcat();
1639 // Too broad for connectivity problems.
1640 DoKmsg();
1641 // Contains unrelated hardware info (camera, NFC, biometrics, ...).
1642 DumpHals();
1643 }
1644
1645 DumpPacketStats();
1646 DumpIpAddrAndRules();
1647 dump_route_tables();
1648 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1649 CommandOptions::WithTimeout(10).Build());
1650 }
1651
1652 // We use "telephony" here for legacy reasons, though this now really means "connectivity" (cellular
1653 // + wifi + networking). This method collects dumpsys for connectivity debugging only. General rules
1654 // for what can be included on user builds: all reported information MUST directly relate to
1655 // connectivity debugging or customer support and MUST NOT contain unrelated personally identifiable
1656 // information. This information MUST NOT identify user-installed packages (UIDs are OK, package
1657 // names are not), and MUST NOT contain logs of user application traffic.
1658 // TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
DumpstateTelephonyOnly()1659 static void DumpstateTelephonyOnly() {
1660 DurationReporter duration_reporter("DUMPSTATE");
1661
1662 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1663
1664 const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
1665
1666 DumpstateRadioCommon(include_sensitive_info);
1667
1668 if (include_sensitive_info) {
1669 // Contains too much unrelated PII, and given the unstructured nature of sysprops, we can't
1670 // really cherrypick all of the connectivity-related ones. Apps generally have no business
1671 // reading these anyway, and there should be APIs to supply the info in a more app-friendly
1672 // way.
1673 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1674 }
1675
1676 printf("========================================================\n");
1677 printf("== Android Framework Services\n");
1678 printf("========================================================\n");
1679
1680 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1681 SEC_TO_MSEC(10));
1682 // TODO(b/146521742) build out an argument to include bound services here for user builds
1683 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1684 SEC_TO_MSEC(10));
1685 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1686 SEC_TO_MSEC(10));
1687 RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1688 RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
1689 SEC_TO_MSEC(10));
1690 if (include_sensitive_info) {
1691 // Contains raw IP addresses, omit from reports on user builds.
1692 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1693 // Contains raw destination IP/MAC addresses, omit from reports on user builds.
1694 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1695 SEC_TO_MSEC(10));
1696 // Contains package/component names, omit from reports on user builds.
1697 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1698 SEC_TO_MSEC(10));
1699 // Contains package names, but should be relatively simple to remove them (also contains
1700 // UIDs already), omit from reports on user builds.
1701 RunDumpsys("BATTERYSTATS", {"deviceidle"}, CommandOptions::WithTimeout(90).Build(),
1702 SEC_TO_MSEC(10));
1703 }
1704
1705 printf("========================================================\n");
1706 printf("== Running Application Services\n");
1707 printf("========================================================\n");
1708
1709 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1710
1711 if (include_sensitive_info) {
1712 printf("========================================================\n");
1713 printf("== Running Application Services (non-platform)\n");
1714 printf("========================================================\n");
1715
1716 // Contains package/component names and potential PII, omit from reports on user builds.
1717 // To get dumps of the active CarrierService(s) on user builds, we supply an argument to the
1718 // carrier_config dumpsys instead.
1719 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1720 DUMPSYS_COMPONENTS_OPTIONS);
1721
1722 printf("========================================================\n");
1723 printf("== Checkins\n");
1724 printf("========================================================\n");
1725
1726 // Contains package/component names, omit from reports on user builds.
1727 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1728 }
1729
1730 printf("========================================================\n");
1731 printf("== dumpstate: done (id %d)\n", ds.id_);
1732 printf("========================================================\n");
1733 }
1734
1735 // This method collects dumpsys for wifi debugging only
DumpstateWifiOnly()1736 static void DumpstateWifiOnly() {
1737 DurationReporter duration_reporter("DUMPSTATE");
1738
1739 DumpstateRadioCommon();
1740
1741 printf("========================================================\n");
1742 printf("== Android Framework Services\n");
1743 printf("========================================================\n");
1744
1745 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1746 SEC_TO_MSEC(10));
1747 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1748 SEC_TO_MSEC(10));
1749
1750 printf("========================================================\n");
1751 printf("== dumpstate: done (id %d)\n", ds.id_);
1752 printf("========================================================\n");
1753 }
1754
DumpTraces(const char ** path)1755 Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
1756 DurationReporter duration_reporter("DUMP TRACES");
1757
1758 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1759 const size_t buf_size = temp_file_pattern.length() + 1;
1760 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1761 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1762
1763 // Create a new, empty file to receive all trace dumps.
1764 //
1765 // TODO: This can be simplified once we remove support for the old style
1766 // dumps. We can have a file descriptor passed in to dump_traces instead
1767 // of creating a file, closing it and then reopening it again.
1768 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1769 if (fd < 0) {
1770 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
1771 return RunStatus::OK;
1772 }
1773
1774 // Nobody should have access to this temporary file except dumpstate, but we
1775 // temporarily grant 'read' to 'others' here because this file is created
1776 // when tombstoned is still running as root, but dumped after dropping. This
1777 // can go away once support for old style dumping has.
1778 const int chmod_ret = fchmod(fd, 0666);
1779 if (chmod_ret < 0) {
1780 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
1781 return RunStatus::OK;
1782 }
1783
1784 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1785 if (proc.get() == nullptr) {
1786 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
1787 return RunStatus::OK;
1788 }
1789
1790 // Number of times process dumping has timed out. If we encounter too many
1791 // failures, we'll give up.
1792 int timeout_failures = 0;
1793 bool dalvik_found = false;
1794
1795 const std::set<int> hal_pids = get_interesting_hal_pids();
1796
1797 struct dirent* d;
1798 while ((d = readdir(proc.get()))) {
1799 RETURN_IF_USER_DENIED_CONSENT();
1800 int pid = atoi(d->d_name);
1801 if (pid <= 0) {
1802 continue;
1803 }
1804
1805 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1806 std::string exe;
1807 if (!android::base::Readlink(link_name, &exe)) {
1808 continue;
1809 }
1810
1811 bool is_java_process;
1812 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1813 // Don't bother dumping backtraces for the zygote.
1814 if (IsZygote(pid)) {
1815 continue;
1816 }
1817
1818 dalvik_found = true;
1819 is_java_process = true;
1820 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1821 is_java_process = false;
1822 } else {
1823 // Probably a native process we don't care about, continue.
1824 continue;
1825 }
1826
1827 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1828 if (timeout_failures == 3) {
1829 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1830 break;
1831 }
1832
1833 const uint64_t start = Nanotime();
1834 const int ret = dump_backtrace_to_file_timeout(
1835 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1836 is_java_process ? 5 : 20, fd);
1837
1838 if (ret == -1) {
1839 // For consistency, the header and footer to this message match those
1840 // dumped by debuggerd in the success case.
1841 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1842 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1843 dprintf(fd, "---- end %d ----", pid);
1844 timeout_failures++;
1845 continue;
1846 }
1847
1848 // We've successfully dumped stack traces, reset the failure count
1849 // and write a summary of the elapsed time to the file and continue with the
1850 // next process.
1851 timeout_failures = 0;
1852
1853 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1854 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1855 }
1856
1857 if (!dalvik_found) {
1858 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1859 }
1860
1861 *path = file_name_buf.release();
1862 return RunStatus::OK;
1863 }
1864
DumpstateBoard()1865 void Dumpstate::DumpstateBoard() {
1866 DurationReporter duration_reporter("dumpstate_board()");
1867 printf("========================================================\n");
1868 printf("== Board\n");
1869 printf("========================================================\n");
1870
1871 if (!IsZipping()) {
1872 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
1873 return;
1874 }
1875
1876 std::vector<std::string> paths;
1877 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
1878 for (int i = 0; i < NUM_OF_DUMPS; i++) {
1879 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1880 kDumpstateBoardFiles[i].c_str()));
1881 remover.emplace_back(android::base::make_scope_guard(
1882 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
1883 }
1884
1885 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1886 if (dumpstate_device == nullptr) {
1887 MYLOGE("No IDumpstateDevice implementation\n");
1888 return;
1889 }
1890
1891 using ScopedNativeHandle =
1892 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1893 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1894 [](native_handle_t* handle) {
1895 native_handle_close(handle);
1896 native_handle_delete(handle);
1897 });
1898 if (handle == nullptr) {
1899 MYLOGE("Could not create native_handle\n");
1900 return;
1901 }
1902
1903 // TODO(128270426): Check for consent in between?
1904 for (size_t i = 0; i < paths.size(); i++) {
1905 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1906
1907 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1908 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1909 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1910 if (fd < 0) {
1911 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1912 return;
1913 }
1914 handle.get()->data[i] = fd.release();
1915 }
1916
1917 // Given that bugreport is required to diagnose failures, it's better to
1918 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1919 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1920 // and grab whatever dumped
1921 std::packaged_task<bool()>
1922 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
1923 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1924 if (!status.isOk()) {
1925 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
1926 return false;
1927 }
1928 return true;
1929 });
1930
1931 auto result = dumpstate_task.get_future();
1932 std::thread(std::move(dumpstate_task)).detach();
1933
1934 constexpr size_t timeout_sec = 30;
1935 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1936 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1937 if (!android::base::SetProperty("ctl.interface_restart",
1938 android::base::StringPrintf("%s/default",
1939 IDumpstateDevice::descriptor))) {
1940 MYLOGE("Couldn't restart dumpstate HAL\n");
1941 }
1942 }
1943 // Wait some time for init to kill dumpstate vendor HAL
1944 constexpr size_t killing_timeout_sec = 10;
1945 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1946 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1947 "there might be racing in content\n", killing_timeout_sec);
1948 }
1949
1950 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1951 for (size_t i = 0; i < paths.size(); i++) {
1952 struct stat s;
1953 if (fstat(handle.get()->data[i], &s) == -1) {
1954 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1955 strerror(errno));
1956 file_sizes[i] = -1;
1957 continue;
1958 }
1959 file_sizes[i] = s.st_size;
1960 }
1961
1962 for (size_t i = 0; i < paths.size(); i++) {
1963 if (file_sizes[i] == -1) {
1964 continue;
1965 }
1966 if (file_sizes[i] == 0) {
1967 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
1968 continue;
1969 }
1970 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
1971 }
1972
1973 printf("*** See dumpstate-board.txt entry ***\n");
1974 }
1975
ShowUsage()1976 static void ShowUsage() {
1977 fprintf(stderr,
1978 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
1979 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1980 " -h: display this help message\n"
1981 " -b: play sound file instead of vibrate, at beginning of job\n"
1982 " -e: play sound file instead of vibrate, at end of job\n"
1983 " -d: append date to filename\n"
1984 " -p: capture screenshot to filename.png\n"
1985 " -z: generate zipped file\n"
1986 " -s: write output to control socket (for init)\n"
1987 " -S: write file location to control socket (for init; requires -z)\n"
1988 " -q: disable vibrate\n"
1989 " -B: send broadcast when finished\n"
1990 " -P: send broadcast when started and update system properties on "
1991 "progress (requires -B)\n"
1992 " -R: take bugreport in remote mode (requires -z, -d and -B, "
1993 "shouldn't be used with -P)\n"
1994 " -w: start binder service and make it wait for a call to startBugreport\n"
1995 " -v: prints the dumpstate header and exit\n");
1996 }
1997
register_sig_handler()1998 static void register_sig_handler() {
1999 signal(SIGPIPE, SIG_IGN);
2000 }
2001
FinishZipFile()2002 bool Dumpstate::FinishZipFile() {
2003 std::string entry_name = base_name_ + "-" + name_ + ".txt";
2004 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
2005 tmp_path_.c_str());
2006 // Final timestamp
2007 char date[80];
2008 time_t the_real_now_please_stand_up = time(nullptr);
2009 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
2010 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
2011 the_real_now_please_stand_up - ds.now_);
2012
2013 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
2014 MYLOGE("Failed to add text entry to .zip file\n");
2015 return false;
2016 }
2017 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
2018 MYLOGE("Failed to add main_entry.txt to .zip file\n");
2019 return false;
2020 }
2021
2022 // Add log file (which contains stderr output) to zip...
2023 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
2024 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
2025 MYLOGE("Failed to add dumpstate log to .zip file\n");
2026 return false;
2027 }
2028 // TODO: Should truncate the existing file.
2029 // ... and re-open it for further logging.
2030 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
2031 return false;
2032 }
2033 fprintf(stderr, "\n");
2034
2035 int32_t err = zip_writer_->Finish();
2036 if (err != 0) {
2037 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
2038 return false;
2039 }
2040
2041 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
2042 ds.zip_file.reset(nullptr);
2043
2044 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
2045 android::os::UnlinkAndLogOnError(tmp_path_);
2046
2047 return true;
2048 }
2049
SHA256_file_hash(const std::string & filepath)2050 static std::string SHA256_file_hash(const std::string& filepath) {
2051 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
2052 | O_CLOEXEC | O_NOFOLLOW)));
2053 if (fd == -1) {
2054 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
2055 return nullptr;
2056 }
2057
2058 SHA256_CTX ctx;
2059 SHA256_Init(&ctx);
2060
2061 std::vector<uint8_t> buffer(65536);
2062 while (1) {
2063 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
2064 if (bytes_read == 0) {
2065 break;
2066 } else if (bytes_read == -1) {
2067 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
2068 return nullptr;
2069 }
2070
2071 SHA256_Update(&ctx, buffer.data(), bytes_read);
2072 }
2073
2074 uint8_t hash[SHA256_DIGEST_LENGTH];
2075 SHA256_Final(hash, &ctx);
2076
2077 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
2078 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
2079 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
2080 }
2081 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2082 return std::string(hash_buffer);
2083 }
2084
SendBroadcast(const std::string & action,const std::vector<std::string> & args)2085 static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2086 // clang-format off
2087 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2088 "--receiver-foreground", "--receiver-include-background", "-a", action};
2089 // clang-format on
2090
2091 am.insert(am.end(), args.begin(), args.end());
2092
2093 RunCommand("", am,
2094 CommandOptions::WithTimeout(20)
2095 .Log("Sending broadcast: '%s'\n")
2096 .Always()
2097 .DropRoot()
2098 .RedirectStderr()
2099 .Build());
2100 }
2101
Vibrate(int duration_ms)2102 static void Vibrate(int duration_ms) {
2103 // clang-format off
2104 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
2105 CommandOptions::WithTimeout(10)
2106 .Log("Vibrate: '%s'\n")
2107 .Always()
2108 .Build());
2109 // clang-format on
2110 }
2111
MaybeResolveSymlink(std::string * path)2112 static void MaybeResolveSymlink(std::string* path) {
2113 std::string resolved_path;
2114 if (android::base::Readlink(*path, &resolved_path)) {
2115 *path = resolved_path;
2116 }
2117 }
2118
2119 /*
2120 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2121 * if we are writing zip files and adds the version file.
2122 */
PrepareToWriteToFile()2123 static void PrepareToWriteToFile() {
2124 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2125
2126 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2127 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
2128 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
2129 if (ds.options_->do_add_date) {
2130 char date[80];
2131 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2132 ds.name_ = date;
2133 } else {
2134 ds.name_ = "undated";
2135 }
2136
2137 if (ds.options_->telephony_only) {
2138 ds.base_name_ += "-telephony";
2139 } else if (ds.options_->wifi_only) {
2140 ds.base_name_ += "-wifi";
2141 }
2142
2143 if (ds.options_->do_fb) {
2144 ds.screenshot_path_ = ds.GetPath(".png");
2145 }
2146 ds.tmp_path_ = ds.GetPath(".tmp");
2147 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2148
2149 std::string destination = ds.options_->bugreport_fd.get() != -1
2150 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
2151 : ds.bugreport_internal_dir_.c_str();
2152 MYLOGD(
2153 "Bugreport dir: %s\n"
2154 "Base name: %s\n"
2155 "Suffix: %s\n"
2156 "Log path: %s\n"
2157 "Temporary path: %s\n"
2158 "Screenshot path: %s\n",
2159 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2160 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
2161
2162 if (ds.options_->do_zip_file) {
2163 ds.path_ = ds.GetPath(".zip");
2164 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2165 create_parent_dirs(ds.path_.c_str());
2166 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2167 if (ds.zip_file == nullptr) {
2168 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2169 } else {
2170 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2171 }
2172 ds.AddTextZipEntry("version.txt", ds.version_);
2173 }
2174 }
2175
2176 /*
2177 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2178 * printing zipped file status, etc.
2179 */
FinalizeFile()2180 static void FinalizeFile() {
2181 /* check if user changed the suffix using system properties */
2182 std::string name =
2183 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2184 bool change_suffix = false;
2185 if (!name.empty()) {
2186 /* must whitelist which characters are allowed, otherwise it could cross directories */
2187 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2188 if (std::regex_match(name.c_str(), valid_regex)) {
2189 change_suffix = true;
2190 } else {
2191 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2192 }
2193 }
2194 if (change_suffix) {
2195 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2196 ds.name_ = name;
2197 if (!ds.screenshot_path_.empty()) {
2198 std::string new_screenshot_path = ds.GetPath(".png");
2199 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2200 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2201 new_screenshot_path.c_str(), strerror(errno));
2202 } else {
2203 ds.screenshot_path_ = new_screenshot_path;
2204 }
2205 }
2206 }
2207
2208 bool do_text_file = true;
2209 if (ds.options_->do_zip_file) {
2210 if (!ds.FinishZipFile()) {
2211 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2212 do_text_file = true;
2213 } else {
2214 do_text_file = false;
2215 // If the user has changed the suffix, we need to change the zip file name.
2216 std::string new_path = ds.GetPath(".zip");
2217 if (ds.path_ != new_path) {
2218 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2219 if (rename(ds.path_.c_str(), new_path.c_str())) {
2220 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2221 strerror(errno));
2222 } else {
2223 ds.path_ = new_path;
2224 }
2225 }
2226 }
2227 }
2228 if (do_text_file) {
2229 ds.path_ = ds.GetPath(".txt");
2230 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2231 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2232 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2233 ds.path_.clear();
2234 }
2235 }
2236 if (ds.options_->use_control_socket) {
2237 if (do_text_file) {
2238 dprintf(ds.control_socket_fd_,
2239 "FAIL:could not create zip file, check %s "
2240 "for more details\n",
2241 ds.log_path_.c_str());
2242 } else {
2243 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2244 }
2245 }
2246 }
2247
2248 /* Broadcasts that we are done with the bugreport */
SendBugreportFinishedBroadcast()2249 static void SendBugreportFinishedBroadcast() {
2250 // TODO(b/111441001): use callback instead of broadcast.
2251 if (!ds.path_.empty()) {
2252 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
2253 // clang-format off
2254
2255 std::vector<std::string> am_args = {
2256 "--receiver-permission", "android.permission.DUMP",
2257 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2258 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2259 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
2260 "--es", "android.intent.extra.BUGREPORT", ds.path_,
2261 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2262 };
2263 // clang-format on
2264 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
2265 am_args.push_back("--es");
2266 am_args.push_back("android.intent.extra.SCREENSHOT");
2267 am_args.push_back(ds.screenshot_path_);
2268 }
2269 if (!ds.options_->notification_title.empty()) {
2270 am_args.push_back("--es");
2271 am_args.push_back("android.intent.extra.TITLE");
2272 am_args.push_back(ds.options_->notification_title);
2273 if (!ds.options_->notification_description.empty()) {
2274 am_args.push_back("--es");
2275 am_args.push_back("android.intent.extra.DESCRIPTION");
2276 am_args.push_back(ds.options_->notification_description);
2277 }
2278 }
2279 if (ds.options_->is_remote_mode) {
2280 am_args.push_back("--es");
2281 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
2282 am_args.push_back(SHA256_file_hash(ds.path_));
2283 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2284 } else {
2285 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2286 }
2287 } else {
2288 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2289 }
2290 }
2291
ModeToString(Dumpstate::BugreportMode mode)2292 static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2293 switch (mode) {
2294 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2295 return "BUGREPORT_FULL";
2296 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2297 return "BUGREPORT_INTERACTIVE";
2298 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2299 return "BUGREPORT_REMOTE";
2300 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2301 return "BUGREPORT_WEAR";
2302 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2303 return "BUGREPORT_TELEPHONY";
2304 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2305 return "BUGREPORT_WIFI";
2306 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2307 return "BUGREPORT_DEFAULT";
2308 }
2309 }
2310
SetOptionsFromMode(Dumpstate::BugreportMode mode,Dumpstate::DumpOptions * options)2311 static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
2312 options->extra_options = ModeToString(mode);
2313 switch (mode) {
2314 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2315 options->do_broadcast = true;
2316 options->do_fb = true;
2317 break;
2318 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2319 // Currently, the dumpstate binder is only used by Shell to update progress.
2320 options->do_start_service = true;
2321 options->do_progress_updates = true;
2322 options->do_fb = false;
2323 options->do_broadcast = true;
2324 break;
2325 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2326 options->do_vibrate = false;
2327 options->is_remote_mode = true;
2328 options->do_fb = false;
2329 options->do_broadcast = true;
2330 break;
2331 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2332 options->do_start_service = true;
2333 options->do_progress_updates = true;
2334 options->do_zip_file = true;
2335 options->do_fb = true;
2336 options->do_broadcast = true;
2337 break;
2338 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2339 options->telephony_only = true;
2340 options->do_progress_updates = true;
2341 options->do_fb = false;
2342 options->do_broadcast = true;
2343 break;
2344 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2345 options->wifi_only = true;
2346 options->do_zip_file = true;
2347 options->do_fb = false;
2348 options->do_broadcast = true;
2349 break;
2350 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2351 break;
2352 }
2353 }
2354
getBugreportModeFromProperty()2355 static Dumpstate::BugreportMode getBugreportModeFromProperty() {
2356 // If the system property is not set, it's assumed to be a default bugreport.
2357 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
2358
2359 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2360 if (!extra_options.empty()) {
2361 // Framework uses a system property to override some command-line args.
2362 // Currently, it contains the type of the requested bugreport.
2363 if (extra_options == "bugreportplus") {
2364 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
2365 } else if (extra_options == "bugreportfull") {
2366 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
2367 } else if (extra_options == "bugreportremote") {
2368 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2369 } else if (extra_options == "bugreportwear") {
2370 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2371 } else if (extra_options == "bugreporttelephony") {
2372 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2373 } else if (extra_options == "bugreportwifi") {
2374 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
2375 } else {
2376 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
2377 }
2378 // Reset the property
2379 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2380 }
2381 return mode;
2382 }
2383
2384 // TODO: Move away from system properties when we have options passed via binder calls.
2385 /* Sets runtime options from the system properties and then clears those properties. */
SetOptionsFromProperties(Dumpstate::DumpOptions * options)2386 static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2387 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2388 SetOptionsFromMode(mode, options);
2389
2390 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2391 if (!options->notification_title.empty()) {
2392 // Reset the property
2393 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2394
2395 options->notification_description =
2396 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2397 if (!options->notification_description.empty()) {
2398 // Reset the property
2399 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2400 }
2401 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2402 options->notification_description.c_str());
2403 }
2404 }
2405
LogDumpOptions(const Dumpstate::DumpOptions & options)2406 static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2407 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2408 MYLOGI("do_add_date: %d\n", options.do_add_date);
2409 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2410 MYLOGI("use_socket: %d\n", options.use_socket);
2411 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2412 MYLOGI("do_fb: %d\n", options.do_fb);
2413 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2414 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2415 MYLOGI("show_header_only: %d\n", options.show_header_only);
2416 MYLOGI("do_start_service: %d\n", options.do_start_service);
2417 MYLOGI("telephony_only: %d\n", options.telephony_only);
2418 MYLOGI("wifi_only: %d\n", options.wifi_only);
2419 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
2420 MYLOGI("fd: %d\n", options.bugreport_fd.get());
2421 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2422 MYLOGI("args: %s\n", options.args.c_str());
2423 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2424 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2425 }
2426
Initialize(BugreportMode bugreport_mode,const android::base::unique_fd & bugreport_fd_in,const android::base::unique_fd & screenshot_fd_in)2427 void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2428 const android::base::unique_fd& bugreport_fd_in,
2429 const android::base::unique_fd& screenshot_fd_in) {
2430 // In the new API world, date is always added; output is always a zip file.
2431 // TODO(111441001): remove these options once they are obsolete.
2432 do_add_date = true;
2433 do_zip_file = true;
2434
2435 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2436 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2437 screenshot_fd.reset(dup(screenshot_fd_in.get()));
2438
2439 extra_options = ModeToString(bugreport_mode);
2440 SetOptionsFromMode(bugreport_mode, this);
2441 }
2442
Initialize(int argc,char * argv[])2443 Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2444 RunStatus status = RunStatus::OK;
2445 int c;
2446 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
2447 switch (c) {
2448 // clang-format off
2449 case 'd': do_add_date = true; break;
2450 case 'z': do_zip_file = true; break;
2451 // o=use_outfile not supported anymore.
2452 // TODO(b/111441001): Remove when all callers have migrated.
2453 case 'o': break;
2454 case 's': use_socket = true; break;
2455 case 'S': use_control_socket = true; break;
2456 case 'v': show_header_only = true; break;
2457 case 'q': do_vibrate = false; break;
2458 case 'p': do_fb = true; break;
2459 case 'P': do_progress_updates = true; break;
2460 case 'R': is_remote_mode = true; break;
2461 case 'B': do_broadcast = true; break;
2462 case 'V': break; // compatibility no-op
2463 case 'w':
2464 // This was already processed
2465 break;
2466 case 'h':
2467 status = RunStatus::HELP;
2468 break;
2469 default:
2470 fprintf(stderr, "Invalid option: %c\n", c);
2471 status = RunStatus::INVALID_INPUT;
2472 break;
2473 // clang-format on
2474 }
2475 }
2476
2477 for (int i = 0; i < argc; i++) {
2478 args += argv[i];
2479 if (i < argc - 1) {
2480 args += " ";
2481 }
2482 }
2483
2484 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2485 optind = 1;
2486
2487 SetOptionsFromProperties(this);
2488 return status;
2489 }
2490
ValidateOptions() const2491 bool Dumpstate::DumpOptions::ValidateOptions() const {
2492 if (bugreport_fd.get() != -1 && !do_zip_file) {
2493 return false;
2494 }
2495
2496 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
2497 return false;
2498 }
2499
2500 if (use_control_socket && !do_zip_file) {
2501 return false;
2502 }
2503
2504 if (do_progress_updates && !do_broadcast) {
2505 return false;
2506 }
2507
2508 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
2509 return false;
2510 }
2511 return true;
2512 }
2513
SetOptions(std::unique_ptr<DumpOptions> options)2514 void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2515 options_ = std::move(options);
2516 }
2517
Run(int32_t calling_uid,const std::string & calling_package)2518 Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2519 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
2520 if (listener_ != nullptr) {
2521 switch (status) {
2522 case Dumpstate::RunStatus::OK:
2523 listener_->onFinished();
2524 break;
2525 case Dumpstate::RunStatus::HELP:
2526 break;
2527 case Dumpstate::RunStatus::INVALID_INPUT:
2528 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
2529 break;
2530 case Dumpstate::RunStatus::ERROR:
2531 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2532 break;
2533 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2534 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2535 break;
2536 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2537 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
2538 break;
2539 }
2540 }
2541 return status;
2542 }
2543
2544 /*
2545 * Dumps relevant information to a bugreport based on the given options.
2546 *
2547 * The bugreport can be dumped to a file or streamed to a socket.
2548 *
2549 * How dumping to file works:
2550 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2551 * stderr is redirected a log file.
2552 *
2553 * The temporary bugreport is then populated via printfs, dumping contents of files and
2554 * output of commands to stdout.
2555 *
2556 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2557 * text file.
2558 *
2559 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2560 * gets added to the archive.
2561 *
2562 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2563 * supplied.
2564 */
RunInternal(int32_t calling_uid,const std::string & calling_package)2565 Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2566 const std::string& calling_package) {
2567 LogDumpOptions(*options_);
2568 if (!options_->ValidateOptions()) {
2569 MYLOGE("Invalid options specified\n");
2570 return RunStatus::INVALID_INPUT;
2571 }
2572 /* set as high priority, and protect from OOM killer */
2573 setpriority(PRIO_PROCESS, 0, -20);
2574
2575 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
2576 if (oom_adj) {
2577 fputs("-1000", oom_adj);
2578 fclose(oom_adj);
2579 } else {
2580 /* fallback to kernels <= 2.6.35 */
2581 oom_adj = fopen("/proc/self/oom_adj", "we");
2582 if (oom_adj) {
2583 fputs("-17", oom_adj);
2584 fclose(oom_adj);
2585 }
2586 }
2587
2588 if (version_ == VERSION_DEFAULT) {
2589 version_ = VERSION_CURRENT;
2590 }
2591
2592 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
2593 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
2594 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
2595 VERSION_SPLIT_ANR.c_str());
2596 return RunStatus::INVALID_INPUT;
2597 }
2598
2599 if (options_->show_header_only) {
2600 PrintHeader();
2601 return RunStatus::OK;
2602 }
2603
2604 if (options_->bugreport_fd.get() != -1) {
2605 // If the output needs to be copied over to the caller's fd, get user consent.
2606 android::String16 package(calling_package.c_str());
2607 CheckUserConsent(calling_uid, package);
2608 }
2609
2610 // Redirect output if needed
2611 bool is_redirecting = options_->OutputToFile();
2612
2613 // TODO: temporarily set progress until it's part of the Dumpstate constructor
2614 std::string stats_path =
2615 is_redirecting
2616 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2617 : "";
2618 progress_.reset(new Progress(stats_path));
2619
2620 /* gets the sequential id */
2621 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
2622 id_ = ++last_id;
2623 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2624
2625 MYLOGI("begin\n");
2626
2627 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2628 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2629 } else {
2630 // Wake lock will be released automatically on process death
2631 MYLOGD("Wake lock acquired.\n");
2632 }
2633
2634 register_sig_handler();
2635
2636 // TODO(b/111441001): maybe skip if already started?
2637 if (options_->do_start_service) {
2638 MYLOGI("Starting 'dumpstate' service\n");
2639 android::status_t ret;
2640 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2641 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2642 }
2643 }
2644
2645 if (PropertiesHelper::IsDryRun()) {
2646 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2647 }
2648
2649 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2650 options_->extra_options.c_str());
2651
2652 MYLOGI("bugreport format version: %s\n", version_.c_str());
2653
2654 do_early_screenshot_ = options_->do_progress_updates;
2655
2656 // If we are going to use a socket, do it as early as possible
2657 // to avoid timeouts from bugreport.
2658 if (options_->use_socket) {
2659 if (!redirect_to_socket(stdout, "dumpstate")) {
2660 return ERROR;
2661 }
2662 }
2663
2664 if (options_->use_control_socket) {
2665 MYLOGD("Opening control socket\n");
2666 control_socket_fd_ = open_socket("dumpstate");
2667 if (control_socket_fd_ == -1) {
2668 return ERROR;
2669 }
2670 options_->do_progress_updates = 1;
2671 }
2672
2673 if (is_redirecting) {
2674 PrepareToWriteToFile();
2675
2676 if (options_->do_progress_updates) {
2677 if (options_->do_broadcast) {
2678 // clang-format off
2679 std::vector<std::string> am_args = {
2680 "--receiver-permission", "android.permission.DUMP",
2681 "--es", "android.intent.extra.NAME", name_,
2682 "--ei", "android.intent.extra.ID", std::to_string(id_),
2683 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2684 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
2685 };
2686 // clang-format on
2687 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
2688 }
2689 if (options_->use_control_socket) {
2690 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
2691 }
2692 }
2693 }
2694
2695 /* read /proc/cmdline before dropping root */
2696 FILE *cmdline = fopen("/proc/cmdline", "re");
2697 if (cmdline) {
2698 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2699 fclose(cmdline);
2700 }
2701
2702 if (options_->do_vibrate) {
2703 Vibrate(150);
2704 }
2705
2706 if (options_->do_fb && do_early_screenshot_) {
2707 MYLOGI("taking early screenshot\n");
2708 TakeScreenshot();
2709 }
2710
2711 if (options_->do_zip_file && zip_file != nullptr) {
2712 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2713 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
2714 strerror(errno));
2715 }
2716 }
2717
2718 int dup_stdout_fd;
2719 int dup_stderr_fd;
2720 if (is_redirecting) {
2721 // Redirect stderr to log_path_ for debugging.
2722 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
2723 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2724 return ERROR;
2725 }
2726 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2727 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2728 strerror(errno));
2729 }
2730
2731 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2732 // moved into zip file later, if zipping.
2733 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
2734 // TODO: why not write to a file instead of stdout to overcome this problem?
2735 /* TODO: rather than generating a text file now and zipping it later,
2736 it would be more efficient to redirect stdout to the zip entry
2737 directly, but the libziparchive doesn't support that option yet. */
2738 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2739 return ERROR;
2740 }
2741 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
2742 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
2743 tmp_path_.c_str(), strerror(errno));
2744 }
2745 }
2746
2747 // Don't buffer stdout
2748 setvbuf(stdout, nullptr, _IONBF, 0);
2749
2750 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2751 // In particular, DurationReport objects should be created passing 'title, NULL', so their
2752 // duration is logged into MYLOG instead.
2753 PrintHeader();
2754
2755 if (options_->telephony_only) {
2756 DumpstateTelephonyOnly();
2757 DumpstateBoard();
2758 } else if (options_->wifi_only) {
2759 DumpstateWifiOnly();
2760 } else {
2761 // Dump state for the default case. This also drops root.
2762 RunStatus s = DumpstateDefault();
2763 if (s != RunStatus::OK) {
2764 if (s == RunStatus::USER_CONSENT_DENIED) {
2765 HandleUserConsentDenied();
2766 }
2767 return s;
2768 }
2769 }
2770
2771 /* close output if needed */
2772 if (is_redirecting) {
2773 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
2774 }
2775
2776 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
2777 if (options_->OutputToFile()) {
2778 FinalizeFile();
2779 }
2780
2781 // Share the final file with the caller if the user has consented.
2782 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2783 if (options_->bugreport_fd.get() != -1) {
2784 status = CopyBugreportIfUserConsented();
2785 if (status != Dumpstate::RunStatus::OK &&
2786 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2787 // Do an early return if there were errors. We make an exception for consent
2788 // timing out because it's possible the user got distracted. In this case the
2789 // bugreport is not shared but made available for manual retrieval.
2790 MYLOGI("User denied consent. Returning\n");
2791 return status;
2792 }
2793 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
2794 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2795 options_->screenshot_fd.get());
2796 if (copy_succeeded) {
2797 android::os::UnlinkAndLogOnError(screenshot_path_);
2798 }
2799 }
2800 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2801 MYLOGI(
2802 "Did not receive user consent yet."
2803 " Will not copy the bugreport artifacts to caller.\n");
2804 const String16 incidentcompanion("incidentcompanion");
2805 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2806 if (ics != nullptr) {
2807 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2808 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2809 consent_callback_.get());
2810 } else {
2811 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2812 }
2813 }
2814 }
2815
2816 /* vibrate a few but shortly times to let user know it's finished */
2817 if (options_->do_vibrate) {
2818 for (int i = 0; i < 3; i++) {
2819 Vibrate(75);
2820 usleep((75 + 50) * 1000);
2821 }
2822 }
2823
2824 /* tell activity manager we're done */
2825 if (options_->do_broadcast) {
2826 SendBugreportFinishedBroadcast();
2827 // Note that listener_ is notified in Run();
2828 }
2829
2830 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2831 progress_->GetInitialMax());
2832 progress_->Save();
2833 MYLOGI("done (id %d)\n", id_);
2834
2835 if (is_redirecting) {
2836 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
2837 }
2838
2839 if (options_->use_control_socket && control_socket_fd_ != -1) {
2840 MYLOGD("Closing control socket\n");
2841 close(control_socket_fd_);
2842 }
2843
2844 tombstone_data_.clear();
2845 anr_data_.clear();
2846
2847 return (consent_callback_ != nullptr &&
2848 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2849 ? USER_CONSENT_TIMED_OUT
2850 : RunStatus::OK;
2851 }
2852
CheckUserConsent(int32_t calling_uid,const android::String16 & calling_package)2853 void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2854 consent_callback_ = new ConsentCallback();
2855 const String16 incidentcompanion("incidentcompanion");
2856 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2857 if (ics != nullptr) {
2858 MYLOGD("Checking user consent via incidentcompanion service\n");
2859 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
2860 calling_uid, calling_package, String16(), String16(),
2861 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
2862 } else {
2863 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2864 }
2865 }
2866
IsUserConsentDenied() const2867 bool Dumpstate::IsUserConsentDenied() const {
2868 return ds.consent_callback_ != nullptr &&
2869 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2870 }
2871
CleanupFiles()2872 void Dumpstate::CleanupFiles() {
2873 android::os::UnlinkAndLogOnError(tmp_path_);
2874 android::os::UnlinkAndLogOnError(screenshot_path_);
2875 android::os::UnlinkAndLogOnError(path_);
2876 }
2877
HandleUserConsentDenied()2878 Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2879 MYLOGD("User denied consent; deleting files and returning\n");
2880 CleanupFiles();
2881 return USER_CONSENT_DENIED;
2882 }
2883
CopyBugreportIfUserConsented()2884 Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2885 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2886 // user consent.
2887 UserConsentResult consent_result = consent_callback_->getResult();
2888 if (consent_result == UserConsentResult::UNAVAILABLE) {
2889 // User has not responded yet.
2890 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2891 // Telephony is a fast report type, particularly on user builds where information may be
2892 // more aggressively limited. To give the user time to read the consent dialog, increase the
2893 // timeout.
2894 uint64_t timeout_ms = options_->telephony_only ? TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS
2895 : USER_CONSENT_TIMEOUT_MS;
2896 if (elapsed_ms < timeout_ms) {
2897 uint delay_seconds = (timeout_ms - elapsed_ms) / 1000;
2898 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2899 sleep(delay_seconds);
2900 }
2901 consent_result = consent_callback_->getResult();
2902 }
2903 if (consent_result == UserConsentResult::DENIED) {
2904 // User has explicitly denied sharing with the app. To be safe delete the
2905 // internal bugreport & tmp files.
2906 return HandleUserConsentDenied();
2907 }
2908 if (consent_result == UserConsentResult::APPROVED) {
2909 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2910 if (copy_succeeded) {
2911 android::os::UnlinkAndLogOnError(path_);
2912 }
2913 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2914 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2915 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2916 // Since we do not have user consent to share the bugreport it does not get
2917 // copied over to the calling app but remains in the internal directory from
2918 // where the user can manually pull it.
2919 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2920 }
2921 // Unknown result; must be a programming error.
2922 MYLOGE("Unknown user consent result:%d\n", consent_result);
2923 return Dumpstate::RunStatus::ERROR;
2924 }
2925
ParseCommandlineAndRun(int argc,char * argv[])2926 Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
2927 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2928 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2929 if (status == Dumpstate::RunStatus::OK) {
2930 SetOptions(std::move(options));
2931 // When directly running dumpstate binary, the output is not expected to be written
2932 // to any external file descriptor.
2933 assert(options_->bugreport_fd.get() == -1);
2934
2935 // calling_uid and calling_package are for user consent to share the bugreport with
2936 // an app; they are irrelvant here because bugreport is only written to a local
2937 // directory, and not shared.
2938 status = Run(-1 /* calling_uid */, "" /* calling_package */);
2939 }
2940 return status;
2941 }
2942
2943 /* Main entry point for dumpstate binary. */
run_main(int argc,char * argv[])2944 int run_main(int argc, char* argv[]) {
2945 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
2946
2947 switch (status) {
2948 case Dumpstate::RunStatus::OK:
2949 exit(0);
2950 case Dumpstate::RunStatus::HELP:
2951 ShowUsage();
2952 exit(0);
2953 case Dumpstate::RunStatus::INVALID_INPUT:
2954 fprintf(stderr, "Invalid combination of args\n");
2955 ShowUsage();
2956 exit(1);
2957 case Dumpstate::RunStatus::ERROR:
2958 FALLTHROUGH_INTENDED;
2959 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2960 FALLTHROUGH_INTENDED;
2961 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2962 exit(2);
2963 }
2964 }
2965
2966 // TODO(111441001): Default DumpOptions to sensible values.
Dumpstate(const std::string & version)2967 Dumpstate::Dumpstate(const std::string& version)
2968 : pid_(getpid()),
2969 options_(new Dumpstate::DumpOptions()),
2970 last_reported_percent_progress_(0),
2971 version_(version),
2972 now_(time(nullptr)) {
2973 }
2974
GetInstance()2975 Dumpstate& Dumpstate::GetInstance() {
2976 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2977 return singleton_;
2978 }
2979
DurationReporter(const std::string & title,bool logcat_only,bool verbose)2980 DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2981 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
2982 if (!title_.empty()) {
2983 started_ = Nanotime();
2984 }
2985 }
2986
~DurationReporter()2987 DurationReporter::~DurationReporter() {
2988 if (!title_.empty()) {
2989 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2990 if (elapsed >= .5f || verbose_) {
2991 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2992 }
2993 if (!logcat_only_) {
2994 // Use "Yoda grammar" to make it easier to grep|sort sections.
2995 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2996 }
2997 }
2998 }
2999
3000 const int32_t Progress::kDefaultMax = 5000;
3001
Progress(const std::string & path)3002 Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
3003 }
3004
Progress(int32_t initial_max,int32_t progress,float growth_factor)3005 Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
3006 : Progress(initial_max, growth_factor, "") {
3007 progress_ = progress;
3008 }
3009
Progress(int32_t initial_max,float growth_factor,const std::string & path)3010 Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
3011 : initial_max_(initial_max),
3012 progress_(0),
3013 max_(initial_max),
3014 growth_factor_(growth_factor),
3015 n_runs_(0),
3016 average_max_(0),
3017 path_(path) {
3018 if (!path_.empty()) {
3019 Load();
3020 }
3021 }
3022
Load()3023 void Progress::Load() {
3024 MYLOGD("Loading stats from %s\n", path_.c_str());
3025 std::string content;
3026 if (!android::base::ReadFileToString(path_, &content)) {
3027 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
3028 return;
3029 }
3030 if (content.empty()) {
3031 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
3032 return;
3033 }
3034 std::vector<std::string> lines = android::base::Split(content, "\n");
3035
3036 if (lines.size() < 1) {
3037 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
3038 (int)lines.size(), max_);
3039 return;
3040 }
3041 char* ptr;
3042 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
3043 average_max_ = strtol(ptr, nullptr, 10);
3044 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
3045 average_max_ > STATS_MAX_AVERAGE) {
3046 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
3047 initial_max_ = Progress::kDefaultMax;
3048 } else {
3049 initial_max_ = average_max_;
3050 }
3051 max_ = initial_max_;
3052
3053 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
3054 }
3055
Save()3056 void Progress::Save() {
3057 int32_t total = n_runs_ * average_max_ + progress_;
3058 int32_t runs = n_runs_ + 1;
3059 int32_t average = floor(((float)total) / runs);
3060 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
3061 path_.c_str());
3062 if (path_.empty()) {
3063 return;
3064 }
3065
3066 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
3067 if (!android::base::WriteStringToFile(content, path_)) {
3068 MYLOGE("Could not save stats on %s\n", path_.c_str());
3069 }
3070 }
3071
Get() const3072 int32_t Progress::Get() const {
3073 return progress_;
3074 }
3075
Inc(int32_t delta_sec)3076 bool Progress::Inc(int32_t delta_sec) {
3077 bool changed = false;
3078 if (delta_sec >= 0) {
3079 progress_ += delta_sec;
3080 if (progress_ > max_) {
3081 int32_t old_max = max_;
3082 max_ = floor((float)progress_ * growth_factor_);
3083 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
3084 changed = true;
3085 }
3086 }
3087 return changed;
3088 }
3089
GetMax() const3090 int32_t Progress::GetMax() const {
3091 return max_;
3092 }
3093
GetInitialMax() const3094 int32_t Progress::GetInitialMax() const {
3095 return initial_max_;
3096 }
3097
Dump(int fd,const std::string & prefix) const3098 void Progress::Dump(int fd, const std::string& prefix) const {
3099 const char* pr = prefix.c_str();
3100 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3101 dprintf(fd, "%smax: %d\n", pr, max_);
3102 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3103 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3104 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3105 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3106 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3107 }
3108
IsZipping() const3109 bool Dumpstate::IsZipping() const {
3110 return zip_writer_ != nullptr;
3111 }
3112
GetPath(const std::string & suffix) const3113 std::string Dumpstate::GetPath(const std::string& suffix) const {
3114 return GetPath(bugreport_internal_dir_, suffix);
3115 }
3116
GetPath(const std::string & directory,const std::string & suffix) const3117 std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3118 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3119 name_.c_str(), suffix.c_str());
3120 }
3121
SetProgress(std::unique_ptr<Progress> progress)3122 void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3123 progress_ = std::move(progress);
3124 }
3125
for_each_userid(void (* func)(int),const char * header)3126 void for_each_userid(void (*func)(int), const char *header) {
3127 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3128 "for_each_userid(%s)", header);
3129 DurationReporter duration_reporter(title);
3130 if (PropertiesHelper::IsDryRun()) return;
3131
3132 DIR *d;
3133 struct dirent *de;
3134
3135 if (header) printf("\n------ %s ------\n", header);
3136 func(0);
3137
3138 if (!(d = opendir("/data/system/users"))) {
3139 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3140 return;
3141 }
3142
3143 while ((de = readdir(d))) {
3144 int userid;
3145 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3146 continue;
3147 }
3148 func(userid);
3149 }
3150
3151 closedir(d);
3152 }
3153
__for_each_pid(void (* helper)(int,const char *,void *),const char * header,void * arg)3154 static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3155 DIR *d;
3156 struct dirent *de;
3157
3158 if (!(d = opendir("/proc"))) {
3159 printf("Failed to open /proc (%s)\n", strerror(errno));
3160 return;
3161 }
3162
3163 if (header) printf("\n------ %s ------\n", header);
3164 while ((de = readdir(d))) {
3165 if (ds.IsUserConsentDenied()) {
3166 MYLOGE(
3167 "Returning early because user denied consent to share bugreport with calling app.");
3168 closedir(d);
3169 return;
3170 }
3171 int pid;
3172 int fd;
3173 char cmdpath[255];
3174 char cmdline[255];
3175
3176 if (!(pid = atoi(de->d_name))) {
3177 continue;
3178 }
3179
3180 memset(cmdline, 0, sizeof(cmdline));
3181
3182 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3183 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3184 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3185 close(fd);
3186 if (cmdline[0]) {
3187 helper(pid, cmdline, arg);
3188 continue;
3189 }
3190 }
3191
3192 // if no cmdline, a kernel thread has comm
3193 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3194 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3195 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3196 close(fd);
3197 if (cmdline[1]) {
3198 cmdline[0] = '[';
3199 size_t len = strcspn(cmdline, "\f\b\r\n");
3200 cmdline[len] = ']';
3201 cmdline[len+1] = '\0';
3202 }
3203 }
3204 if (!cmdline[0]) {
3205 strcpy(cmdline, "N/A");
3206 }
3207 helper(pid, cmdline, arg);
3208 }
3209
3210 closedir(d);
3211 }
3212
for_each_pid_helper(int pid,const char * cmdline,void * arg)3213 static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3214 for_each_pid_func *func = (for_each_pid_func*) arg;
3215 func(pid, cmdline);
3216 }
3217
for_each_pid(for_each_pid_func func,const char * header)3218 void for_each_pid(for_each_pid_func func, const char *header) {
3219 std::string title = header == nullptr ? "for_each_pid"
3220 : android::base::StringPrintf("for_each_pid(%s)", header);
3221 DurationReporter duration_reporter(title);
3222 if (PropertiesHelper::IsDryRun()) return;
3223
3224 __for_each_pid(for_each_pid_helper, header, (void *) func);
3225 }
3226
for_each_tid_helper(int pid,const char * cmdline,void * arg)3227 static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3228 DIR *d;
3229 struct dirent *de;
3230 char taskpath[255];
3231 for_each_tid_func *func = (for_each_tid_func *) arg;
3232
3233 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3234
3235 if (!(d = opendir(taskpath))) {
3236 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3237 return;
3238 }
3239
3240 func(pid, pid, cmdline);
3241
3242 while ((de = readdir(d))) {
3243 if (ds.IsUserConsentDenied()) {
3244 MYLOGE(
3245 "Returning early because user denied consent to share bugreport with calling app.");
3246 closedir(d);
3247 return;
3248 }
3249 int tid;
3250 int fd;
3251 char commpath[255];
3252 char comm[255];
3253
3254 if (!(tid = atoi(de->d_name))) {
3255 continue;
3256 }
3257
3258 if (tid == pid)
3259 continue;
3260
3261 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3262 memset(comm, 0, sizeof(comm));
3263 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3264 strcpy(comm, "N/A");
3265 } else {
3266 char *c;
3267 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3268 close(fd);
3269
3270 c = strrchr(comm, '\n');
3271 if (c) {
3272 *c = '\0';
3273 }
3274 }
3275 func(pid, tid, comm);
3276 }
3277
3278 closedir(d);
3279 }
3280
for_each_tid(for_each_tid_func func,const char * header)3281 void for_each_tid(for_each_tid_func func, const char *header) {
3282 std::string title = header == nullptr ? "for_each_tid"
3283 : android::base::StringPrintf("for_each_tid(%s)", header);
3284 DurationReporter duration_reporter(title);
3285
3286 if (PropertiesHelper::IsDryRun()) return;
3287
3288 __for_each_pid(for_each_tid_helper, header, (void *) func);
3289 }
3290
show_wchan(int pid,int tid,const char * name)3291 void show_wchan(int pid, int tid, const char *name) {
3292 if (PropertiesHelper::IsDryRun()) return;
3293
3294 char path[255];
3295 char buffer[255];
3296 int fd, ret, save_errno;
3297 char name_buffer[255];
3298
3299 memset(buffer, 0, sizeof(buffer));
3300
3301 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3302 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3303 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3304 return;
3305 }
3306
3307 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3308 save_errno = errno;
3309 close(fd);
3310
3311 if (ret < 0) {
3312 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3313 return;
3314 }
3315
3316 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3317 pid == tid ? 0 : 3, "", name);
3318
3319 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3320
3321 return;
3322 }
3323
3324 // print time in centiseconds
snprcent(char * buffer,size_t len,size_t spc,unsigned long long time)3325 static void snprcent(char *buffer, size_t len, size_t spc,
3326 unsigned long long time) {
3327 static long hz; // cache discovered hz
3328
3329 if (hz <= 0) {
3330 hz = sysconf(_SC_CLK_TCK);
3331 if (hz <= 0) {
3332 hz = 1000;
3333 }
3334 }
3335
3336 // convert to centiseconds
3337 time = (time * 100 + (hz / 2)) / hz;
3338
3339 char str[16];
3340
3341 snprintf(str, sizeof(str), " %llu.%02u",
3342 time / 100, (unsigned)(time % 100));
3343 size_t offset = strlen(buffer);
3344 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3345 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3346 }
3347
3348 // print permille as a percent
snprdec(char * buffer,size_t len,size_t spc,unsigned permille)3349 static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3350 char str[16];
3351
3352 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3353 size_t offset = strlen(buffer);
3354 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3355 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3356 }
3357
show_showtime(int pid,const char * name)3358 void show_showtime(int pid, const char *name) {
3359 if (PropertiesHelper::IsDryRun()) return;
3360
3361 char path[255];
3362 char buffer[1023];
3363 int fd, ret, save_errno;
3364
3365 memset(buffer, 0, sizeof(buffer));
3366
3367 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3368 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3369 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3370 return;
3371 }
3372
3373 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3374 save_errno = errno;
3375 close(fd);
3376
3377 if (ret < 0) {
3378 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3379 return;
3380 }
3381
3382 // field 14 is utime
3383 // field 15 is stime
3384 // field 42 is iotime
3385 unsigned long long utime = 0, stime = 0, iotime = 0;
3386 if (sscanf(buffer,
3387 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3388 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3389 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3390 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3391 &utime, &stime, &iotime) != 3) {
3392 return;
3393 }
3394
3395 unsigned long long total = utime + stime;
3396 if (!total) {
3397 return;
3398 }
3399
3400 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3401 if (permille > 1000) {
3402 permille = 1000;
3403 }
3404
3405 // try to beautify and stabilize columns at <80 characters
3406 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3407 if ((name[0] != '[') || utime) {
3408 snprcent(buffer, sizeof(buffer), 57, utime);
3409 }
3410 snprcent(buffer, sizeof(buffer), 65, stime);
3411 if ((name[0] != '[') || iotime) {
3412 snprcent(buffer, sizeof(buffer), 73, iotime);
3413 }
3414 if (iotime) {
3415 snprdec(buffer, sizeof(buffer), 79, permille);
3416 }
3417 puts(buffer); // adds a trailing newline
3418
3419 return;
3420 }
3421
do_dmesg()3422 void do_dmesg() {
3423 const char *title = "KERNEL LOG (dmesg)";
3424 DurationReporter duration_reporter(title);
3425 printf("------ %s ------\n", title);
3426
3427 if (PropertiesHelper::IsDryRun()) return;
3428
3429 /* Get size of kernel buffer */
3430 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3431 if (size <= 0) {
3432 printf("Unexpected klogctl return value: %d\n\n", size);
3433 return;
3434 }
3435 char *buf = (char *) malloc(size + 1);
3436 if (buf == nullptr) {
3437 printf("memory allocation failed\n\n");
3438 return;
3439 }
3440 int retval = klogctl(KLOG_READ_ALL, buf, size);
3441 if (retval < 0) {
3442 printf("klogctl failure\n\n");
3443 free(buf);
3444 return;
3445 }
3446 buf[retval] = '\0';
3447 printf("%s\n\n", buf);
3448 free(buf);
3449 return;
3450 }
3451
do_showmap(int pid,const char * name)3452 void do_showmap(int pid, const char *name) {
3453 char title[255];
3454 char arg[255];
3455
3456 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3457 snprintf(arg, sizeof(arg), "%d", pid);
3458 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3459 }
3460
DumpFile(const std::string & title,const std::string & path)3461 int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3462 DurationReporter duration_reporter(title);
3463
3464 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3465
3466 UpdateProgress(WEIGHT_FILE);
3467
3468 return status;
3469 }
3470
read_file_as_long(const char * path,long int * output)3471 int read_file_as_long(const char *path, long int *output) {
3472 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3473 if (fd < 0) {
3474 int err = errno;
3475 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3476 return -1;
3477 }
3478 char buffer[50];
3479 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3480 if (bytes_read == -1) {
3481 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3482 return -2;
3483 }
3484 if (bytes_read == 0) {
3485 MYLOGE("File %s is empty\n", path);
3486 return -3;
3487 }
3488 *output = atoi(buffer);
3489 return 0;
3490 }
3491
3492 /* calls skip to gate calling dump_from_fd recursively
3493 * in the specified directory. dump_from_fd defaults to
3494 * dump_file_from_fd above when set to NULL. skip defaults
3495 * to false when set to NULL. dump_from_fd will always be
3496 * called with title NULL.
3497 */
dump_files(const std::string & title,const char * dir,bool (* skip)(const char * path),int (* dump_from_fd)(const char * title,const char * path,int fd))3498 int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3499 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3500 DurationReporter duration_reporter(title);
3501 DIR *dirp;
3502 struct dirent *d;
3503 char *newpath = nullptr;
3504 const char *slash = "/";
3505 int retval = 0;
3506
3507 if (!title.empty()) {
3508 printf("------ %s (%s) ------\n", title.c_str(), dir);
3509 }
3510 if (PropertiesHelper::IsDryRun()) return 0;
3511
3512 if (dir[strlen(dir) - 1] == '/') {
3513 ++slash;
3514 }
3515 dirp = opendir(dir);
3516 if (dirp == nullptr) {
3517 retval = -errno;
3518 MYLOGE("%s: %s\n", dir, strerror(errno));
3519 return retval;
3520 }
3521
3522 if (!dump_from_fd) {
3523 dump_from_fd = dump_file_from_fd;
3524 }
3525 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3526 if ((d->d_name[0] == '.')
3527 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3528 || (d->d_name[1] == '\0'))) {
3529 continue;
3530 }
3531 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3532 (d->d_type == DT_DIR) ? "/" : "");
3533 if (!newpath) {
3534 retval = -errno;
3535 continue;
3536 }
3537 if (skip && (*skip)(newpath)) {
3538 continue;
3539 }
3540 if (d->d_type == DT_DIR) {
3541 int ret = dump_files("", newpath, skip, dump_from_fd);
3542 if (ret < 0) {
3543 retval = ret;
3544 }
3545 continue;
3546 }
3547 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3548 if (fd.get() < 0) {
3549 retval = -1;
3550 printf("*** %s: %s\n", newpath, strerror(errno));
3551 continue;
3552 }
3553 (*dump_from_fd)(nullptr, newpath, fd.get());
3554 }
3555 closedir(dirp);
3556 if (!title.empty()) {
3557 printf("\n");
3558 }
3559 return retval;
3560 }
3561
3562 /* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3563 * it's possible to avoid issues where opening the file itself can get
3564 * stuck.
3565 */
dump_file_from_fd(const char * title,const char * path,int fd)3566 int dump_file_from_fd(const char *title, const char *path, int fd) {
3567 if (PropertiesHelper::IsDryRun()) return 0;
3568
3569 int flags = fcntl(fd, F_GETFL);
3570 if (flags == -1) {
3571 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3572 return -1;
3573 } else if (!(flags & O_NONBLOCK)) {
3574 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3575 return -1;
3576 }
3577 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3578 }
3579
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options,bool verbose_duration)3580 int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3581 const CommandOptions& options, bool verbose_duration) {
3582 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
3583
3584 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3585
3586 /* TODO: for now we're simplifying the progress calculation by using the
3587 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3588 * where its weight should be much higher proportionally to its timeout.
3589 * Ideally, it should use a options.EstimatedDuration() instead...*/
3590 UpdateProgress(options.Timeout());
3591
3592 return status;
3593 }
3594
RunDumpsys(const std::string & title,const std::vector<std::string> & dumpsys_args,const CommandOptions & options,long dumpsysTimeoutMs)3595 void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3596 const CommandOptions& options, long dumpsysTimeoutMs) {
3597 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3598 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3599 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3600 RunCommand(title, dumpsys, options);
3601 }
3602
open_socket(const char * service)3603 int open_socket(const char *service) {
3604 int s = android_get_control_socket(service);
3605 if (s < 0) {
3606 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3607 return -1;
3608 }
3609 fcntl(s, F_SETFD, FD_CLOEXEC);
3610
3611 // Set backlog to 0 to make sure that queue size will be minimum.
3612 // In Linux, because the minimum queue will be 1, connect() will be blocked
3613 // if the other clients already called connect() and the connection request was not accepted.
3614 if (listen(s, 0) < 0) {
3615 MYLOGE("listen(control socket): %s\n", strerror(errno));
3616 return -1;
3617 }
3618
3619 struct sockaddr addr;
3620 socklen_t alen = sizeof(addr);
3621 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
3622
3623 // Close socket just after accept(), to make sure that connect() by client will get error
3624 // when the socket is used by the other services.
3625 // There is still a race condition possibility between accept and close, but there is no way
3626 // to close-on-accept atomically.
3627 // See detail; b/123306389#comment25
3628 close(s);
3629
3630 if (fd < 0) {
3631 MYLOGE("accept(control socket): %s\n", strerror(errno));
3632 return -1;
3633 }
3634
3635 return fd;
3636 }
3637
3638 /* redirect output to a service control socket */
redirect_to_socket(FILE * redirect,const char * service)3639 bool redirect_to_socket(FILE* redirect, const char* service) {
3640 int fd = open_socket(service);
3641 if (fd == -1) {
3642 return false;
3643 }
3644 fflush(redirect);
3645 // TODO: handle dup2 failure
3646 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3647 close(fd);
3648 return true;
3649 }
3650
3651 // TODO: should call is_valid_output_file and/or be merged into it.
create_parent_dirs(const char * path)3652 void create_parent_dirs(const char *path) {
3653 char *chp = const_cast<char *> (path);
3654
3655 /* skip initial slash */
3656 if (chp[0] == '/')
3657 chp++;
3658
3659 /* create leading directories, if necessary */
3660 struct stat dir_stat;
3661 while (chp && chp[0]) {
3662 chp = strchr(chp, '/');
3663 if (chp) {
3664 *chp = 0;
3665 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3666 MYLOGI("Creating directory %s\n", path);
3667 if (mkdir(path, 0770)) { /* drwxrwx--- */
3668 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3669 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3670 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3671 }
3672 }
3673 *chp++ = '/';
3674 }
3675 }
3676 }
3677
_redirect_to_file(FILE * redirect,char * path,int truncate_flag)3678 bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3679 create_parent_dirs(path);
3680
3681 int fd = TEMP_FAILURE_RETRY(open(path,
3682 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3683 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3684 if (fd < 0) {
3685 MYLOGE("%s: %s\n", path, strerror(errno));
3686 return false;
3687 }
3688
3689 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3690 close(fd);
3691 return true;
3692 }
3693
redirect_to_file(FILE * redirect,char * path)3694 bool redirect_to_file(FILE* redirect, char* path) {
3695 return _redirect_to_file(redirect, path, O_TRUNC);
3696 }
3697
redirect_to_existing_file(FILE * redirect,char * path)3698 bool redirect_to_existing_file(FILE* redirect, char* path) {
3699 return _redirect_to_file(redirect, path, O_APPEND);
3700 }
3701
dump_route_tables()3702 void dump_route_tables() {
3703 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3704 if (PropertiesHelper::IsDryRun()) return;
3705 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3706 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3707 FILE* fp = fopen(RT_TABLES_PATH, "re");
3708 if (!fp) {
3709 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3710 return;
3711 }
3712 char table[16];
3713 // Each line has an integer (the table number), a space, and a string (the table name). We only
3714 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3715 // Add a fixed max limit so this doesn't go awry.
3716 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3717 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3718 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3719 }
3720 fclose(fp);
3721 }
3722
3723 // TODO: make this function thread safe if sections are generated in parallel.
UpdateProgress(int32_t delta_sec)3724 void Dumpstate::UpdateProgress(int32_t delta_sec) {
3725 if (progress_ == nullptr) {
3726 MYLOGE("UpdateProgress: progress_ not set\n");
3727 return;
3728 }
3729
3730 // Always update progess so stats can be tuned...
3731 progress_->Inc(delta_sec);
3732
3733 // ...but only notifiy listeners when necessary.
3734 if (!options_->do_progress_updates) return;
3735
3736 int progress = progress_->Get();
3737 int max = progress_->GetMax();
3738 int percent = 100 * progress / max;
3739
3740 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
3741 return;
3742 }
3743 last_reported_percent_progress_ = percent;
3744
3745 if (control_socket_fd_ >= 0) {
3746 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3747 fsync(control_socket_fd_);
3748 }
3749
3750 if (listener_ != nullptr) {
3751 if (percent % 5 == 0) {
3752 // We don't want to spam logcat, so only log multiples of 5.
3753 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3754 percent);
3755 } else {
3756 // stderr is ignored on normal invocations, but useful when calling
3757 // /system/bin/dumpstate directly for debuggging.
3758 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3759 progress, max, percent);
3760 }
3761
3762 listener_->onProgress(percent);
3763 }
3764 }
3765
TakeScreenshot(const std::string & path)3766 void Dumpstate::TakeScreenshot(const std::string& path) {
3767 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3768 int status =
3769 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3770 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3771 if (status == 0) {
3772 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3773 } else {
3774 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3775 }
3776 }
3777
is_dir(const char * pathname)3778 bool is_dir(const char* pathname) {
3779 struct stat info;
3780 if (stat(pathname, &info) == -1) {
3781 return false;
3782 }
3783 return S_ISDIR(info.st_mode);
3784 }
3785
get_mtime(int fd,time_t default_mtime)3786 time_t get_mtime(int fd, time_t default_mtime) {
3787 struct stat info;
3788 if (fstat(fd, &info) == -1) {
3789 return default_mtime;
3790 }
3791 return info.st_mtime;
3792 }
3793