blob: 25a50ddc4e8603036b07c2db121f43094a0687d6 [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
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 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Kevin Jeon2c02e8e2022-07-07 21:45:17 +000018#define ATRACE_TAG ATRACE_TAG_ALWAYS
Colin Crossf45fa6b2012-03-26 12:38:26 -070019
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070020#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070021#include <errno.h>
22#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010023#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080024#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070025#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010026#include <math.h>
27#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070028#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -070032#include <sys/mount.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080033#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070034#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070035#include <sys/resource.h>
36#include <sys/stat.h>
37#include <sys/time.h>
38#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010039#include <signal.h>
40#include <stdarg.h>
41#include <string.h>
42#include <sys/capability.h>
43#include <sys/inotify.h>
44#include <sys/klog.h>
45#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070046#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070047
48#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070049#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000050#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070051#include <functional>
52#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070054#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010055#include <regex>
56#include <set>
57#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070058#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010059#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070060
Kedar Chitnis9fd8c052021-11-16 09:09:22 +000061#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
Felipe Leme96c2bbb2016-09-26 09:21:21 -070062#include <android-base/file.h>
63#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070064#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080065#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070066#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070067#include <android-base/unique_fd.h>
Kedar Chitnis9fd8c052021-11-16 09:09:22 +000068#include <android/binder_manager.h>
69#include <android/binder_process.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010070#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080071#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Hunter Knepshield8540faf2020-02-04 19:47:20 -080072#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
73#include <android/hardware/dumpstate/1.1/types.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080074#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000075#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010076#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080077#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070078#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010079#include <cutils/sockets.h>
Kevin Jeon2c02e8e2022-07-07 21:45:17 +000080#include <cutils/trace.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000081#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000083#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010084#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080085#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010086#include <log/log.h>
Tom Cherryf4472f32020-08-05 09:31:17 -070087#include <log/log_read.h>
Felipe Leme75876a22016-10-27 16:31:27 -070088#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070089#include <private/android_filesystem_config.h>
90#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080091#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070092#include <utils/StrongPointer.h>
Devin Moore8df81bb2022-06-08 22:47:02 +000093#include <vintf/VintfObject.h>
Felipe Lemef0292972016-11-22 13:57:05 -080094#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070095#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070096#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080097
Kedar Chitnis9fd8c052021-11-16 09:09:22 +000098namespace dumpstate_hal_hidl_1_0 = android::hardware::dumpstate::V1_0;
99namespace dumpstate_hal_hidl = android::hardware::dumpstate::V1_1;
100namespace dumpstate_hal_aidl = aidl::android::hardware::dumpstate;
101
Vishnu Naire97d6122018-01-18 13:58:56 -0800102using ::std::literals::chrono_literals::operator""ms;
103using ::std::literals::chrono_literals::operator""s;
Rhed Jao5377d792020-07-16 17:37:39 +0800104using ::std::placeholders::_1;
Steven Morelandcb7ef822016-11-29 13:20:37 -0800105
Felipe Leme47e9be22016-12-21 15:37:07 -0800106// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -0800107using android::defaultServiceManager;
108using android::Dumpsys;
109using android::INVALID_OPERATION;
110using android::IServiceManager;
111using android::OK;
112using android::sp;
113using android::status_t;
114using android::String16;
115using android::String8;
116using android::TIMED_OUT;
117using android::UNKNOWN_ERROR;
118using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000119using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000120using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800121using android::os::dumpstate::CommandOptions;
122using android::os::dumpstate::DumpFileToFd;
Rhed Jao5377d792020-07-16 17:37:39 +0800123using android::os::dumpstate::DumpPool;
Vishnu Naire97d6122018-01-18 13:58:56 -0800124using android::os::dumpstate::PropertiesHelper;
Rhed Jao3c2fdbd2020-07-20 17:46:29 +0800125using android::os::dumpstate::TaskQueue;
Chris Morinbc223142022-02-04 14:17:11 -0800126using android::os::dumpstate::WaitForTask;
Felipe Leme47e9be22016-12-21 15:37:07 -0800127
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100128// Keep in sync with
129// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
130static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
131
132/* Most simple commands have 10 as timeout, so 5 is a good estimate */
133static const int32_t WEIGHT_FILE = 5;
134
135// TODO: temporary variables and functions used during C++ refactoring
136static Dumpstate& ds = Dumpstate::GetInstance();
137static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100138 const CommandOptions& options = CommandOptions::DEFAULT,
Rhed Jao3c2fdbd2020-07-20 17:46:29 +0800139 bool verbose_duration = false, int out_fd = STDOUT_FILENO) {
140 return ds.RunCommand(title, full_command, options, verbose_duration, out_fd);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100141}
142
143// Reasonable value for max stats.
144static const int STATS_MAX_N_RUNS = 1000;
145static const long STATS_MAX_AVERAGE = 100000;
146
147CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
148
Nandana Duttd2f5f082019-01-18 17:13:52 +0000149typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
150
Colin Crossf45fa6b2012-03-26 12:38:26 -0700151/* read before root is shed */
152static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700153static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000154static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Hunter Knepshield70610fa2020-01-03 15:27:33 -0800155// Because telephony reports are significantly faster to collect (< 10 seconds vs. > 2 minutes),
156// it's often the case that they time out far too quickly for consent with such a hefty dialog for
157// the user to read. For telephony reports only, we increase the default timeout to 2 minutes to
158// roughly match full reports' durations.
159static const uint64_t TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS = 2 * 60 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700160
Felipe Leme1d486fe2016-10-14 18:06:47 -0700161// TODO: variables and functions below should be part of dumpstate object
162
Felipe Leme635ca312016-01-05 14:23:02 -0800163static std::set<std::string> mount_points;
164void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800165
Todd Poynor2a83daa2013-11-22 15:44:22 -0800166#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700167#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700168#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800169
Felipe Lemee82a27d2016-01-05 13:35:44 -0800170#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700171#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700172#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700173#define LOGPERSIST_DATA_DIR "/data/misc/logd"
Jerry Changa1df8a92020-01-02 16:03:39 +0800174#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
David Brazdild2991962016-06-03 14:40:44 +0100175#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
176#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800177#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900178#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800179#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Yifan Hong3945e1b2019-10-29 12:59:23 -0700180#define OTA_METADATA_DIR "/metadata/ota"
Yifan Hong0efa7972020-02-03 16:45:02 -0800181#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
Kiyoung Kimc2d22ac2020-02-04 19:43:36 +0900182#define LINKERCONFIG_DIR "/linkerconfig"
Calin Juravlef84d3692020-04-28 15:31:12 -0700183#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
Primiano Tuccifaaaafb2021-01-14 12:26:29 +0000184#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
Li Li2eedd412021-06-30 15:11:53 -0700185#define CGROUPFS_DIR "/sys/fs/cgroup"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700186
Narayan Kamath8f788292017-05-25 13:20:39 +0100187// TODO(narayan): Since this information has to be kept in sync
188// with tombstoned, we should just put it in a common header.
189//
190// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100191static const std::string TOMBSTONE_DIR = "/data/tombstones/";
192static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
193static const std::string ANR_DIR = "/data/anr/";
194static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700195
Felipe Lemee844a9d2016-09-21 15:01:39 -0700196// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000197
Nandana Dutt5c390032019-03-12 10:52:56 +0000198#define RETURN_IF_USER_DENIED_CONSENT() \
199 if (ds.IsUserConsentDenied()) { \
200 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
201 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
202 }
203
204// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
205// if consent is found to be denied.
206#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
207 RETURN_IF_USER_DENIED_CONSENT(); \
208 func_ptr(__VA_ARGS__); \
209 RETURN_IF_USER_DENIED_CONSENT();
210
Rhed Jao5377d792020-07-16 17:37:39 +0800211// Runs func_ptr, and logs a duration report after it's finished.
212#define RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, ...) \
213 { \
214 DurationReporter duration_reporter_in_macro(log_title); \
215 func_ptr(__VA_ARGS__); \
216 }
217
218// Similar with RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK, an additional duration report
219// is output after a slow function is finished.
220#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(log_title, func_ptr, ...) \
221 RETURN_IF_USER_DENIED_CONSENT(); \
222 RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \
223 RETURN_IF_USER_DENIED_CONSENT();
224
Chris Morinbc223142022-02-04 14:17:11 -0800225#define WAIT_TASK_WITH_CONSENT_CHECK(future) \
Rhed Jao3c2fdbd2020-07-20 17:46:29 +0800226 RETURN_IF_USER_DENIED_CONSENT(); \
Chris Morinbc223142022-02-04 14:17:11 -0800227 WaitForTask(future); \
Rhed Jao3c2fdbd2020-07-20 17:46:29 +0800228 RETURN_IF_USER_DENIED_CONSENT();
229
Sahana Raof35ed432019-07-12 10:47:52 +0100230static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
231
Rhed Jao5377d792020-07-16 17:37:39 +0800232// Names of parallel tasks, they are used for the DumpPool to identify the dump
233// task and the log title of the duration report.
234static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
Rhed Jao3c2fdbd2020-07-20 17:46:29 +0800235static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
236static const std::string DUMP_HALS_TASK = "DUMP HALS";
237static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
Rhed Jaoe017f982020-07-21 17:58:41 +0800238static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
Rhed Jao5377d792020-07-16 17:37:39 +0800239
Nandana Dutt979388e2018-11-30 16:48:55 +0000240namespace android {
241namespace os {
242namespace {
243
244static int Open(std::string path, int flags, mode_t mode = 0) {
245 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
246 if (fd == -1) {
247 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
248 }
249 return fd;
250}
251
mhasank2d75c442020-06-11 15:05:25 -0700252static int OpenForWrite(std::string path) {
253 return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
254 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
255}
Nandana Dutt979388e2018-11-30 16:48:55 +0000256
257static int OpenForRead(std::string path) {
258 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
259}
260
261bool CopyFile(int in_fd, int out_fd) {
262 char buf[4096];
263 ssize_t byte_count;
264 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
265 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
266 return false;
267 }
268 }
269 return (byte_count != -1);
270}
271
272static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000273 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000274
275 // Obtain a handle to the source file.
276 android::base::unique_fd in_fd(OpenForRead(input_file));
277 if (out_fd != -1 && in_fd.get() != -1) {
278 if (CopyFile(in_fd.get(), out_fd)) {
279 return true;
280 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000281 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000282 }
283 return false;
284}
285
Nandana Duttd2f5f082019-01-18 17:13:52 +0000286static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt8ae16e62020-03-27 10:20:22 +0000287 if (file.empty()) {
288 return false;
289 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000290 if (unlink(file.c_str())) {
291 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000292 return false;
293 }
294 return true;
295}
Nandana Dutt979388e2018-11-30 16:48:55 +0000296
Nikita Ioffea325a572019-05-16 19:49:47 +0100297int64_t GetModuleMetadataVersion() {
298 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
299 if (binder == nullptr) {
300 MYLOGE("Failed to retrieve package_native service");
301 return 0L;
302 }
303 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
304 std::string package_name;
305 auto status = package_service->getModuleMetadataPackageName(&package_name);
306 if (!status.isOk()) {
307 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
308 return 0L;
309 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100310 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100311 int64_t version_code;
312 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
313 &version_code);
314 if (!status.isOk()) {
315 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
316 return 0L;
317 }
318 return version_code;
319}
320
mhasank2d75c442020-06-11 15:05:25 -0700321static bool PathExists(const std::string& path) {
322 struct stat sb;
323 return stat(path.c_str(), &sb) == 0;
324}
325
326static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
327 if (input_file == output_file) {
328 MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
329 output_file.c_str());
330 return false;
331 }
332 else if (PathExists(output_file)) {
333 MYLOGD("Cannot overwrite an existing file (%s)\n", output_file.c_str());
334 return false;
335 }
336
337 MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
338 android::base::unique_fd out_fd(OpenForWrite(output_file));
339 return CopyFileToFd(input_file, out_fd.get());
340}
341
Nandana Dutt979388e2018-11-30 16:48:55 +0000342} // namespace
343} // namespace os
344} // namespace android
345
Felipe Leme678727a2016-09-21 17:22:11 -0700346static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800347 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Rhed Jaoe017f982020-07-21 17:58:41 +0800348 long dumpsysTimeoutMs = 0, int out_fd = STDOUT_FILENO) {
349 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs, out_fd);
350}
351static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
352 int out_fd) {
353 return ds.RunDumpsys(title, dumpsysArgs, Dumpstate::DEFAULT_DUMPSYS, 0, out_fd);
Felipe Leme678727a2016-09-21 17:22:11 -0700354}
355static int DumpFile(const std::string& title, const std::string& path) {
356 return ds.DumpFile(title, path);
357}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800358
Felipe Lemee844a9d2016-09-21 15:01:39 -0700359// Relative directory (inside the zip) for all files copied as-is into the bugreport.
360static const std::string ZIP_ROOT_DIR = "FS";
361
Vishnu Naire97d6122018-01-18 13:58:56 -0800362static const std::string kProtoPath = "proto/";
363static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700364static const std::string kDumpstateBoardFiles[] = {
365 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700366 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700367};
368static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
369
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700370static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700371static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700372
Felipe Lemef0292972016-11-22 13:57:05 -0800373static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
374
Narayan Kamath8f788292017-05-25 13:20:39 +0100375/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100376 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
Rhed Jao01dc0c62020-06-03 17:13:30 +0800377 * The returned vector is sorted by the mtimes of the dumps with descending
Chris Morinc2cba7a2022-02-01 17:06:50 -0800378 * order.
Narayan Kamath8f788292017-05-25 13:20:39 +0100379 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700380static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
Chris Morinc2cba7a2022-02-01 17:06:50 -0800381 const std::string& file_prefix) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100382 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100383
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700384 if (dump_dir == nullptr) {
385 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700386 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700387 }
388
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700389 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100390 struct dirent* entry = nullptr;
391 while ((entry = readdir(dump_dir.get()))) {
392 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100393 continue;
394 }
395
Narayan Kamathbd863722017-06-01 18:50:12 +0100396 const std::string base_name(entry->d_name);
397 if (base_name.find(file_prefix) != 0) {
398 continue;
399 }
400
401 const std::string abs_path = dir_path + base_name;
402 android::base::unique_fd fd(
403 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
404 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700405 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100406 break;
407 }
408
409 struct stat st = {};
410 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700411 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100412 continue;
413 }
414
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700415 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700416 }
Rhed Jao01dc0c62020-06-03 17:13:30 +0800417 if (!dump_data.empty()) {
418 std::sort(dump_data.begin(), dump_data.end(),
419 [](const auto& a, const auto& b) { return a.mtime > b.mtime; });
420 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100421
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700422 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100423}
424
Narayan Kamathbd863722017-06-01 18:50:12 +0100425static bool AddDumps(const std::vector<DumpData>::const_iterator start,
426 const std::vector<DumpData>::const_iterator end,
427 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100428 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100429 for (auto it = start; it != end; ++it) {
430 const std::string& name = it->name;
431 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100432 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100433
434 // Seek to the beginning of the file before dumping any data. A given
435 // DumpData entry might be dumped multiple times in the report.
436 //
437 // For example, the most recent ANR entry is dumped to the body of the
438 // main entry and it also shows up as a separate entry in the bugreport
439 // ZIP file.
440 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
441 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
442 strerror(errno));
443 }
444
Chris Morinc2cba7a2022-02-01 17:06:50 -0800445 if (add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800446 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100447 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100448 }
449 } else {
450 dump_file_from_fd(type_name, name.c_str(), fd);
451 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100452 }
453
454 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700455}
456
Felipe Leme635ca312016-01-05 14:23:02 -0800457// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700458void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800459 char path[PATH_MAX];
460
461 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
462 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700463 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800464 char linkname[PATH_MAX];
465 ssize_t r = readlink(path, linkname, PATH_MAX);
466 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800467 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800468 return;
469 }
470 linkname[r] = '\0';
471
472 if (mount_points.find(linkname) == mount_points.end()) {
473 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700474 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700475 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800476 mount_points.insert(linkname);
477 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800478 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800479 }
480 }
481}
482
483void add_mountinfo() {
Felipe Leme678727a2016-09-21 17:22:11 -0700484 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800485 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800486 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700487 for_each_pid(do_mountinfo, nullptr);
488 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800489}
490
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700491static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
492{
493 DIR *d;
494 struct dirent *de;
495 char path[PATH_MAX];
496
497 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700498 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700499 return;
500 }
501
502 while ((de = readdir(d))) {
503 if (de->d_type != DT_LNK) {
504 continue;
505 }
506 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700507 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700508 }
509
510 closedir(d);
511}
512
Mark Salyzyn326842f2015-04-30 09:49:41 -0700513static bool skip_not_stat(const char *path) {
514 static const char stat[] = "/stat";
515 size_t len = strlen(path);
516 if (path[len - 1] == '/') { /* Directory? */
517 return false;
518 }
519 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
520}
521
Felipe Leme4c2d6632016-09-28 14:32:00 -0700522static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800523 return false;
524}
525
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700526unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700527
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800528//
529// stat offsets
530// Name units description
531// ---- ----- -----------
532// read I/Os requests number of read I/Os processed
533#define __STAT_READ_IOS 0
534// read merges requests number of read I/Os merged with in-queue I/O
535#define __STAT_READ_MERGES 1
536// read sectors sectors number of sectors read
537#define __STAT_READ_SECTORS 2
538// read ticks milliseconds total wait time for read requests
539#define __STAT_READ_TICKS 3
540// write I/Os requests number of write I/Os processed
541#define __STAT_WRITE_IOS 4
542// write merges requests number of write I/Os merged with in-queue I/O
543#define __STAT_WRITE_MERGES 5
544// write sectors sectors number of sectors written
545#define __STAT_WRITE_SECTORS 6
546// write ticks milliseconds total wait time for write requests
547#define __STAT_WRITE_TICKS 7
548// in_flight requests number of I/Os currently in flight
549#define __STAT_IN_FLIGHT 8
550// io_ticks milliseconds total time this block device has been active
551#define __STAT_IO_TICKS 9
552// time_in_queue milliseconds total wait time for all requests
553#define __STAT_IN_QUEUE 10
554#define __STAT_NUMBER_FIELD 11
555//
556// read I/Os, write I/Os
557// =====================
558//
559// These values increment when an I/O request completes.
560//
561// read merges, write merges
562// =========================
563//
564// These values increment when an I/O request is merged with an
565// already-queued I/O request.
566//
567// read sectors, write sectors
568// ===========================
569//
570// These values count the number of sectors read from or written to this
571// block device. The "sectors" in question are the standard UNIX 512-byte
572// sectors, not any device- or filesystem-specific block size. The
573// counters are incremented when the I/O completes.
574#define SECTOR_SIZE 512
575//
576// read ticks, write ticks
577// =======================
578//
579// These values count the number of milliseconds that I/O requests have
580// waited on this block device. If there are multiple I/O requests waiting,
581// these values will increase at a rate greater than 1000/second; for
582// example, if 60 read requests wait for an average of 30 ms, the read_ticks
583// field will increase by 60*30 = 1800.
584//
585// in_flight
586// =========
587//
588// This value counts the number of I/O requests that have been issued to
589// the device driver but have not yet completed. It does not include I/O
590// requests that are in the queue but not yet issued to the device driver.
591//
592// io_ticks
593// ========
594//
595// This value counts the number of milliseconds during which the device has
596// had I/O requests queued.
597//
598// time_in_queue
599// =============
600//
601// This value counts the number of milliseconds that I/O requests have waited
602// on this block device. If there are multiple I/O requests waiting, this
603// value will increase as the product of the number of milliseconds times the
604// number of requests waiting (see "read ticks" above for an example).
605#define S_TO_MS 1000
606//
607
Mark Salyzyn326842f2015-04-30 09:49:41 -0700608static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800609 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700610 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700611 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700612 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700613 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700614 getline(&buffer, &i, fp);
615 fclose(fp);
616 if (!buffer) {
617 return -errno;
618 }
619 i = strlen(buffer);
620 while ((i > 0) && (buffer[i - 1] == '\n')) {
621 buffer[--i] = '\0';
622 }
623 if (!*buffer) {
624 free(buffer);
625 return 0;
626 }
627 z = true;
628 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800629 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700630 if (fields[i] != 0) {
631 z = false;
632 }
633 }
634 if (z) { /* never accessed */
635 free(buffer);
636 return 0;
637 }
638
Wei Wang509bb5d2017-06-09 14:42:12 -0700639 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
640 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700641 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700642
643 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
644 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
645 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700646 free(buffer);
647
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800648 if (fields[__STAT_IO_TICKS]) {
649 unsigned long read_perf = 0;
650 unsigned long read_ios = 0;
651 if (fields[__STAT_READ_TICKS]) {
652 unsigned long long divisor = fields[__STAT_READ_TICKS]
653 * fields[__STAT_IO_TICKS];
654 read_perf = ((unsigned long long)SECTOR_SIZE
655 * fields[__STAT_READ_SECTORS]
656 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
657 / divisor;
658 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
659 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
660 / divisor;
661 }
662
663 unsigned long write_perf = 0;
664 unsigned long write_ios = 0;
665 if (fields[__STAT_WRITE_TICKS]) {
666 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
667 * fields[__STAT_IO_TICKS];
668 write_perf = ((unsigned long long)SECTOR_SIZE
669 * fields[__STAT_WRITE_SECTORS]
670 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
671 / divisor;
672 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
673 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
674 / divisor;
675 }
676
677 unsigned queue = (fields[__STAT_IN_QUEUE]
678 + (fields[__STAT_IO_TICKS] >> 1))
679 / fields[__STAT_IO_TICKS];
680
681 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700682 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800683 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700684 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
Felipe Lemed8b94e52016-12-08 10:21:44 -0800685 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800686 }
687
688 /* bugreport timeout factor adjustment */
689 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
690 worst_write_perf = write_perf;
691 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700692 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700693 return 0;
694}
695
Yao Chenbe3bbc12018-01-17 16:31:10 -0800696static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
697
Tom Cherryf4472f32020-08-05 09:31:17 -0700698// Returns the actual readable size of the given buffer or -1 on error.
699static long logcat_buffer_readable_size(const std::string& buffer) {
700 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
701 android_logger_list_alloc(0, 0, 0), &android_logger_list_free};
702 auto logger = android_logger_open(logger_list.get(), android_name_to_log_id(buffer.c_str()));
703
704 return android_logger_get_log_readable_size(logger);
705}
706
707// Returns timeout in ms to read a list of buffers.
Yao Chenbe3bbc12018-01-17 16:31:10 -0800708static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
709 unsigned long timeout_ms = 0;
710 for (const auto& buffer : buffers) {
Tom Cherryf4472f32020-08-05 09:31:17 -0700711 long readable_size = logcat_buffer_readable_size(buffer);
712 if (readable_size > 0) {
713 // Engineering margin is ten-fold our guess.
714 timeout_ms += 10 * (readable_size + worst_write_perf) / worst_write_perf;
715 }
Yao Chenbe3bbc12018-01-17 16:31:10 -0800716 }
717 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700718}
719
Dieter Hsu105ad0c2020-09-29 15:23:33 +0800720// Opens a socket and returns its file descriptor.
721static int open_socket(const char* service);
722
Nandana Duttd2f5f082019-01-18 17:13:52 +0000723Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
724}
725
726android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
727 std::lock_guard<std::mutex> lock(lock_);
728 result_ = APPROVED;
729 MYLOGD("User approved consent to share bugreport\n");
Paul Chang0d2aad72020-02-13 20:04:03 +0800730
731 // Maybe copy screenshot so calling app can display the screenshot to the user as soon as
732 // consent is granted.
733 if (ds.options_->is_screenshot_copied) {
734 return android::binder::Status::ok();
735 }
736
737 if (!ds.options_->do_screenshot || ds.options_->screenshot_fd.get() == -1 ||
738 !ds.do_early_screenshot_) {
739 return android::binder::Status::ok();
740 }
741
742 bool copy_succeeded = android::os::CopyFileToFd(ds.screenshot_path_,
743 ds.options_->screenshot_fd.get());
744 ds.options_->is_screenshot_copied = copy_succeeded;
745 if (copy_succeeded) {
746 android::os::UnlinkAndLogOnError(ds.screenshot_path_);
747 }
Nandana Duttd2f5f082019-01-18 17:13:52 +0000748 return android::binder::Status::ok();
749}
750
751android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
752 std::lock_guard<std::mutex> lock(lock_);
753 result_ = DENIED;
754 MYLOGW("User denied consent to share bugreport\n");
755 return android::binder::Status::ok();
756}
757
758UserConsentResult Dumpstate::ConsentCallback::getResult() {
759 std::lock_guard<std::mutex> lock(lock_);
760 return result_;
761}
762
763uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
Hunter Knepshieldf0a39052020-01-03 14:53:04 -0800764 return (Nanotime() - start_time_) / NANOS_PER_MILLI;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000765}
766
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700767void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700768 std::string build, fingerprint, radio, bootloader, network;
769 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700770
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700771 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
772 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700773 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
774 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
775 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700776 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700777
Felipe Lemed8b94e52016-12-08 10:21:44 -0800778 printf("========================================================\n");
779 printf("== dumpstate: %s\n", date);
780 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700781
Felipe Lemed8b94e52016-12-08 10:21:44 -0800782 printf("\n");
783 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700784 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800785 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
786 printf("Bootloader: %s\n", bootloader.c_str());
787 printf("Radio: %s\n", radio.c_str());
788 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100789 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
790 if (module_metadata_version != 0) {
791 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
792 }
Anton Hansson37c041d2021-04-14 17:49:06 +0100793 printf("SDK extension versions [r=%s s=%s]\n",
794 android::base::GetProperty("build.version.extensions.r", "-").c_str(),
795 android::base::GetProperty("build.version.extensions.s", "-").c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700796
Felipe Lemed8b94e52016-12-08 10:21:44 -0800797 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800798 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800799 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800800 printf("Uptime: ");
801 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
802 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800803 printf("Bugreport format version: %s\n", version_.c_str());
Rhed Jao5377d792020-07-16 17:37:39 +0800804 printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
805 id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
Kedar Chitnis9fd8c052021-11-16 09:09:22 +0000806 options_->args.c_str(), options_->bugreport_mode_string.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800807 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800808}
809
Felipe Leme24b66ee2016-06-16 10:55:26 -0700810// List of file extensions that can cause a zip file attachment to be rejected by some email
811// service providers.
812static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
813 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
814 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
815 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
816};
817
Vishnu Naire97d6122018-01-18 13:58:56 -0800818status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
819 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700820 std::string valid_name = entry_name;
821
822 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700823 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700824 if (idx != std::string::npos) {
825 std::string extension = entry_name.substr(idx);
826 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
827 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
828 valid_name = entry_name + ".renamed";
829 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
830 }
831 }
832
Felipe Leme6fe9db62016-02-12 09:04:16 -0800833 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
834 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Kevin Jeon9bbe0ac2022-05-05 22:05:43 +0000835 size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
836 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), flags,
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700837 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700838 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700839 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700840 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800841 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800842 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000843 bool finished_entry = false;
844 auto finish_entry = [this, &finished_entry] {
845 if (!finished_entry) {
846 // This should only be called when we're going to return an earlier error,
847 // which would've been logged. This may imply the file is already corrupt
848 // and any further logging from FinishEntry is more likely to mislead than
849 // not.
850 this->zip_writer_->FinishEntry();
851 }
852 };
853 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800854 auto start = std::chrono::steady_clock::now();
855 auto end = start + timeout;
856 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800857
Felipe Leme770410d2016-01-26 17:07:14 -0800858 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800859 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800860 if (timeout.count() > 0) {
861 // lambda to recalculate the timeout.
862 auto time_left_ms = [end]() {
863 auto now = std::chrono::steady_clock::now();
864 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
865 return std::max(diff.count(), 0LL);
866 };
867
868 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
869 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000870 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
871 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800872 return -errno;
873 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000874 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800875 entry_name.c_str(), strerror(errno), timeout.count());
876 return TIMED_OUT;
877 }
878 }
879
Zach Riggle22200402016-08-18 01:01:24 -0400880 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800881 if (bytes_read == 0) {
882 break;
883 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800884 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800885 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800886 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700887 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800888 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700889 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800890 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800891 }
892 }
893
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700894 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000895 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700896 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700897 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800898 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800899 }
900
Vishnu Naire97d6122018-01-18 13:58:56 -0800901 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800902}
903
Felipe Leme1d486fe2016-10-14 18:06:47 -0700904bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
905 android::base::unique_fd fd(
906 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700907 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800908 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800909 return false;
910 }
911
Vishnu Naire97d6122018-01-18 13:58:56 -0800912 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800913}
914
915/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700916static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800917 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800918}
919
Felipe Leme1d486fe2016-10-14 18:06:47 -0700920void Dumpstate::AddDir(const std::string& dir, bool recursive) {
Felipe Leme678727a2016-09-21 17:22:11 -0700921 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800922 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700923 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800924}
925
Felipe Leme1d486fe2016-10-14 18:06:47 -0700926bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800927 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Kevin Jeon9bbe0ac2022-05-05 22:05:43 +0000928 size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
929 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), flags, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700930 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700931 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700932 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800933 return false;
934 }
935
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700936 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700937 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700938 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700939 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800940 return false;
941 }
942
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700943 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700944 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700945 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800946 return false;
947 }
948
949 return true;
950}
951
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800952static void DoKmsg() {
953 struct stat st;
954 if (!stat(PSTORE_LAST_KMSG, &st)) {
955 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
956 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
957 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
958 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
959 } else {
960 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
961 DumpFile("LAST KMSG", "/proc/last_kmsg");
962 }
963}
964
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800965static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800966 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800967 RunCommand(
968 "KERNEL LOG",
969 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
970 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
971}
972
Nandana Duttdb379fa2019-10-09 16:54:41 +0100973static void DoSystemLogcat(time_t since) {
974 char since_str[80];
975 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
976
977 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
978 RunCommand("SYSTEM LOG",
979 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
980 since_str},
981 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
982}
983
Hunter Knepshield820f9bc2020-02-05 20:10:53 -0800984static void DoRadioLogcat() {
985 unsigned long timeout_ms = logcat_timeout({"radio"});
986 RunCommand(
987 "RADIO LOG",
988 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
989 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
990}
991
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800992static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800993 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800994 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
995 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800996 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100997 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800998 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
999 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -08001000 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001001 RunCommand(
1002 "EVENT LOG",
1003 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +01001004 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -08001005 timeout_ms = logcat_timeout({"stats"});
1006 RunCommand(
1007 "STATS LOG",
1008 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +01001009 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001010 DoRadioLogcat();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001011
1012 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
1013
1014 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001015 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
1016 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001017}
1018
Mike Ma5c267872019-08-21 11:31:34 -07001019static void DumpIncidentReport() {
Mike Ma5c267872019-08-21 11:31:34 -07001020 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
1021 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
1022 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1023 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1024 if (fd < 0) {
1025 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
1026 return;
1027 }
Kevin Jeon774abde2022-09-28 18:20:43 +00001028 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build());
Mike Ma5c267872019-08-21 11:31:34 -07001029 bool empty = 0 == lseek(fd, 0, SEEK_END);
1030 if (!empty) {
1031 // Use a different name from "incident.proto"
1032 // /proto/incident.proto is reserved for incident service dump
1033 // i.e. metadata for debugging.
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001034 ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "incident_report" + kProtoExt,
1035 path);
1036 } else {
1037 unlink(path.c_str());
Mike Ma5c267872019-08-21 11:31:34 -07001038 }
Mike Ma5c267872019-08-21 11:31:34 -07001039}
1040
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00001041static void MaybeAddSystemTraceToZip() {
1042 // This function copies into the .zip the system trace that was snapshotted
1043 // by the early call to MaybeSnapshotSystemTrace(), if any background
1044 // tracing was happening.
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00001045 if (!ds.has_system_trace_) {
1046 // No background trace was happening at the time dumpstate was invoked.
1047 return;
1048 }
1049 ds.AddZipEntry(
1050 ZIP_ROOT_DIR + SYSTEM_TRACE_SNAPSHOT,
1051 SYSTEM_TRACE_SNAPSHOT);
1052 android::os::UnlinkAndLogOnError(SYSTEM_TRACE_SNAPSHOT);
1053}
1054
Sunny Goyal35949782019-11-19 15:54:36 -08001055static void DumpVisibleWindowViews() {
Sunny Goyal35949782019-11-19 15:54:36 -08001056 DurationReporter duration_reporter("VISIBLE WINDOW VIEWS");
1057 const std::string path = ds.bugreport_internal_dir_ + "/tmp_visible_window_views";
1058 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
1059 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1060 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1061 if (fd < 0) {
1062 MYLOGE("Could not open %s to dump visible views.\n", path.c_str());
1063 return;
1064 }
1065 RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"},
Kevin Jeon774abde2022-09-28 18:20:43 +00001066 CommandOptions::WithTimeout(10).Build());
Sunny Goyal35949782019-11-19 15:54:36 -08001067 bool empty = 0 == lseek(fd, 0, SEEK_END);
1068 if (!empty) {
1069 ds.AddZipEntry("visible_windows.zip", path);
1070 } else {
1071 MYLOGW("Failed to dump visible windows\n");
1072 }
1073 unlink(path.c_str());
1074}
1075
Jayachandran Ca94c7172017-06-10 15:08:12 -07001076static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001077 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
1078 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +09001079 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -07001080 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +09001081 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
1082 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
1083 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
1084 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -07001085}
1086
David Andersond9ba4752018-12-11 18:26:59 -08001087static void DumpDynamicPartitionInfo() {
1088 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
1089 return;
1090 }
1091
1092 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -07001093 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -08001094}
1095
Chris Morin5a50d482022-02-01 17:41:18 -08001096static void AddAnrTraceDir(const std::string& anr_traces_dir) {
Narayan Kamath8f788292017-05-25 13:20:39 +01001097 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
1098 anr_traces_dir.c_str());
1099
1100 // If we're here, dump_traces_path will always be a temporary file
1101 // (created with mkostemp or similar) that contains dumps taken earlier
1102 // on in the process.
1103 if (dump_traces_path != nullptr) {
Chris Morin5a50d482022-02-01 17:41:18 -08001104 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
1105 dump_traces_path);
1106 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
Narayan Kamath8f788292017-05-25 13:20:39 +01001107
1108 const int ret = unlink(dump_traces_path);
1109 if (ret == -1) {
1110 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
1111 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -07001112 }
1113 }
1114
Narayan Kamathbd863722017-06-01 18:50:12 +01001115 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001116 if (ds.anr_data_.size() > 0) {
Chris Morin5a50d482022-02-01 17:41:18 -08001117 // The "last" ANR will always be present in the body of the main entry.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001118 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Chris Morin5a50d482022-02-01 17:41:18 -08001119 "VM TRACES AT LAST ANR", false /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001120
Narayan Kamath6b9516c2017-10-27 11:15:51 +01001121 // Historical ANRs are always included as separate entries in the bugreport zip file.
Chris Morin5a50d482022-02-01 17:41:18 -08001122 AddDumps(ds.anr_data_.begin(), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +01001123 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001124 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001125 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1126 }
1127}
1128
1129static void AddAnrTraceFiles() {
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001130 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001131
Chris Morin5a50d482022-02-01 17:41:18 -08001132 AddAnrTraceDir(anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001133
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001134 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1135
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001136 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001137 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001138 int i = 0;
1139 while (true) {
1140 const std::string slow_trace_path =
1141 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1142 if (stat(slow_trace_path.c_str(), &st)) {
1143 // No traces file at this index, done with the files.
1144 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001145 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001146 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1147 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001148 }
1149}
1150
Wei Wang509bb5d2017-06-09 14:42:12 -07001151static void DumpBlockStatFiles() {
1152 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001153
Wei Wang1dc1ef52017-06-12 11:28:37 -07001154 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1155
1156 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001157 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1158 return;
1159 }
1160
1161 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001162 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001163 if ((d->d_name[0] == '.')
1164 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1165 || (d->d_name[1] == '\0'))) {
1166 continue;
1167 }
1168 const std::string new_path =
1169 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1170 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1171 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1172 printf("\n");
1173 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001174 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001175}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001176
1177static void DumpPacketStats() {
1178 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001179}
1180
1181static void DumpIpAddrAndRules() {
1182 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1183 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1184 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1185 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1186 RunCommand("IP RULES", {"ip", "rule", "show"});
1187 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1188}
1189
Nandana Dutt5c390032019-03-12 10:52:56 +00001190static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1191 std::chrono::milliseconds timeout,
1192 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001193 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001194 sp<android::IServiceManager> sm = defaultServiceManager();
1195 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001196 Vector<String16> args;
1197 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001198 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1199 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001200 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001201 std::string path(title);
1202 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001203 size_t bytes_written = 0;
Gavin Corkeryf18d1832021-08-25 17:23:40 +01001204 if (PropertiesHelper::IsDryRun()) {
1205 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1206 dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1));
1207 } else {
1208 status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
1209 if (status == OK) {
1210 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1211 std::chrono::duration<double> elapsed_seconds;
1212 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
1213 service == String16("meminfo")) {
1214 // Use a longer timeout for meminfo, since 30s is not always enough.
1215 status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
1216 /* as_proto = */ false, elapsed_seconds,
1217 bytes_written);
1218 } else {
1219 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1220 /* as_proto = */ false, elapsed_seconds,
1221 bytes_written);
1222 }
1223 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1224 bool dump_complete = (status == OK);
1225 dumpsys.stopDumpThread(dump_complete);
Gavin Corkeryfac7e2b2021-07-08 22:39:02 +01001226 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001227 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001228
1229 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1230 std::chrono::steady_clock::now() - start);
1231 if (elapsed_duration > timeout) {
1232 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1233 elapsed_duration.count());
1234 break;
1235 }
1236 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001237 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001238}
1239
Vishnu Nair64afc022018-02-01 15:29:34 -08001240static void RunDumpsysText(const std::string& title, int priority,
1241 std::chrono::milliseconds timeout,
1242 std::chrono::milliseconds service_timeout) {
1243 DurationReporter duration_reporter(title);
1244 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1245 fsync(STDOUT_FILENO);
1246 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1247}
1248
1249/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001250static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1251 std::chrono::milliseconds timeout,
1252 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001253 DurationReporter duration_reporter(title);
1254 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1255 fsync(STDOUT_FILENO);
1256 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1257 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001258
1259 RETURN_IF_USER_DENIED_CONSENT();
1260
1261 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1262 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001263}
1264
Nandana Dutt5c390032019-03-12 10:52:56 +00001265static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1266 std::chrono::milliseconds timeout,
1267 std::chrono::milliseconds service_timeout) {
Vishnu Naire97d6122018-01-18 13:58:56 -08001268 sp<android::IServiceManager> sm = defaultServiceManager();
1269 Dumpsys dumpsys(sm.get());
1270 Vector<String16> args;
1271 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1272 DurationReporter duration_reporter(title);
1273
1274 auto start = std::chrono::steady_clock::now();
1275 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1276 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001277 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001278 std::string path(kProtoPath);
1279 path.append(String8(service).c_str());
1280 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1281 path.append("_CRITICAL");
1282 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1283 path.append("_HIGH");
1284 }
1285 path.append(kProtoExt);
Steven Morelandcbd69fc2021-07-20 20:45:43 +00001286 status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001287 if (status == OK) {
1288 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1289 bool dumpTerminated = (status == OK);
1290 dumpsys.stopDumpThread(dumpTerminated);
1291 }
1292 ZipWriter::FileEntry file_entry;
1293 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001294
1295 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1296 std::chrono::steady_clock::now() - start);
1297 if (elapsed_duration > timeout) {
1298 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1299 elapsed_duration.count());
1300 break;
1301 }
1302 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001303 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001304}
1305
Nandana Dutta7db6342018-11-21 14:53:34 +00001306// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001307static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001308 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1309 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001310
1311 RETURN_IF_USER_DENIED_CONSENT();
1312
1313 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1314 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001315}
1316
1317// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001318static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001319 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1320 // high priority. Reduce timeout once they are able to dump in a shorter time or
1321 // moved to a parallel task.
1322 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1323 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001324
1325 RETURN_IF_USER_DENIED_CONSENT();
1326
1327 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1328 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001329}
1330
1331// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001332static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001333 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001334
1335 RETURN_IF_USER_DENIED_CONSENT();
1336
1337 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1338 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001339}
1340
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001341/*
1342 * |out_fd| A fd to support the DumpPool to output results to a temporary file.
1343 * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
1344 * if it's not running in the parallel task.
1345 */
1346static void DumpHals(int out_fd = STDOUT_FILENO) {
Yifan Hong30528a22020-08-07 18:24:06 -07001347 RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001348 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
1349 false, out_fd);
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001350
Steven Moreland44cd9482018-01-04 16:24:13 -08001351 using android::hidl::manager::V1_0::IServiceManager;
1352 using android::hardware::defaultServiceManager;
1353
1354 sp<IServiceManager> sm = defaultServiceManager();
1355 if (sm == nullptr) {
1356 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1357 return;
1358 }
1359
1360 auto ret = sm->list([&](const auto& interfaces) {
1361 for (const std::string& interface : interfaces) {
1362 std::string cleanName = interface;
1363 std::replace_if(cleanName.begin(),
1364 cleanName.end(),
1365 [](char c) {
1366 return !isalnum(c) &&
1367 std::string("@-_:.").find(c) == std::string::npos;
1368 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001369 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001370
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001371 bool empty = false;
Steven Moreland44cd9482018-01-04 16:24:13 -08001372 {
1373 auto fd = android::base::unique_fd(
1374 TEMP_FAILURE_RETRY(open(path.c_str(),
1375 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1376 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1377 if (fd < 0) {
1378 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1379 continue;
1380 }
1381 RunCommandToFd(fd,
1382 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001383 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001384 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1385
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001386 empty = 0 == lseek(fd, 0, SEEK_END);
Steven Moreland44cd9482018-01-04 16:24:13 -08001387 }
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001388 if (!empty) {
1389 ds.EnqueueAddZipEntryAndCleanupIfNeeded("lshal-debug/" + cleanName + ".txt",
1390 path);
1391 } else {
1392 unlink(path.c_str());
1393 }
Steven Moreland44cd9482018-01-04 16:24:13 -08001394 }
1395 });
1396
1397 if (!ret.isOk()) {
1398 MYLOGE("Could not list hals from hwservicemanager.\n");
1399 }
1400}
1401
Devin Moore8df81bb2022-06-08 22:47:02 +00001402// Dump all of the files that make up the vendor interface.
1403// See the files listed in dumpFileList() for the latest list of files.
1404static void DumpVintf() {
1405 const auto vintfFiles = android::vintf::details::dumpFileList();
1406 for (const auto vintfFile : vintfFiles) {
1407 struct stat st;
1408 if (stat(vintfFile.c_str(), &st) == 0) {
1409 if (S_ISDIR(st.st_mode)) {
1410 ds.AddDir(vintfFile, true /* recursive */);
1411 } else {
1412 ds.EnqueueAddZipEntryAndCleanupIfNeeded(ZIP_ROOT_DIR + vintfFile,
1413 vintfFile);
1414 }
1415 }
1416 }
1417}
1418
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001419static void DumpExternalFragmentationInfo() {
1420 struct stat st;
1421 if (stat("/proc/buddyinfo", &st) != 0) {
1422 MYLOGE("Unable to dump external fragmentation info\n");
1423 return;
1424 }
1425
1426 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1427 std::ifstream ifs("/proc/buddyinfo");
1428 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1429 for (std::string line; std::getline(ifs, line);) {
1430 std::smatch match_results;
1431 if (std::regex_match(line, match_results, unusable_index_regex)) {
1432 std::stringstream free_pages(std::string{match_results[3]});
1433 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1434 std::istream_iterator<int>());
1435
1436 int total_free_pages = 0;
1437 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1438 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1439 }
1440
1441 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1442 match_results[2].str().c_str());
1443
1444 int usable_free_pages = total_free_pages;
1445 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1446 auto unusable_index = (total_free_pages - usable_free_pages) /
1447 static_cast<double>(total_free_pages);
1448 printf(" %5.3f", unusable_index);
1449 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1450 }
1451
1452 printf("\n");
1453 }
1454 }
1455 printf("\n");
1456}
1457
mhasankd451a472020-05-26 18:02:39 -07001458static void DumpstateLimitedOnly() {
1459 // Trimmed-down version of dumpstate to only include a whitelisted
1460 // set of logs (system log, event log, and system server / system app
1461 // crashes, and networking logs). See b/136273873 and b/138459828
1462 // for context.
1463 DurationReporter duration_reporter("DUMPSTATE");
1464 unsigned long timeout_ms;
1465 // calculate timeout
1466 timeout_ms = logcat_timeout({"main", "system", "crash"});
1467 RunCommand("SYSTEM LOG",
1468 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
1469 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
1470 timeout_ms = logcat_timeout({"events"});
1471 RunCommand(
1472 "EVENT LOG",
1473 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
1474 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
1475
1476 printf("========================================================\n");
1477 printf("== Networking Service\n");
1478 printf("========================================================\n");
1479
1480 RunDumpsys("DUMPSYS NETWORK_SERVICE_LIMITED", {"wifi", "-a"},
1481 CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Hugo Benichiaa162682020-10-30 23:28:56 +09001482 RunDumpsys("DUMPSYS CONNECTIVITY REQUESTS", {"connectivity", "requests"},
1483 CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
mhasankd451a472020-05-26 18:02:39 -07001484
1485 printf("========================================================\n");
1486 printf("== Dropbox crashes\n");
1487 printf("========================================================\n");
1488
1489 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1490 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1491
1492 printf("========================================================\n");
1493 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1494 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1495 printf("========================================================\n");
1496 printf("== dumpstate: done (id %d)\n", ds.id_);
1497 printf("========================================================\n");
1498}
1499
Rhed Jaoe017f982020-07-21 17:58:41 +08001500/*
1501 * |out_fd| A fd to support the DumpPool to output results to a temporary file.
1502 * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
1503 * if it's not running in the parallel task.
1504 */
1505static void DumpCheckins(int out_fd = STDOUT_FILENO) {
1506 dprintf(out_fd, "========================================================\n");
1507 dprintf(out_fd, "== Checkins\n");
1508 dprintf(out_fd, "========================================================\n");
1509
1510 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
Rhed Jaoe017f982020-07-21 17:58:41 +08001511 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
1512 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
1513 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
1514 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"}, out_fd);
1515}
1516
1517/*
1518 * Runs dumpsys on activity service to dump all application activities, services
1519 * and providers in the device.
1520 *
1521 * |out_fd| A fd to support the DumpPool to output results to a temporary file.
1522 * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
1523 * if it's not running in the parallel task.
1524 */
1525static void DumpAppInfos(int out_fd = STDOUT_FILENO) {
1526 dprintf(out_fd, "========================================================\n");
1527 dprintf(out_fd, "== Running Application Activities\n");
1528 dprintf(out_fd, "========================================================\n");
1529
1530 // The following dumpsys internally collects output from running apps, so it can take a long
1531 // time. So let's extend the timeout.
1532
1533 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1534
1535 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
1536
1537 dprintf(out_fd, "========================================================\n");
1538 dprintf(out_fd, "== Running Application Services (platform)\n");
1539 dprintf(out_fd, "========================================================\n");
1540
1541 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
1542 DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
1543
1544 dprintf(out_fd, "========================================================\n");
1545 dprintf(out_fd, "== Running Application Services (non-platform)\n");
1546 dprintf(out_fd, "========================================================\n");
1547
1548 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1549 DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
1550
1551 dprintf(out_fd, "========================================================\n");
1552 dprintf(out_fd, "== Running Application Providers (platform)\n");
1553 dprintf(out_fd, "========================================================\n");
1554
1555 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
Rhed Jaob049f182021-01-11 21:08:43 +08001556 DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
Rhed Jaoe017f982020-07-21 17:58:41 +08001557
1558 dprintf(out_fd, "========================================================\n");
1559 dprintf(out_fd, "== Running Application Providers (non-platform)\n");
1560 dprintf(out_fd, "========================================================\n");
1561
1562 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1563 DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
1564}
1565
Nandana Dutt5c390032019-03-12 10:52:56 +00001566// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1567// via the consent they are shown. Ignores other errors that occur while running various
1568// commands. The consent checking is currently done around long running tasks, which happen to
1569// be distributed fairly evenly throughout the function.
1570static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001571 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001572
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001573 // Enqueue slow functions into the thread pool, if the parallel run is enabled.
Chris Morinbc223142022-02-04 14:17:11 -08001574 std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001575 if (ds.dump_pool_) {
1576 // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
1577 // drop root user. Restarts it with two threads for the parallel run.
1578 ds.dump_pool_->start(/* thread_counts = */2);
1579
Chris Morinbc223142022-02-04 14:17:11 -08001580 dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
1581 dump_incident_report = ds.dump_pool_->enqueueTask(
1582 DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
1583 dump_board = ds.dump_pool_->enqueueTaskWithFd(
1584 DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
1585 dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001586 }
1587
Nandana Dutt5c390032019-03-12 10:52:56 +00001588 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1589 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1590 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001591 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001592 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001593 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001594 DumpFile("MEMORY INFO", "/proc/meminfo");
1595 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001596 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001597
1598 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1599
Sunny Goyal35949782019-11-19 15:54:36 -08001600 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
1601
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001602 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1603 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1604 DumpFile("SLAB INFO", "/proc/slabinfo");
1605 DumpFile("ZONEINFO", "/proc/zoneinfo");
1606 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1607 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001608 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001609
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001610 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001611
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001612 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001613 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001614
1615 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1616 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001617
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001618 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001619 WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001620 } else {
1621 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
1622 }
Steven Moreland81b429e2017-01-31 19:50:46 -08001623
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001624 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001625 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001626 struct stat s;
1627 if (stat("/proc/modules", &s) != 0) {
1628 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1629 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001630 RunCommand("LSMOD", {"lsmod"});
Woody Linc198f252021-05-04 16:37:11 +08001631 RunCommand("MODULES INFO",
1632 {"sh", "-c", "cat /proc/modules | cut -d' ' -f1 | "
1633 " while read MOD ; do echo modinfo:$MOD ; modinfo $MOD ; "
1634 "done"}, CommandOptions::AS_ROOT);
Felipe Lemee4eca582016-06-10 17:48:08 -07001635 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001636
Tom Cherryb87dbfa2020-07-28 11:28:53 -07001637 if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001638 DoKernelLogcat();
1639 } else {
1640 do_dmesg();
1641 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001642
Devin Moore8df81bb2022-06-08 22:47:02 +00001643 DumpVintf();
1644
Felipe Lemef0292972016-11-22 13:57:05 -08001645 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001646
1647 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1648
Jeff Brown1dc94e32014-09-11 14:15:27 -07001649 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001650 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001651
Jack Yu5a6b2e22020-08-14 18:13:35 +08001652 /* Dump Nfc NCI logs */
1653 ds.AddDir("/data/misc/nfc/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001654
Paul Chang0d2aad72020-02-13 20:04:03 +08001655 if (ds.options_->do_screenshot && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001656 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001657 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001658 }
1659
Felipe Lemee184f662016-10-27 10:04:47 -07001660 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001661
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00001662 MaybeAddSystemTraceToZip();
1663
Narayan Kamath8f788292017-05-25 13:20:39 +01001664 // NOTE: tombstones are always added as separate entries in the zip archive
1665 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001666 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001667 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001668 if (!tombstones_dumped) {
1669 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001670 }
1671
Jayachandran Ca94c7172017-06-10 15:08:12 -07001672 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001673
Lorenzo Colitti807f2dd2022-05-27 12:48:37 +09001674 RunDumpsys("EBPF MAP STATS", {"connectivity", "trafficcontroller"});
Chenbo Feng276a3b62018-08-07 11:44:49 -07001675
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001676 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001677
Jayachandran Ca94c7172017-06-10 15:08:12 -07001678 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001679
1680 dump_route_tables();
1681
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001682 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1683 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1684 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001685
Nandana Dutt5c390032019-03-12 10:52:56 +00001686 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001687
Chiachang Wang668ede42021-05-17 17:14:20 +08001688 // The dump mechanism in connectivity is refactored due to modularization work. Connectivity can
1689 // only register with a default priority(NORMAL priority). Dumpstate has to call connectivity
1690 // dump with priority parameters to dump high priority information.
1691 RunDumpsys("SERVICE HIGH connectivity", {"connectivity", "--dump-priority", "HIGH"},
1692 CommandOptions::WithTimeout(10).Build());
1693
Elliott Hughes23ccc622017-02-28 10:14:22 -08001694 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001695
Jin Qianf334d662017-10-10 14:41:37 -07001696 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001697
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001698 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001699
Colin Crossf45fa6b2012-03-26 12:38:26 -07001700 /* Binder state is expensive to look at as it uses a lot of memory. */
Hridya Valsaraju920ba712020-02-09 16:27:01 -08001701 std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ?
1702 "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs";
1703
1704 DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log");
1705 DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log");
1706 DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions");
1707 DumpFile("BINDER STATS", binder_logs_dir + "/stats");
1708 DumpFile("BINDER STATE", binder_logs_dir + "/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001709
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001710 /* Add window and surface trace files. */
1711 if (!PropertiesHelper::IsUserBuild()) {
1712 ds.AddDir(WMTRACE_DATA_DIR, false);
1713 }
1714
Yifan Hongd90cc652020-02-08 16:52:02 -08001715 ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
1716
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001717 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001718 WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_board));
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001719 } else {
1720 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
1721 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001722
Steven Moreland7440ddb2016-12-15 16:13:39 -08001723 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001724 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1725 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001726 // su does not exist on user builds, so try running without it.
1727 // This way any implementations of vril-dump that do not require
1728 // root can run on user builds.
1729 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001730 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001731 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001732 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001733 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001734 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001735 }
1736
Felipe Lemed8b94e52016-12-08 10:21:44 -08001737 printf("========================================================\n");
1738 printf("== Android Framework Services\n");
1739 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001740
Nandana Dutt5c390032019-03-12 10:52:56 +00001741 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001742
Jack He91ff2fe2021-02-18 18:23:43 -08001743 /* Dump Bluetooth HCI logs after getting bluetooth_manager dumpsys */
1744 ds.AddDir("/data/misc/bluetooth/logs", true);
1745
Rhed Jaoe017f982020-07-21 17:58:41 +08001746 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001747 WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_checkins));
Rhed Jaoe017f982020-07-21 17:58:41 +08001748 } else {
1749 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
1750 }
Dianne Hackborn02bea972013-06-26 18:59:09 -07001751
Rhed Jaoc5f7ec32020-12-22 22:11:08 +08001752 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpAppInfos);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001753
Adrian Roos8b397ab2017-04-04 16:35:44 -07001754 printf("========================================================\n");
1755 printf("== Dropbox crashes\n");
1756 printf("========================================================\n");
1757
1758 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1759 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1760
Felipe Lemed8b94e52016-12-08 10:21:44 -08001761 printf("========================================================\n");
1762 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1763 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1764 printf("========================================================\n");
1765 printf("== dumpstate: done (id %d)\n", ds.id_);
1766 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001767
1768 printf("========================================================\n");
1769 printf("== Obtaining statsd metadata\n");
1770 printf("========================================================\n");
1771 // This differs from the usual dumpsys stats, which is the stats report data.
1772 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001773
Kiyoung Kimc2d22ac2020-02-04 19:43:36 +09001774 // Add linker configuration directory
1775 ds.AddDir(LINKERCONFIG_DIR, true);
1776
Li Li830179f2022-01-04 12:53:29 -08001777 /* Dump frozen cgroupfs */
1778 dump_frozen_cgroupfs();
Li Li2eedd412021-06-30 15:11:53 -07001779
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001780 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001781 WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08001782 } else {
1783 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
1784 DumpIncidentReport);
1785 }
Mike Ma5c267872019-08-21 11:31:34 -07001786
Nandana Dutt5c390032019-03-12 10:52:56 +00001787 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001788}
1789
Nandana Dutt5c390032019-03-12 10:52:56 +00001790/*
1791 * Dumps state for the default case; drops root after it's no longer necessary.
1792 *
1793 * Returns RunStatus::OK if everything went fine.
1794 * Returns RunStatus::ERROR if there was an error.
1795 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1796 * with the caller.
1797 */
Jichao Lie89d9c12019-11-21 19:02:51 -08001798Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
Nandana Duttdb379fa2019-10-09 16:54:41 +01001799 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1800 // buffer.
1801 DoLogcat();
1802 // Capture timestamp after first logcat to use in next logcat
1803 time_t logcat_ts = time(nullptr);
1804
Nandana Dutt4be45d12018-09-26 15:04:23 +01001805 /* collect stack traces from Dalvik and native processes (needs root) */
Chris Morinbc223142022-02-04 14:17:11 -08001806 std::future<std::string> dump_traces;
Rhed Jao5377d792020-07-16 17:37:39 +08001807 if (dump_pool_) {
1808 RETURN_IF_USER_DENIED_CONSENT();
1809 // One thread is enough since we only need to enqueue DumpTraces here.
1810 dump_pool_->start(/* thread_counts = */1);
1811
1812 // DumpTraces takes long time, post it to the another thread in the
1813 // pool, if pool is available
Chris Morinbc223142022-02-04 14:17:11 -08001814 dump_traces = dump_pool_->enqueueTask(
1815 DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
Rhed Jao5377d792020-07-16 17:37:39 +08001816 } else {
1817 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
1818 &dump_traces_path);
1819 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01001820
1821 /* Run some operations that require root. */
Gavin Corkeryf18d1832021-08-25 17:23:40 +01001822 if (!PropertiesHelper::IsDryRun()) {
Chris Morinc2cba7a2022-02-01 17:06:50 -08001823 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
1824 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
Gavin Corkeryf18d1832021-08-25 17:23:40 +01001825 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01001826
1827 ds.AddDir(RECOVERY_DIR, true);
1828 ds.AddDir(RECOVERY_DATA_DIR, true);
1829 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1830 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1831 if (!PropertiesHelper::IsUserBuild()) {
1832 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1833 ds.AddDir(PROFILE_DATA_DIR_REF, true);
Calin Juravlef84d3692020-04-28 15:31:12 -07001834 ds.AddZipEntry(ZIP_ROOT_DIR + PACKAGE_DEX_USE_LIST, PACKAGE_DEX_USE_LIST);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001835 }
Jerry Changa1df8a92020-01-02 16:03:39 +08001836 ds.AddDir(PREREBOOT_DATA_DIR, false);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001837 add_mountinfo();
1838 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001839 DumpDynamicPartitionInfo();
Yifan Hong3945e1b2019-10-29 12:59:23 -07001840 ds.AddDir(OTA_METADATA_DIR, true);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001841
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001842 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001843 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1844
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001845 // Dump IPsec stats. No keys are exposed here.
1846 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1847
Nandana Dutt4be45d12018-09-26 15:04:23 +01001848 // Run ss as root so we can see socket marks.
1849 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1850
1851 // Run iotop as root to show top 100 IO threads
1852 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1853
Erick Reyese68df822019-02-11 14:46:36 -08001854 // Gather shared memory buffer info if the product implements it
Hridya Valsaraju1da80c52021-01-09 22:10:11 -08001855 RunCommand("Dmabuf dump", {"dmabuf_dump"});
1856 RunCommand("Dmabuf per-buffer/per-exporter/per-device stats", {"dmabuf_dump", "-b"});
Erick Reyese68df822019-02-11 14:46:36 -08001857
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001858 DumpFile("PSI cpu", "/proc/pressure/cpu");
1859 DumpFile("PSI memory", "/proc/pressure/memory");
1860 DumpFile("PSI io", "/proc/pressure/io");
1861
Rhed Jao5377d792020-07-16 17:37:39 +08001862 if (dump_pool_) {
1863 RETURN_IF_USER_DENIED_CONSENT();
Chris Morinbc223142022-02-04 14:17:11 -08001864 WaitForTask(std::move(dump_traces));
Rhed Jao5377d792020-07-16 17:37:39 +08001865
Chris Morinbc223142022-02-04 14:17:11 -08001866 // Current running thread in the pool is the root user also. Delete
1867 // the pool and make a new one later to ensure none of threads in the pool are root.
1868 dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
Rhed Jao5377d792020-07-16 17:37:39 +08001869 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01001870 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001871 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001872 }
1873
Nandana Dutt5c390032019-03-12 10:52:56 +00001874 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001875 Dumpstate::RunStatus status = dumpstate();
1876 // Capture logcat since the last time we did it.
1877 DoSystemLogcat(logcat_ts);
1878 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001879}
1880
Rhed Jaob5685b32020-08-14 17:19:17 +08001881// Common states for telephony and wifi which are needed to be collected before
1882// dumpstate drop the root user.
1883static void DumpstateRadioAsRoot() {
1884 DumpIpTablesAsRoot();
1885 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1886}
1887
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001888// This method collects common dumpsys for telephony and wifi. Typically, wifi
1889// reports are fine to include all information, but telephony reports on user
1890// builds need to strip some content (see DumpstateTelephonyOnly).
1891static void DumpstateRadioCommon(bool include_sensitive_info = true) {
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001892 // We need to be picky about some stuff for telephony reports on user builds.
1893 if (!include_sensitive_info) {
1894 // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
1895 DoRadioLogcat();
1896 } else {
Rhed Jaob5685b32020-08-14 17:19:17 +08001897 // DumpHals takes long time, post it to the another thread in the pool,
1898 // if pool is available.
Chris Morinbc223142022-02-04 14:17:11 -08001899 std::future<std::string> dump_hals;
Rhed Jaob5685b32020-08-14 17:19:17 +08001900 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001901 dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
Rhed Jaob5685b32020-08-14 17:19:17 +08001902 }
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001903 // Contains various system properties and process startup info.
1904 do_dmesg();
1905 // Logs other than the radio buffer may contain package/component names and potential PII.
1906 DoLogcat();
1907 // Too broad for connectivity problems.
1908 DoKmsg();
Rhed Jaob5685b32020-08-14 17:19:17 +08001909 // DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
1910 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08001911 WaitForTask(std::move(dump_hals));
Rhed Jaob5685b32020-08-14 17:19:17 +08001912 } else {
1913 RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
1914 }
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001915 }
1916
Jayachandran Ca94c7172017-06-10 15:08:12 -07001917 DumpPacketStats();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001918 DumpIpAddrAndRules();
1919 dump_route_tables();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001920 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1921 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001922}
1923
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001924// We use "telephony" here for legacy reasons, though this now really means "connectivity" (cellular
1925// + wifi + networking). This method collects dumpsys for connectivity debugging only. General rules
1926// for what can be included on user builds: all reported information MUST directly relate to
1927// connectivity debugging or customer support and MUST NOT contain unrelated personally identifiable
1928// information. This information MUST NOT identify user-installed packages (UIDs are OK, package
1929// names are not), and MUST NOT contain logs of user application traffic.
1930// TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
Hunter Knepshield0cc6c212020-01-07 16:57:10 -08001931static void DumpstateTelephonyOnly(const std::string& calling_package) {
mukesh agrawal253dad42018-01-23 21:59:59 -08001932 DurationReporter duration_reporter("DUMPSTATE");
Jichao Lie89d9c12019-11-21 19:02:51 -08001933
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001934 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001935
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001936 const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001937
Rhed Jaob5685b32020-08-14 17:19:17 +08001938 DumpstateRadioAsRoot();
1939 if (!DropRootUser()) {
1940 return;
1941 }
1942
1943 // Starts thread pool after the root user is dropped, and two additional threads
1944 // are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
Chris Morinbc223142022-02-04 14:17:11 -08001945 std::future<std::string> dump_board;
Rhed Jaob5685b32020-08-14 17:19:17 +08001946 if (ds.dump_pool_) {
1947 ds.dump_pool_->start(/*thread_counts =*/2);
1948
1949 // DumpstateBoard takes long time, post it to the another thread in the pool,
1950 // if pool is available.
Chris Morinbc223142022-02-04 14:17:11 -08001951 dump_board = ds.dump_pool_->enqueueTaskWithFd(
1952 DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
Rhed Jaob5685b32020-08-14 17:19:17 +08001953 }
1954
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001955 DumpstateRadioCommon(include_sensitive_info);
1956
1957 if (include_sensitive_info) {
1958 // Contains too much unrelated PII, and given the unstructured nature of sysprops, we can't
1959 // really cherrypick all of the connectivity-related ones. Apps generally have no business
1960 // reading these anyway, and there should be APIs to supply the info in a more app-friendly
1961 // way.
1962 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1963 }
Jayachandran Ca94c7172017-06-10 15:08:12 -07001964
1965 printf("========================================================\n");
1966 printf("== Android Framework Services\n");
1967 printf("========================================================\n");
1968
Vishnu Nair652cc802017-11-30 15:18:30 -08001969 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1970 SEC_TO_MSEC(10));
Hunter Knepshield31cbae12021-05-11 16:23:24 -07001971 RunDumpsys("DUMPSYS", {"vcn_management"}, CommandOptions::WithTimeout(90).Build(),
1972 SEC_TO_MSEC(10));
Hunter Knepshield0cc6c212020-01-07 16:57:10 -08001973 if (include_sensitive_info) {
1974 // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
1975 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1976 SEC_TO_MSEC(10));
1977 } else {
1978 // If the caller is a carrier app and has a carrier service, dump it here since we aren't
1979 // running dumpsys activity service all-non-platform below. Due to the increased output, we
1980 // give a higher timeout as well.
1981 RunDumpsys("DUMPSYS", {"carrier_config", "--requesting-package", calling_package},
1982 CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(30));
1983 }
1984 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001985 RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1986 RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001987 SEC_TO_MSEC(10));
Hunter Knepshield0fe51b12020-03-05 16:58:20 -08001988 RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(),
1989 SEC_TO_MSEC(10));
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001990 if (include_sensitive_info) {
1991 // Contains raw IP addresses, omit from reports on user builds.
1992 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1993 // Contains raw destination IP/MAC addresses, omit from reports on user builds.
1994 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1995 SEC_TO_MSEC(10));
1996 // Contains package/component names, omit from reports on user builds.
1997 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1998 SEC_TO_MSEC(10));
1999 // Contains package names, but should be relatively simple to remove them (also contains
2000 // UIDs already), omit from reports on user builds.
2001 RunDumpsys("BATTERYSTATS", {"deviceidle"}, CommandOptions::WithTimeout(90).Build(),
2002 SEC_TO_MSEC(10));
2003 }
Jayachandran Ca94c7172017-06-10 15:08:12 -07002004
2005 printf("========================================================\n");
2006 printf("== Running Application Services\n");
2007 printf("========================================================\n");
2008
2009 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
2010
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002011 if (include_sensitive_info) {
2012 printf("========================================================\n");
2013 printf("== Running Application Services (non-platform)\n");
2014 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07002015
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002016 // Contains package/component names and potential PII, omit from reports on user builds.
2017 // To get dumps of the active CarrierService(s) on user builds, we supply an argument to the
2018 // carrier_config dumpsys instead.
2019 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
2020 DUMPSYS_COMPONENTS_OPTIONS);
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07002021
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002022 printf("========================================================\n");
2023 printf("== Checkins\n");
2024 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07002025
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002026 // Contains package/component names, omit from reports on user builds.
2027 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
2028 }
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07002029
2030 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07002031 printf("== dumpstate: done (id %d)\n", ds.id_);
2032 printf("========================================================\n");
Rhed Jaob5685b32020-08-14 17:19:17 +08002033
2034 if (ds.dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08002035 WaitForTask(std::move(dump_board));
Rhed Jaob5685b32020-08-14 17:19:17 +08002036 } else {
2037 RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
2038 }
Jayachandran Ca94c7172017-06-10 15:08:12 -07002039}
2040
mukesh agrawal253dad42018-01-23 21:59:59 -08002041// This method collects dumpsys for wifi debugging only
2042static void DumpstateWifiOnly() {
2043 DurationReporter duration_reporter("DUMPSTATE");
2044
Rhed Jaob5685b32020-08-14 17:19:17 +08002045 DumpstateRadioAsRoot();
2046 if (!DropRootUser()) {
2047 return;
2048 }
2049
2050 // Starts thread pool after the root user is dropped. Only one additional
2051 // thread is needed for DumpHals in the DumpstateRadioCommon.
2052 if (ds.dump_pool_) {
2053 ds.dump_pool_->start(/*thread_counts =*/1);
2054 }
2055
mukesh agrawal253dad42018-01-23 21:59:59 -08002056 DumpstateRadioCommon();
2057
2058 printf("========================================================\n");
2059 printf("== Android Framework Services\n");
2060 printf("========================================================\n");
2061
2062 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
2063 SEC_TO_MSEC(10));
2064 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
2065 SEC_TO_MSEC(10));
2066
2067 printf("========================================================\n");
2068 printf("== dumpstate: done (id %d)\n", ds.id_);
2069 printf("========================================================\n");
2070}
2071
Nandana Duttcf419a72019-03-14 10:40:17 +00002072Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Gavin Corkery789d7a52021-02-24 23:52:35 +00002073 const std::string temp_file_pattern = ds.bugreport_internal_dir_ + "/dumptrace_XXXXXX";
Nandana Duttfaafd522019-03-11 09:23:09 +00002074 const size_t buf_size = temp_file_pattern.length() + 1;
2075 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
2076 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
2077
2078 // Create a new, empty file to receive all trace dumps.
2079 //
2080 // TODO: This can be simplified once we remove support for the old style
2081 // dumps. We can have a file descriptor passed in to dump_traces instead
2082 // of creating a file, closing it and then reopening it again.
2083 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
2084 if (fd < 0) {
2085 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00002086 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00002087 }
2088
2089 // Nobody should have access to this temporary file except dumpstate, but we
2090 // temporarily grant 'read' to 'others' here because this file is created
2091 // when tombstoned is still running as root, but dumped after dropping. This
2092 // can go away once support for old style dumping has.
2093 const int chmod_ret = fchmod(fd, 0666);
2094 if (chmod_ret < 0) {
2095 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00002096 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00002097 }
2098
2099 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
2100 if (proc.get() == nullptr) {
2101 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00002102 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00002103 }
2104
2105 // Number of times process dumping has timed out. If we encounter too many
2106 // failures, we'll give up.
2107 int timeout_failures = 0;
2108 bool dalvik_found = false;
2109
Jayant Chowdharya0a8eb22022-05-20 03:30:09 +00002110 const std::set<int> hal_pids = get_interesting_pids();
Nandana Duttfaafd522019-03-11 09:23:09 +00002111
2112 struct dirent* d;
2113 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00002114 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00002115 int pid = atoi(d->d_name);
2116 if (pid <= 0) {
2117 continue;
2118 }
2119
2120 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
2121 std::string exe;
2122 if (!android::base::Readlink(link_name, &exe)) {
2123 continue;
2124 }
2125
2126 bool is_java_process;
2127 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
2128 // Don't bother dumping backtraces for the zygote.
2129 if (IsZygote(pid)) {
2130 continue;
2131 }
2132
2133 dalvik_found = true;
2134 is_java_process = true;
2135 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
2136 is_java_process = false;
2137 } else {
2138 // Probably a native process we don't care about, continue.
2139 continue;
2140 }
2141
2142 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
2143 if (timeout_failures == 3) {
2144 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
2145 break;
2146 }
2147
2148 const uint64_t start = Nanotime();
2149 const int ret = dump_backtrace_to_file_timeout(
2150 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
2151 is_java_process ? 5 : 20, fd);
2152
2153 if (ret == -1) {
2154 // For consistency, the header and footer to this message match those
2155 // dumped by debuggerd in the success case.
2156 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
2157 dprintf(fd, "Dump failed, likely due to a timeout.\n");
2158 dprintf(fd, "---- end %d ----", pid);
2159 timeout_failures++;
2160 continue;
2161 }
2162
2163 // We've successfully dumped stack traces, reset the failure count
2164 // and write a summary of the elapsed time to the file and continue with the
2165 // next process.
2166 timeout_failures = 0;
2167
2168 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
2169 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
2170 }
2171
2172 if (!dalvik_found) {
2173 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
2174 }
2175
Nandana Duttcf419a72019-03-14 10:40:17 +00002176 *path = file_name_buf.release();
2177 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00002178}
2179
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002180static dumpstate_hal_hidl::DumpstateMode GetDumpstateHalModeHidl(
2181 const Dumpstate::BugreportMode bugreport_mode) {
2182 switch (bugreport_mode) {
2183 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2184 return dumpstate_hal_hidl::DumpstateMode::FULL;
2185 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2186 return dumpstate_hal_hidl::DumpstateMode::INTERACTIVE;
2187 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2188 return dumpstate_hal_hidl::DumpstateMode::REMOTE;
2189 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2190 return dumpstate_hal_hidl::DumpstateMode::WEAR;
2191 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2192 return dumpstate_hal_hidl::DumpstateMode::CONNECTIVITY;
2193 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2194 return dumpstate_hal_hidl::DumpstateMode::WIFI;
2195 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2196 return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
2197 }
2198 return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
2199}
2200
2201static dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode GetDumpstateHalModeAidl(
2202 const Dumpstate::BugreportMode bugreport_mode) {
2203 switch (bugreport_mode) {
2204 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2205 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::FULL;
2206 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2207 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::INTERACTIVE;
2208 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2209 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::REMOTE;
2210 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2211 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WEAR;
2212 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2213 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::CONNECTIVITY;
2214 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2215 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WIFI;
2216 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2217 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
2218 }
2219 return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
2220}
2221
2222static void DoDumpstateBoardHidl(
2223 const sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_1_0,
2224 const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
2225 const Dumpstate::BugreportMode bugreport_mode,
2226 const size_t timeout_sec) {
2227
2228 using ScopedNativeHandle =
2229 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
2230 ScopedNativeHandle handle(native_handle_create(static_cast<int>(dumpstate_fds.size()), 0),
2231 [](native_handle_t* handle) {
2232 // we don't close file handle's here
2233 // via native_handle_close(handle)
2234 // instead we let dumpstate_fds close the file handles when
2235 // dumpstate_fds gets destroyed
2236 native_handle_delete(handle);
2237 });
2238 if (handle == nullptr) {
2239 MYLOGE("Could not create native_handle for dumpstate HAL\n");
2240 return;
2241 }
2242
2243 for (size_t i = 0; i < dumpstate_fds.size(); i++) {
2244 handle.get()->data[i] = dumpstate_fds[i].get();
2245 }
2246
2247 // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
2248 // implement just 1.0.
2249 const char* descriptor_to_kill;
2250 using DumpstateBoardTask = std::packaged_task<bool()>;
2251 DumpstateBoardTask dumpstate_board_task;
2252 sp<dumpstate_hal_hidl::IDumpstateDevice> dumpstate_hal(
2253 dumpstate_hal_hidl::IDumpstateDevice::castFrom(dumpstate_hal_1_0));
2254 if (dumpstate_hal != nullptr) {
2255 MYLOGI("Using IDumpstateDevice v1.1 HIDL HAL");
2256
2257 dumpstate_hal_hidl::DumpstateMode dumpstate_hal_mode =
2258 GetDumpstateHalModeHidl(bugreport_mode);
2259
2260 descriptor_to_kill = dumpstate_hal_hidl::IDumpstateDevice::descriptor;
2261 dumpstate_board_task =
2262 DumpstateBoardTask([timeout_sec, dumpstate_hal_mode, dumpstate_hal, &handle]() -> bool {
2263 ::android::hardware::Return<dumpstate_hal_hidl::DumpstateStatus> status =
2264 dumpstate_hal->dumpstateBoard_1_1(handle.get(), dumpstate_hal_mode,
2265 SEC_TO_MSEC(timeout_sec));
2266 if (!status.isOk()) {
2267 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
2268 return false;
2269 } else if (status != dumpstate_hal_hidl::DumpstateStatus::OK) {
2270 MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n",
2271 dumpstate_hal_hidl::toString(status).c_str());
2272 return false;
2273 }
2274 return true;
2275 });
2276 } else {
2277 MYLOGI("Using IDumpstateDevice v1.0 HIDL HAL");
2278
2279 descriptor_to_kill = dumpstate_hal_hidl_1_0::IDumpstateDevice::descriptor;
2280 dumpstate_board_task = DumpstateBoardTask([dumpstate_hal_1_0, &handle]() -> bool {
2281 ::android::hardware::Return<void> status =
2282 dumpstate_hal_1_0->dumpstateBoard(handle.get());
2283 if (!status.isOk()) {
2284 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
2285 return false;
2286 }
2287 return true;
2288 });
2289 }
2290 auto result = dumpstate_board_task.get_future();
2291 std::thread(std::move(dumpstate_board_task)).detach();
2292
2293 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
2294 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
2295 if (!android::base::SetProperty(
2296 "ctl.interface_restart",
2297 android::base::StringPrintf("%s/default", descriptor_to_kill))) {
2298 MYLOGE("Couldn't restart dumpstate HAL\n");
2299 }
2300 }
2301 // Wait some time for init to kill dumpstate vendor HAL
2302 constexpr size_t killing_timeout_sec = 10;
2303 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
2304 MYLOGE(
2305 "killing dumpstateBoard timed out after %zus, continue and "
2306 "there might be racing in content\n",
2307 killing_timeout_sec);
2308 }
2309}
2310
2311static void DoDumpstateBoardAidl(
2312 const std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal,
2313 const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
2314 const Dumpstate::BugreportMode bugreport_mode, const size_t timeout_sec) {
2315 MYLOGI("Using IDumpstateDevice AIDL HAL");
2316
2317 const char* descriptor_to_kill;
2318 using DumpstateBoardTask = std::packaged_task<bool()>;
2319 DumpstateBoardTask dumpstate_board_task;
2320 dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode dumpstate_hal_mode =
2321 GetDumpstateHalModeAidl(bugreport_mode);
2322
2323 descriptor_to_kill = dumpstate_hal_aidl::IDumpstateDevice::descriptor;
2324 dumpstate_board_task = DumpstateBoardTask([dumpstate_hal, &dumpstate_fds, dumpstate_hal_mode,
2325 timeout_sec]() -> bool {
2326 auto status = dumpstate_hal->dumpstateBoard(dumpstate_fds, dumpstate_hal_mode, timeout_sec);
2327
2328 if (!status.isOk()) {
2329 MYLOGE("dumpstateBoard failed: %s\n", status.getDescription().c_str());
2330 return false;
2331 }
2332 return true;
2333 });
2334 auto result = dumpstate_board_task.get_future();
2335 std::thread(std::move(dumpstate_board_task)).detach();
2336
2337 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
2338 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
2339 if (!android::base::SetProperty(
2340 "ctl.interface_restart",
2341 android::base::StringPrintf("%s/default", descriptor_to_kill))) {
2342 MYLOGE("Couldn't restart dumpstate HAL\n");
2343 }
2344 }
2345 // Wait some time for init to kill dumpstate vendor HAL
2346 constexpr size_t killing_timeout_sec = 10;
2347 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
2348 MYLOGE(
2349 "killing dumpstateBoard timed out after %zus, continue and "
2350 "there might be racing in content\n",
2351 killing_timeout_sec);
2352 }
2353}
2354
2355static std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> GetDumpstateBoardAidlService() {
2356 const std::string aidl_instance_name =
2357 std::string(dumpstate_hal_aidl::IDumpstateDevice::descriptor) + "/default";
2358
2359 if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
2360 return nullptr;
2361 }
2362
2363 ndk::SpAIBinder dumpstateBinder(AServiceManager_waitForService(aidl_instance_name.c_str()));
2364
2365 return dumpstate_hal_aidl::IDumpstateDevice::fromBinder(dumpstateBinder);
2366}
2367
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08002368void Dumpstate::DumpstateBoard(int out_fd) {
2369 dprintf(out_fd, "========================================================\n");
2370 dprintf(out_fd, "== Board\n");
2371 dprintf(out_fd, "========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08002372
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002373 /*
Hridya Valsarajud09460c2021-04-15 22:11:18 -07002374 * mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
Hridya Valsaraju51101602021-04-02 14:32:46 -07002375 * set to true and unmount it after invoking dumpstateBoard_* methods.
2376 * This is to enable debug builds to not have debugfs mounted during runtime.
2377 * It will also ensure that debugfs is only accessed by the dumpstate HAL.
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002378 */
Hridya Valsaraju51101602021-04-02 14:32:46 -07002379 auto mount_debugfs =
Hridya Valsarajud09460c2021-04-15 22:11:18 -07002380 android::base::GetBoolProperty("ro.product.debugfs_restrictions.enabled", false);
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002381 if (mount_debugfs) {
2382 RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
2383 AS_ROOT_20);
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002384 RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"}, AS_ROOT_20);
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002385 }
2386
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07002387 std::vector<std::string> paths;
2388 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07002389 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002390 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
2391 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002392 remover.emplace_back(android::base::make_scope_guard(
2393 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07002394 }
Jie Song9fbfad02017-06-20 16:29:42 -07002395
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002396 // get dumpstate HAL AIDL implementation
2397 std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal_handle_aidl(
2398 GetDumpstateBoardAidlService());
2399 if (dumpstate_hal_handle_aidl == nullptr) {
2400 MYLOGI("No IDumpstateDevice AIDL implementation\n");
2401 }
2402
2403 // get dumpstate HAL HIDL implementation, only if AIDL HAL implementation not found
2404 sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_handle_hidl_1_0 = nullptr;
2405 if (dumpstate_hal_handle_aidl == nullptr) {
2406 dumpstate_hal_handle_hidl_1_0 = dumpstate_hal_hidl_1_0::IDumpstateDevice::getService();
2407 if (dumpstate_hal_handle_hidl_1_0 == nullptr) {
2408 MYLOGI("No IDumpstateDevice HIDL implementation\n");
2409 }
2410 }
2411
2412 // if neither HIDL nor AIDL implementation found, then return
2413 if (dumpstate_hal_handle_hidl_1_0 == nullptr && dumpstate_hal_handle_aidl == nullptr) {
2414 MYLOGE("Could not find IDumpstateDevice implementation\n");
Wei Wang587eac92018-04-05 12:17:20 -07002415 return;
2416 }
2417
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002418 // this is used to hold the file descriptors and when this variable goes out of scope
2419 // the file descriptors are closed
2420 std::vector<::ndk::ScopedFileDescriptor> dumpstate_fds;
Wei Wang587eac92018-04-05 12:17:20 -07002421
Nandana Dutt5c390032019-03-12 10:52:56 +00002422 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07002423 for (size_t i = 0; i < paths.size(); i++) {
2424 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
2425
2426 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
2427 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
2428 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
2429 if (fd < 0) {
2430 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
2431 return;
2432 }
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002433
2434 dumpstate_fds.emplace_back(fd.release());
2435 // we call fd.release() here to make sure "fd" does not get closed
2436 // after "fd" goes out of scope after this block.
2437 // "fd" will be closed when "dumpstate_fds" goes out of scope
2438 // i.e. when we exit this function
Wei Wang587eac92018-04-05 12:17:20 -07002439 }
2440
Hunter Knepshield8540faf2020-02-04 19:47:20 -08002441 // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
2442 // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
2443 // will kill the HAL and grab whatever it dumped in time.
Michael Eastwood8523ea02022-03-10 16:33:08 -08002444 constexpr size_t timeout_sec = 45;
Wei Wang587eac92018-04-05 12:17:20 -07002445
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002446 if (dumpstate_hal_handle_aidl != nullptr) {
2447 DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
2448 timeout_sec);
2449 } else if (dumpstate_hal_handle_hidl_1_0 != nullptr) {
2450 // run HIDL HAL only if AIDL HAL not found
2451 DoDumpstateBoardHidl(dumpstate_hal_handle_hidl_1_0, dumpstate_fds, options_->bugreport_mode,
2452 timeout_sec);
Wei Wang587eac92018-04-05 12:17:20 -07002453 }
2454
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002455 if (mount_debugfs) {
Hridya Valsaraju51101602021-04-02 14:32:46 -07002456 auto keep_debugfs_mounted =
2457 android::base::GetProperty("persist.dbg.keep_debugfs_mounted", "");
2458 if (keep_debugfs_mounted.empty())
2459 RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20);
Hridya Valsaraju9376bfa2020-10-21 15:48:48 -07002460 }
2461
Wei Wang587eac92018-04-05 12:17:20 -07002462 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
2463 for (size_t i = 0; i < paths.size(); i++) {
2464 struct stat s;
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002465 if (fstat(dumpstate_fds[i].get(), &s) == -1) {
2466 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), strerror(errno));
Wei Wang587eac92018-04-05 12:17:20 -07002467 file_sizes[i] = -1;
2468 continue;
2469 }
2470 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07002471 }
2472
2473 for (size_t i = 0; i < paths.size(); i++) {
2474 if (file_sizes[i] == -1) {
2475 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07002476 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07002477 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07002478 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07002479 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07002480 }
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08002481 remover[i].Disable();
2482 EnqueueAddZipEntryAndCleanupIfNeeded(kDumpstateBoardFiles[i], paths[i]);
2483 dprintf(out_fd, "*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
Jie Song9fbfad02017-06-20 16:29:42 -07002484 }
Felipe Leme6f674ae2016-11-18 17:10:33 -08002485}
2486
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002487static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07002488 fprintf(stderr,
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002489 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-p] "
2490 "[-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07002491 " -h: display this help message\n"
2492 " -b: play sound file instead of vibrate, at beginning of job\n"
2493 " -e: play sound file instead of vibrate, at end of job\n"
mhasank2d75c442020-06-11 15:05:25 -07002494 " -o: write to custom directory (only in limited mode)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01002495 " -p: capture screenshot to filename.png\n"
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002496 " -s: write zipped file to control socket (for init)\n"
2497 " -S: write file location to control socket (for init)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07002498 " -q: disable vibrate\n"
Abhijeet Kaure370d682019-10-01 16:49:30 +01002499 " -P: send broadcast when started and do progress updates\n"
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002500 " -R: take bugreport in remote mode (shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00002501 " -w: start binder service and make it wait for a call to startBugreport\n"
mhasankd451a472020-05-26 18:02:39 -07002502 " -L: output limited information that is safe for submission in feedback reports\n"
Felipe Lemed071c682016-10-20 16:48:00 -07002503 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002504}
2505
Wei Liuf87959e2016-08-26 14:51:42 -07002506static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07002507 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07002508}
2509
Felipe Leme1d486fe2016-10-14 18:06:47 -07002510bool Dumpstate::FinishZipFile() {
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08002511 // Runs all enqueued adding zip entry and cleanup tasks before finishing the zip file.
2512 if (zip_entry_tasks_) {
2513 zip_entry_tasks_->run(/* do_cancel = */false);
2514 }
2515
Felipe Leme9a523ae2016-10-20 15:10:33 -07002516 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07002517 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07002518 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07002519 // Final timestamp
2520 char date[80];
2521 time_t the_real_now_please_stand_up = time(nullptr);
2522 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002523 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07002524 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07002525
Felipe Leme9a523ae2016-10-20 15:10:33 -07002526 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08002527 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08002528 return false;
2529 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07002530 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08002531 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08002532 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08002533 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08002534
Felipe Leme0f3fb202016-06-10 17:10:53 -07002535 // Add log file (which contains stderr output) to zip...
2536 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07002537 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07002538 MYLOGE("Failed to add dumpstate log to .zip file\n");
2539 return false;
2540 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002541 // TODO: Should truncate the existing file.
2542 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00002543 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
2544 return false;
2545 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07002546 fprintf(stderr, "\n");
2547
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07002548 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07002549 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07002550 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002551 return false;
2552 }
2553
Felipe Leme1d486fe2016-10-14 18:06:47 -07002554 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
2555 ds.zip_file.reset(nullptr);
2556
Felipe Lemee9d2c542016-11-15 11:48:26 -08002557 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002558 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07002559
Felipe Leme1e9edc62015-12-21 16:02:13 -08002560 return true;
2561}
Felipe Leme6e01fa62015-11-11 19:35:14 -08002562
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002563static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2564 // clang-format off
2565 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2566 "--receiver-foreground", "--receiver-include-background", "-a", action};
2567 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002568
2569 am.insert(am.end(), args.begin(), args.end());
2570
Felipe Leme8d2410e2017-02-08 09:46:08 -08002571 RunCommand("", am,
2572 CommandOptions::WithTimeout(20)
2573 .Log("Sending broadcast: '%s'\n")
2574 .Always()
2575 .DropRoot()
2576 .RedirectStderr()
2577 .Build());
2578}
2579
Felipe Leme35b8cf12017-02-10 15:47:29 -08002580static void Vibrate(int duration_ms) {
2581 // clang-format off
Lais Andrade51156962021-02-22 19:21:35 +00002582 std::vector<std::string> args = {"cmd", "vibrator_manager", "synced", "-f", "-d", "dumpstate",
2583 "oneshot", std::to_string(duration_ms)};
2584 RunCommand("", args,
Felipe Leme35b8cf12017-02-10 15:47:29 -08002585 CommandOptions::WithTimeout(10)
2586 .Log("Vibrate: '%s'\n")
2587 .Always()
2588 .Build());
2589 // clang-format on
2590}
2591
Nandana Dutt979388e2018-11-30 16:48:55 +00002592static void MaybeResolveSymlink(std::string* path) {
2593 std::string resolved_path;
2594 if (android::base::Readlink(*path, &resolved_path)) {
2595 *path = resolved_path;
2596 }
2597}
2598
Nandana Dutt4be45d12018-09-26 15:04:23 +01002599/*
2600 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002601 * and adds the version file. Return false if zip_file could not be open to write.
Nandana Dutt4be45d12018-09-26 15:04:23 +01002602 */
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002603static bool PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002604 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2605
Nandana Dutt4be45d12018-09-26 15:04:23 +01002606 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2607 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002608 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002609 char date[80];
2610 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2611 ds.name_ = date;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002612
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002613 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002614 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002615 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002616 ds.base_name_ += "-wifi";
2617 }
2618
Paul Chang0d2aad72020-02-13 20:04:03 +08002619 if (ds.options_->do_screenshot) {
Nandana Dutt9d17b942020-03-26 10:02:59 +00002620 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-png.tmp" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002621 }
2622 ds.tmp_path_ = ds.GetPath(".tmp");
2623 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2624
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002625 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00002626 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002627 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002628 MYLOGD(
Nandana Dutt235c6672019-11-14 15:22:32 +00002629 "Bugreport dir: [%s] "
2630 "Base name: [%s] "
2631 "Suffix: [%s] "
2632 "Log path: [%s] "
2633 "Temporary path: [%s] "
2634 "Screenshot path: [%s]\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002635 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2636 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002637
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002638 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
2639 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2640 create_parent_dirs(ds.path_.c_str());
2641 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2642 if (ds.zip_file == nullptr) {
2643 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2644 return false;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002645 }
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002646 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2647 ds.AddTextZipEntry("version.txt", ds.version_);
2648 return true;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002649}
2650
2651/*
Abhijeet Kaure370d682019-10-01 16:49:30 +01002652 * Finalizes writing to the file by zipping the tmp file to the final location,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002653 * printing zipped file status, etc.
2654 */
2655static void FinalizeFile() {
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002656 bool do_text_file = !ds.FinishZipFile();
2657 if (do_text_file) {
2658 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002659 }
mhasank2d75c442020-06-11 15:05:25 -07002660
2661 std::string final_path = ds.path_;
2662 if (ds.options_->OutputToCustomFile()) {
mhasank3a4cfb42020-06-15 18:06:43 -07002663 final_path = ds.GetPath(ds.options_->out_dir, ".zip");
mhasank2d75c442020-06-11 15:05:25 -07002664 android::os::CopyFileToFile(ds.path_, final_path);
2665 }
2666
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002667 if (ds.options_->stream_to_socket) {
2668 android::os::CopyFileToFd(ds.path_, ds.control_socket_fd_);
2669 } else if (ds.options_->progress_updates_to_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002670 if (do_text_file) {
2671 dprintf(ds.control_socket_fd_,
2672 "FAIL:could not create zip file, check %s "
2673 "for more details\n",
2674 ds.log_path_.c_str());
2675 } else {
mhasank2d75c442020-06-11 15:05:25 -07002676 dprintf(ds.control_socket_fd_, "OK:%s\n", final_path.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002677 }
2678 }
2679}
2680
Nandana Dutt4be45d12018-09-26 15:04:23 +01002681
Nandana Dutt58d72e22018-11-16 10:30:48 +00002682static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2683 switch (mode) {
2684 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2685 return "BUGREPORT_FULL";
2686 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2687 return "BUGREPORT_INTERACTIVE";
2688 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2689 return "BUGREPORT_REMOTE";
2690 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2691 return "BUGREPORT_WEAR";
2692 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2693 return "BUGREPORT_TELEPHONY";
2694 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2695 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002696 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2697 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002698 }
2699}
2700
Paul Changf59c2b72020-03-10 02:08:55 +08002701static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options,
2702 bool is_screenshot_requested) {
Paul Chang0d2aad72020-02-13 20:04:03 +08002703 // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
2704 // default system screenshots.
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002705 options->bugreport_mode = mode;
2706 options->bugreport_mode_string = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002707 switch (mode) {
2708 case Dumpstate::BugreportMode::BUGREPORT_FULL:
Paul Changf59c2b72020-03-10 02:08:55 +08002709 options->do_screenshot = is_screenshot_requested;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002710 break;
2711 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002712 // Currently, the dumpstate binder is only used by Shell to update progress.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002713 options->do_progress_updates = true;
Paul Changf59c2b72020-03-10 02:08:55 +08002714 options->do_screenshot = is_screenshot_requested;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002715 break;
2716 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002717 options->do_vibrate = false;
2718 options->is_remote_mode = true;
Paul Chang0d2aad72020-02-13 20:04:03 +08002719 options->do_screenshot = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002720 break;
2721 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002722 options->do_progress_updates = true;
Paul Changf59c2b72020-03-10 02:08:55 +08002723 options->do_screenshot = is_screenshot_requested;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002724 break;
Hunter Knepshield8540faf2020-02-04 19:47:20 -08002725 // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
Nandana Dutt58d72e22018-11-16 10:30:48 +00002726 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002727 options->telephony_only = true;
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002728 options->do_progress_updates = true;
Paul Chang0d2aad72020-02-13 20:04:03 +08002729 options->do_screenshot = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002730 break;
2731 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002732 options->wifi_only = true;
Paul Chang0d2aad72020-02-13 20:04:03 +08002733 options->do_screenshot = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002734 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002735 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2736 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002737 }
2738}
2739
Nandana Dutt58d72e22018-11-16 10:30:48 +00002740static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
Nandana Dutt235c6672019-11-14 15:22:32 +00002741 MYLOGI(
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002742 "do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
Rhed Jao25f50e02020-08-20 00:10:32 +08002743 "is_remote_mode: %d show_header_only: %d telephony_only: %d "
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002744 "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s "
mhasankd451a472020-05-26 18:02:39 -07002745 "limited_only: %d args: %s\n",
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002746 options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
Paul Chang0d2aad72020-02-13 20:04:03 +08002747 options.do_screenshot, options.is_remote_mode, options.show_header_only,
Rhed Jao25f50e02020-08-20 00:10:32 +08002748 options.telephony_only, options.wifi_only,
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002749 options.do_progress_updates, options.bugreport_fd.get(),
2750 options.bugreport_mode_string.c_str(),
2751 options.limited_only, options.args.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002752}
2753
Nandana Dutt54dbd672019-01-11 12:58:05 +00002754void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2755 const android::base::unique_fd& bugreport_fd_in,
Paul Changf59c2b72020-03-10 02:08:55 +08002756 const android::base::unique_fd& screenshot_fd_in,
2757 bool is_screenshot_requested) {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002758 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
Todd Frederick621533f2022-03-26 02:54:17 +00002759 bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
2760 screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002761
Paul Changf59c2b72020-03-10 02:08:55 +08002762 SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002763}
2764
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002765Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2766 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002767 int c;
mhasankd451a472020-05-26 18:02:39 -07002768 while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002769 switch (c) {
2770 // clang-format off
mhasank3a4cfb42020-06-15 18:06:43 -07002771 case 'o': out_dir = optarg; break;
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002772 case 's': stream_to_socket = true; break;
2773 case 'S': progress_updates_to_socket = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002774 case 'v': show_header_only = true; break;
2775 case 'q': do_vibrate = false; break;
Paul Chang0d2aad72020-02-13 20:04:03 +08002776 case 'p': do_screenshot = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002777 case 'P': do_progress_updates = true; break;
2778 case 'R': is_remote_mode = true; break;
mhasankd451a472020-05-26 18:02:39 -07002779 case 'L': limited_only = true; break;
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002780 case 'V':
2781 case 'd':
2782 case 'z':
2783 // compatibility no-op
2784 break;
Nandana Dutt235864b2019-01-22 12:10:16 +00002785 case 'w':
2786 // This was already processed
2787 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002788 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002789 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002790 break;
2791 default:
2792 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002793 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002794 break;
2795 // clang-format on
2796 }
2797 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002798
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002799 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002800 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002801 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002802 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002803 }
2804 }
2805
2806 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2807 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002808
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002809 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002810}
2811
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002812bool Dumpstate::DumpOptions::ValidateOptions() const {
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002813 if (bugreport_fd.get() != -1 && stream_to_socket) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002814 return false;
2815 }
2816
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002817 if ((progress_updates_to_socket || do_progress_updates) && stream_to_socket) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002818 return false;
2819 }
2820
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002821 if (is_remote_mode && (do_progress_updates || stream_to_socket)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002822 return false;
2823 }
2824 return true;
2825}
2826
Nandana Dutt197661d2018-11-16 16:40:21 +00002827void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2828 options_ = std::move(options);
2829}
2830
Abhijeet Kaura407fb82020-03-27 12:51:12 +00002831void Dumpstate::Initialize() {
2832 /* gets the sequential id */
2833 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
2834 id_ = ++last_id;
2835 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2836}
2837
Nandana Duttd2f5f082019-01-18 17:13:52 +00002838Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2839 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002840 if (listener_ != nullptr) {
2841 switch (status) {
2842 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002843 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002844 break;
2845 case Dumpstate::RunStatus::HELP:
2846 break;
2847 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002848 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002849 break;
2850 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002851 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2852 break;
2853 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2854 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2855 break;
2856 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2857 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002858 break;
2859 }
2860 }
2861 return status;
2862}
2863
Nandana Dutt8ae16e62020-03-27 10:20:22 +00002864void Dumpstate::Cancel() {
2865 CleanupTmpFiles();
2866 android::os::UnlinkAndLogOnError(log_path_);
2867 for (int i = 0; i < NUM_OF_DUMPS; i++) {
2868 android::os::UnlinkAndLogOnError(ds.bugreport_internal_dir_ + "/" +
2869 kDumpstateBoardFiles[i]);
2870 }
2871 tombstone_data_.clear();
2872 anr_data_.clear();
Rhed Jao0daac912020-08-21 14:48:20 +08002873
2874 // Instead of shutdown the pool, we delete temporary files directly since
2875 // shutdown blocking the call.
2876 if (dump_pool_) {
2877 dump_pool_->deleteTempFiles();
2878 }
2879 if (zip_entry_tasks_) {
2880 zip_entry_tasks_->run(/*do_cancel =*/ true);
2881 }
Nandana Dutt8ae16e62020-03-27 10:20:22 +00002882}
2883
Nandana Dutt979388e2018-11-30 16:48:55 +00002884/*
2885 * Dumps relevant information to a bugreport based on the given options.
2886 *
2887 * The bugreport can be dumped to a file or streamed to a socket.
2888 *
2889 * How dumping to file works:
2890 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2891 * stderr is redirected a log file.
2892 *
2893 * The temporary bugreport is then populated via printfs, dumping contents of files and
2894 * output of commands to stdout.
2895 *
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002896 * A bunch of other files and dumps are added to the zip archive.
Nandana Dutt979388e2018-11-30 16:48:55 +00002897 *
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002898 * The temporary bugreport file and the log file also get added to the archive.
Nandana Dutt979388e2018-11-30 16:48:55 +00002899 *
mhasank2d75c442020-06-11 15:05:25 -07002900 * Bugreports are first generated in a local directory and later copied to the caller's fd
2901 * or directory if supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002902 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002903Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2904 const std::string& calling_package) {
Rhed Jao5377d792020-07-16 17:37:39 +08002905 DurationReporter duration_reporter("RUN INTERNAL", /* logcat_only = */true);
Nandana Dutt979388e2018-11-30 16:48:55 +00002906 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002907 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002908 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002909 return RunStatus::INVALID_INPUT;
2910 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002911 /* set as high priority, and protect from OOM killer */
2912 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002913
Felipe Lemed071c682016-10-20 16:48:00 -07002914 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002915 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002916 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002917 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002918 } else {
2919 /* fallback to kernels <= 2.6.35 */
2920 oom_adj = fopen("/proc/self/oom_adj", "we");
2921 if (oom_adj) {
2922 fputs("-17", oom_adj);
2923 fclose(oom_adj);
2924 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002925 }
2926
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002927 if (version_ == VERSION_DEFAULT) {
2928 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002929 }
2930
Chris Morin5a50d482022-02-01 17:41:18 -08002931 if (version_ != VERSION_CURRENT) {
2932 MYLOGE("invalid version requested ('%s'); supported values are: ('%s', '%s')\n",
2933 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002934 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002935 }
2936
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002937 if (options_->show_header_only) {
2938 PrintHeader();
2939 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002940 }
2941
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002942 MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
2943 calling_uid, calling_package.c_str());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002944
Felipe Leme7447d7c2016-11-03 18:12:22 -07002945 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002946 std::string stats_path =
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002947 android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002948 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002949
Sahana Raof35ed432019-07-12 10:47:52 +01002950 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2951 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2952 } else {
2953 // Wake lock will be released automatically on process death
2954 MYLOGD("Wake lock acquired.\n");
2955 }
2956
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002957 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002958
Felipe Lemef0292972016-11-22 13:57:05 -08002959 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002960 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2961 }
2962
Nandana Dutt235c6672019-11-14 15:22:32 +00002963 MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
Kedar Chitnis9fd8c052021-11-16 09:09:22 +00002964 id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002965
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002966 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002967
Christopher Ferrised9354f2014-10-01 17:35:01 -07002968 // If we are going to use a socket, do it as early as possible
2969 // to avoid timeouts from bugreport.
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002970 if (options_->stream_to_socket || options_->progress_updates_to_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002971 MYLOGD("Opening control socket\n");
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002972 control_socket_fd_ = open_socket_fn_("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002973 if (control_socket_fd_ == -1) {
2974 return ERROR;
2975 }
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002976 if (options_->progress_updates_to_socket) {
2977 options_->do_progress_updates = 1;
2978 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07002979 }
2980
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002981 if (!PrepareToWriteToFile()) {
2982 return ERROR;
2983 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08002984
Dieter Hsu105ad0c2020-09-29 15:23:33 +08002985 // Interactive, wear & telephony modes are default to true.
2986 // and may enable from cli option or when using control socket
2987 if (options_->do_progress_updates) {
2988 // clang-format off
2989 std::vector<std::string> am_args = {
2990 "--receiver-permission", "android.permission.DUMP",
2991 };
2992 // clang-format on
2993 // Send STARTED broadcast for apps that listen to bugreport generation events
2994 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
2995 if (options_->progress_updates_to_socket) {
2996 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08002997 }
2998 }
2999
Nick Kralevichf3599b32016-01-25 15:05:16 -08003000 /* read /proc/cmdline before dropping root */
3001 FILE *cmdline = fopen("/proc/cmdline", "re");
3002 if (cmdline) {
3003 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
3004 fclose(cmdline);
3005 }
3006
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003007 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08003008 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05003009 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07003010
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003011 if (zip_file != nullptr) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003012 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
3013 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003014 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08003015 }
3016 }
3017
Nandana Dutt3f8c7172018-09-25 12:01:54 +01003018 int dup_stdout_fd;
3019 int dup_stderr_fd;
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003020 // Redirect stderr to log_path_ for debugging.
3021 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
3022 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
3023 return ERROR;
3024 }
3025 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
3026 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
3027 strerror(errno));
3028 }
Nandana Dutt979388e2018-11-30 16:48:55 +00003029
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003030 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
3031 // moved into zip file later, if zipping.
3032 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
3033 // TODO: why not write to a file instead of stdout to overcome this problem?
3034 /* TODO: rather than generating a text file now and zipping it later,
3035 it would be more efficient to redirect stdout to the zip entry
3036 directly, but the libziparchive doesn't support that option yet. */
3037 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
3038 return ERROR;
3039 }
3040 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
3041 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
3042 tmp_path_.c_str(), strerror(errno));
Colin Crossf45fa6b2012-03-26 12:38:26 -07003043 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08003044
3045 // Don't buffer stdout
3046 setvbuf(stdout, nullptr, _IONBF, 0);
3047
Rhed Jao5377d792020-07-16 17:37:39 +08003048 // Enable the parallel run if the client requests to output to a file.
3049 EnableParallelRunIfNeeded();
3050 // Using scope guard to make sure the dump pool can be shut down correctly.
3051 auto scope_guard_to_shutdown_pool = android::base::make_scope_guard([=]() {
3052 ShutdownDumpPool();
3053 });
3054
Felipe Leme608385d2016-02-01 10:35:38 -08003055 // NOTE: there should be no stdout output until now, otherwise it would break the header.
3056 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08003057 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003058 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07003059
Gavin Corkery6968f552020-11-22 18:09:05 +00003060 bool is_dumpstate_restricted = options_->telephony_only
3061 || options_->wifi_only
3062 || options_->limited_only;
3063 if (!is_dumpstate_restricted) {
Paul Chang0d2aad72020-02-13 20:04:03 +08003064 // Invoke critical dumpsys first to preserve system state, before doing anything else.
Jichao Lie89d9c12019-11-21 19:02:51 -08003065 RunDumpsysCritical();
Gavin Corkery6968f552020-11-22 18:09:05 +00003066 }
3067 MaybeTakeEarlyScreenshot();
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00003068
3069 if (!is_dumpstate_restricted) {
3070 // Snapshot the system trace now (if running) to avoid that dumpstate's
3071 // own activity pushes out interesting data from the trace ring buffer.
3072 // The trace file is added to the zip by MaybeAddSystemTraceToZip().
3073 MaybeSnapshotSystemTrace();
Yohei Yukawa95305b32021-03-09 07:54:27 -08003074
3075 // If a winscope trace is running, snapshot it now. It will be pulled into bugreport later
3076 // from WMTRACE_DATA_DIR.
3077 MaybeSnapshotWinTrace();
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00003078 }
Gavin Corkery6968f552020-11-22 18:09:05 +00003079 onUiIntensiveBugreportDumpsFinished(calling_uid);
3080 MaybeCheckUserConsent(calling_uid, calling_package);
3081 if (options_->telephony_only) {
3082 DumpstateTelephonyOnly(calling_package);
3083 } else if (options_->wifi_only) {
3084 DumpstateWifiOnly();
3085 } else if (options_->limited_only) {
3086 DumpstateLimitedOnly();
3087 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01003088 // Dump state for the default case. This also drops root.
Jichao Lie89d9c12019-11-21 19:02:51 -08003089 RunStatus s = DumpstateDefaultAfterCritical();
Nandana Dutt5c390032019-03-12 10:52:56 +00003090 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01003091 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00003092 HandleUserConsentDenied();
3093 }
3094 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08003095 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07003096 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07003097
Felipe Leme55b42a62015-11-10 17:39:08 -08003098 /* close output if needed */
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003099 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07003100
Abhijeet Kaure370d682019-10-01 16:49:30 +01003101 // Zip the (now complete) .tmp file within the internal directory.
Kevin Jeon2c02e8e2022-07-07 21:45:17 +00003102 ATRACE_BEGIN("FinalizeFile");
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003103 FinalizeFile();
Kevin Jeon2c02e8e2022-07-07 21:45:17 +00003104 ATRACE_END();
Colin Crossf45fa6b2012-03-26 12:38:26 -07003105
Abhijeet Kaur3172b532019-10-15 15:07:03 +01003106 // Share the final file with the caller if the user has consented or Shell is the caller.
Nandana Duttd2f5f082019-01-18 17:13:52 +00003107 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
Abhijeet Kaure370d682019-10-01 16:49:30 +01003108 if (CalledByApi()) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01003109 status = CopyBugreportIfUserConsented(calling_uid);
Nandana Duttd2f5f082019-01-18 17:13:52 +00003110 if (status != Dumpstate::RunStatus::OK &&
3111 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
3112 // Do an early return if there were errors. We make an exception for consent
3113 // timing out because it's possible the user got distracted. In this case the
3114 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00003115 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00003116 return status;
3117 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00003118 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
3119 MYLOGI(
3120 "Did not receive user consent yet."
3121 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01003122 const String16 incidentcompanion("incidentcompanion");
3123 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
3124 if (ics != nullptr) {
3125 MYLOGD("Canceling user consent request via incidentcompanion service\n");
3126 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
3127 consent_callback_.get());
3128 } else {
3129 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
3130 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00003131 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003132 }
3133
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08003134 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003135 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09003136 for (int i = 0; i < 3; i++) {
3137 Vibrate(75);
3138 usleep((75 + 50) * 1000);
3139 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08003140 }
3141
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003142 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
3143 progress_->GetInitialMax());
3144 progress_->Save();
3145 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07003146
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003147 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08003148
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003149 if (control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07003150 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003151 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07003152 }
3153
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003154 tombstone_data_.clear();
3155 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01003156
Nandana Duttd2f5f082019-01-18 17:13:52 +00003157 return (consent_callback_ != nullptr &&
3158 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
3159 ? USER_CONSENT_TIMED_OUT
3160 : RunStatus::OK;
3161}
3162
Paul Chang0d2aad72020-02-13 20:04:03 +08003163void Dumpstate::MaybeTakeEarlyScreenshot() {
3164 if (!options_->do_screenshot || !do_early_screenshot_) {
3165 return;
3166 }
3167
3168 TakeScreenshot();
3169}
3170
Primiano Tuccifaaaafb2021-01-14 12:26:29 +00003171void Dumpstate::MaybeSnapshotSystemTrace() {
3172 // If a background system trace is happening and is marked as "suitable for
3173 // bugreport" (i.e. bugreport_score > 0 in the trace config), this command
3174 // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely)
3175 // case that no trace is ongoing, this command is a no-op.
3176 // Note: this should not be enqueued as we need to freeze the trace before
3177 // dumpstate starts. Otherwise the trace ring buffers will contain mostly
3178 // the dumpstate's own activity which is irrelevant.
3179 int res = RunCommand(
3180 "SERIALIZE PERFETTO TRACE",
3181 {"perfetto", "--save-for-bugreport"},
3182 CommandOptions::WithTimeout(10)
3183 .DropRoot()
3184 .CloseAllFileDescriptorsOnExec()
3185 .Build());
3186 has_system_trace_ = res == 0;
3187 // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
3188 // file in the later stages.
3189}
3190
Yohei Yukawa95305b32021-03-09 07:54:27 -08003191void Dumpstate::MaybeSnapshotWinTrace() {
Yohei Yukawa02b1d2c2021-03-16 09:20:30 -07003192 // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol.
3193 for (const auto& service : {"window", "input_method"}) {
3194 RunCommand(
3195 // Empty name because it's not intended to be classified as a bugreport section.
3196 // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
3197 "", {"cmd", service, "tracing", "save-for-bugreport"},
3198 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3199 }
Yohei Yukawa95305b32021-03-09 07:54:27 -08003200}
3201
Paul Changeb4b4642020-05-28 22:05:47 +08003202void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
Paul Changc490e662020-04-11 18:14:09 +08003203 if (calling_uid == AID_SHELL || !CalledByApi()) {
3204 return;
3205 }
3206 if (listener_ != nullptr) {
3207 // Let listener know ui intensive bugreport dumps are finished, then it can do event
3208 // handling if required.
Paul Changeb4b4642020-05-28 22:05:47 +08003209 listener_->onUiIntensiveBugreportDumpsFinished();
Paul Changc490e662020-04-11 18:14:09 +08003210 }
3211}
3212
Jichao Lie89d9c12019-11-21 19:02:51 -08003213void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
3214 if (calling_uid == AID_SHELL || !CalledByApi()) {
3215 // No need to get consent for shell triggered dumpstates, or not through
3216 // bugreporting API (i.e. no fd to copy back).
Abhijeet Kaur3172b532019-10-15 15:07:03 +01003217 return;
3218 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003219 consent_callback_ = new ConsentCallback();
3220 const String16 incidentcompanion("incidentcompanion");
3221 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
Jichao Lie89d9c12019-11-21 19:02:51 -08003222 android::String16 package(calling_package.c_str());
Nandana Duttd2f5f082019-01-18 17:13:52 +00003223 if (ics != nullptr) {
3224 MYLOGD("Checking user consent via incidentcompanion service\n");
3225 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Jichao Lie89d9c12019-11-21 19:02:51 -08003226 calling_uid, package, String16(), String16(),
Joe Onorato1c36d752019-03-17 18:26:43 -07003227 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00003228 } else {
3229 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
3230 }
3231}
3232
Nandana Dutt5c390032019-03-12 10:52:56 +00003233bool Dumpstate::IsUserConsentDenied() const {
3234 return ds.consent_callback_ != nullptr &&
3235 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
3236}
3237
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01003238bool Dumpstate::CalledByApi() const {
3239 return ds.options_->bugreport_fd.get() != -1 ? true : false;
3240}
3241
Nandana Dutt8ae16e62020-03-27 10:20:22 +00003242void Dumpstate::CleanupTmpFiles() {
Nandana Duttd2f5f082019-01-18 17:13:52 +00003243 android::os::UnlinkAndLogOnError(tmp_path_);
3244 android::os::UnlinkAndLogOnError(screenshot_path_);
3245 android::os::UnlinkAndLogOnError(path_);
Gavin Corkery789d7a52021-02-24 23:52:35 +00003246 if (dump_traces_path != nullptr) {
3247 android::os::UnlinkAndLogOnError(dump_traces_path);
3248 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003249}
3250
Rhed Jao5377d792020-07-16 17:37:39 +08003251void Dumpstate::EnableParallelRunIfNeeded() {
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003252 if (!PropertiesHelper::IsParallelRun()) {
Rhed Jao5377d792020-07-16 17:37:39 +08003253 return;
3254 }
3255 dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08003256 zip_entry_tasks_ = std::make_unique<TaskQueue>();
Rhed Jao5377d792020-07-16 17:37:39 +08003257}
3258
3259void Dumpstate::ShutdownDumpPool() {
3260 if (dump_pool_) {
Chris Morinbc223142022-02-04 14:17:11 -08003261 dump_pool_.reset();
Rhed Jao5377d792020-07-16 17:37:39 +08003262 }
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08003263 if (zip_entry_tasks_) {
3264 zip_entry_tasks_->run(/* do_cancel = */true);
3265 zip_entry_tasks_ = nullptr;
3266 }
3267}
3268
3269void Dumpstate::EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
3270 const std::string& entry_path) {
3271 auto func_add_zip_entry_and_cleanup = [=](bool task_cancelled) {
3272 if (!task_cancelled) {
3273 AddZipEntry(entry_name, entry_path);
3274 }
3275 android::os::UnlinkAndLogOnError(entry_path);
3276 };
3277 if (zip_entry_tasks_) {
3278 // Enqueues AddZipEntryAndCleanup function if the parallel run is enabled.
3279 zip_entry_tasks_->add(func_add_zip_entry_and_cleanup, _1);
3280 } else {
3281 // Invokes AddZipEntryAndCleanup immediately
3282 std::invoke(func_add_zip_entry_and_cleanup, /* task_cancelled = */false);
3283 }
Rhed Jao5377d792020-07-16 17:37:39 +08003284}
3285
Nandana Duttd2f5f082019-01-18 17:13:52 +00003286Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
3287 MYLOGD("User denied consent; deleting files and returning\n");
Nandana Dutt8ae16e62020-03-27 10:20:22 +00003288 CleanupTmpFiles();
Nandana Duttd2f5f082019-01-18 17:13:52 +00003289 return USER_CONSENT_DENIED;
3290}
3291
Abhijeet Kaur3172b532019-10-15 15:07:03 +01003292Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00003293 // If the caller has asked to copy the bugreport over to their directory, we need explicit
Abhijeet Kaur3172b532019-10-15 15:07:03 +01003294 // user consent (unless the caller is Shell).
3295 UserConsentResult consent_result;
3296 if (calling_uid == AID_SHELL) {
3297 consent_result = UserConsentResult::APPROVED;
3298 } else {
3299 consent_result = consent_callback_->getResult();
3300 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003301 if (consent_result == UserConsentResult::UNAVAILABLE) {
3302 // User has not responded yet.
3303 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
Hunter Knepshield70610fa2020-01-03 15:27:33 -08003304 // Telephony is a fast report type, particularly on user builds where information may be
3305 // more aggressively limited. To give the user time to read the consent dialog, increase the
3306 // timeout.
3307 uint64_t timeout_ms = options_->telephony_only ? TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS
3308 : USER_CONSENT_TIMEOUT_MS;
3309 if (elapsed_ms < timeout_ms) {
3310 uint delay_seconds = (timeout_ms - elapsed_ms) / 1000;
Nandana Duttd2f5f082019-01-18 17:13:52 +00003311 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
3312 sleep(delay_seconds);
3313 }
3314 consent_result = consent_callback_->getResult();
3315 }
3316 if (consent_result == UserConsentResult::DENIED) {
3317 // User has explicitly denied sharing with the app. To be safe delete the
3318 // internal bugreport & tmp files.
3319 return HandleUserConsentDenied();
3320 }
3321 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00003322 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
3323 if (copy_succeeded) {
3324 android::os::UnlinkAndLogOnError(path_);
Abhijeet Kaur9ce94672020-04-01 17:22:36 +01003325 if (options_->do_screenshot &&
3326 options_->screenshot_fd.get() != -1 &&
3327 !options_->is_screenshot_copied) {
3328 copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
3329 options_->screenshot_fd.get());
3330 options_->is_screenshot_copied = copy_succeeded;
3331 if (copy_succeeded) {
3332 android::os::UnlinkAndLogOnError(screenshot_path_);
3333 }
3334 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003335 }
3336 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
3337 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
3338 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
3339 // Since we do not have user consent to share the bugreport it does not get
3340 // copied over to the calling app but remains in the internal directory from
3341 // where the user can manually pull it.
Paul Changce644212021-05-11 16:06:45 +08003342 std::string final_path = GetPath(".zip");
3343 bool copy_succeeded = android::os::CopyFileToFile(path_, final_path);
3344 if (copy_succeeded) {
3345 android::os::UnlinkAndLogOnError(path_);
3346 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00003347 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
3348 }
3349 // Unknown result; must be a programming error.
3350 MYLOGE("Unknown user consent result:%d\n", consent_result);
3351 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003352}
3353
Nandana Duttf02564e2019-02-15 15:24:24 +00003354Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003355 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
3356 Dumpstate::RunStatus status = options->Initialize(argc, argv);
3357 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00003358 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00003359 // When directly running dumpstate binary, the output is not expected to be written
3360 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00003361 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00003362
3363 // calling_uid and calling_package are for user consent to share the bugreport with
Abhijeet Kaura407fb82020-03-27 12:51:12 +00003364 // an app; they are irrelevant here because bugreport is triggered via command line.
3365 // Update Last ID before calling Run().
3366 Initialize();
Nandana Duttf02564e2019-02-15 15:24:24 +00003367 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003368 }
Nandana Duttf02564e2019-02-15 15:24:24 +00003369 return status;
3370}
3371
3372/* Main entry point for dumpstate binary. */
3373int run_main(int argc, char* argv[]) {
3374 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003375
3376 switch (status) {
3377 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00003378 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003379 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00003380 ShowUsage();
3381 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003382 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00003383 fprintf(stderr, "Invalid combination of args\n");
3384 ShowUsage();
3385 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003386 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00003387 FALLTHROUGH_INTENDED;
3388 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
3389 FALLTHROUGH_INTENDED;
3390 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00003391 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01003392 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07003393}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003394
3395// TODO(111441001): Default DumpOptions to sensible values.
3396Dumpstate::Dumpstate(const std::string& version)
3397 : pid_(getpid()),
3398 options_(new Dumpstate::DumpOptions()),
Nandana Dutt402a8392019-06-14 14:25:13 +01003399 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003400 version_(version),
Dieter Hsu105ad0c2020-09-29 15:23:33 +08003401 now_(time(nullptr)),
3402 open_socket_fn_(open_socket) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003403}
3404
3405Dumpstate& Dumpstate::GetInstance() {
3406 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
3407 return singleton_;
3408}
3409
Rhed Jao5377d792020-07-16 17:37:39 +08003410DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose,
3411 int duration_fd) : title_(title), logcat_only_(logcat_only), verbose_(verbose),
3412 duration_fd_(duration_fd) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003413 if (!title_.empty()) {
3414 started_ = Nanotime();
Kevin Jeon2c02e8e2022-07-07 21:45:17 +00003415 if (title_.find("SHOW MAP") == std::string::npos) {
3416 ATRACE_ASYNC_BEGIN(title_.c_str(), 0);
3417 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003418 }
3419}
3420
3421DurationReporter::~DurationReporter() {
3422 if (!title_.empty()) {
3423 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
chenqiwuaf8b2d92019-12-12 18:53:51 +08003424 if (elapsed >= .5f || verbose_) {
3425 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003426 }
chenqiwuaf8b2d92019-12-12 18:53:51 +08003427 if (!logcat_only_) {
3428 // Use "Yoda grammar" to make it easier to grep|sort sections.
Rhed Jao5377d792020-07-16 17:37:39 +08003429 dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
3430 elapsed, title_.c_str());
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003431 }
Kevin Jeon2c02e8e2022-07-07 21:45:17 +00003432 if (title_.find("SHOW MAP") == std::string::npos) {
3433 ATRACE_ASYNC_END(title_.c_str(), 0);
3434 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003435 }
3436}
3437
3438const int32_t Progress::kDefaultMax = 5000;
3439
3440Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
3441}
3442
3443Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
3444 : Progress(initial_max, growth_factor, "") {
3445 progress_ = progress;
3446}
3447
3448Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
3449 : initial_max_(initial_max),
3450 progress_(0),
3451 max_(initial_max),
3452 growth_factor_(growth_factor),
3453 n_runs_(0),
3454 average_max_(0),
3455 path_(path) {
3456 if (!path_.empty()) {
3457 Load();
3458 }
3459}
3460
3461void Progress::Load() {
3462 MYLOGD("Loading stats from %s\n", path_.c_str());
3463 std::string content;
3464 if (!android::base::ReadFileToString(path_, &content)) {
3465 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
3466 return;
3467 }
3468 if (content.empty()) {
3469 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
3470 return;
3471 }
3472 std::vector<std::string> lines = android::base::Split(content, "\n");
3473
3474 if (lines.size() < 1) {
3475 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
3476 (int)lines.size(), max_);
3477 return;
3478 }
3479 char* ptr;
3480 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
3481 average_max_ = strtol(ptr, nullptr, 10);
3482 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
3483 average_max_ > STATS_MAX_AVERAGE) {
3484 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
3485 initial_max_ = Progress::kDefaultMax;
3486 } else {
3487 initial_max_ = average_max_;
3488 }
3489 max_ = initial_max_;
3490
3491 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
3492}
3493
3494void Progress::Save() {
3495 int32_t total = n_runs_ * average_max_ + progress_;
3496 int32_t runs = n_runs_ + 1;
3497 int32_t average = floor(((float)total) / runs);
3498 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
3499 path_.c_str());
3500 if (path_.empty()) {
3501 return;
3502 }
3503
3504 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
3505 if (!android::base::WriteStringToFile(content, path_)) {
3506 MYLOGE("Could not save stats on %s\n", path_.c_str());
3507 }
3508}
3509
3510int32_t Progress::Get() const {
3511 return progress_;
3512}
3513
3514bool Progress::Inc(int32_t delta_sec) {
3515 bool changed = false;
3516 if (delta_sec >= 0) {
3517 progress_ += delta_sec;
3518 if (progress_ > max_) {
3519 int32_t old_max = max_;
3520 max_ = floor((float)progress_ * growth_factor_);
3521 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
3522 changed = true;
3523 }
3524 }
3525 return changed;
3526}
3527
3528int32_t Progress::GetMax() const {
3529 return max_;
3530}
3531
3532int32_t Progress::GetInitialMax() const {
3533 return initial_max_;
3534}
3535
3536void Progress::Dump(int fd, const std::string& prefix) const {
3537 const char* pr = prefix.c_str();
3538 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3539 dprintf(fd, "%smax: %d\n", pr, max_);
3540 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3541 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3542 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3543 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3544 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3545}
3546
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003547std::string Dumpstate::GetPath(const std::string& suffix) const {
3548 return GetPath(bugreport_internal_dir_, suffix);
3549}
3550
3551std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3552 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3553 name_.c_str(), suffix.c_str());
3554}
3555
3556void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3557 progress_ = std::move(progress);
3558}
3559
3560void for_each_userid(void (*func)(int), const char *header) {
3561 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3562 "for_each_userid(%s)", header);
3563 DurationReporter duration_reporter(title);
3564 if (PropertiesHelper::IsDryRun()) return;
3565
3566 DIR *d;
3567 struct dirent *de;
3568
3569 if (header) printf("\n------ %s ------\n", header);
3570 func(0);
3571
3572 if (!(d = opendir("/data/system/users"))) {
3573 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3574 return;
3575 }
3576
3577 while ((de = readdir(d))) {
3578 int userid;
3579 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3580 continue;
3581 }
3582 func(userid);
3583 }
3584
3585 closedir(d);
3586}
3587
3588static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3589 DIR *d;
3590 struct dirent *de;
3591
3592 if (!(d = opendir("/proc"))) {
3593 printf("Failed to open /proc (%s)\n", strerror(errno));
3594 return;
3595 }
3596
3597 if (header) printf("\n------ %s ------\n", header);
3598 while ((de = readdir(d))) {
3599 if (ds.IsUserConsentDenied()) {
3600 MYLOGE(
3601 "Returning early because user denied consent to share bugreport with calling app.");
3602 closedir(d);
3603 return;
3604 }
3605 int pid;
3606 int fd;
3607 char cmdpath[255];
3608 char cmdline[255];
3609
3610 if (!(pid = atoi(de->d_name))) {
3611 continue;
3612 }
3613
3614 memset(cmdline, 0, sizeof(cmdline));
3615
3616 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3617 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3618 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3619 close(fd);
3620 if (cmdline[0]) {
3621 helper(pid, cmdline, arg);
3622 continue;
3623 }
3624 }
3625
3626 // if no cmdline, a kernel thread has comm
3627 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3628 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3629 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3630 close(fd);
3631 if (cmdline[1]) {
3632 cmdline[0] = '[';
3633 size_t len = strcspn(cmdline, "\f\b\r\n");
3634 cmdline[len] = ']';
3635 cmdline[len+1] = '\0';
3636 }
3637 }
3638 if (!cmdline[0]) {
3639 strcpy(cmdline, "N/A");
3640 }
3641 helper(pid, cmdline, arg);
3642 }
3643
3644 closedir(d);
3645}
3646
3647static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3648 for_each_pid_func *func = (for_each_pid_func*) arg;
3649 func(pid, cmdline);
3650}
3651
3652void for_each_pid(for_each_pid_func func, const char *header) {
3653 std::string title = header == nullptr ? "for_each_pid"
3654 : android::base::StringPrintf("for_each_pid(%s)", header);
3655 DurationReporter duration_reporter(title);
3656 if (PropertiesHelper::IsDryRun()) return;
3657
3658 __for_each_pid(for_each_pid_helper, header, (void *) func);
3659}
3660
3661static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3662 DIR *d;
3663 struct dirent *de;
3664 char taskpath[255];
3665 for_each_tid_func *func = (for_each_tid_func *) arg;
3666
3667 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3668
3669 if (!(d = opendir(taskpath))) {
3670 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3671 return;
3672 }
3673
3674 func(pid, pid, cmdline);
3675
3676 while ((de = readdir(d))) {
3677 if (ds.IsUserConsentDenied()) {
3678 MYLOGE(
3679 "Returning early because user denied consent to share bugreport with calling app.");
3680 closedir(d);
3681 return;
3682 }
3683 int tid;
3684 int fd;
3685 char commpath[255];
3686 char comm[255];
3687
3688 if (!(tid = atoi(de->d_name))) {
3689 continue;
3690 }
3691
3692 if (tid == pid)
3693 continue;
3694
3695 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3696 memset(comm, 0, sizeof(comm));
3697 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3698 strcpy(comm, "N/A");
3699 } else {
3700 char *c;
3701 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3702 close(fd);
3703
3704 c = strrchr(comm, '\n');
3705 if (c) {
3706 *c = '\0';
3707 }
3708 }
3709 func(pid, tid, comm);
3710 }
3711
3712 closedir(d);
3713}
3714
3715void for_each_tid(for_each_tid_func func, const char *header) {
3716 std::string title = header == nullptr ? "for_each_tid"
3717 : android::base::StringPrintf("for_each_tid(%s)", header);
3718 DurationReporter duration_reporter(title);
3719
3720 if (PropertiesHelper::IsDryRun()) return;
3721
3722 __for_each_pid(for_each_tid_helper, header, (void *) func);
3723}
3724
3725void show_wchan(int pid, int tid, const char *name) {
3726 if (PropertiesHelper::IsDryRun()) return;
3727
3728 char path[255];
3729 char buffer[255];
3730 int fd, ret, save_errno;
3731 char name_buffer[255];
3732
3733 memset(buffer, 0, sizeof(buffer));
3734
3735 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3736 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3737 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3738 return;
3739 }
3740
3741 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3742 save_errno = errno;
3743 close(fd);
3744
3745 if (ret < 0) {
3746 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3747 return;
3748 }
3749
3750 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3751 pid == tid ? 0 : 3, "", name);
3752
3753 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3754
3755 return;
3756}
3757
3758// print time in centiseconds
3759static void snprcent(char *buffer, size_t len, size_t spc,
3760 unsigned long long time) {
3761 static long hz; // cache discovered hz
3762
3763 if (hz <= 0) {
3764 hz = sysconf(_SC_CLK_TCK);
3765 if (hz <= 0) {
3766 hz = 1000;
3767 }
3768 }
3769
3770 // convert to centiseconds
3771 time = (time * 100 + (hz / 2)) / hz;
3772
3773 char str[16];
3774
3775 snprintf(str, sizeof(str), " %llu.%02u",
3776 time / 100, (unsigned)(time % 100));
3777 size_t offset = strlen(buffer);
3778 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3779 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3780}
3781
3782// print permille as a percent
3783static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3784 char str[16];
3785
3786 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3787 size_t offset = strlen(buffer);
3788 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3789 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3790}
3791
3792void show_showtime(int pid, const char *name) {
3793 if (PropertiesHelper::IsDryRun()) return;
3794
3795 char path[255];
3796 char buffer[1023];
3797 int fd, ret, save_errno;
3798
3799 memset(buffer, 0, sizeof(buffer));
3800
3801 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3802 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3803 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3804 return;
3805 }
3806
3807 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3808 save_errno = errno;
3809 close(fd);
3810
3811 if (ret < 0) {
3812 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3813 return;
3814 }
3815
3816 // field 14 is utime
3817 // field 15 is stime
3818 // field 42 is iotime
3819 unsigned long long utime = 0, stime = 0, iotime = 0;
3820 if (sscanf(buffer,
3821 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3822 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3823 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3824 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3825 &utime, &stime, &iotime) != 3) {
3826 return;
3827 }
3828
3829 unsigned long long total = utime + stime;
3830 if (!total) {
3831 return;
3832 }
3833
3834 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3835 if (permille > 1000) {
3836 permille = 1000;
3837 }
3838
3839 // try to beautify and stabilize columns at <80 characters
3840 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3841 if ((name[0] != '[') || utime) {
3842 snprcent(buffer, sizeof(buffer), 57, utime);
3843 }
3844 snprcent(buffer, sizeof(buffer), 65, stime);
3845 if ((name[0] != '[') || iotime) {
3846 snprcent(buffer, sizeof(buffer), 73, iotime);
3847 }
3848 if (iotime) {
3849 snprdec(buffer, sizeof(buffer), 79, permille);
3850 }
3851 puts(buffer); // adds a trailing newline
3852
3853 return;
3854}
3855
3856void do_dmesg() {
3857 const char *title = "KERNEL LOG (dmesg)";
3858 DurationReporter duration_reporter(title);
3859 printf("------ %s ------\n", title);
3860
3861 if (PropertiesHelper::IsDryRun()) return;
3862
3863 /* Get size of kernel buffer */
3864 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3865 if (size <= 0) {
3866 printf("Unexpected klogctl return value: %d\n\n", size);
3867 return;
3868 }
3869 char *buf = (char *) malloc(size + 1);
3870 if (buf == nullptr) {
3871 printf("memory allocation failed\n\n");
3872 return;
3873 }
3874 int retval = klogctl(KLOG_READ_ALL, buf, size);
3875 if (retval < 0) {
3876 printf("klogctl failure\n\n");
3877 free(buf);
3878 return;
3879 }
3880 buf[retval] = '\0';
3881 printf("%s\n\n", buf);
3882 free(buf);
3883 return;
3884}
3885
3886void do_showmap(int pid, const char *name) {
3887 char title[255];
3888 char arg[255];
3889
3890 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3891 snprintf(arg, sizeof(arg), "%d", pid);
3892 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3893}
3894
3895int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3896 DurationReporter duration_reporter(title);
3897
3898 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3899
3900 UpdateProgress(WEIGHT_FILE);
3901
3902 return status;
3903}
3904
3905int read_file_as_long(const char *path, long int *output) {
3906 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3907 if (fd < 0) {
3908 int err = errno;
3909 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3910 return -1;
3911 }
3912 char buffer[50];
3913 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3914 if (bytes_read == -1) {
3915 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3916 return -2;
3917 }
3918 if (bytes_read == 0) {
3919 MYLOGE("File %s is empty\n", path);
3920 return -3;
3921 }
3922 *output = atoi(buffer);
3923 return 0;
3924}
3925
3926/* calls skip to gate calling dump_from_fd recursively
3927 * in the specified directory. dump_from_fd defaults to
3928 * dump_file_from_fd above when set to NULL. skip defaults
3929 * to false when set to NULL. dump_from_fd will always be
3930 * called with title NULL.
3931 */
3932int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3933 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3934 DurationReporter duration_reporter(title);
3935 DIR *dirp;
3936 struct dirent *d;
3937 char *newpath = nullptr;
3938 const char *slash = "/";
3939 int retval = 0;
3940
3941 if (!title.empty()) {
3942 printf("------ %s (%s) ------\n", title.c_str(), dir);
3943 }
3944 if (PropertiesHelper::IsDryRun()) return 0;
3945
3946 if (dir[strlen(dir) - 1] == '/') {
3947 ++slash;
3948 }
3949 dirp = opendir(dir);
3950 if (dirp == nullptr) {
3951 retval = -errno;
3952 MYLOGE("%s: %s\n", dir, strerror(errno));
3953 return retval;
3954 }
3955
3956 if (!dump_from_fd) {
3957 dump_from_fd = dump_file_from_fd;
3958 }
3959 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3960 if ((d->d_name[0] == '.')
3961 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3962 || (d->d_name[1] == '\0'))) {
3963 continue;
3964 }
3965 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3966 (d->d_type == DT_DIR) ? "/" : "");
3967 if (!newpath) {
3968 retval = -errno;
3969 continue;
3970 }
3971 if (skip && (*skip)(newpath)) {
3972 continue;
3973 }
3974 if (d->d_type == DT_DIR) {
3975 int ret = dump_files("", newpath, skip, dump_from_fd);
3976 if (ret < 0) {
3977 retval = ret;
3978 }
3979 continue;
3980 }
3981 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3982 if (fd.get() < 0) {
3983 retval = -1;
3984 printf("*** %s: %s\n", newpath, strerror(errno));
3985 continue;
3986 }
3987 (*dump_from_fd)(nullptr, newpath, fd.get());
3988 }
3989 closedir(dirp);
3990 if (!title.empty()) {
3991 printf("\n");
3992 }
3993 return retval;
3994}
3995
3996/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3997 * it's possible to avoid issues where opening the file itself can get
3998 * stuck.
3999 */
4000int dump_file_from_fd(const char *title, const char *path, int fd) {
4001 if (PropertiesHelper::IsDryRun()) return 0;
4002
4003 int flags = fcntl(fd, F_GETFL);
4004 if (flags == -1) {
4005 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
4006 return -1;
4007 } else if (!(flags & O_NONBLOCK)) {
4008 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
4009 return -1;
4010 }
4011 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
4012}
4013
4014int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08004015 const CommandOptions& options, bool verbose_duration, int out_fd) {
4016 DurationReporter duration_reporter(title, false /* logcat_only */,
4017 verbose_duration, out_fd);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004018
Rhed Jao3c2fdbd2020-07-20 17:46:29 +08004019 int status = RunCommandToFd(out_fd, title, full_command, options);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004020
4021 /* TODO: for now we're simplifying the progress calculation by using the
4022 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
4023 * where its weight should be much higher proportionally to its timeout.
4024 * Ideally, it should use a options.EstimatedDuration() instead...*/
4025 UpdateProgress(options.Timeout());
4026
4027 return status;
4028}
4029
4030void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
Rhed Jaoe017f982020-07-21 17:58:41 +08004031 const CommandOptions& options, long dumpsysTimeoutMs, int out_fd) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004032 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
4033 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
4034 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
Rhed Jaoe017f982020-07-21 17:58:41 +08004035 RunCommand(title, dumpsys, options, false, out_fd);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004036}
4037
Dieter Hsu105ad0c2020-09-29 15:23:33 +08004038static int open_socket(const char* service) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004039 int s = android_get_control_socket(service);
4040 if (s < 0) {
4041 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
4042 return -1;
4043 }
4044 fcntl(s, F_SETFD, FD_CLOEXEC);
4045
4046 // Set backlog to 0 to make sure that queue size will be minimum.
4047 // In Linux, because the minimum queue will be 1, connect() will be blocked
4048 // if the other clients already called connect() and the connection request was not accepted.
4049 if (listen(s, 0) < 0) {
4050 MYLOGE("listen(control socket): %s\n", strerror(errno));
4051 return -1;
4052 }
4053
4054 struct sockaddr addr;
4055 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01004056 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004057
4058 // Close socket just after accept(), to make sure that connect() by client will get error
4059 // when the socket is used by the other services.
4060 // There is still a race condition possibility between accept and close, but there is no way
4061 // to close-on-accept atomically.
4062 // See detail; b/123306389#comment25
4063 close(s);
4064
4065 if (fd < 0) {
4066 MYLOGE("accept(control socket): %s\n", strerror(errno));
4067 return -1;
4068 }
4069
4070 return fd;
4071}
4072
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004073// TODO: should call is_valid_output_file and/or be merged into it.
4074void create_parent_dirs(const char *path) {
4075 char *chp = const_cast<char *> (path);
4076
4077 /* skip initial slash */
4078 if (chp[0] == '/')
4079 chp++;
4080
4081 /* create leading directories, if necessary */
4082 struct stat dir_stat;
4083 while (chp && chp[0]) {
4084 chp = strchr(chp, '/');
4085 if (chp) {
4086 *chp = 0;
4087 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
4088 MYLOGI("Creating directory %s\n", path);
4089 if (mkdir(path, 0770)) { /* drwxrwx--- */
4090 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
4091 } else if (chown(path, AID_SHELL, AID_SHELL)) {
4092 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
4093 }
4094 }
4095 *chp++ = '/';
4096 }
4097 }
4098}
4099
4100bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
4101 create_parent_dirs(path);
4102
4103 int fd = TEMP_FAILURE_RETRY(open(path,
4104 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
4105 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
4106 if (fd < 0) {
4107 MYLOGE("%s: %s\n", path, strerror(errno));
4108 return false;
4109 }
4110
4111 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
4112 close(fd);
4113 return true;
4114}
4115
4116bool redirect_to_file(FILE* redirect, char* path) {
4117 return _redirect_to_file(redirect, path, O_TRUNC);
4118}
4119
4120bool redirect_to_existing_file(FILE* redirect, char* path) {
4121 return _redirect_to_file(redirect, path, O_APPEND);
4122}
4123
4124void dump_route_tables() {
4125 DurationReporter duration_reporter("DUMP ROUTE TABLES");
4126 if (PropertiesHelper::IsDryRun()) return;
4127 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
4128 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
4129 FILE* fp = fopen(RT_TABLES_PATH, "re");
4130 if (!fp) {
4131 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
4132 return;
4133 }
4134 char table[16];
4135 // Each line has an integer (the table number), a space, and a string (the table name). We only
4136 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
4137 // Add a fixed max limit so this doesn't go awry.
4138 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
4139 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
4140 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
4141 }
4142 fclose(fp);
4143}
4144
Li Li830179f2022-01-04 12:53:29 -08004145void dump_frozen_cgroupfs(const char *dir, int level,
4146 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
4147 DIR *dirp;
4148 struct dirent *d;
4149 char *newpath = nullptr;
4150
4151 dirp = opendir(dir);
4152 if (dirp == nullptr) {
4153 MYLOGE("%s: %s\n", dir, strerror(errno));
4154 return;
4155 }
4156
4157 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
4158 if ((d->d_name[0] == '.')
4159 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
4160 || (d->d_name[1] == '\0'))) {
4161 continue;
4162 }
4163 if (d->d_type == DT_DIR) {
4164 asprintf(&newpath, "%s/%s/", dir, d->d_name);
4165 if (!newpath) {
4166 continue;
4167 }
4168 if (level == 0 && !strncmp(d->d_name, "uid_", 4)) {
4169 dump_frozen_cgroupfs(newpath, 1, dump_from_fd);
4170 } else if (level == 1 && !strncmp(d->d_name, "pid_", 4)) {
4171 char *freezer = nullptr;
4172 asprintf(&freezer, "%s/%s", newpath, "cgroup.freeze");
4173 if (freezer) {
4174 FILE* fp = fopen(freezer, "r");
4175 if (fp != NULL) {
4176 int frozen;
4177 fscanf(fp, "%d", &frozen);
4178 if (frozen > 0) {
4179 dump_files("", newpath, skip_none, dump_from_fd);
4180 }
4181 fclose(fp);
4182 }
4183 free(freezer);
4184 }
4185 }
4186 }
4187 }
4188 closedir(dirp);
4189}
4190
4191void dump_frozen_cgroupfs() {
Li Li830179f2022-01-04 12:53:29 -08004192 MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR);
4193 DurationReporter duration_reporter("FROZEN CGROUPFS");
4194 if (PropertiesHelper::IsDryRun()) return;
4195 dump_frozen_cgroupfs(CGROUPFS_DIR, 0, _add_file_from_fd);
4196}
4197
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004198void Dumpstate::UpdateProgress(int32_t delta_sec) {
4199 if (progress_ == nullptr) {
4200 MYLOGE("UpdateProgress: progress_ not set\n");
4201 return;
4202 }
Rhed Jaobf63d8a2020-07-21 15:42:55 +08004203 // This function updates progress related members of the dumpstate and reports
4204 // progress percentage to the bugreport client. Since it could be called by
4205 // different dump tasks at the same time if the parallel run is enabled, a
4206 // mutex lock is necessary here to synchronize the call.
4207 std::lock_guard<std::recursive_mutex> lock(mutex_);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004208
4209 // Always update progess so stats can be tuned...
Nandana Dutt402a8392019-06-14 14:25:13 +01004210 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004211
4212 // ...but only notifiy listeners when necessary.
4213 if (!options_->do_progress_updates) return;
4214
4215 int progress = progress_->Get();
4216 int max = progress_->GetMax();
Nandana Dutt402a8392019-06-14 14:25:13 +01004217 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004218
Nandana Dutt402a8392019-06-14 14:25:13 +01004219 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004220 return;
4221 }
Nandana Dutt402a8392019-06-14 14:25:13 +01004222 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004223
4224 if (control_socket_fd_ >= 0) {
4225 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
4226 fsync(control_socket_fd_);
4227 }
4228
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004229 if (listener_ != nullptr) {
Nandana Dutt235c6672019-11-14 15:22:32 +00004230 if (percent % 10 == 0) {
4231 // We don't want to spam logcat, so only log multiples of 10.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01004232 MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004233 } else {
4234 // stderr is ignored on normal invocations, but useful when calling
4235 // /system/bin/dumpstate directly for debuggging.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01004236 fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004237 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004238
4239 listener_->onProgress(percent);
4240 }
4241}
4242
4243void Dumpstate::TakeScreenshot(const std::string& path) {
4244 const std::string& real_path = path.empty() ? screenshot_path_ : path;
4245 int status =
4246 RunCommand("", {"/system/bin/screencap", "-p", real_path},
4247 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
4248 if (status == 0) {
4249 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
4250 } else {
4251 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
4252 }
Paul Chang0d2aad72020-02-13 20:04:03 +08004253 if (listener_ != nullptr) {
4254 // Show a visual indication to indicate screenshot is taken via
4255 // IDumpstateListener.onScreenshotTaken()
4256 listener_->onScreenshotTaken(status == 0);
4257 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01004258}
4259
4260bool is_dir(const char* pathname) {
4261 struct stat info;
4262 if (stat(pathname, &info) == -1) {
4263 return false;
4264 }
4265 return S_ISDIR(info.st_mode);
4266}
4267
4268time_t get_mtime(int fd, time_t default_mtime) {
4269 struct stat info;
4270 if (fstat(fd, &info) == -1) {
4271 return default_mtime;
4272 }
4273 return info.st_mtime;
4274}