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