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