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