blob: 8e0f8a35d62f0929c9aed86ed59d5a7bfe47e35f [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"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010022#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010025#include <math.h>
26#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080031#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010037#include <signal.h>
38#include <stdarg.h>
39#include <string.h>
40#include <sys/capability.h>
41#include <sys/inotify.h>
42#include <sys/klog.h>
43#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070045
46#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070047#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000048#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070049#include <functional>
50#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010051#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070052#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <regex>
54#include <set>
55#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070056#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010057#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070058
Felipe Leme96c2bbb2016-09-26 09:21:21 -070059#include <android-base/file.h>
60#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070061#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080062#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070063#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070064#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010065#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080066#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080067#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000068#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010069#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080070#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070071#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010072#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080074#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000075#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010076#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080077#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010078#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070079#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070080#include <private/android_filesystem_config.h>
81#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070083#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080084#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070085#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070086#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080087
Steven Morelandcb7ef822016-11-29 13:20:37 -080088using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080089using ::std::literals::chrono_literals::operator""ms;
90using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080091
Felipe Leme47e9be22016-12-21 15:37:07 -080092// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080093using android::defaultServiceManager;
94using android::Dumpsys;
95using android::INVALID_OPERATION;
96using android::IServiceManager;
97using android::OK;
98using android::sp;
99using android::status_t;
100using android::String16;
101using android::String8;
102using android::TIMED_OUT;
103using android::UNKNOWN_ERROR;
104using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000105using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000106using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107using android::os::dumpstate::CommandOptions;
108using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100124}
125
126// Reasonable value for max stats.
127static const int STATS_MAX_N_RUNS = 1000;
128static const long STATS_MAX_AVERAGE = 100000;
129
130CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
Nandana Duttd2f5f082019-01-18 17:13:52 +0000132typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134/* read before root is shed */
135static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700136static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000137static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Hunter Knepshield70610fa2020-01-03 15:27:33 -0800138// Because telephony reports are significantly faster to collect (< 10 seconds vs. > 2 minutes),
139// it's often the case that they time out far too quickly for consent with such a hefty dialog for
140// the user to read. For telephony reports only, we increase the default timeout to 2 minutes to
141// roughly match full reports' durations.
142static const uint64_t TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS = 2 * 60 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700143
Felipe Leme1d486fe2016-10-14 18:06:47 -0700144// TODO: variables and functions below should be part of dumpstate object
145
Felipe Leme635ca312016-01-05 14:23:02 -0800146static std::set<std::string> mount_points;
147void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800148
Todd Poynor2a83daa2013-11-22 15:44:22 -0800149#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700150#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700151#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800152
Felipe Lemee82a27d2016-01-05 13:35:44 -0800153#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700154#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700155#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700156#define LOGPERSIST_DATA_DIR "/data/misc/logd"
Jerry Changa1df8a92020-01-02 16:03:39 +0800157#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
David Brazdild2991962016-06-03 14:40:44 +0100158#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
159#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800160#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900161#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800162#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Yifan Hong3945e1b2019-10-29 12:59:23 -0700163#define OTA_METADATA_DIR "/metadata/ota"
Yifan Hong0efa7972020-02-03 16:45:02 -0800164#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
Kiyoung Kimc2d22ac2020-02-04 19:43:36 +0900165#define LINKERCONFIG_DIR "/linkerconfig"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700166
Narayan Kamath8f788292017-05-25 13:20:39 +0100167// TODO(narayan): Since this information has to be kept in sync
168// with tombstoned, we should just put it in a common header.
169//
170// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100171static const std::string TOMBSTONE_DIR = "/data/tombstones/";
172static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
173static const std::string ANR_DIR = "/data/anr/";
174static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700175
Felipe Lemee844a9d2016-09-21 15:01:39 -0700176// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000177
Nandana Dutt5c390032019-03-12 10:52:56 +0000178#define RETURN_IF_USER_DENIED_CONSENT() \
179 if (ds.IsUserConsentDenied()) { \
180 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
181 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
182 }
183
184// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
185// if consent is found to be denied.
186#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
187 RETURN_IF_USER_DENIED_CONSENT(); \
188 func_ptr(__VA_ARGS__); \
189 RETURN_IF_USER_DENIED_CONSENT();
190
Sahana Raof35ed432019-07-12 10:47:52 +0100191static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
192
Nandana Dutt979388e2018-11-30 16:48:55 +0000193namespace android {
194namespace os {
195namespace {
196
197static int Open(std::string path, int flags, mode_t mode = 0) {
198 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
199 if (fd == -1) {
200 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
201 }
202 return fd;
203}
204
Nandana Dutt979388e2018-11-30 16:48:55 +0000205
206static int OpenForRead(std::string path) {
207 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
208}
209
210bool CopyFile(int in_fd, int out_fd) {
211 char buf[4096];
212 ssize_t byte_count;
213 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
214 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
215 return false;
216 }
217 }
218 return (byte_count != -1);
219}
220
221static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000222 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000223
224 // Obtain a handle to the source file.
225 android::base::unique_fd in_fd(OpenForRead(input_file));
226 if (out_fd != -1 && in_fd.get() != -1) {
227 if (CopyFile(in_fd.get(), out_fd)) {
228 return true;
229 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000230 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000231 }
232 return false;
233}
234
Nandana Duttd2f5f082019-01-18 17:13:52 +0000235static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000236 if (unlink(file.c_str())) {
237 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000238 return false;
239 }
240 return true;
241}
Nandana Dutt979388e2018-11-30 16:48:55 +0000242
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000243
Nikita Ioffea325a572019-05-16 19:49:47 +0100244int64_t GetModuleMetadataVersion() {
245 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
246 if (binder == nullptr) {
247 MYLOGE("Failed to retrieve package_native service");
248 return 0L;
249 }
250 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
251 std::string package_name;
252 auto status = package_service->getModuleMetadataPackageName(&package_name);
253 if (!status.isOk()) {
254 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
255 return 0L;
256 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100257 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100258 int64_t version_code;
259 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
260 &version_code);
261 if (!status.isOk()) {
262 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
263 return 0L;
264 }
265 return version_code;
266}
267
Nandana Dutt979388e2018-11-30 16:48:55 +0000268} // namespace
269} // namespace os
270} // namespace android
271
Felipe Leme678727a2016-09-21 17:22:11 -0700272static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800273 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800274 long dumpsysTimeoutMs = 0) {
275 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700276}
277static int DumpFile(const std::string& title, const std::string& path) {
278 return ds.DumpFile(title, path);
279}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800280
Felipe Lemee844a9d2016-09-21 15:01:39 -0700281// Relative directory (inside the zip) for all files copied as-is into the bugreport.
282static const std::string ZIP_ROOT_DIR = "FS";
283
Vishnu Naire97d6122018-01-18 13:58:56 -0800284static const std::string kProtoPath = "proto/";
285static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700286static const std::string kDumpstateBoardFiles[] = {
287 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700288 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700289};
290static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
291
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700292static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700293static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700294
Felipe Lemef0292972016-11-22 13:57:05 -0800295static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
296
Narayan Kamath8f788292017-05-25 13:20:39 +0100297/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100298 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
299 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
300 * is set, the vector only contains files that were written in the last 30 minutes.
Narayan Kamath8f788292017-05-25 13:20:39 +0100301 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700302static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
303 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700304 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100305 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
306
Narayan Kamathbd863722017-06-01 18:50:12 +0100307 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100308
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700309 if (dump_dir == nullptr) {
310 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700311 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700312 }
313
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700314 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100315 struct dirent* entry = nullptr;
316 while ((entry = readdir(dump_dir.get()))) {
317 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100318 continue;
319 }
320
Narayan Kamathbd863722017-06-01 18:50:12 +0100321 const std::string base_name(entry->d_name);
322 if (base_name.find(file_prefix) != 0) {
323 continue;
324 }
325
326 const std::string abs_path = dir_path + base_name;
327 android::base::unique_fd fd(
328 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
329 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700330 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100331 break;
332 }
333
334 struct stat st = {};
335 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700336 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100337 continue;
338 }
339
Narayan Kamath3f31b632018-02-22 19:42:36 +0000340 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100341 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100342 continue;
343 }
344
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700345 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700346 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100347
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700348 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100349}
350
Narayan Kamathbd863722017-06-01 18:50:12 +0100351static bool AddDumps(const std::vector<DumpData>::const_iterator start,
352 const std::vector<DumpData>::const_iterator end,
353 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100354 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100355 for (auto it = start; it != end; ++it) {
356 const std::string& name = it->name;
357 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100358 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100359
360 // Seek to the beginning of the file before dumping any data. A given
361 // DumpData entry might be dumped multiple times in the report.
362 //
363 // For example, the most recent ANR entry is dumped to the body of the
364 // main entry and it also shows up as a separate entry in the bugreport
365 // ZIP file.
366 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
367 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
368 strerror(errno));
369 }
370
Narayan Kamath8f788292017-05-25 13:20:39 +0100371 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800372 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100373 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100374 }
375 } else {
376 dump_file_from_fd(type_name, name.c_str(), fd);
377 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100378 }
379
380 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700381}
382
Felipe Leme635ca312016-01-05 14:23:02 -0800383// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700384void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800385 char path[PATH_MAX];
386
387 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
388 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700389 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800390 char linkname[PATH_MAX];
391 ssize_t r = readlink(path, linkname, PATH_MAX);
392 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800393 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800394 return;
395 }
396 linkname[r] = '\0';
397
398 if (mount_points.find(linkname) == mount_points.end()) {
399 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700400 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700401 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800402 mount_points.insert(linkname);
403 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800404 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800405 }
406 }
407}
408
409void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700410 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700411 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800412 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800413 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700414 for_each_pid(do_mountinfo, nullptr);
415 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800416}
417
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700418static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
419{
420 DIR *d;
421 struct dirent *de;
422 char path[PATH_MAX];
423
424 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700425 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700426 return;
427 }
428
429 while ((de = readdir(d))) {
430 if (de->d_type != DT_LNK) {
431 continue;
432 }
433 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700434 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700435 }
436
437 closedir(d);
438}
439
Mark Salyzyn326842f2015-04-30 09:49:41 -0700440static bool skip_not_stat(const char *path) {
441 static const char stat[] = "/stat";
442 size_t len = strlen(path);
443 if (path[len - 1] == '/') { /* Directory? */
444 return false;
445 }
446 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
447}
448
Felipe Leme4c2d6632016-09-28 14:32:00 -0700449static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800450 return false;
451}
452
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700453unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700454
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800455//
456// stat offsets
457// Name units description
458// ---- ----- -----------
459// read I/Os requests number of read I/Os processed
460#define __STAT_READ_IOS 0
461// read merges requests number of read I/Os merged with in-queue I/O
462#define __STAT_READ_MERGES 1
463// read sectors sectors number of sectors read
464#define __STAT_READ_SECTORS 2
465// read ticks milliseconds total wait time for read requests
466#define __STAT_READ_TICKS 3
467// write I/Os requests number of write I/Os processed
468#define __STAT_WRITE_IOS 4
469// write merges requests number of write I/Os merged with in-queue I/O
470#define __STAT_WRITE_MERGES 5
471// write sectors sectors number of sectors written
472#define __STAT_WRITE_SECTORS 6
473// write ticks milliseconds total wait time for write requests
474#define __STAT_WRITE_TICKS 7
475// in_flight requests number of I/Os currently in flight
476#define __STAT_IN_FLIGHT 8
477// io_ticks milliseconds total time this block device has been active
478#define __STAT_IO_TICKS 9
479// time_in_queue milliseconds total wait time for all requests
480#define __STAT_IN_QUEUE 10
481#define __STAT_NUMBER_FIELD 11
482//
483// read I/Os, write I/Os
484// =====================
485//
486// These values increment when an I/O request completes.
487//
488// read merges, write merges
489// =========================
490//
491// These values increment when an I/O request is merged with an
492// already-queued I/O request.
493//
494// read sectors, write sectors
495// ===========================
496//
497// These values count the number of sectors read from or written to this
498// block device. The "sectors" in question are the standard UNIX 512-byte
499// sectors, not any device- or filesystem-specific block size. The
500// counters are incremented when the I/O completes.
501#define SECTOR_SIZE 512
502//
503// read ticks, write ticks
504// =======================
505//
506// These values count the number of milliseconds that I/O requests have
507// waited on this block device. If there are multiple I/O requests waiting,
508// these values will increase at a rate greater than 1000/second; for
509// example, if 60 read requests wait for an average of 30 ms, the read_ticks
510// field will increase by 60*30 = 1800.
511//
512// in_flight
513// =========
514//
515// This value counts the number of I/O requests that have been issued to
516// the device driver but have not yet completed. It does not include I/O
517// requests that are in the queue but not yet issued to the device driver.
518//
519// io_ticks
520// ========
521//
522// This value counts the number of milliseconds during which the device has
523// had I/O requests queued.
524//
525// time_in_queue
526// =============
527//
528// This value counts the number of milliseconds that I/O requests have waited
529// on this block device. If there are multiple I/O requests waiting, this
530// value will increase as the product of the number of milliseconds times the
531// number of requests waiting (see "read ticks" above for an example).
532#define S_TO_MS 1000
533//
534
Mark Salyzyn326842f2015-04-30 09:49:41 -0700535static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800536 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700537 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700538 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700539 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700540 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700541 getline(&buffer, &i, fp);
542 fclose(fp);
543 if (!buffer) {
544 return -errno;
545 }
546 i = strlen(buffer);
547 while ((i > 0) && (buffer[i - 1] == '\n')) {
548 buffer[--i] = '\0';
549 }
550 if (!*buffer) {
551 free(buffer);
552 return 0;
553 }
554 z = true;
555 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800556 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700557 if (fields[i] != 0) {
558 z = false;
559 }
560 }
561 if (z) { /* never accessed */
562 free(buffer);
563 return 0;
564 }
565
Wei Wang509bb5d2017-06-09 14:42:12 -0700566 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
567 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700568 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700569
570 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
571 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
572 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700573 free(buffer);
574
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800575 if (fields[__STAT_IO_TICKS]) {
576 unsigned long read_perf = 0;
577 unsigned long read_ios = 0;
578 if (fields[__STAT_READ_TICKS]) {
579 unsigned long long divisor = fields[__STAT_READ_TICKS]
580 * fields[__STAT_IO_TICKS];
581 read_perf = ((unsigned long long)SECTOR_SIZE
582 * fields[__STAT_READ_SECTORS]
583 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
584 / divisor;
585 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
586 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
587 / divisor;
588 }
589
590 unsigned long write_perf = 0;
591 unsigned long write_ios = 0;
592 if (fields[__STAT_WRITE_TICKS]) {
593 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
594 * fields[__STAT_IO_TICKS];
595 write_perf = ((unsigned long long)SECTOR_SIZE
596 * fields[__STAT_WRITE_SECTORS]
597 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
598 / divisor;
599 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
600 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
601 / divisor;
602 }
603
604 unsigned queue = (fields[__STAT_IN_QUEUE]
605 + (fields[__STAT_IO_TICKS] >> 1))
606 / fields[__STAT_IO_TICKS];
607
608 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700609 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 -0800610 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700611 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 -0800612 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800613 }
614
615 /* bugreport timeout factor adjustment */
616 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
617 worst_write_perf = write_perf;
618 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700619 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700620 return 0;
621}
622
Yao Chenbe3bbc12018-01-17 16:31:10 -0800623static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
624
625/* timeout in ms to read a list of buffers */
626static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
627 unsigned long timeout_ms = 0;
628 for (const auto& buffer : buffers) {
629 log_id_t id = android_name_to_log_id(buffer.c_str());
630 unsigned long property_size = __android_logger_get_buffer_size(id);
631 /* Engineering margin is ten-fold our guess */
632 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
633 }
634 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700635}
636
Nandana Duttd2f5f082019-01-18 17:13:52 +0000637Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
638}
639
640android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
641 std::lock_guard<std::mutex> lock(lock_);
642 result_ = APPROVED;
643 MYLOGD("User approved consent to share bugreport\n");
644 return android::binder::Status::ok();
645}
646
647android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
648 std::lock_guard<std::mutex> lock(lock_);
649 result_ = DENIED;
650 MYLOGW("User denied consent to share bugreport\n");
651 return android::binder::Status::ok();
652}
653
654UserConsentResult Dumpstate::ConsentCallback::getResult() {
655 std::lock_guard<std::mutex> lock(lock_);
656 return result_;
657}
658
659uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
Hunter Knepshieldf0a39052020-01-03 14:53:04 -0800660 return (Nanotime() - start_time_) / NANOS_PER_MILLI;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000661}
662
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700663void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700664 std::string build, fingerprint, radio, bootloader, network;
665 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700666
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700667 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
668 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700669 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
670 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
671 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700672 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700673
Felipe Lemed8b94e52016-12-08 10:21:44 -0800674 printf("========================================================\n");
675 printf("== dumpstate: %s\n", date);
676 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700677
Felipe Lemed8b94e52016-12-08 10:21:44 -0800678 printf("\n");
679 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700680 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800681 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
682 printf("Bootloader: %s\n", bootloader.c_str());
683 printf("Radio: %s\n", radio.c_str());
684 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100685 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
686 if (module_metadata_version != 0) {
687 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
688 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700689
Felipe Lemed8b94e52016-12-08 10:21:44 -0800690 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800691 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800692 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800693 printf("Uptime: ");
694 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
695 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800696 printf("Bugreport format version: %s\n", version_.c_str());
Abhijeet Kaure370d682019-10-01 16:49:30 +0100697 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
698 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800699 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800700}
701
Felipe Leme24b66ee2016-06-16 10:55:26 -0700702// List of file extensions that can cause a zip file attachment to be rejected by some email
703// service providers.
704static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
705 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
706 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
707 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
708};
709
Vishnu Naire97d6122018-01-18 13:58:56 -0800710status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
711 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700712 if (!IsZipping()) {
713 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
714 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800715 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800716 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700717 std::string valid_name = entry_name;
718
719 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700720 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700721 if (idx != std::string::npos) {
722 std::string extension = entry_name.substr(idx);
723 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
724 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
725 valid_name = entry_name + ".renamed";
726 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
727 }
728 }
729
Felipe Leme6fe9db62016-02-12 09:04:16 -0800730 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
731 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700732 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
733 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700734 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700735 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700736 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800737 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800738 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000739 bool finished_entry = false;
740 auto finish_entry = [this, &finished_entry] {
741 if (!finished_entry) {
742 // This should only be called when we're going to return an earlier error,
743 // which would've been logged. This may imply the file is already corrupt
744 // and any further logging from FinishEntry is more likely to mislead than
745 // not.
746 this->zip_writer_->FinishEntry();
747 }
748 };
749 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800750 auto start = std::chrono::steady_clock::now();
751 auto end = start + timeout;
752 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800753
Felipe Leme770410d2016-01-26 17:07:14 -0800754 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800755 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800756 if (timeout.count() > 0) {
757 // lambda to recalculate the timeout.
758 auto time_left_ms = [end]() {
759 auto now = std::chrono::steady_clock::now();
760 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
761 return std::max(diff.count(), 0LL);
762 };
763
764 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
765 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000766 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
767 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800768 return -errno;
769 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000770 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800771 entry_name.c_str(), strerror(errno), timeout.count());
772 return TIMED_OUT;
773 }
774 }
775
Zach Riggle22200402016-08-18 01:01:24 -0400776 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800777 if (bytes_read == 0) {
778 break;
779 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800780 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800781 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800782 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700783 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800784 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700785 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800786 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800787 }
788 }
789
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700790 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000791 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700792 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700793 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800794 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800795 }
796
Vishnu Naire97d6122018-01-18 13:58:56 -0800797 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800798}
799
Felipe Leme1d486fe2016-10-14 18:06:47 -0700800bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
801 android::base::unique_fd fd(
802 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700803 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800804 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800805 return false;
806 }
807
Vishnu Naire97d6122018-01-18 13:58:56 -0800808 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800809}
810
811/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700812static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800813 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800814}
815
Felipe Leme1d486fe2016-10-14 18:06:47 -0700816void Dumpstate::AddDir(const std::string& dir, bool recursive) {
817 if (!IsZipping()) {
818 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800819 return;
820 }
Felipe Leme678727a2016-09-21 17:22:11 -0700821 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800822 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700823 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800824}
825
Felipe Leme1d486fe2016-10-14 18:06:47 -0700826bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
827 if (!IsZipping()) {
828 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
829 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800830 return false;
831 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800832 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700833 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700834 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700835 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700836 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800837 return false;
838 }
839
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700840 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700841 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700842 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700843 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800844 return false;
845 }
846
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700847 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700848 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700849 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800850 return false;
851 }
852
853 return true;
854}
855
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800856static void DoKmsg() {
857 struct stat st;
858 if (!stat(PSTORE_LAST_KMSG, &st)) {
859 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
860 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
861 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
862 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
863 } else {
864 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
865 DumpFile("LAST KMSG", "/proc/last_kmsg");
866 }
867}
868
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800869static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800870 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800871 RunCommand(
872 "KERNEL LOG",
873 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
874 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
875}
876
Nandana Duttdb379fa2019-10-09 16:54:41 +0100877static void DoSystemLogcat(time_t since) {
878 char since_str[80];
879 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
880
881 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
882 RunCommand("SYSTEM LOG",
883 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
884 since_str},
885 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
886}
887
Hunter Knepshield820f9bc2020-02-05 20:10:53 -0800888static void DoRadioLogcat() {
889 unsigned long timeout_ms = logcat_timeout({"radio"});
890 RunCommand(
891 "RADIO LOG",
892 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
893 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
894}
895
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800896static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800897 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800898 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
899 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800900 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100901 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800902 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
903 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800904 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800905 RunCommand(
906 "EVENT LOG",
907 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100908 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800909 timeout_ms = logcat_timeout({"stats"});
910 RunCommand(
911 "STATS LOG",
912 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100913 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Hunter Knepshield820f9bc2020-02-05 20:10:53 -0800914 DoRadioLogcat();
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800915
916 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
917
918 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800919 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
920 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800921}
922
Mike Ma5c267872019-08-21 11:31:34 -0700923static void DumpIncidentReport() {
924 if (!ds.IsZipping()) {
925 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
926 return;
927 }
928 DurationReporter duration_reporter("INCIDENT REPORT");
929 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
930 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
931 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
932 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
933 if (fd < 0) {
934 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
935 return;
936 }
937 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
938 bool empty = 0 == lseek(fd, 0, SEEK_END);
939 if (!empty) {
940 // Use a different name from "incident.proto"
941 // /proto/incident.proto is reserved for incident service dump
942 // i.e. metadata for debugging.
943 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
944 }
945 unlink(path.c_str());
946}
947
Sunny Goyal35949782019-11-19 15:54:36 -0800948static void DumpVisibleWindowViews() {
949 if (!ds.IsZipping()) {
950 MYLOGD("Not dumping visible views because it's not a zipped bugreport\n");
951 return;
952 }
953 DurationReporter duration_reporter("VISIBLE WINDOW VIEWS");
954 const std::string path = ds.bugreport_internal_dir_ + "/tmp_visible_window_views";
955 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
956 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
957 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
958 if (fd < 0) {
959 MYLOGE("Could not open %s to dump visible views.\n", path.c_str());
960 return;
961 }
962 RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"},
963 CommandOptions::WithTimeout(120).Build());
964 bool empty = 0 == lseek(fd, 0, SEEK_END);
965 if (!empty) {
966 ds.AddZipEntry("visible_windows.zip", path);
967 } else {
968 MYLOGW("Failed to dump visible windows\n");
969 }
970 unlink(path.c_str());
971}
972
Jayachandran Ca94c7172017-06-10 15:08:12 -0700973static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700974 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
975 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900976 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700977 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900978 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
979 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
980 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
981 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700982}
983
David Andersond9ba4752018-12-11 18:26:59 -0800984static void DumpDynamicPartitionInfo() {
985 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
986 return;
987 }
988
989 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700990 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800991}
992
Narayan Kamath8f788292017-05-25 13:20:39 +0100993static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
994 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
995 anr_traces_dir.c_str());
996
997 // If we're here, dump_traces_path will always be a temporary file
998 // (created with mkostemp or similar) that contains dumps taken earlier
999 // on in the process.
1000 if (dump_traces_path != nullptr) {
1001 if (add_to_zip) {
1002 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
1003 } else {
1004 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
1005 dump_traces_path);
1006 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
1007 }
1008
1009 const int ret = unlink(dump_traces_path);
1010 if (ret == -1) {
1011 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
1012 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -07001013 }
1014 }
1015
Narayan Kamathbd863722017-06-01 18:50:12 +01001016 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001017 if (ds.anr_data_.size() > 0) {
1018 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +01001019 "VM TRACES AT LAST ANR", add_to_zip);
1020
Narayan Kamath6b9516c2017-10-27 11:15:51 +01001021 // The "last" ANR will always be included as separate entry in the zip file. In addition,
1022 // it will be present in the body of the main entry if |add_to_zip| == false.
1023 //
1024 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001025 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +01001026 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001027 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001028 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1029 }
1030}
1031
1032static void AddAnrTraceFiles() {
1033 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1034
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001035 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001036
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001037 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001038
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001039 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1040
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001041 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001042 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001043 int i = 0;
1044 while (true) {
1045 const std::string slow_trace_path =
1046 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1047 if (stat(slow_trace_path.c_str(), &st)) {
1048 // No traces file at this index, done with the files.
1049 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001050 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001051 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1052 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001053 }
1054}
1055
Wei Wang509bb5d2017-06-09 14:42:12 -07001056static void DumpBlockStatFiles() {
1057 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001058
Wei Wang1dc1ef52017-06-12 11:28:37 -07001059 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1060
1061 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001062 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1063 return;
1064 }
1065
1066 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001067 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001068 if ((d->d_name[0] == '.')
1069 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1070 || (d->d_name[1] == '\0'))) {
1071 continue;
1072 }
1073 const std::string new_path =
1074 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1075 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1076 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1077 printf("\n");
1078 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001079 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001080}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001081
1082static void DumpPacketStats() {
1083 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1084 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1085 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1086 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1087 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1088}
1089
1090static void DumpIpAddrAndRules() {
1091 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1092 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1093 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1094 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1095 RunCommand("IP RULES", {"ip", "rule", "show"});
1096 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1097}
1098
Nandana Dutt5c390032019-03-12 10:52:56 +00001099static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1100 std::chrono::milliseconds timeout,
1101 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001102 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001103 sp<android::IServiceManager> sm = defaultServiceManager();
1104 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001105 Vector<String16> args;
1106 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001107 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1108 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001109 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001110 std::string path(title);
1111 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001112 size_t bytes_written = 0;
Steven Moreland5a30d342019-10-08 13:53:28 -07001113 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001114 if (status == OK) {
1115 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1116 std::chrono::duration<double> elapsed_seconds;
1117 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1118 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001119 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1120 bool dump_complete = (status == OK);
1121 dumpsys.stopDumpThread(dump_complete);
1122 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001123
1124 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1125 std::chrono::steady_clock::now() - start);
1126 if (elapsed_duration > timeout) {
1127 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1128 elapsed_duration.count());
1129 break;
1130 }
1131 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001132 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001133}
1134
Vishnu Nair64afc022018-02-01 15:29:34 -08001135static void RunDumpsysText(const std::string& title, int priority,
1136 std::chrono::milliseconds timeout,
1137 std::chrono::milliseconds service_timeout) {
1138 DurationReporter duration_reporter(title);
1139 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1140 fsync(STDOUT_FILENO);
1141 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1142}
1143
1144/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001145static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1146 std::chrono::milliseconds timeout,
1147 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001148 DurationReporter duration_reporter(title);
1149 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1150 fsync(STDOUT_FILENO);
1151 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1152 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001153
1154 RETURN_IF_USER_DENIED_CONSENT();
1155
1156 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1157 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001158}
1159
Nandana Dutt5c390032019-03-12 10:52:56 +00001160static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1161 std::chrono::milliseconds timeout,
1162 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001163 if (!ds.IsZipping()) {
1164 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001165 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001166 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001167 sp<android::IServiceManager> sm = defaultServiceManager();
1168 Dumpsys dumpsys(sm.get());
1169 Vector<String16> args;
1170 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1171 DurationReporter duration_reporter(title);
1172
1173 auto start = std::chrono::steady_clock::now();
1174 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1175 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001176 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001177 std::string path(kProtoPath);
1178 path.append(String8(service).c_str());
1179 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1180 path.append("_CRITICAL");
1181 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1182 path.append("_HIGH");
1183 }
1184 path.append(kProtoExt);
Steven Moreland5a30d342019-10-08 13:53:28 -07001185 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001186 if (status == OK) {
1187 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1188 bool dumpTerminated = (status == OK);
1189 dumpsys.stopDumpThread(dumpTerminated);
1190 }
1191 ZipWriter::FileEntry file_entry;
1192 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001193
1194 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1195 std::chrono::steady_clock::now() - start);
1196 if (elapsed_duration > timeout) {
1197 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1198 elapsed_duration.count());
1199 break;
1200 }
1201 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001202 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001203}
1204
Nandana Dutta7db6342018-11-21 14:53:34 +00001205// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001206static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001207 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1208 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001209
1210 RETURN_IF_USER_DENIED_CONSENT();
1211
1212 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1213 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001214}
1215
1216// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001217static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001218 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1219 // high priority. Reduce timeout once they are able to dump in a shorter time or
1220 // moved to a parallel task.
1221 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1222 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001223
1224 RETURN_IF_USER_DENIED_CONSENT();
1225
1226 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1227 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001228}
1229
1230// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001231static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001232 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001233
1234 RETURN_IF_USER_DENIED_CONSENT();
1235
1236 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1237 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001238}
1239
Steven Moreland44cd9482018-01-04 16:24:13 -08001240static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001241 if (!ds.IsZipping()) {
1242 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1243 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1244 return;
1245 }
1246 DurationReporter duration_reporter("DUMP HALS");
1247 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001248 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001249
Steven Moreland44cd9482018-01-04 16:24:13 -08001250 using android::hidl::manager::V1_0::IServiceManager;
1251 using android::hardware::defaultServiceManager;
1252
1253 sp<IServiceManager> sm = defaultServiceManager();
1254 if (sm == nullptr) {
1255 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1256 return;
1257 }
1258
1259 auto ret = sm->list([&](const auto& interfaces) {
1260 for (const std::string& interface : interfaces) {
1261 std::string cleanName = interface;
1262 std::replace_if(cleanName.begin(),
1263 cleanName.end(),
1264 [](char c) {
1265 return !isalnum(c) &&
1266 std::string("@-_:.").find(c) == std::string::npos;
1267 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001268 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001269
1270 {
1271 auto fd = android::base::unique_fd(
1272 TEMP_FAILURE_RETRY(open(path.c_str(),
1273 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1274 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1275 if (fd < 0) {
1276 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1277 continue;
1278 }
1279 RunCommandToFd(fd,
1280 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001281 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001282 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1283
1284 bool empty = 0 == lseek(fd, 0, SEEK_END);
1285 if (!empty) {
1286 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1287 }
1288 }
1289
1290 unlink(path.c_str());
1291 }
1292 });
1293
1294 if (!ret.isOk()) {
1295 MYLOGE("Could not list hals from hwservicemanager.\n");
1296 }
1297}
1298
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001299static void DumpExternalFragmentationInfo() {
1300 struct stat st;
1301 if (stat("/proc/buddyinfo", &st) != 0) {
1302 MYLOGE("Unable to dump external fragmentation info\n");
1303 return;
1304 }
1305
1306 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1307 std::ifstream ifs("/proc/buddyinfo");
1308 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1309 for (std::string line; std::getline(ifs, line);) {
1310 std::smatch match_results;
1311 if (std::regex_match(line, match_results, unusable_index_regex)) {
1312 std::stringstream free_pages(std::string{match_results[3]});
1313 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1314 std::istream_iterator<int>());
1315
1316 int total_free_pages = 0;
1317 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1318 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1319 }
1320
1321 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1322 match_results[2].str().c_str());
1323
1324 int usable_free_pages = total_free_pages;
1325 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1326 auto unusable_index = (total_free_pages - usable_free_pages) /
1327 static_cast<double>(total_free_pages);
1328 printf(" %5.3f", unusable_index);
1329 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1330 }
1331
1332 printf("\n");
1333 }
1334 }
1335 printf("\n");
1336}
1337
Nandana Dutt5c390032019-03-12 10:52:56 +00001338// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1339// via the consent they are shown. Ignores other errors that occur while running various
1340// commands. The consent checking is currently done around long running tasks, which happen to
1341// be distributed fairly evenly throughout the function.
1342static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001343 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001344
Nandana Dutt5c390032019-03-12 10:52:56 +00001345 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1346 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1347 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001348 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001349 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001350 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001351 DumpFile("MEMORY INFO", "/proc/meminfo");
1352 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001353 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001354
1355 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1356
Sunny Goyal35949782019-11-19 15:54:36 -08001357 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
1358
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001359 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1360 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1361 DumpFile("SLAB INFO", "/proc/slabinfo");
1362 DumpFile("ZONEINFO", "/proc/zoneinfo");
1363 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1364 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001365 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001366
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001367 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1368 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001369
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001370 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001371 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001372
1373 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1374 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001375
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001376 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001377
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001378 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001379 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001380 struct stat s;
1381 if (stat("/proc/modules", &s) != 0) {
1382 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1383 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001384 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001385 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001386
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001387 if (__android_logger_property_get_bool(
1388 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1389 DoKernelLogcat();
1390 } else {
1391 do_dmesg();
1392 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393
Felipe Lemef0292972016-11-22 13:57:05 -08001394 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001395
1396 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1397
Jeff Brown1dc94e32014-09-11 14:15:27 -07001398 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001399 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001400
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001401 /* Dump Bluetooth HCI logs */
1402 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001403
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001404 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001405 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001406 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001407 }
1408
Felipe Lemee184f662016-10-27 10:04:47 -07001409 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001410
Narayan Kamath8f788292017-05-25 13:20:39 +01001411 // NOTE: tombstones are always added as separate entries in the zip archive
1412 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001413 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001414 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001415 if (!tombstones_dumped) {
1416 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001417 }
1418
Jayachandran Ca94c7172017-06-10 15:08:12 -07001419 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001420
Chenbo Feng276a3b62018-08-07 11:44:49 -07001421 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1422
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001423 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001424
Jayachandran Ca94c7172017-06-10 15:08:12 -07001425 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001426
1427 dump_route_tables();
1428
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001429 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1430 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1431 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001432
Nandana Dutt5c390032019-03-12 10:52:56 +00001433 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001434
Elliott Hughes23ccc622017-02-28 10:14:22 -08001435 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001436
Jin Qianf334d662017-10-10 14:41:37 -07001437 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001438
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001439 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001440
Colin Crossf45fa6b2012-03-26 12:38:26 -07001441 /* Binder state is expensive to look at as it uses a lot of memory. */
Hridya Valsaraju920ba712020-02-09 16:27:01 -08001442 std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ?
1443 "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs";
1444
1445 DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log");
1446 DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log");
1447 DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions");
1448 DumpFile("BINDER STATS", binder_logs_dir + "/stats");
1449 DumpFile("BINDER STATE", binder_logs_dir + "/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001450
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001451 /* Add window and surface trace files. */
1452 if (!PropertiesHelper::IsUserBuild()) {
1453 ds.AddDir(WMTRACE_DATA_DIR, false);
1454 }
1455
Nandana Dutt5c390032019-03-12 10:52:56 +00001456 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001457
Steven Moreland7440ddb2016-12-15 16:13:39 -08001458 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001459 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1460 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001461 // su does not exist on user builds, so try running without it.
1462 // This way any implementations of vril-dump that do not require
1463 // root can run on user builds.
1464 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001465 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001466 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001467 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001468 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001469 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001470 }
1471
Felipe Lemed8b94e52016-12-08 10:21:44 -08001472 printf("========================================================\n");
1473 printf("== Android Framework Services\n");
1474 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001475
Nandana Dutt5c390032019-03-12 10:52:56 +00001476 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001477
Felipe Lemed8b94e52016-12-08 10:21:44 -08001478 printf("========================================================\n");
1479 printf("== Checkins\n");
1480 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001481
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001482 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001483
1484 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1485
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001486 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1487 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1488 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1489 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001490
Felipe Lemed8b94e52016-12-08 10:21:44 -08001491 printf("========================================================\n");
1492 printf("== Running Application Activities\n");
1493 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001494
Makoto Onuki60780982018-04-16 15:34:00 -07001495 // The following dumpsys internally collects output from running apps, so it can take a long
1496 // time. So let's extend the timeout.
1497
1498 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1499
1500 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001501
Felipe Lemed8b94e52016-12-08 10:21:44 -08001502 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001503 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001504 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001505
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001506 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001507 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001508
Felipe Lemed8b94e52016-12-08 10:21:44 -08001509 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001510 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001511 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001512
Makoto Onuki60780982018-04-16 15:34:00 -07001513 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1514 DUMPSYS_COMPONENTS_OPTIONS);
1515
1516 printf("========================================================\n");
1517 printf("== Running Application Providers (platform)\n");
1518 printf("========================================================\n");
1519
1520 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1521 DUMPSYS_COMPONENTS_OPTIONS);
1522
1523 printf("========================================================\n");
1524 printf("== Running Application Providers (non-platform)\n");
1525 printf("========================================================\n");
1526
1527 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1528 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001529
Adrian Roos8b397ab2017-04-04 16:35:44 -07001530 printf("========================================================\n");
1531 printf("== Dropbox crashes\n");
1532 printf("========================================================\n");
1533
1534 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1535 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1536
Felipe Lemed8b94e52016-12-08 10:21:44 -08001537 printf("========================================================\n");
1538 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1539 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1540 printf("========================================================\n");
1541 printf("== dumpstate: done (id %d)\n", ds.id_);
1542 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001543
1544 printf("========================================================\n");
1545 printf("== Obtaining statsd metadata\n");
1546 printf("========================================================\n");
1547 // This differs from the usual dumpsys stats, which is the stats report data.
1548 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001549
Kiyoung Kimc2d22ac2020-02-04 19:43:36 +09001550 // Add linker configuration directory
1551 ds.AddDir(LINKERCONFIG_DIR, true);
1552
Mike Ma5c267872019-08-21 11:31:34 -07001553 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1554
Nandana Dutt5c390032019-03-12 10:52:56 +00001555 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001556}
1557
Nandana Dutt5c390032019-03-12 10:52:56 +00001558/*
1559 * Dumps state for the default case; drops root after it's no longer necessary.
1560 *
1561 * Returns RunStatus::OK if everything went fine.
1562 * Returns RunStatus::ERROR if there was an error.
1563 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1564 * with the caller.
1565 */
Jichao Lie89d9c12019-11-21 19:02:51 -08001566Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
Nandana Duttdb379fa2019-10-09 16:54:41 +01001567 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1568 // buffer.
1569 DoLogcat();
1570 // Capture timestamp after first logcat to use in next logcat
1571 time_t logcat_ts = time(nullptr);
1572
Nandana Dutt4be45d12018-09-26 15:04:23 +01001573 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001574 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001575
1576 /* Run some operations that require root. */
1577 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1578 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1579
1580 ds.AddDir(RECOVERY_DIR, true);
1581 ds.AddDir(RECOVERY_DATA_DIR, true);
1582 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1583 ds.AddDir(LOGPERSIST_DATA_DIR, false);
Yifan Hong0efa7972020-02-03 16:45:02 -08001584 ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001585 if (!PropertiesHelper::IsUserBuild()) {
1586 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1587 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1588 }
Jerry Changa1df8a92020-01-02 16:03:39 +08001589 ds.AddDir(PREREBOOT_DATA_DIR, false);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001590 add_mountinfo();
1591 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001592 DumpDynamicPartitionInfo();
Yifan Hong3945e1b2019-10-29 12:59:23 -07001593 ds.AddDir(OTA_METADATA_DIR, true);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001594
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001595 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001596 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1597
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001598 // Dump IPsec stats. No keys are exposed here.
1599 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1600
Nandana Dutt4be45d12018-09-26 15:04:23 +01001601 // Run ss as root so we can see socket marks.
1602 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1603
1604 // Run iotop as root to show top 100 IO threads
1605 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1606
Erick Reyese68df822019-02-11 14:46:36 -08001607 // Gather shared memory buffer info if the product implements it
1608 struct stat st;
1609 if (!stat("/product/bin/dmabuf_dump", &st)) {
1610 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1611 }
1612
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001613 DumpFile("PSI cpu", "/proc/pressure/cpu");
1614 DumpFile("PSI memory", "/proc/pressure/memory");
1615 DumpFile("PSI io", "/proc/pressure/io");
1616
Nandana Dutt4be45d12018-09-26 15:04:23 +01001617 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001618 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001619 }
1620
Nandana Dutt5c390032019-03-12 10:52:56 +00001621 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001622 Dumpstate::RunStatus status = dumpstate();
1623 // Capture logcat since the last time we did it.
1624 DoSystemLogcat(logcat_ts);
1625 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001626}
1627
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001628// This method collects common dumpsys for telephony and wifi. Typically, wifi
1629// reports are fine to include all information, but telephony reports on user
1630// builds need to strip some content (see DumpstateTelephonyOnly).
1631static void DumpstateRadioCommon(bool include_sensitive_info = true) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001632 DumpIpTablesAsRoot();
1633
Jayachandran Cb4389d92019-07-08 09:46:05 -07001634 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1635
Jayachandran Ca94c7172017-06-10 15:08:12 -07001636 if (!DropRootUser()) {
1637 return;
1638 }
1639
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001640 // We need to be picky about some stuff for telephony reports on user builds.
1641 if (!include_sensitive_info) {
1642 // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
1643 DoRadioLogcat();
1644 } else {
1645 // Contains various system properties and process startup info.
1646 do_dmesg();
1647 // Logs other than the radio buffer may contain package/component names and potential PII.
1648 DoLogcat();
1649 // Too broad for connectivity problems.
1650 DoKmsg();
1651 // Contains unrelated hardware info (camera, NFC, biometrics, ...).
1652 DumpHals();
1653 }
1654
Jayachandran Ca94c7172017-06-10 15:08:12 -07001655 DumpPacketStats();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001656 DumpIpAddrAndRules();
1657 dump_route_tables();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001658 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1659 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001660}
1661
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001662// We use "telephony" here for legacy reasons, though this now really means "connectivity" (cellular
1663// + wifi + networking). This method collects dumpsys for connectivity debugging only. General rules
1664// for what can be included on user builds: all reported information MUST directly relate to
1665// connectivity debugging or customer support and MUST NOT contain unrelated personally identifiable
1666// information. This information MUST NOT identify user-installed packages (UIDs are OK, package
1667// names are not), and MUST NOT contain logs of user application traffic.
1668// TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
mukesh agrawal253dad42018-01-23 21:59:59 -08001669static void DumpstateTelephonyOnly() {
1670 DurationReporter duration_reporter("DUMPSTATE");
Jichao Lie89d9c12019-11-21 19:02:51 -08001671
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001672 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001673
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001674 const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001675
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001676 DumpstateRadioCommon(include_sensitive_info);
1677
1678 if (include_sensitive_info) {
1679 // Contains too much unrelated PII, and given the unstructured nature of sysprops, we can't
1680 // really cherrypick all of the connectivity-related ones. Apps generally have no business
1681 // reading these anyway, and there should be APIs to supply the info in a more app-friendly
1682 // way.
1683 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1684 }
Jayachandran Ca94c7172017-06-10 15:08:12 -07001685
1686 printf("========================================================\n");
1687 printf("== Android Framework Services\n");
1688 printf("========================================================\n");
1689
Vishnu Nair652cc802017-11-30 15:18:30 -08001690 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1691 SEC_TO_MSEC(10));
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001692 // TODO(b/146521742) build out an argument to include bound services here for user builds
Vishnu Nair652cc802017-11-30 15:18:30 -08001693 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1694 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001695 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1696 SEC_TO_MSEC(10));
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001697 RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1698 RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001699 SEC_TO_MSEC(10));
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001700 if (include_sensitive_info) {
1701 // Contains raw IP addresses, omit from reports on user builds.
1702 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
1703 // Contains raw destination IP/MAC addresses, omit from reports on user builds.
1704 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1705 SEC_TO_MSEC(10));
1706 // Contains package/component names, omit from reports on user builds.
1707 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1708 SEC_TO_MSEC(10));
1709 // Contains package names, but should be relatively simple to remove them (also contains
1710 // UIDs already), omit from reports on user builds.
1711 RunDumpsys("BATTERYSTATS", {"deviceidle"}, CommandOptions::WithTimeout(90).Build(),
1712 SEC_TO_MSEC(10));
1713 }
Jayachandran Ca94c7172017-06-10 15:08:12 -07001714
1715 printf("========================================================\n");
1716 printf("== Running Application Services\n");
1717 printf("========================================================\n");
1718
1719 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1720
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001721 if (include_sensitive_info) {
1722 printf("========================================================\n");
1723 printf("== Running Application Services (non-platform)\n");
1724 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001725
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001726 // Contains package/component names and potential PII, omit from reports on user builds.
1727 // To get dumps of the active CarrierService(s) on user builds, we supply an argument to the
1728 // carrier_config dumpsys instead.
1729 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1730 DUMPSYS_COMPONENTS_OPTIONS);
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001731
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001732 printf("========================================================\n");
1733 printf("== Checkins\n");
1734 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001735
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08001736 // Contains package/component names, omit from reports on user builds.
1737 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1738 }
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001739
1740 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001741 printf("== dumpstate: done (id %d)\n", ds.id_);
1742 printf("========================================================\n");
1743}
1744
mukesh agrawal253dad42018-01-23 21:59:59 -08001745// This method collects dumpsys for wifi debugging only
1746static void DumpstateWifiOnly() {
1747 DurationReporter duration_reporter("DUMPSTATE");
1748
1749 DumpstateRadioCommon();
1750
1751 printf("========================================================\n");
1752 printf("== Android Framework Services\n");
1753 printf("========================================================\n");
1754
1755 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1756 SEC_TO_MSEC(10));
1757 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1758 SEC_TO_MSEC(10));
1759
1760 printf("========================================================\n");
1761 printf("== dumpstate: done (id %d)\n", ds.id_);
1762 printf("========================================================\n");
1763}
1764
Nandana Duttcf419a72019-03-14 10:40:17 +00001765Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001766 DurationReporter duration_reporter("DUMP TRACES");
1767
1768 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1769 const size_t buf_size = temp_file_pattern.length() + 1;
1770 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1771 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1772
1773 // Create a new, empty file to receive all trace dumps.
1774 //
1775 // TODO: This can be simplified once we remove support for the old style
1776 // dumps. We can have a file descriptor passed in to dump_traces instead
1777 // of creating a file, closing it and then reopening it again.
1778 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1779 if (fd < 0) {
1780 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001781 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001782 }
1783
1784 // Nobody should have access to this temporary file except dumpstate, but we
1785 // temporarily grant 'read' to 'others' here because this file is created
1786 // when tombstoned is still running as root, but dumped after dropping. This
1787 // can go away once support for old style dumping has.
1788 const int chmod_ret = fchmod(fd, 0666);
1789 if (chmod_ret < 0) {
1790 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001791 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001792 }
1793
1794 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1795 if (proc.get() == nullptr) {
1796 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001797 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001798 }
1799
1800 // Number of times process dumping has timed out. If we encounter too many
1801 // failures, we'll give up.
1802 int timeout_failures = 0;
1803 bool dalvik_found = false;
1804
1805 const std::set<int> hal_pids = get_interesting_hal_pids();
1806
1807 struct dirent* d;
1808 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001809 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001810 int pid = atoi(d->d_name);
1811 if (pid <= 0) {
1812 continue;
1813 }
1814
1815 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1816 std::string exe;
1817 if (!android::base::Readlink(link_name, &exe)) {
1818 continue;
1819 }
1820
1821 bool is_java_process;
1822 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1823 // Don't bother dumping backtraces for the zygote.
1824 if (IsZygote(pid)) {
1825 continue;
1826 }
1827
1828 dalvik_found = true;
1829 is_java_process = true;
1830 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1831 is_java_process = false;
1832 } else {
1833 // Probably a native process we don't care about, continue.
1834 continue;
1835 }
1836
1837 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1838 if (timeout_failures == 3) {
1839 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1840 break;
1841 }
1842
1843 const uint64_t start = Nanotime();
1844 const int ret = dump_backtrace_to_file_timeout(
1845 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1846 is_java_process ? 5 : 20, fd);
1847
1848 if (ret == -1) {
1849 // For consistency, the header and footer to this message match those
1850 // dumped by debuggerd in the success case.
1851 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1852 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1853 dprintf(fd, "---- end %d ----", pid);
1854 timeout_failures++;
1855 continue;
1856 }
1857
1858 // We've successfully dumped stack traces, reset the failure count
1859 // and write a summary of the elapsed time to the file and continue with the
1860 // next process.
1861 timeout_failures = 0;
1862
1863 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1864 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1865 }
1866
1867 if (!dalvik_found) {
1868 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1869 }
1870
Nandana Duttcf419a72019-03-14 10:40:17 +00001871 *path = file_name_buf.release();
1872 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001873}
1874
Felipe Leme6f674ae2016-11-18 17:10:33 -08001875void Dumpstate::DumpstateBoard() {
1876 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001877 printf("========================================================\n");
1878 printf("== Board\n");
1879 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001880
Felipe Leme6f674ae2016-11-18 17:10:33 -08001881 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001882 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001883 return;
1884 }
1885
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001886 std::vector<std::string> paths;
1887 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001888 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001889 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1890 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001891 remover.emplace_back(android::base::make_scope_guard(
1892 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001893 }
Jie Song9fbfad02017-06-20 16:29:42 -07001894
Wei Wang587eac92018-04-05 12:17:20 -07001895 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1896 if (dumpstate_device == nullptr) {
1897 MYLOGE("No IDumpstateDevice implementation\n");
1898 return;
1899 }
1900
1901 using ScopedNativeHandle =
1902 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1903 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1904 [](native_handle_t* handle) {
1905 native_handle_close(handle);
1906 native_handle_delete(handle);
1907 });
1908 if (handle == nullptr) {
1909 MYLOGE("Could not create native_handle\n");
1910 return;
1911 }
1912
Nandana Dutt5c390032019-03-12 10:52:56 +00001913 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001914 for (size_t i = 0; i < paths.size(); i++) {
1915 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1916
1917 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1918 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1919 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1920 if (fd < 0) {
1921 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1922 return;
1923 }
1924 handle.get()->data[i] = fd.release();
1925 }
1926
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001927 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001928 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1929 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1930 // and grab whatever dumped
1931 std::packaged_task<bool()>
1932 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001933 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1934 if (!status.isOk()) {
1935 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001936 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001937 }
Wei Wang587eac92018-04-05 12:17:20 -07001938 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001939 });
Wei Wang587eac92018-04-05 12:17:20 -07001940
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001941 auto result = dumpstate_task.get_future();
1942 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001943
1944 constexpr size_t timeout_sec = 30;
1945 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1946 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1947 if (!android::base::SetProperty("ctl.interface_restart",
1948 android::base::StringPrintf("%s/default",
1949 IDumpstateDevice::descriptor))) {
1950 MYLOGE("Couldn't restart dumpstate HAL\n");
1951 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001952 }
Wei Wang587eac92018-04-05 12:17:20 -07001953 // Wait some time for init to kill dumpstate vendor HAL
1954 constexpr size_t killing_timeout_sec = 10;
1955 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1956 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1957 "there might be racing in content\n", killing_timeout_sec);
1958 }
1959
1960 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1961 for (size_t i = 0; i < paths.size(); i++) {
1962 struct stat s;
1963 if (fstat(handle.get()->data[i], &s) == -1) {
1964 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1965 strerror(errno));
1966 file_sizes[i] = -1;
1967 continue;
1968 }
1969 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001970 }
1971
1972 for (size_t i = 0; i < paths.size(); i++) {
1973 if (file_sizes[i] == -1) {
1974 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001975 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001976 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001977 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001978 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001979 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001980 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001981 }
1982
Felipe Lemed8b94e52016-12-08 10:21:44 -08001983 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001984}
1985
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001986static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001987 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001988 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Abhijeet Kaure370d682019-10-01 16:49:30 +01001989 "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001990 " -h: display this help message\n"
1991 " -b: play sound file instead of vibrate, at beginning of job\n"
1992 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001993 " -d: append date to filename\n"
1994 " -p: capture screenshot to filename.png\n"
1995 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001996 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001997 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001998 " -q: disable vibrate\n"
Abhijeet Kaure370d682019-10-01 16:49:30 +01001999 " -P: send broadcast when started and do progress updates\n"
2000 " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00002001 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07002002 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002003}
2004
Wei Liuf87959e2016-08-26 14:51:42 -07002005static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07002006 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07002007}
2008
Felipe Leme1d486fe2016-10-14 18:06:47 -07002009bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07002010 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07002011 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07002012 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07002013 // Final timestamp
2014 char date[80];
2015 time_t the_real_now_please_stand_up = time(nullptr);
2016 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002017 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07002018 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07002019
Felipe Leme9a523ae2016-10-20 15:10:33 -07002020 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08002021 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08002022 return false;
2023 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07002024 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08002025 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08002026 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08002027 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08002028
Felipe Leme0f3fb202016-06-10 17:10:53 -07002029 // Add log file (which contains stderr output) to zip...
2030 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07002031 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07002032 MYLOGE("Failed to add dumpstate log to .zip file\n");
2033 return false;
2034 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002035 // TODO: Should truncate the existing file.
2036 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00002037 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
2038 return false;
2039 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07002040 fprintf(stderr, "\n");
2041
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07002042 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07002043 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07002044 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002045 return false;
2046 }
2047
Felipe Leme1d486fe2016-10-14 18:06:47 -07002048 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
2049 ds.zip_file.reset(nullptr);
2050
Felipe Lemee9d2c542016-11-15 11:48:26 -08002051 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002052 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07002053
Felipe Leme1e9edc62015-12-21 16:02:13 -08002054 return true;
2055}
Felipe Leme6e01fa62015-11-11 19:35:14 -08002056
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002057static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2058 // clang-format off
2059 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2060 "--receiver-foreground", "--receiver-include-background", "-a", action};
2061 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002062
2063 am.insert(am.end(), args.begin(), args.end());
2064
Felipe Leme8d2410e2017-02-08 09:46:08 -08002065 RunCommand("", am,
2066 CommandOptions::WithTimeout(20)
2067 .Log("Sending broadcast: '%s'\n")
2068 .Always()
2069 .DropRoot()
2070 .RedirectStderr()
2071 .Build());
2072}
2073
Felipe Leme35b8cf12017-02-10 15:47:29 -08002074static void Vibrate(int duration_ms) {
2075 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002076 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002077 CommandOptions::WithTimeout(10)
2078 .Log("Vibrate: '%s'\n")
2079 .Always()
2080 .Build());
2081 // clang-format on
2082}
2083
Nandana Dutt979388e2018-11-30 16:48:55 +00002084static void MaybeResolveSymlink(std::string* path) {
2085 std::string resolved_path;
2086 if (android::base::Readlink(*path, &resolved_path)) {
2087 *path = resolved_path;
2088 }
2089}
2090
Nandana Dutt4be45d12018-09-26 15:04:23 +01002091/*
2092 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2093 * if we are writing zip files and adds the version file.
2094 */
2095static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002096 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2097
Nandana Dutt4be45d12018-09-26 15:04:23 +01002098 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2099 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002100 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002101 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002102 char date[80];
2103 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2104 ds.name_ = date;
2105 } else {
2106 ds.name_ = "undated";
2107 }
2108
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002109 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002110 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002111 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002112 ds.base_name_ += "-wifi";
2113 }
2114
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002115 if (ds.options_->do_fb) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002116 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002117 }
2118 ds.tmp_path_ = ds.GetPath(".tmp");
2119 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2120
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002121 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00002122 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002123 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002124 MYLOGD(
Nandana Dutt235c6672019-11-14 15:22:32 +00002125 "Bugreport dir: [%s] "
2126 "Base name: [%s] "
2127 "Suffix: [%s] "
2128 "Log path: [%s] "
2129 "Temporary path: [%s] "
2130 "Screenshot path: [%s]\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002131 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2132 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002133
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002134 if (ds.options_->do_zip_file) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002135 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002136 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2137 create_parent_dirs(ds.path_.c_str());
2138 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2139 if (ds.zip_file == nullptr) {
2140 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2141 } else {
2142 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2143 }
2144 ds.AddTextZipEntry("version.txt", ds.version_);
2145 }
2146}
2147
2148/*
Abhijeet Kaure370d682019-10-01 16:49:30 +01002149 * Finalizes writing to the file by zipping the tmp file to the final location,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002150 * printing zipped file status, etc.
2151 */
2152static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002153 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002154 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002155 if (!ds.FinishZipFile()) {
2156 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2157 do_text_file = true;
2158 } else {
2159 do_text_file = false;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002160 }
2161 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002162 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002163 if (do_text_file) {
2164 dprintf(ds.control_socket_fd_,
2165 "FAIL:could not create zip file, check %s "
2166 "for more details\n",
2167 ds.log_path_.c_str());
2168 } else {
2169 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2170 }
2171 }
2172}
2173
Nandana Dutt4be45d12018-09-26 15:04:23 +01002174
Nandana Dutt58d72e22018-11-16 10:30:48 +00002175static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2176 switch (mode) {
2177 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2178 return "BUGREPORT_FULL";
2179 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2180 return "BUGREPORT_INTERACTIVE";
2181 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2182 return "BUGREPORT_REMOTE";
2183 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2184 return "BUGREPORT_WEAR";
2185 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2186 return "BUGREPORT_TELEPHONY";
2187 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2188 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002189 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2190 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002191 }
2192}
2193
2194static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002195 options->bugreport_mode = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002196 switch (mode) {
2197 case Dumpstate::BugreportMode::BUGREPORT_FULL:
Nandana Dutt58d72e22018-11-16 10:30:48 +00002198 options->do_fb = true;
2199 break;
2200 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002201 // Currently, the dumpstate binder is only used by Shell to update progress.
2202 options->do_start_service = true;
2203 options->do_progress_updates = true;
2204 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002205 break;
2206 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002207 options->do_vibrate = false;
2208 options->is_remote_mode = true;
2209 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002210 break;
2211 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002212 options->do_start_service = true;
2213 options->do_progress_updates = true;
2214 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002215 options->do_fb = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002216 break;
2217 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002218 options->telephony_only = true;
Hunter Knepshield820f9bc2020-02-05 20:10:53 -08002219 options->do_progress_updates = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002220 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002221 break;
2222 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002223 options->wifi_only = true;
2224 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002225 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002226 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002227 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2228 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002229 }
2230}
2231
Nandana Dutt58d72e22018-11-16 10:30:48 +00002232static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
Nandana Dutt235c6672019-11-14 15:22:32 +00002233 MYLOGI(
2234 "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d "
2235 "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
2236 "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s args: %s\n",
2237 options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
2238 options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service,
2239 options.telephony_only, options.wifi_only, options.do_progress_updates,
2240 options.bugreport_fd.get(), options.bugreport_mode.c_str(), options.args.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002241}
2242
Nandana Dutt54dbd672019-01-11 12:58:05 +00002243void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2244 const android::base::unique_fd& bugreport_fd_in,
2245 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002246 // In the new API world, date is always added; output is always a zip file.
2247 // TODO(111441001): remove these options once they are obsolete.
2248 do_add_date = true;
2249 do_zip_file = true;
2250
Nandana Dutt54dbd672019-01-11 12:58:05 +00002251 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2252 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2253 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002254
Nandana Dutt58d72e22018-11-16 10:30:48 +00002255 SetOptionsFromMode(bugreport_mode, this);
2256}
2257
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002258Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2259 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002260 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002261 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002262 switch (c) {
2263 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002264 case 'd': do_add_date = true; break;
2265 case 'z': do_zip_file = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002266 case 's': use_socket = true; break;
2267 case 'S': use_control_socket = true; break;
2268 case 'v': show_header_only = true; break;
2269 case 'q': do_vibrate = false; break;
2270 case 'p': do_fb = true; break;
2271 case 'P': do_progress_updates = true; break;
2272 case 'R': is_remote_mode = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002273 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002274 case 'w':
2275 // This was already processed
2276 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002277 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002278 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002279 break;
2280 default:
2281 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002282 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002283 break;
2284 // clang-format on
2285 }
2286 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002287
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002288 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002289 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002290 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002291 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002292 }
2293 }
2294
2295 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2296 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002297
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002298 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002299}
2300
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002301bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002302 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002303 return false;
2304 }
2305
Abhijeet Kaure370d682019-10-01 16:49:30 +01002306 if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002307 return false;
2308 }
2309
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002310 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002311 return false;
2312 }
2313
Abhijeet Kaure370d682019-10-01 16:49:30 +01002314 if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002315 return false;
2316 }
2317 return true;
2318}
2319
Nandana Dutt197661d2018-11-16 16:40:21 +00002320void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2321 options_ = std::move(options);
2322}
2323
Nandana Duttd2f5f082019-01-18 17:13:52 +00002324Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2325 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002326 if (listener_ != nullptr) {
2327 switch (status) {
2328 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002329 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002330 break;
2331 case Dumpstate::RunStatus::HELP:
2332 break;
2333 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002334 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002335 break;
2336 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002337 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2338 break;
2339 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2340 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2341 break;
2342 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2343 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002344 break;
2345 }
2346 }
2347 return status;
2348}
2349
Nandana Dutt979388e2018-11-30 16:48:55 +00002350/*
2351 * Dumps relevant information to a bugreport based on the given options.
2352 *
2353 * The bugreport can be dumped to a file or streamed to a socket.
2354 *
2355 * How dumping to file works:
2356 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2357 * stderr is redirected a log file.
2358 *
2359 * The temporary bugreport is then populated via printfs, dumping contents of files and
2360 * output of commands to stdout.
2361 *
2362 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2363 * text file.
2364 *
2365 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2366 * gets added to the archive.
2367 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002368 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2369 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002370 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002371Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2372 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002373 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002374 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002375 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002376 return RunStatus::INVALID_INPUT;
2377 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002378 /* set as high priority, and protect from OOM killer */
2379 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002380
Felipe Lemed071c682016-10-20 16:48:00 -07002381 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002382 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002383 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002384 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002385 } else {
2386 /* fallback to kernels <= 2.6.35 */
2387 oom_adj = fopen("/proc/self/oom_adj", "we");
2388 if (oom_adj) {
2389 fputs("-17", oom_adj);
2390 fclose(oom_adj);
2391 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002392 }
2393
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002394 if (version_ == VERSION_DEFAULT) {
2395 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002396 }
2397
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002398 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002399 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002400 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002401 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002402 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002403 }
2404
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002405 if (options_->show_header_only) {
2406 PrintHeader();
2407 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002408 }
2409
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002410 MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
2411 calling_uid, calling_package.c_str());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002412
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002413 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002414 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002415
2416 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002417 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002418 is_redirecting
2419 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2420 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002421 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002422
Felipe Lemed071c682016-10-20 16:48:00 -07002423 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002424 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002425 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002426 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2427
Sahana Raof35ed432019-07-12 10:47:52 +01002428 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2429 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2430 } else {
2431 // Wake lock will be released automatically on process death
2432 MYLOGD("Wake lock acquired.\n");
2433 }
2434
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002435 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002436
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002437 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002438 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002439 MYLOGI("Starting 'dumpstate' service\n");
2440 android::status_t ret;
2441 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2442 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2443 }
2444 }
2445
Felipe Lemef0292972016-11-22 13:57:05 -08002446 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002447 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2448 }
2449
Nandana Dutt235c6672019-11-14 15:22:32 +00002450 MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
2451 id_, options_->args.c_str(), options_->bugreport_mode.c_str(), version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002452
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002453 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002454
Christopher Ferrised9354f2014-10-01 17:35:01 -07002455 // If we are going to use a socket, do it as early as possible
2456 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002457 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002458 if (!redirect_to_socket(stdout, "dumpstate")) {
2459 return ERROR;
2460 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002461 }
2462
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002463 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002464 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002465 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002466 if (control_socket_fd_ == -1) {
2467 return ERROR;
2468 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002469 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002470 }
2471
Felipe Leme71bbfc52015-11-23 14:14:51 -08002472 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002473 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002474
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002475 if (options_->do_progress_updates) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002476 // clang-format off
2477 std::vector<std::string> am_args = {
2478 "--receiver-permission", "android.permission.DUMP",
2479 };
2480 // clang-format on
2481 // Send STARTED broadcast for apps that listen to bugreport generation events
2482 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002483 if (options_->use_control_socket) {
2484 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002485 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002486 }
2487 }
2488
Nick Kralevichf3599b32016-01-25 15:05:16 -08002489 /* read /proc/cmdline before dropping root */
2490 FILE *cmdline = fopen("/proc/cmdline", "re");
2491 if (cmdline) {
2492 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2493 fclose(cmdline);
2494 }
2495
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002496 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002497 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002498 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002499
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002500 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002501 MYLOGI("taking early screenshot\n");
2502 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002503 }
2504
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002505 if (options_->do_zip_file && zip_file != nullptr) {
2506 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2507 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002508 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002509 }
2510 }
2511
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002512 int dup_stdout_fd;
2513 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002514 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002515 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002516 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002517 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2518 return ERROR;
2519 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002520 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2521 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2522 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002523 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002524
2525 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2526 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002527 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002528 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002529 /* TODO: rather than generating a text file now and zipping it later,
2530 it would be more efficient to redirect stdout to the zip entry
2531 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002532 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2533 return ERROR;
2534 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002535 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002536 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002537 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002538 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002539 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002540
2541 // Don't buffer stdout
2542 setvbuf(stdout, nullptr, _IONBF, 0);
2543
Felipe Leme608385d2016-02-01 10:35:38 -08002544 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2545 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002546 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002547 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002548
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002549 if (options_->telephony_only) {
Jichao Lie89d9c12019-11-21 19:02:51 -08002550 MaybeCheckUserConsent(calling_uid, calling_package);
Jayachandran Ca94c7172017-06-10 15:08:12 -07002551 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002552 DumpstateBoard();
2553 } else if (options_->wifi_only) {
Jichao Lie89d9c12019-11-21 19:02:51 -08002554 MaybeCheckUserConsent(calling_uid, calling_package);
mukesh agrawal253dad42018-01-23 21:59:59 -08002555 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002556 } else {
Jichao Lie89d9c12019-11-21 19:02:51 -08002557 // Invoking the critical dumpsys calls before DumpTraces() to try and
2558 // keep the system stats as close to its initial state as possible.
2559 RunDumpsysCritical();
2560
2561 // Run consent check only after critical dumpsys has finished -- so the consent
2562 // isn't going to pollute the system state / logs.
2563 MaybeCheckUserConsent(calling_uid, calling_package);
2564
Nandana Dutt4be45d12018-09-26 15:04:23 +01002565 // Dump state for the default case. This also drops root.
Jichao Lie89d9c12019-11-21 19:02:51 -08002566 RunStatus s = DumpstateDefaultAfterCritical();
Nandana Dutt5c390032019-03-12 10:52:56 +00002567 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002568 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002569 HandleUserConsentDenied();
2570 }
2571 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002572 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002573 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002574
Felipe Leme55b42a62015-11-10 17:39:08 -08002575 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002576 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002577 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002578 }
2579
Abhijeet Kaure370d682019-10-01 16:49:30 +01002580 // Zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002581 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002582 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002583 }
2584
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002585 // Share the final file with the caller if the user has consented or Shell is the caller.
Nandana Duttd2f5f082019-01-18 17:13:52 +00002586 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
Abhijeet Kaure370d682019-10-01 16:49:30 +01002587 if (CalledByApi()) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002588 status = CopyBugreportIfUserConsented(calling_uid);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002589 if (status != Dumpstate::RunStatus::OK &&
2590 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2591 // Do an early return if there were errors. We make an exception for consent
2592 // timing out because it's possible the user got distracted. In this case the
2593 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002594 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002595 return status;
2596 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002597 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002598 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2599 options_->screenshot_fd.get());
2600 if (copy_succeeded) {
2601 android::os::UnlinkAndLogOnError(screenshot_path_);
2602 }
2603 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002604 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2605 MYLOGI(
2606 "Did not receive user consent yet."
2607 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002608 const String16 incidentcompanion("incidentcompanion");
2609 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2610 if (ics != nullptr) {
2611 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2612 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2613 consent_callback_.get());
2614 } else {
2615 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2616 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002617 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002618 }
2619
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002620 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002621 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002622 for (int i = 0; i < 3; i++) {
2623 Vibrate(75);
2624 usleep((75 + 50) * 1000);
2625 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002626 }
2627
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002628 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2629 progress_->GetInitialMax());
2630 progress_->Save();
2631 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002632
Felipe Leme107a05f2016-03-08 15:11:15 -08002633 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002634 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002635 }
2636
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002637 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002638 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002639 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002640 }
2641
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002642 tombstone_data_.clear();
2643 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002644
Nandana Duttd2f5f082019-01-18 17:13:52 +00002645 return (consent_callback_ != nullptr &&
2646 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2647 ? USER_CONSENT_TIMED_OUT
2648 : RunStatus::OK;
2649}
2650
Jichao Lie89d9c12019-11-21 19:02:51 -08002651void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
2652 if (calling_uid == AID_SHELL || !CalledByApi()) {
2653 // No need to get consent for shell triggered dumpstates, or not through
2654 // bugreporting API (i.e. no fd to copy back).
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002655 return;
2656 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002657 consent_callback_ = new ConsentCallback();
2658 const String16 incidentcompanion("incidentcompanion");
2659 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
Jichao Lie89d9c12019-11-21 19:02:51 -08002660 android::String16 package(calling_package.c_str());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002661 if (ics != nullptr) {
2662 MYLOGD("Checking user consent via incidentcompanion service\n");
2663 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Jichao Lie89d9c12019-11-21 19:02:51 -08002664 calling_uid, package, String16(), String16(),
Joe Onorato1c36d752019-03-17 18:26:43 -07002665 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002666 } else {
2667 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2668 }
2669}
2670
Nandana Dutt5c390032019-03-12 10:52:56 +00002671bool Dumpstate::IsUserConsentDenied() const {
2672 return ds.consent_callback_ != nullptr &&
2673 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2674}
2675
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002676bool Dumpstate::CalledByApi() const {
2677 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2678}
2679
Nandana Duttd2f5f082019-01-18 17:13:52 +00002680void Dumpstate::CleanupFiles() {
2681 android::os::UnlinkAndLogOnError(tmp_path_);
2682 android::os::UnlinkAndLogOnError(screenshot_path_);
2683 android::os::UnlinkAndLogOnError(path_);
2684}
2685
2686Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2687 MYLOGD("User denied consent; deleting files and returning\n");
2688 CleanupFiles();
2689 return USER_CONSENT_DENIED;
2690}
2691
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002692Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002693 // If the caller has asked to copy the bugreport over to their directory, we need explicit
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002694 // user consent (unless the caller is Shell).
2695 UserConsentResult consent_result;
2696 if (calling_uid == AID_SHELL) {
2697 consent_result = UserConsentResult::APPROVED;
2698 } else {
2699 consent_result = consent_callback_->getResult();
2700 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002701 if (consent_result == UserConsentResult::UNAVAILABLE) {
2702 // User has not responded yet.
2703 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
Hunter Knepshield70610fa2020-01-03 15:27:33 -08002704 // Telephony is a fast report type, particularly on user builds where information may be
2705 // more aggressively limited. To give the user time to read the consent dialog, increase the
2706 // timeout.
2707 uint64_t timeout_ms = options_->telephony_only ? TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS
2708 : USER_CONSENT_TIMEOUT_MS;
2709 if (elapsed_ms < timeout_ms) {
2710 uint delay_seconds = (timeout_ms - elapsed_ms) / 1000;
Nandana Duttd2f5f082019-01-18 17:13:52 +00002711 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2712 sleep(delay_seconds);
2713 }
2714 consent_result = consent_callback_->getResult();
2715 }
2716 if (consent_result == UserConsentResult::DENIED) {
2717 // User has explicitly denied sharing with the app. To be safe delete the
2718 // internal bugreport & tmp files.
2719 return HandleUserConsentDenied();
2720 }
2721 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002722 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2723 if (copy_succeeded) {
2724 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002725 }
2726 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2727 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2728 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2729 // Since we do not have user consent to share the bugreport it does not get
2730 // copied over to the calling app but remains in the internal directory from
2731 // where the user can manually pull it.
2732 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2733 }
2734 // Unknown result; must be a programming error.
2735 MYLOGE("Unknown user consent result:%d\n", consent_result);
2736 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002737}
2738
Nandana Duttf02564e2019-02-15 15:24:24 +00002739Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002740 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2741 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2742 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002743 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002744 // When directly running dumpstate binary, the output is not expected to be written
2745 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002746 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002747
2748 // calling_uid and calling_package are for user consent to share the bugreport with
2749 // an app; they are irrelvant here because bugreport is only written to a local
2750 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002751 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002752 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002753 return status;
2754}
2755
2756/* Main entry point for dumpstate binary. */
2757int run_main(int argc, char* argv[]) {
2758 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002759
2760 switch (status) {
2761 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002762 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002763 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002764 ShowUsage();
2765 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002766 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002767 fprintf(stderr, "Invalid combination of args\n");
2768 ShowUsage();
2769 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002770 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002771 FALLTHROUGH_INTENDED;
2772 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2773 FALLTHROUGH_INTENDED;
2774 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002775 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002776 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002777}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002778
2779// TODO(111441001): Default DumpOptions to sensible values.
2780Dumpstate::Dumpstate(const std::string& version)
2781 : pid_(getpid()),
2782 options_(new Dumpstate::DumpOptions()),
Nandana Dutt402a8392019-06-14 14:25:13 +01002783 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002784 version_(version),
2785 now_(time(nullptr)) {
2786}
2787
2788Dumpstate& Dumpstate::GetInstance() {
2789 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2790 return singleton_;
2791}
2792
Nandana Dutt8d945c02019-08-14 13:30:07 +01002793DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2794 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002795 if (!title_.empty()) {
2796 started_ = Nanotime();
2797 }
2798}
2799
2800DurationReporter::~DurationReporter() {
2801 if (!title_.empty()) {
2802 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
chenqiwuaf8b2d92019-12-12 18:53:51 +08002803 if (elapsed >= .5f || verbose_) {
2804 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002805 }
chenqiwuaf8b2d92019-12-12 18:53:51 +08002806 if (!logcat_only_) {
2807 // Use "Yoda grammar" to make it easier to grep|sort sections.
2808 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002809 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002810 }
2811}
2812
2813const int32_t Progress::kDefaultMax = 5000;
2814
2815Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2816}
2817
2818Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2819 : Progress(initial_max, growth_factor, "") {
2820 progress_ = progress;
2821}
2822
2823Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2824 : initial_max_(initial_max),
2825 progress_(0),
2826 max_(initial_max),
2827 growth_factor_(growth_factor),
2828 n_runs_(0),
2829 average_max_(0),
2830 path_(path) {
2831 if (!path_.empty()) {
2832 Load();
2833 }
2834}
2835
2836void Progress::Load() {
2837 MYLOGD("Loading stats from %s\n", path_.c_str());
2838 std::string content;
2839 if (!android::base::ReadFileToString(path_, &content)) {
2840 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2841 return;
2842 }
2843 if (content.empty()) {
2844 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2845 return;
2846 }
2847 std::vector<std::string> lines = android::base::Split(content, "\n");
2848
2849 if (lines.size() < 1) {
2850 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2851 (int)lines.size(), max_);
2852 return;
2853 }
2854 char* ptr;
2855 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2856 average_max_ = strtol(ptr, nullptr, 10);
2857 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2858 average_max_ > STATS_MAX_AVERAGE) {
2859 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2860 initial_max_ = Progress::kDefaultMax;
2861 } else {
2862 initial_max_ = average_max_;
2863 }
2864 max_ = initial_max_;
2865
2866 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2867}
2868
2869void Progress::Save() {
2870 int32_t total = n_runs_ * average_max_ + progress_;
2871 int32_t runs = n_runs_ + 1;
2872 int32_t average = floor(((float)total) / runs);
2873 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2874 path_.c_str());
2875 if (path_.empty()) {
2876 return;
2877 }
2878
2879 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2880 if (!android::base::WriteStringToFile(content, path_)) {
2881 MYLOGE("Could not save stats on %s\n", path_.c_str());
2882 }
2883}
2884
2885int32_t Progress::Get() const {
2886 return progress_;
2887}
2888
2889bool Progress::Inc(int32_t delta_sec) {
2890 bool changed = false;
2891 if (delta_sec >= 0) {
2892 progress_ += delta_sec;
2893 if (progress_ > max_) {
2894 int32_t old_max = max_;
2895 max_ = floor((float)progress_ * growth_factor_);
2896 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2897 changed = true;
2898 }
2899 }
2900 return changed;
2901}
2902
2903int32_t Progress::GetMax() const {
2904 return max_;
2905}
2906
2907int32_t Progress::GetInitialMax() const {
2908 return initial_max_;
2909}
2910
2911void Progress::Dump(int fd, const std::string& prefix) const {
2912 const char* pr = prefix.c_str();
2913 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2914 dprintf(fd, "%smax: %d\n", pr, max_);
2915 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2916 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2917 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2918 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2919 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2920}
2921
2922bool Dumpstate::IsZipping() const {
2923 return zip_writer_ != nullptr;
2924}
2925
2926std::string Dumpstate::GetPath(const std::string& suffix) const {
2927 return GetPath(bugreport_internal_dir_, suffix);
2928}
2929
2930std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2931 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2932 name_.c_str(), suffix.c_str());
2933}
2934
2935void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2936 progress_ = std::move(progress);
2937}
2938
2939void for_each_userid(void (*func)(int), const char *header) {
2940 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2941 "for_each_userid(%s)", header);
2942 DurationReporter duration_reporter(title);
2943 if (PropertiesHelper::IsDryRun()) return;
2944
2945 DIR *d;
2946 struct dirent *de;
2947
2948 if (header) printf("\n------ %s ------\n", header);
2949 func(0);
2950
2951 if (!(d = opendir("/data/system/users"))) {
2952 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2953 return;
2954 }
2955
2956 while ((de = readdir(d))) {
2957 int userid;
2958 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2959 continue;
2960 }
2961 func(userid);
2962 }
2963
2964 closedir(d);
2965}
2966
2967static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2968 DIR *d;
2969 struct dirent *de;
2970
2971 if (!(d = opendir("/proc"))) {
2972 printf("Failed to open /proc (%s)\n", strerror(errno));
2973 return;
2974 }
2975
2976 if (header) printf("\n------ %s ------\n", header);
2977 while ((de = readdir(d))) {
2978 if (ds.IsUserConsentDenied()) {
2979 MYLOGE(
2980 "Returning early because user denied consent to share bugreport with calling app.");
2981 closedir(d);
2982 return;
2983 }
2984 int pid;
2985 int fd;
2986 char cmdpath[255];
2987 char cmdline[255];
2988
2989 if (!(pid = atoi(de->d_name))) {
2990 continue;
2991 }
2992
2993 memset(cmdline, 0, sizeof(cmdline));
2994
2995 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
2996 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2997 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
2998 close(fd);
2999 if (cmdline[0]) {
3000 helper(pid, cmdline, arg);
3001 continue;
3002 }
3003 }
3004
3005 // if no cmdline, a kernel thread has comm
3006 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3007 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3008 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3009 close(fd);
3010 if (cmdline[1]) {
3011 cmdline[0] = '[';
3012 size_t len = strcspn(cmdline, "\f\b\r\n");
3013 cmdline[len] = ']';
3014 cmdline[len+1] = '\0';
3015 }
3016 }
3017 if (!cmdline[0]) {
3018 strcpy(cmdline, "N/A");
3019 }
3020 helper(pid, cmdline, arg);
3021 }
3022
3023 closedir(d);
3024}
3025
3026static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3027 for_each_pid_func *func = (for_each_pid_func*) arg;
3028 func(pid, cmdline);
3029}
3030
3031void for_each_pid(for_each_pid_func func, const char *header) {
3032 std::string title = header == nullptr ? "for_each_pid"
3033 : android::base::StringPrintf("for_each_pid(%s)", header);
3034 DurationReporter duration_reporter(title);
3035 if (PropertiesHelper::IsDryRun()) return;
3036
3037 __for_each_pid(for_each_pid_helper, header, (void *) func);
3038}
3039
3040static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3041 DIR *d;
3042 struct dirent *de;
3043 char taskpath[255];
3044 for_each_tid_func *func = (for_each_tid_func *) arg;
3045
3046 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3047
3048 if (!(d = opendir(taskpath))) {
3049 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3050 return;
3051 }
3052
3053 func(pid, pid, cmdline);
3054
3055 while ((de = readdir(d))) {
3056 if (ds.IsUserConsentDenied()) {
3057 MYLOGE(
3058 "Returning early because user denied consent to share bugreport with calling app.");
3059 closedir(d);
3060 return;
3061 }
3062 int tid;
3063 int fd;
3064 char commpath[255];
3065 char comm[255];
3066
3067 if (!(tid = atoi(de->d_name))) {
3068 continue;
3069 }
3070
3071 if (tid == pid)
3072 continue;
3073
3074 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3075 memset(comm, 0, sizeof(comm));
3076 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3077 strcpy(comm, "N/A");
3078 } else {
3079 char *c;
3080 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3081 close(fd);
3082
3083 c = strrchr(comm, '\n');
3084 if (c) {
3085 *c = '\0';
3086 }
3087 }
3088 func(pid, tid, comm);
3089 }
3090
3091 closedir(d);
3092}
3093
3094void for_each_tid(for_each_tid_func func, const char *header) {
3095 std::string title = header == nullptr ? "for_each_tid"
3096 : android::base::StringPrintf("for_each_tid(%s)", header);
3097 DurationReporter duration_reporter(title);
3098
3099 if (PropertiesHelper::IsDryRun()) return;
3100
3101 __for_each_pid(for_each_tid_helper, header, (void *) func);
3102}
3103
3104void show_wchan(int pid, int tid, const char *name) {
3105 if (PropertiesHelper::IsDryRun()) return;
3106
3107 char path[255];
3108 char buffer[255];
3109 int fd, ret, save_errno;
3110 char name_buffer[255];
3111
3112 memset(buffer, 0, sizeof(buffer));
3113
3114 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3115 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3116 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3117 return;
3118 }
3119
3120 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3121 save_errno = errno;
3122 close(fd);
3123
3124 if (ret < 0) {
3125 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3126 return;
3127 }
3128
3129 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3130 pid == tid ? 0 : 3, "", name);
3131
3132 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3133
3134 return;
3135}
3136
3137// print time in centiseconds
3138static void snprcent(char *buffer, size_t len, size_t spc,
3139 unsigned long long time) {
3140 static long hz; // cache discovered hz
3141
3142 if (hz <= 0) {
3143 hz = sysconf(_SC_CLK_TCK);
3144 if (hz <= 0) {
3145 hz = 1000;
3146 }
3147 }
3148
3149 // convert to centiseconds
3150 time = (time * 100 + (hz / 2)) / hz;
3151
3152 char str[16];
3153
3154 snprintf(str, sizeof(str), " %llu.%02u",
3155 time / 100, (unsigned)(time % 100));
3156 size_t offset = strlen(buffer);
3157 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3158 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3159}
3160
3161// print permille as a percent
3162static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3163 char str[16];
3164
3165 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3166 size_t offset = strlen(buffer);
3167 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3168 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3169}
3170
3171void show_showtime(int pid, const char *name) {
3172 if (PropertiesHelper::IsDryRun()) return;
3173
3174 char path[255];
3175 char buffer[1023];
3176 int fd, ret, save_errno;
3177
3178 memset(buffer, 0, sizeof(buffer));
3179
3180 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3181 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3182 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3183 return;
3184 }
3185
3186 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3187 save_errno = errno;
3188 close(fd);
3189
3190 if (ret < 0) {
3191 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3192 return;
3193 }
3194
3195 // field 14 is utime
3196 // field 15 is stime
3197 // field 42 is iotime
3198 unsigned long long utime = 0, stime = 0, iotime = 0;
3199 if (sscanf(buffer,
3200 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3201 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3202 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3203 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3204 &utime, &stime, &iotime) != 3) {
3205 return;
3206 }
3207
3208 unsigned long long total = utime + stime;
3209 if (!total) {
3210 return;
3211 }
3212
3213 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3214 if (permille > 1000) {
3215 permille = 1000;
3216 }
3217
3218 // try to beautify and stabilize columns at <80 characters
3219 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3220 if ((name[0] != '[') || utime) {
3221 snprcent(buffer, sizeof(buffer), 57, utime);
3222 }
3223 snprcent(buffer, sizeof(buffer), 65, stime);
3224 if ((name[0] != '[') || iotime) {
3225 snprcent(buffer, sizeof(buffer), 73, iotime);
3226 }
3227 if (iotime) {
3228 snprdec(buffer, sizeof(buffer), 79, permille);
3229 }
3230 puts(buffer); // adds a trailing newline
3231
3232 return;
3233}
3234
3235void do_dmesg() {
3236 const char *title = "KERNEL LOG (dmesg)";
3237 DurationReporter duration_reporter(title);
3238 printf("------ %s ------\n", title);
3239
3240 if (PropertiesHelper::IsDryRun()) return;
3241
3242 /* Get size of kernel buffer */
3243 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3244 if (size <= 0) {
3245 printf("Unexpected klogctl return value: %d\n\n", size);
3246 return;
3247 }
3248 char *buf = (char *) malloc(size + 1);
3249 if (buf == nullptr) {
3250 printf("memory allocation failed\n\n");
3251 return;
3252 }
3253 int retval = klogctl(KLOG_READ_ALL, buf, size);
3254 if (retval < 0) {
3255 printf("klogctl failure\n\n");
3256 free(buf);
3257 return;
3258 }
3259 buf[retval] = '\0';
3260 printf("%s\n\n", buf);
3261 free(buf);
3262 return;
3263}
3264
3265void do_showmap(int pid, const char *name) {
3266 char title[255];
3267 char arg[255];
3268
3269 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3270 snprintf(arg, sizeof(arg), "%d", pid);
3271 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3272}
3273
3274int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3275 DurationReporter duration_reporter(title);
3276
3277 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3278
3279 UpdateProgress(WEIGHT_FILE);
3280
3281 return status;
3282}
3283
3284int read_file_as_long(const char *path, long int *output) {
3285 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3286 if (fd < 0) {
3287 int err = errno;
3288 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3289 return -1;
3290 }
3291 char buffer[50];
3292 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3293 if (bytes_read == -1) {
3294 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3295 return -2;
3296 }
3297 if (bytes_read == 0) {
3298 MYLOGE("File %s is empty\n", path);
3299 return -3;
3300 }
3301 *output = atoi(buffer);
3302 return 0;
3303}
3304
3305/* calls skip to gate calling dump_from_fd recursively
3306 * in the specified directory. dump_from_fd defaults to
3307 * dump_file_from_fd above when set to NULL. skip defaults
3308 * to false when set to NULL. dump_from_fd will always be
3309 * called with title NULL.
3310 */
3311int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3312 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3313 DurationReporter duration_reporter(title);
3314 DIR *dirp;
3315 struct dirent *d;
3316 char *newpath = nullptr;
3317 const char *slash = "/";
3318 int retval = 0;
3319
3320 if (!title.empty()) {
3321 printf("------ %s (%s) ------\n", title.c_str(), dir);
3322 }
3323 if (PropertiesHelper::IsDryRun()) return 0;
3324
3325 if (dir[strlen(dir) - 1] == '/') {
3326 ++slash;
3327 }
3328 dirp = opendir(dir);
3329 if (dirp == nullptr) {
3330 retval = -errno;
3331 MYLOGE("%s: %s\n", dir, strerror(errno));
3332 return retval;
3333 }
3334
3335 if (!dump_from_fd) {
3336 dump_from_fd = dump_file_from_fd;
3337 }
3338 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3339 if ((d->d_name[0] == '.')
3340 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3341 || (d->d_name[1] == '\0'))) {
3342 continue;
3343 }
3344 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3345 (d->d_type == DT_DIR) ? "/" : "");
3346 if (!newpath) {
3347 retval = -errno;
3348 continue;
3349 }
3350 if (skip && (*skip)(newpath)) {
3351 continue;
3352 }
3353 if (d->d_type == DT_DIR) {
3354 int ret = dump_files("", newpath, skip, dump_from_fd);
3355 if (ret < 0) {
3356 retval = ret;
3357 }
3358 continue;
3359 }
3360 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3361 if (fd.get() < 0) {
3362 retval = -1;
3363 printf("*** %s: %s\n", newpath, strerror(errno));
3364 continue;
3365 }
3366 (*dump_from_fd)(nullptr, newpath, fd.get());
3367 }
3368 closedir(dirp);
3369 if (!title.empty()) {
3370 printf("\n");
3371 }
3372 return retval;
3373}
3374
3375/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3376 * it's possible to avoid issues where opening the file itself can get
3377 * stuck.
3378 */
3379int dump_file_from_fd(const char *title, const char *path, int fd) {
3380 if (PropertiesHelper::IsDryRun()) return 0;
3381
3382 int flags = fcntl(fd, F_GETFL);
3383 if (flags == -1) {
3384 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3385 return -1;
3386 } else if (!(flags & O_NONBLOCK)) {
3387 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3388 return -1;
3389 }
3390 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3391}
3392
3393int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003394 const CommandOptions& options, bool verbose_duration) {
3395 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003396
3397 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3398
3399 /* TODO: for now we're simplifying the progress calculation by using the
3400 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3401 * where its weight should be much higher proportionally to its timeout.
3402 * Ideally, it should use a options.EstimatedDuration() instead...*/
3403 UpdateProgress(options.Timeout());
3404
3405 return status;
3406}
3407
3408void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3409 const CommandOptions& options, long dumpsysTimeoutMs) {
3410 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3411 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3412 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3413 RunCommand(title, dumpsys, options);
3414}
3415
3416int open_socket(const char *service) {
3417 int s = android_get_control_socket(service);
3418 if (s < 0) {
3419 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3420 return -1;
3421 }
3422 fcntl(s, F_SETFD, FD_CLOEXEC);
3423
3424 // Set backlog to 0 to make sure that queue size will be minimum.
3425 // In Linux, because the minimum queue will be 1, connect() will be blocked
3426 // if the other clients already called connect() and the connection request was not accepted.
3427 if (listen(s, 0) < 0) {
3428 MYLOGE("listen(control socket): %s\n", strerror(errno));
3429 return -1;
3430 }
3431
3432 struct sockaddr addr;
3433 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003434 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003435
3436 // Close socket just after accept(), to make sure that connect() by client will get error
3437 // when the socket is used by the other services.
3438 // There is still a race condition possibility between accept and close, but there is no way
3439 // to close-on-accept atomically.
3440 // See detail; b/123306389#comment25
3441 close(s);
3442
3443 if (fd < 0) {
3444 MYLOGE("accept(control socket): %s\n", strerror(errno));
3445 return -1;
3446 }
3447
3448 return fd;
3449}
3450
3451/* redirect output to a service control socket */
3452bool redirect_to_socket(FILE* redirect, const char* service) {
3453 int fd = open_socket(service);
3454 if (fd == -1) {
3455 return false;
3456 }
3457 fflush(redirect);
3458 // TODO: handle dup2 failure
3459 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3460 close(fd);
3461 return true;
3462}
3463
3464// TODO: should call is_valid_output_file and/or be merged into it.
3465void create_parent_dirs(const char *path) {
3466 char *chp = const_cast<char *> (path);
3467
3468 /* skip initial slash */
3469 if (chp[0] == '/')
3470 chp++;
3471
3472 /* create leading directories, if necessary */
3473 struct stat dir_stat;
3474 while (chp && chp[0]) {
3475 chp = strchr(chp, '/');
3476 if (chp) {
3477 *chp = 0;
3478 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3479 MYLOGI("Creating directory %s\n", path);
3480 if (mkdir(path, 0770)) { /* drwxrwx--- */
3481 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3482 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3483 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3484 }
3485 }
3486 *chp++ = '/';
3487 }
3488 }
3489}
3490
3491bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3492 create_parent_dirs(path);
3493
3494 int fd = TEMP_FAILURE_RETRY(open(path,
3495 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3496 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3497 if (fd < 0) {
3498 MYLOGE("%s: %s\n", path, strerror(errno));
3499 return false;
3500 }
3501
3502 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3503 close(fd);
3504 return true;
3505}
3506
3507bool redirect_to_file(FILE* redirect, char* path) {
3508 return _redirect_to_file(redirect, path, O_TRUNC);
3509}
3510
3511bool redirect_to_existing_file(FILE* redirect, char* path) {
3512 return _redirect_to_file(redirect, path, O_APPEND);
3513}
3514
3515void dump_route_tables() {
3516 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3517 if (PropertiesHelper::IsDryRun()) return;
3518 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3519 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3520 FILE* fp = fopen(RT_TABLES_PATH, "re");
3521 if (!fp) {
3522 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3523 return;
3524 }
3525 char table[16];
3526 // Each line has an integer (the table number), a space, and a string (the table name). We only
3527 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3528 // Add a fixed max limit so this doesn't go awry.
3529 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3530 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3531 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3532 }
3533 fclose(fp);
3534}
3535
3536// TODO: make this function thread safe if sections are generated in parallel.
3537void Dumpstate::UpdateProgress(int32_t delta_sec) {
3538 if (progress_ == nullptr) {
3539 MYLOGE("UpdateProgress: progress_ not set\n");
3540 return;
3541 }
3542
3543 // Always update progess so stats can be tuned...
Nandana Dutt402a8392019-06-14 14:25:13 +01003544 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003545
3546 // ...but only notifiy listeners when necessary.
3547 if (!options_->do_progress_updates) return;
3548
3549 int progress = progress_->Get();
3550 int max = progress_->GetMax();
Nandana Dutt402a8392019-06-14 14:25:13 +01003551 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003552
Nandana Dutt402a8392019-06-14 14:25:13 +01003553 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003554 return;
3555 }
Nandana Dutt402a8392019-06-14 14:25:13 +01003556 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003557
3558 if (control_socket_fd_ >= 0) {
3559 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3560 fsync(control_socket_fd_);
3561 }
3562
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003563 if (listener_ != nullptr) {
Nandana Dutt235c6672019-11-14 15:22:32 +00003564 if (percent % 10 == 0) {
3565 // We don't want to spam logcat, so only log multiples of 10.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003566 MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003567 } else {
3568 // stderr is ignored on normal invocations, but useful when calling
3569 // /system/bin/dumpstate directly for debuggging.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003570 fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003571 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003572
3573 listener_->onProgress(percent);
3574 }
3575}
3576
3577void Dumpstate::TakeScreenshot(const std::string& path) {
3578 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3579 int status =
3580 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3581 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3582 if (status == 0) {
3583 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3584 } else {
3585 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3586 }
3587}
3588
3589bool is_dir(const char* pathname) {
3590 struct stat info;
3591 if (stat(pathname, &info) == -1) {
3592 return false;
3593 }
3594 return S_ISDIR(info.st_mode);
3595}
3596
3597time_t get_mtime(int fd, time_t default_mtime) {
3598 struct stat info;
3599 if (fstat(fd, &info) == -1) {
3600 return default_mtime;
3601 }
3602 return info.st_mtime;
3603}