blob: 498f7270bcc906753e2aea18e1b6fd04aad99a79 [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;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700138
Felipe Leme1d486fe2016-10-14 18:06:47 -0700139// TODO: variables and functions below should be part of dumpstate object
140
Felipe Leme635ca312016-01-05 14:23:02 -0800141static std::set<std::string> mount_points;
142void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800143
Todd Poynor2a83daa2013-11-22 15:44:22 -0800144#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700145#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700146#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800147
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700149#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700150#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700151#define LOGPERSIST_DATA_DIR "/data/misc/logd"
Jerry Changa1df8a92020-01-02 16:03:39 +0800152#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
David Brazdild2991962016-06-03 14:40:44 +0100153#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
154#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800155#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900156#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800157#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Yifan Hong3945e1b2019-10-29 12:59:23 -0700158#define OTA_METADATA_DIR "/metadata/ota"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700159
Narayan Kamath8f788292017-05-25 13:20:39 +0100160// TODO(narayan): Since this information has to be kept in sync
161// with tombstoned, we should just put it in a common header.
162//
163// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100164static const std::string TOMBSTONE_DIR = "/data/tombstones/";
165static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
166static const std::string ANR_DIR = "/data/anr/";
167static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700168
Felipe Lemee844a9d2016-09-21 15:01:39 -0700169// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000170
Nandana Dutt5c390032019-03-12 10:52:56 +0000171#define RETURN_IF_USER_DENIED_CONSENT() \
172 if (ds.IsUserConsentDenied()) { \
173 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
174 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
175 }
176
177// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
178// if consent is found to be denied.
179#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
180 RETURN_IF_USER_DENIED_CONSENT(); \
181 func_ptr(__VA_ARGS__); \
182 RETURN_IF_USER_DENIED_CONSENT();
183
Sahana Raof35ed432019-07-12 10:47:52 +0100184static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
185
Nandana Dutt979388e2018-11-30 16:48:55 +0000186namespace android {
187namespace os {
188namespace {
189
190static int Open(std::string path, int flags, mode_t mode = 0) {
191 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
192 if (fd == -1) {
193 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
194 }
195 return fd;
196}
197
Nandana Dutt979388e2018-11-30 16:48:55 +0000198
199static int OpenForRead(std::string path) {
200 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
201}
202
203bool CopyFile(int in_fd, int out_fd) {
204 char buf[4096];
205 ssize_t byte_count;
206 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
207 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
208 return false;
209 }
210 }
211 return (byte_count != -1);
212}
213
214static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000215 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000216
217 // Obtain a handle to the source file.
218 android::base::unique_fd in_fd(OpenForRead(input_file));
219 if (out_fd != -1 && in_fd.get() != -1) {
220 if (CopyFile(in_fd.get(), out_fd)) {
221 return true;
222 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000223 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000224 }
225 return false;
226}
227
Nandana Duttd2f5f082019-01-18 17:13:52 +0000228static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000229 if (unlink(file.c_str())) {
230 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000231 return false;
232 }
233 return true;
234}
Nandana Dutt979388e2018-11-30 16:48:55 +0000235
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000236static bool IsFileEmpty(const std::string& file_path) {
237 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
238 if(file.bad()) {
239 MYLOGE("Cannot open file: %s\n", file_path.c_str());
240 return true;
241 }
242 return file.tellg() <= 0;
243}
244
Nikita Ioffea325a572019-05-16 19:49:47 +0100245int64_t GetModuleMetadataVersion() {
246 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
247 if (binder == nullptr) {
248 MYLOGE("Failed to retrieve package_native service");
249 return 0L;
250 }
251 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
252 std::string package_name;
253 auto status = package_service->getModuleMetadataPackageName(&package_name);
254 if (!status.isOk()) {
255 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
256 return 0L;
257 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100258 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100259 int64_t version_code;
260 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
261 &version_code);
262 if (!status.isOk()) {
263 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
264 return 0L;
265 }
266 return version_code;
267}
268
Nandana Dutt979388e2018-11-30 16:48:55 +0000269} // namespace
270} // namespace os
271} // namespace android
272
Felipe Leme678727a2016-09-21 17:22:11 -0700273static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800274 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800275 long dumpsysTimeoutMs = 0) {
276 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700277}
278static int DumpFile(const std::string& title, const std::string& path) {
279 return ds.DumpFile(title, path);
280}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800281
Felipe Lemee844a9d2016-09-21 15:01:39 -0700282// Relative directory (inside the zip) for all files copied as-is into the bugreport.
283static const std::string ZIP_ROOT_DIR = "FS";
284
Vishnu Naire97d6122018-01-18 13:58:56 -0800285static const std::string kProtoPath = "proto/";
286static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700287static const std::string kDumpstateBoardFiles[] = {
288 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700289 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700290};
291static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
292
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700293static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700294static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700295static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700296static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
297static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700298
Felipe Lemef0292972016-11-22 13:57:05 -0800299static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
300
Narayan Kamath8f788292017-05-25 13:20:39 +0100301/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100302 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
303 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
304 * is set, the vector only contains files that were written in the last 30 minutes.
Narayan Kamath8f788292017-05-25 13:20:39 +0100305 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700306static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
307 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700308 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100309 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
310
Narayan Kamathbd863722017-06-01 18:50:12 +0100311 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100312
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700313 if (dump_dir == nullptr) {
314 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700315 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700316 }
317
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700318 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100319 struct dirent* entry = nullptr;
320 while ((entry = readdir(dump_dir.get()))) {
321 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100322 continue;
323 }
324
Narayan Kamathbd863722017-06-01 18:50:12 +0100325 const std::string base_name(entry->d_name);
326 if (base_name.find(file_prefix) != 0) {
327 continue;
328 }
329
330 const std::string abs_path = dir_path + base_name;
331 android::base::unique_fd fd(
332 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
333 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700334 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100335 break;
336 }
337
338 struct stat st = {};
339 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700340 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100341 continue;
342 }
343
Narayan Kamath3f31b632018-02-22 19:42:36 +0000344 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100345 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100346 continue;
347 }
348
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700349 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700350 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100351
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700352 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100353}
354
Narayan Kamathbd863722017-06-01 18:50:12 +0100355static bool AddDumps(const std::vector<DumpData>::const_iterator start,
356 const std::vector<DumpData>::const_iterator end,
357 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100358 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100359 for (auto it = start; it != end; ++it) {
360 const std::string& name = it->name;
361 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100362 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100363
364 // Seek to the beginning of the file before dumping any data. A given
365 // DumpData entry might be dumped multiple times in the report.
366 //
367 // For example, the most recent ANR entry is dumped to the body of the
368 // main entry and it also shows up as a separate entry in the bugreport
369 // ZIP file.
370 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
371 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
372 strerror(errno));
373 }
374
Narayan Kamath8f788292017-05-25 13:20:39 +0100375 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800376 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100377 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100378 }
379 } else {
380 dump_file_from_fd(type_name, name.c_str(), fd);
381 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100382 }
383
384 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700385}
386
Felipe Leme635ca312016-01-05 14:23:02 -0800387// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700388void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800389 char path[PATH_MAX];
390
391 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
392 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700393 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800394 char linkname[PATH_MAX];
395 ssize_t r = readlink(path, linkname, PATH_MAX);
396 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800397 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800398 return;
399 }
400 linkname[r] = '\0';
401
402 if (mount_points.find(linkname) == mount_points.end()) {
403 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700404 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700405 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800406 mount_points.insert(linkname);
407 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800408 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800409 }
410 }
411}
412
413void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700414 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700415 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800416 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800417 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700418 for_each_pid(do_mountinfo, nullptr);
419 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800420}
421
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700422static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
423{
424 DIR *d;
425 struct dirent *de;
426 char path[PATH_MAX];
427
428 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700429 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700430 return;
431 }
432
433 while ((de = readdir(d))) {
434 if (de->d_type != DT_LNK) {
435 continue;
436 }
437 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700438 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700439 }
440
441 closedir(d);
442}
443
Mark Salyzyn326842f2015-04-30 09:49:41 -0700444static bool skip_not_stat(const char *path) {
445 static const char stat[] = "/stat";
446 size_t len = strlen(path);
447 if (path[len - 1] == '/') { /* Directory? */
448 return false;
449 }
450 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
451}
452
Felipe Leme4c2d6632016-09-28 14:32:00 -0700453static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800454 return false;
455}
456
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700457unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700458
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800459//
460// stat offsets
461// Name units description
462// ---- ----- -----------
463// read I/Os requests number of read I/Os processed
464#define __STAT_READ_IOS 0
465// read merges requests number of read I/Os merged with in-queue I/O
466#define __STAT_READ_MERGES 1
467// read sectors sectors number of sectors read
468#define __STAT_READ_SECTORS 2
469// read ticks milliseconds total wait time for read requests
470#define __STAT_READ_TICKS 3
471// write I/Os requests number of write I/Os processed
472#define __STAT_WRITE_IOS 4
473// write merges requests number of write I/Os merged with in-queue I/O
474#define __STAT_WRITE_MERGES 5
475// write sectors sectors number of sectors written
476#define __STAT_WRITE_SECTORS 6
477// write ticks milliseconds total wait time for write requests
478#define __STAT_WRITE_TICKS 7
479// in_flight requests number of I/Os currently in flight
480#define __STAT_IN_FLIGHT 8
481// io_ticks milliseconds total time this block device has been active
482#define __STAT_IO_TICKS 9
483// time_in_queue milliseconds total wait time for all requests
484#define __STAT_IN_QUEUE 10
485#define __STAT_NUMBER_FIELD 11
486//
487// read I/Os, write I/Os
488// =====================
489//
490// These values increment when an I/O request completes.
491//
492// read merges, write merges
493// =========================
494//
495// These values increment when an I/O request is merged with an
496// already-queued I/O request.
497//
498// read sectors, write sectors
499// ===========================
500//
501// These values count the number of sectors read from or written to this
502// block device. The "sectors" in question are the standard UNIX 512-byte
503// sectors, not any device- or filesystem-specific block size. The
504// counters are incremented when the I/O completes.
505#define SECTOR_SIZE 512
506//
507// read ticks, write ticks
508// =======================
509//
510// These values count the number of milliseconds that I/O requests have
511// waited on this block device. If there are multiple I/O requests waiting,
512// these values will increase at a rate greater than 1000/second; for
513// example, if 60 read requests wait for an average of 30 ms, the read_ticks
514// field will increase by 60*30 = 1800.
515//
516// in_flight
517// =========
518//
519// This value counts the number of I/O requests that have been issued to
520// the device driver but have not yet completed. It does not include I/O
521// requests that are in the queue but not yet issued to the device driver.
522//
523// io_ticks
524// ========
525//
526// This value counts the number of milliseconds during which the device has
527// had I/O requests queued.
528//
529// time_in_queue
530// =============
531//
532// This value counts the number of milliseconds that I/O requests have waited
533// on this block device. If there are multiple I/O requests waiting, this
534// value will increase as the product of the number of milliseconds times the
535// number of requests waiting (see "read ticks" above for an example).
536#define S_TO_MS 1000
537//
538
Mark Salyzyn326842f2015-04-30 09:49:41 -0700539static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800540 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700541 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700542 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700543 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700544 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700545 getline(&buffer, &i, fp);
546 fclose(fp);
547 if (!buffer) {
548 return -errno;
549 }
550 i = strlen(buffer);
551 while ((i > 0) && (buffer[i - 1] == '\n')) {
552 buffer[--i] = '\0';
553 }
554 if (!*buffer) {
555 free(buffer);
556 return 0;
557 }
558 z = true;
559 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800560 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700561 if (fields[i] != 0) {
562 z = false;
563 }
564 }
565 if (z) { /* never accessed */
566 free(buffer);
567 return 0;
568 }
569
Wei Wang509bb5d2017-06-09 14:42:12 -0700570 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
571 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700572 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700573
574 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
575 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
576 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700577 free(buffer);
578
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800579 if (fields[__STAT_IO_TICKS]) {
580 unsigned long read_perf = 0;
581 unsigned long read_ios = 0;
582 if (fields[__STAT_READ_TICKS]) {
583 unsigned long long divisor = fields[__STAT_READ_TICKS]
584 * fields[__STAT_IO_TICKS];
585 read_perf = ((unsigned long long)SECTOR_SIZE
586 * fields[__STAT_READ_SECTORS]
587 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
588 / divisor;
589 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
590 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
591 / divisor;
592 }
593
594 unsigned long write_perf = 0;
595 unsigned long write_ios = 0;
596 if (fields[__STAT_WRITE_TICKS]) {
597 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
598 * fields[__STAT_IO_TICKS];
599 write_perf = ((unsigned long long)SECTOR_SIZE
600 * fields[__STAT_WRITE_SECTORS]
601 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
602 / divisor;
603 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
604 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
605 / divisor;
606 }
607
608 unsigned queue = (fields[__STAT_IN_QUEUE]
609 + (fields[__STAT_IO_TICKS] >> 1))
610 / fields[__STAT_IO_TICKS];
611
612 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700613 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 -0800614 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700615 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 -0800616 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800617 }
618
619 /* bugreport timeout factor adjustment */
620 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
621 worst_write_perf = write_perf;
622 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700623 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700624 return 0;
625}
626
Yao Chenbe3bbc12018-01-17 16:31:10 -0800627static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
628
629/* timeout in ms to read a list of buffers */
630static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
631 unsigned long timeout_ms = 0;
632 for (const auto& buffer : buffers) {
633 log_id_t id = android_name_to_log_id(buffer.c_str());
634 unsigned long property_size = __android_logger_get_buffer_size(id);
635 /* Engineering margin is ten-fold our guess */
636 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
637 }
638 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700639}
640
Nandana Duttd2f5f082019-01-18 17:13:52 +0000641Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
642}
643
644android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
645 std::lock_guard<std::mutex> lock(lock_);
646 result_ = APPROVED;
647 MYLOGD("User approved consent to share bugreport\n");
648 return android::binder::Status::ok();
649}
650
651android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
652 std::lock_guard<std::mutex> lock(lock_);
653 result_ = DENIED;
654 MYLOGW("User denied consent to share bugreport\n");
655 return android::binder::Status::ok();
656}
657
658UserConsentResult Dumpstate::ConsentCallback::getResult() {
659 std::lock_guard<std::mutex> lock(lock_);
660 return result_;
661}
662
663uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
664 return Nanotime() - start_time_;
665}
666
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700667void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700668 std::string build, fingerprint, radio, bootloader, network;
669 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700670
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700671 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
672 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700673 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
674 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
675 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700676 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700677
Felipe Lemed8b94e52016-12-08 10:21:44 -0800678 printf("========================================================\n");
679 printf("== dumpstate: %s\n", date);
680 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700681
Felipe Lemed8b94e52016-12-08 10:21:44 -0800682 printf("\n");
683 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700684 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800685 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
686 printf("Bootloader: %s\n", bootloader.c_str());
687 printf("Radio: %s\n", radio.c_str());
688 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100689 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
690 if (module_metadata_version != 0) {
691 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
692 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700693
Felipe Lemed8b94e52016-12-08 10:21:44 -0800694 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800695 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800696 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800697 printf("Uptime: ");
698 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
699 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800700 printf("Bugreport format version: %s\n", version_.c_str());
701 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
Nandana Dutt5fb117b2018-09-27 09:23:36 +0100702 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800703 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800704}
705
Felipe Leme24b66ee2016-06-16 10:55:26 -0700706// List of file extensions that can cause a zip file attachment to be rejected by some email
707// service providers.
708static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
709 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
710 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
711 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
712};
713
Vishnu Naire97d6122018-01-18 13:58:56 -0800714status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
715 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700716 if (!IsZipping()) {
717 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
718 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800719 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800720 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700721 std::string valid_name = entry_name;
722
723 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700724 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700725 if (idx != std::string::npos) {
726 std::string extension = entry_name.substr(idx);
727 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
728 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
729 valid_name = entry_name + ".renamed";
730 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
731 }
732 }
733
Felipe Leme6fe9db62016-02-12 09:04:16 -0800734 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
735 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700736 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
737 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700738 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700739 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700740 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800741 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800742 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000743 bool finished_entry = false;
744 auto finish_entry = [this, &finished_entry] {
745 if (!finished_entry) {
746 // This should only be called when we're going to return an earlier error,
747 // which would've been logged. This may imply the file is already corrupt
748 // and any further logging from FinishEntry is more likely to mislead than
749 // not.
750 this->zip_writer_->FinishEntry();
751 }
752 };
753 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800754 auto start = std::chrono::steady_clock::now();
755 auto end = start + timeout;
756 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800757
Felipe Leme770410d2016-01-26 17:07:14 -0800758 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800759 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800760 if (timeout.count() > 0) {
761 // lambda to recalculate the timeout.
762 auto time_left_ms = [end]() {
763 auto now = std::chrono::steady_clock::now();
764 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
765 return std::max(diff.count(), 0LL);
766 };
767
768 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
769 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000770 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
771 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800772 return -errno;
773 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000774 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800775 entry_name.c_str(), strerror(errno), timeout.count());
776 return TIMED_OUT;
777 }
778 }
779
Zach Riggle22200402016-08-18 01:01:24 -0400780 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800781 if (bytes_read == 0) {
782 break;
783 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800784 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800785 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700787 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800788 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700789 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800790 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800791 }
792 }
793
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700794 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000795 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700796 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700797 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800798 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800799 }
800
Vishnu Naire97d6122018-01-18 13:58:56 -0800801 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800802}
803
Felipe Leme1d486fe2016-10-14 18:06:47 -0700804bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
805 android::base::unique_fd fd(
806 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700807 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800808 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800809 return false;
810 }
811
Vishnu Naire97d6122018-01-18 13:58:56 -0800812 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800813}
814
815/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700816static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800817 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800818}
819
Felipe Leme1d486fe2016-10-14 18:06:47 -0700820void Dumpstate::AddDir(const std::string& dir, bool recursive) {
821 if (!IsZipping()) {
822 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800823 return;
824 }
Felipe Leme678727a2016-09-21 17:22:11 -0700825 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800826 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700827 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800828}
829
Felipe Leme1d486fe2016-10-14 18:06:47 -0700830bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
831 if (!IsZipping()) {
832 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
833 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800834 return false;
835 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800836 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700837 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700838 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700839 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700840 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800841 return false;
842 }
843
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700844 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700845 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700846 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700847 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800848 return false;
849 }
850
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700851 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700852 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700853 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800854 return false;
855 }
856
857 return true;
858}
859
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800860static void DoKmsg() {
861 struct stat st;
862 if (!stat(PSTORE_LAST_KMSG, &st)) {
863 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
864 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
865 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
866 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
867 } else {
868 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
869 DumpFile("LAST KMSG", "/proc/last_kmsg");
870 }
871}
872
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800873static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800874 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800875 RunCommand(
876 "KERNEL LOG",
877 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
878 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
879}
880
Nandana Duttdb379fa2019-10-09 16:54:41 +0100881static void DoSystemLogcat(time_t since) {
882 char since_str[80];
883 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
884
885 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
886 RunCommand("SYSTEM LOG",
887 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
888 since_str},
889 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
890}
891
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800892static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800893 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800894 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
895 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800896 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100897 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800898 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
899 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800900 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800901 RunCommand(
902 "EVENT LOG",
903 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100904 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800905 timeout_ms = logcat_timeout({"stats"});
906 RunCommand(
907 "STATS LOG",
908 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100909 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800910 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800911 RunCommand(
912 "RADIO LOG",
913 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100914 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
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
Jayachandran Ca94c7172017-06-10 15:08:12 -0700948static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700949 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
950 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900951 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700952 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900953 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
954 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
955 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
956 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700957}
958
David Andersond9ba4752018-12-11 18:26:59 -0800959static void DumpDynamicPartitionInfo() {
960 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
961 return;
962 }
963
964 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700965 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800966}
967
Narayan Kamath8f788292017-05-25 13:20:39 +0100968static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
969 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
970 anr_traces_dir.c_str());
971
972 // If we're here, dump_traces_path will always be a temporary file
973 // (created with mkostemp or similar) that contains dumps taken earlier
974 // on in the process.
975 if (dump_traces_path != nullptr) {
976 if (add_to_zip) {
977 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
978 } else {
979 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
980 dump_traces_path);
981 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
982 }
983
984 const int ret = unlink(dump_traces_path);
985 if (ret == -1) {
986 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
987 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700988 }
989 }
990
Narayan Kamathbd863722017-06-01 18:50:12 +0100991 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700992 if (ds.anr_data_.size() > 0) {
993 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100994 "VM TRACES AT LAST ANR", add_to_zip);
995
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100996 // The "last" ANR will always be included as separate entry in the zip file. In addition,
997 // it will be present in the body of the main entry if |add_to_zip| == false.
998 //
999 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001000 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +01001001 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001002 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001003 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1004 }
1005}
1006
1007static void AddAnrTraceFiles() {
1008 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1009
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001010 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001011
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001012 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001013
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001014 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1015
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001016 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001017 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001018 int i = 0;
1019 while (true) {
1020 const std::string slow_trace_path =
1021 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1022 if (stat(slow_trace_path.c_str(), &st)) {
1023 // No traces file at this index, done with the files.
1024 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001025 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001026 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1027 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001028 }
1029}
1030
Wei Wang509bb5d2017-06-09 14:42:12 -07001031static void DumpBlockStatFiles() {
1032 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001033
Wei Wang1dc1ef52017-06-12 11:28:37 -07001034 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1035
1036 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001037 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1038 return;
1039 }
1040
1041 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001042 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001043 if ((d->d_name[0] == '.')
1044 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1045 || (d->d_name[1] == '\0'))) {
1046 continue;
1047 }
1048 const std::string new_path =
1049 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1050 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1051 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1052 printf("\n");
1053 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001054 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001055}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001056
1057static void DumpPacketStats() {
1058 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1059 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1060 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1061 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1062 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1063}
1064
1065static void DumpIpAddrAndRules() {
1066 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1067 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1068 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1069 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1070 RunCommand("IP RULES", {"ip", "rule", "show"});
1071 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1072}
1073
Nandana Dutt5c390032019-03-12 10:52:56 +00001074static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1075 std::chrono::milliseconds timeout,
1076 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001077 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001078 sp<android::IServiceManager> sm = defaultServiceManager();
1079 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001080 Vector<String16> args;
1081 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001082 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1083 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001084 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001085 std::string path(title);
1086 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001087 size_t bytes_written = 0;
Steven Moreland5a30d342019-10-08 13:53:28 -07001088 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001089 if (status == OK) {
1090 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1091 std::chrono::duration<double> elapsed_seconds;
1092 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1093 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001094 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1095 bool dump_complete = (status == OK);
1096 dumpsys.stopDumpThread(dump_complete);
1097 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001098
1099 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1100 std::chrono::steady_clock::now() - start);
1101 if (elapsed_duration > timeout) {
1102 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1103 elapsed_duration.count());
1104 break;
1105 }
1106 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001107 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001108}
1109
Vishnu Nair64afc022018-02-01 15:29:34 -08001110static void RunDumpsysText(const std::string& title, int priority,
1111 std::chrono::milliseconds timeout,
1112 std::chrono::milliseconds service_timeout) {
1113 DurationReporter duration_reporter(title);
1114 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1115 fsync(STDOUT_FILENO);
1116 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1117}
1118
1119/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001120static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1121 std::chrono::milliseconds timeout,
1122 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001123 DurationReporter duration_reporter(title);
1124 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1125 fsync(STDOUT_FILENO);
1126 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1127 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001128
1129 RETURN_IF_USER_DENIED_CONSENT();
1130
1131 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1132 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001133}
1134
Nandana Dutt5c390032019-03-12 10:52:56 +00001135static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1136 std::chrono::milliseconds timeout,
1137 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001138 if (!ds.IsZipping()) {
1139 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001140 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001141 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001142 sp<android::IServiceManager> sm = defaultServiceManager();
1143 Dumpsys dumpsys(sm.get());
1144 Vector<String16> args;
1145 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1146 DurationReporter duration_reporter(title);
1147
1148 auto start = std::chrono::steady_clock::now();
1149 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1150 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001151 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001152 std::string path(kProtoPath);
1153 path.append(String8(service).c_str());
1154 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1155 path.append("_CRITICAL");
1156 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1157 path.append("_HIGH");
1158 }
1159 path.append(kProtoExt);
Steven Moreland5a30d342019-10-08 13:53:28 -07001160 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001161 if (status == OK) {
1162 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1163 bool dumpTerminated = (status == OK);
1164 dumpsys.stopDumpThread(dumpTerminated);
1165 }
1166 ZipWriter::FileEntry file_entry;
1167 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001168
1169 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1170 std::chrono::steady_clock::now() - start);
1171 if (elapsed_duration > timeout) {
1172 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1173 elapsed_duration.count());
1174 break;
1175 }
1176 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001177 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001178}
1179
Nandana Dutta7db6342018-11-21 14:53:34 +00001180// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001181static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001182 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1183 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001184
1185 RETURN_IF_USER_DENIED_CONSENT();
1186
1187 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1188 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001189}
1190
1191// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001192static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001193 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1194 // high priority. Reduce timeout once they are able to dump in a shorter time or
1195 // moved to a parallel task.
1196 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1197 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001198
1199 RETURN_IF_USER_DENIED_CONSENT();
1200
1201 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1202 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001203}
1204
1205// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001206static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001207 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001208
1209 RETURN_IF_USER_DENIED_CONSENT();
1210
1211 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1212 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001213}
1214
Steven Moreland44cd9482018-01-04 16:24:13 -08001215static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001216 if (!ds.IsZipping()) {
1217 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1218 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1219 return;
1220 }
1221 DurationReporter duration_reporter("DUMP HALS");
1222 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001223 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001224
Steven Moreland44cd9482018-01-04 16:24:13 -08001225 using android::hidl::manager::V1_0::IServiceManager;
1226 using android::hardware::defaultServiceManager;
1227
1228 sp<IServiceManager> sm = defaultServiceManager();
1229 if (sm == nullptr) {
1230 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1231 return;
1232 }
1233
1234 auto ret = sm->list([&](const auto& interfaces) {
1235 for (const std::string& interface : interfaces) {
1236 std::string cleanName = interface;
1237 std::replace_if(cleanName.begin(),
1238 cleanName.end(),
1239 [](char c) {
1240 return !isalnum(c) &&
1241 std::string("@-_:.").find(c) == std::string::npos;
1242 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001243 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001244
1245 {
1246 auto fd = android::base::unique_fd(
1247 TEMP_FAILURE_RETRY(open(path.c_str(),
1248 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1249 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1250 if (fd < 0) {
1251 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1252 continue;
1253 }
1254 RunCommandToFd(fd,
1255 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001256 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001257 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1258
1259 bool empty = 0 == lseek(fd, 0, SEEK_END);
1260 if (!empty) {
1261 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1262 }
1263 }
1264
1265 unlink(path.c_str());
1266 }
1267 });
1268
1269 if (!ret.isOk()) {
1270 MYLOGE("Could not list hals from hwservicemanager.\n");
1271 }
1272}
1273
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001274static void DumpExternalFragmentationInfo() {
1275 struct stat st;
1276 if (stat("/proc/buddyinfo", &st) != 0) {
1277 MYLOGE("Unable to dump external fragmentation info\n");
1278 return;
1279 }
1280
1281 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1282 std::ifstream ifs("/proc/buddyinfo");
1283 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1284 for (std::string line; std::getline(ifs, line);) {
1285 std::smatch match_results;
1286 if (std::regex_match(line, match_results, unusable_index_regex)) {
1287 std::stringstream free_pages(std::string{match_results[3]});
1288 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1289 std::istream_iterator<int>());
1290
1291 int total_free_pages = 0;
1292 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1293 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1294 }
1295
1296 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1297 match_results[2].str().c_str());
1298
1299 int usable_free_pages = total_free_pages;
1300 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1301 auto unusable_index = (total_free_pages - usable_free_pages) /
1302 static_cast<double>(total_free_pages);
1303 printf(" %5.3f", unusable_index);
1304 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1305 }
1306
1307 printf("\n");
1308 }
1309 }
1310 printf("\n");
1311}
1312
Nandana Dutt5c390032019-03-12 10:52:56 +00001313// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1314// via the consent they are shown. Ignores other errors that occur while running various
1315// commands. The consent checking is currently done around long running tasks, which happen to
1316// be distributed fairly evenly throughout the function.
1317static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001318 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001319
Nandana Dutt5c390032019-03-12 10:52:56 +00001320 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1321 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1322 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001323 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001324 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001325 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001326 DumpFile("MEMORY INFO", "/proc/meminfo");
1327 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001328 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001329
1330 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1331
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001332 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1333 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1334 DumpFile("SLAB INFO", "/proc/slabinfo");
1335 DumpFile("ZONEINFO", "/proc/zoneinfo");
1336 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1337 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001338 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001339
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001340 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1341 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001342
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001343 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001344 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001345
1346 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1347 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001348
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001349 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001350
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001351 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001352 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001353 struct stat s;
1354 if (stat("/proc/modules", &s) != 0) {
1355 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1356 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001357 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001358 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001359
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001360 if (__android_logger_property_get_bool(
1361 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1362 DoKernelLogcat();
1363 } else {
1364 do_dmesg();
1365 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001366
Felipe Lemef0292972016-11-22 13:57:05 -08001367 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001368
1369 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1370
Jeff Brown1dc94e32014-09-11 14:15:27 -07001371 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001372 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001373
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001374 /* Dump Bluetooth HCI logs */
1375 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001376
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001377 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001378 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001379 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001380 }
1381
Felipe Lemee184f662016-10-27 10:04:47 -07001382 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001383
Narayan Kamath8f788292017-05-25 13:20:39 +01001384 // NOTE: tombstones are always added as separate entries in the zip archive
1385 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001386 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001387 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001388 if (!tombstones_dumped) {
1389 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001390 }
1391
Jayachandran Ca94c7172017-06-10 15:08:12 -07001392 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393
Chenbo Feng276a3b62018-08-07 11:44:49 -07001394 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1395
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001396 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001397
Jayachandran Ca94c7172017-06-10 15:08:12 -07001398 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001399
1400 dump_route_tables();
1401
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001402 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1403 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1404 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001405
Nandana Dutt5c390032019-03-12 10:52:56 +00001406 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001407
Elliott Hughes23ccc622017-02-28 10:14:22 -08001408 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001409
Jin Qianf334d662017-10-10 14:41:37 -07001410 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001411
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001412 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001413
Colin Crossf45fa6b2012-03-26 12:38:26 -07001414 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001415 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1416 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1417 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1418 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1419 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001420
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001421 /* Add window and surface trace files. */
1422 if (!PropertiesHelper::IsUserBuild()) {
1423 ds.AddDir(WMTRACE_DATA_DIR, false);
1424 }
1425
Nandana Dutt5c390032019-03-12 10:52:56 +00001426 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001427
Steven Moreland7440ddb2016-12-15 16:13:39 -08001428 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001429 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1430 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001431 // su does not exist on user builds, so try running without it.
1432 // This way any implementations of vril-dump that do not require
1433 // root can run on user builds.
1434 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001435 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001436 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001437 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001438 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001439 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001440 }
1441
Felipe Lemed8b94e52016-12-08 10:21:44 -08001442 printf("========================================================\n");
1443 printf("== Android Framework Services\n");
1444 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001445
Nandana Dutt5c390032019-03-12 10:52:56 +00001446 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001447
Felipe Lemed8b94e52016-12-08 10:21:44 -08001448 printf("========================================================\n");
1449 printf("== Checkins\n");
1450 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001451
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001452 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001453
1454 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1455
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001456 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1457 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1458 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1459 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001460
Felipe Lemed8b94e52016-12-08 10:21:44 -08001461 printf("========================================================\n");
1462 printf("== Running Application Activities\n");
1463 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001464
Makoto Onuki60780982018-04-16 15:34:00 -07001465 // The following dumpsys internally collects output from running apps, so it can take a long
1466 // time. So let's extend the timeout.
1467
1468 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1469
1470 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001471
Felipe Lemed8b94e52016-12-08 10:21:44 -08001472 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001473 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001474 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001475
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001476 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001477 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001478
Felipe Lemed8b94e52016-12-08 10:21:44 -08001479 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001480 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001481 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001482
Makoto Onuki60780982018-04-16 15:34:00 -07001483 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1484 DUMPSYS_COMPONENTS_OPTIONS);
1485
1486 printf("========================================================\n");
1487 printf("== Running Application Providers (platform)\n");
1488 printf("========================================================\n");
1489
1490 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1491 DUMPSYS_COMPONENTS_OPTIONS);
1492
1493 printf("========================================================\n");
1494 printf("== Running Application Providers (non-platform)\n");
1495 printf("========================================================\n");
1496
1497 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1498 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001499
Adrian Roos8b397ab2017-04-04 16:35:44 -07001500 printf("========================================================\n");
1501 printf("== Dropbox crashes\n");
1502 printf("========================================================\n");
1503
1504 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1505 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1506
Felipe Lemed8b94e52016-12-08 10:21:44 -08001507 printf("========================================================\n");
1508 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1509 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1510 printf("========================================================\n");
1511 printf("== dumpstate: done (id %d)\n", ds.id_);
1512 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001513
1514 printf("========================================================\n");
1515 printf("== Obtaining statsd metadata\n");
1516 printf("========================================================\n");
1517 // This differs from the usual dumpsys stats, which is the stats report data.
1518 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001519
1520 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1521
Nandana Dutt5c390032019-03-12 10:52:56 +00001522 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001523}
1524
Nandana Dutt5c390032019-03-12 10:52:56 +00001525/*
1526 * Dumps state for the default case; drops root after it's no longer necessary.
1527 *
1528 * Returns RunStatus::OK if everything went fine.
1529 * Returns RunStatus::ERROR if there was an error.
1530 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1531 * with the caller.
1532 */
1533static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001534 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001535 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001536 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001537
Nandana Duttdb379fa2019-10-09 16:54:41 +01001538 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1539 // buffer.
1540 DoLogcat();
1541 // Capture timestamp after first logcat to use in next logcat
1542 time_t logcat_ts = time(nullptr);
1543
Nandana Dutt4be45d12018-09-26 15:04:23 +01001544 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001545 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001546
1547 /* Run some operations that require root. */
1548 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1549 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1550
1551 ds.AddDir(RECOVERY_DIR, true);
1552 ds.AddDir(RECOVERY_DATA_DIR, true);
1553 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1554 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1555 if (!PropertiesHelper::IsUserBuild()) {
1556 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1557 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1558 }
Jerry Changa1df8a92020-01-02 16:03:39 +08001559 ds.AddDir(PREREBOOT_DATA_DIR, false);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001560 add_mountinfo();
1561 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001562 DumpDynamicPartitionInfo();
Yifan Hong3945e1b2019-10-29 12:59:23 -07001563 ds.AddDir(OTA_METADATA_DIR, true);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001564
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001565 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001566 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1567
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001568 // Dump IPsec stats. No keys are exposed here.
1569 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1570
Nandana Dutt4be45d12018-09-26 15:04:23 +01001571 // Run ss as root so we can see socket marks.
1572 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1573
1574 // Run iotop as root to show top 100 IO threads
1575 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1576
Erick Reyese68df822019-02-11 14:46:36 -08001577 // Gather shared memory buffer info if the product implements it
1578 struct stat st;
1579 if (!stat("/product/bin/dmabuf_dump", &st)) {
1580 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1581 }
1582
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001583 DumpFile("PSI cpu", "/proc/pressure/cpu");
1584 DumpFile("PSI memory", "/proc/pressure/memory");
1585 DumpFile("PSI io", "/proc/pressure/io");
1586
Nandana Dutt4be45d12018-09-26 15:04:23 +01001587 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001588 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001589 }
1590
Nandana Dutt5c390032019-03-12 10:52:56 +00001591 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001592 Dumpstate::RunStatus status = dumpstate();
1593 // Capture logcat since the last time we did it.
1594 DoSystemLogcat(logcat_ts);
1595 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001596}
1597
mukesh agrawal253dad42018-01-23 21:59:59 -08001598// This method collects common dumpsys for telephony and wifi
1599static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001600 DumpIpTablesAsRoot();
1601
Jayachandran C69968272019-07-08 09:46:05 -07001602 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1603
Jayachandran Ca94c7172017-06-10 15:08:12 -07001604 if (!DropRootUser()) {
1605 return;
1606 }
1607
1608 do_dmesg();
1609 DoLogcat();
1610 DumpPacketStats();
1611 DoKmsg();
1612 DumpIpAddrAndRules();
1613 dump_route_tables();
Jayachandran C69968272019-07-08 09:46:05 -07001614 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001615
1616 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1617 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001618}
1619
1620// This method collects dumpsys for telephony debugging only
1621static void DumpstateTelephonyOnly() {
1622 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001623 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001624
1625 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001626
1627 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1628
1629 printf("========================================================\n");
1630 printf("== Android Framework Services\n");
1631 printf("========================================================\n");
1632
Vishnu Nair652cc802017-11-30 15:18:30 -08001633 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1634 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001635 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1636 SEC_TO_MSEC(10));
1637 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001638 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1639 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001640 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1641 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001642 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1643 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001644
1645 printf("========================================================\n");
1646 printf("== Running Application Services\n");
1647 printf("========================================================\n");
1648
1649 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1650
1651 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001652 printf("== Running Application Services (non-platform)\n");
1653 printf("========================================================\n");
1654
1655 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1656 DUMPSYS_COMPONENTS_OPTIONS);
1657
1658 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001659 printf("== Checkins\n");
1660 printf("========================================================\n");
1661
1662 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1663
1664 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001665 printf("== dumpstate: done (id %d)\n", ds.id_);
1666 printf("========================================================\n");
1667}
1668
mukesh agrawal253dad42018-01-23 21:59:59 -08001669// This method collects dumpsys for wifi debugging only
1670static void DumpstateWifiOnly() {
1671 DurationReporter duration_reporter("DUMPSTATE");
1672
1673 DumpstateRadioCommon();
1674
1675 printf("========================================================\n");
1676 printf("== Android Framework Services\n");
1677 printf("========================================================\n");
1678
1679 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1680 SEC_TO_MSEC(10));
1681 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1682 SEC_TO_MSEC(10));
1683
1684 printf("========================================================\n");
1685 printf("== dumpstate: done (id %d)\n", ds.id_);
1686 printf("========================================================\n");
1687}
1688
Nandana Duttcf419a72019-03-14 10:40:17 +00001689Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001690 DurationReporter duration_reporter("DUMP TRACES");
1691
1692 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1693 const size_t buf_size = temp_file_pattern.length() + 1;
1694 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1695 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1696
1697 // Create a new, empty file to receive all trace dumps.
1698 //
1699 // TODO: This can be simplified once we remove support for the old style
1700 // dumps. We can have a file descriptor passed in to dump_traces instead
1701 // of creating a file, closing it and then reopening it again.
1702 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1703 if (fd < 0) {
1704 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001705 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001706 }
1707
1708 // Nobody should have access to this temporary file except dumpstate, but we
1709 // temporarily grant 'read' to 'others' here because this file is created
1710 // when tombstoned is still running as root, but dumped after dropping. This
1711 // can go away once support for old style dumping has.
1712 const int chmod_ret = fchmod(fd, 0666);
1713 if (chmod_ret < 0) {
1714 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001715 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001716 }
1717
1718 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1719 if (proc.get() == nullptr) {
1720 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001721 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001722 }
1723
1724 // Number of times process dumping has timed out. If we encounter too many
1725 // failures, we'll give up.
1726 int timeout_failures = 0;
1727 bool dalvik_found = false;
1728
1729 const std::set<int> hal_pids = get_interesting_hal_pids();
1730
1731 struct dirent* d;
1732 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001733 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001734 int pid = atoi(d->d_name);
1735 if (pid <= 0) {
1736 continue;
1737 }
1738
1739 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1740 std::string exe;
1741 if (!android::base::Readlink(link_name, &exe)) {
1742 continue;
1743 }
1744
1745 bool is_java_process;
1746 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1747 // Don't bother dumping backtraces for the zygote.
1748 if (IsZygote(pid)) {
1749 continue;
1750 }
1751
1752 dalvik_found = true;
1753 is_java_process = true;
1754 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1755 is_java_process = false;
1756 } else {
1757 // Probably a native process we don't care about, continue.
1758 continue;
1759 }
1760
1761 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1762 if (timeout_failures == 3) {
1763 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1764 break;
1765 }
1766
1767 const uint64_t start = Nanotime();
1768 const int ret = dump_backtrace_to_file_timeout(
1769 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1770 is_java_process ? 5 : 20, fd);
1771
1772 if (ret == -1) {
1773 // For consistency, the header and footer to this message match those
1774 // dumped by debuggerd in the success case.
1775 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1776 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1777 dprintf(fd, "---- end %d ----", pid);
1778 timeout_failures++;
1779 continue;
1780 }
1781
1782 // We've successfully dumped stack traces, reset the failure count
1783 // and write a summary of the elapsed time to the file and continue with the
1784 // next process.
1785 timeout_failures = 0;
1786
1787 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1788 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1789 }
1790
1791 if (!dalvik_found) {
1792 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1793 }
1794
Nandana Duttcf419a72019-03-14 10:40:17 +00001795 *path = file_name_buf.release();
1796 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001797}
1798
Felipe Leme6f674ae2016-11-18 17:10:33 -08001799void Dumpstate::DumpstateBoard() {
1800 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001801 printf("========================================================\n");
1802 printf("== Board\n");
1803 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001804
Felipe Leme6f674ae2016-11-18 17:10:33 -08001805 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001806 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001807 return;
1808 }
1809
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001810 std::vector<std::string> paths;
1811 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001812 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001813 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1814 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001815 remover.emplace_back(android::base::make_scope_guard(
1816 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001817 }
Jie Song9fbfad02017-06-20 16:29:42 -07001818
Wei Wang587eac92018-04-05 12:17:20 -07001819 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1820 if (dumpstate_device == nullptr) {
1821 MYLOGE("No IDumpstateDevice implementation\n");
1822 return;
1823 }
1824
1825 using ScopedNativeHandle =
1826 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1827 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1828 [](native_handle_t* handle) {
1829 native_handle_close(handle);
1830 native_handle_delete(handle);
1831 });
1832 if (handle == nullptr) {
1833 MYLOGE("Could not create native_handle\n");
1834 return;
1835 }
1836
Nandana Dutt5c390032019-03-12 10:52:56 +00001837 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001838 for (size_t i = 0; i < paths.size(); i++) {
1839 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1840
1841 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1842 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1843 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1844 if (fd < 0) {
1845 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1846 return;
1847 }
1848 handle.get()->data[i] = fd.release();
1849 }
1850
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001851 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001852 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1853 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1854 // and grab whatever dumped
1855 std::packaged_task<bool()>
1856 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001857 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1858 if (!status.isOk()) {
1859 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001860 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001861 }
Wei Wang587eac92018-04-05 12:17:20 -07001862 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001863 });
Wei Wang587eac92018-04-05 12:17:20 -07001864
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001865 auto result = dumpstate_task.get_future();
1866 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001867
1868 constexpr size_t timeout_sec = 30;
1869 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1870 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1871 if (!android::base::SetProperty("ctl.interface_restart",
1872 android::base::StringPrintf("%s/default",
1873 IDumpstateDevice::descriptor))) {
1874 MYLOGE("Couldn't restart dumpstate HAL\n");
1875 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001876 }
Wei Wang587eac92018-04-05 12:17:20 -07001877 // Wait some time for init to kill dumpstate vendor HAL
1878 constexpr size_t killing_timeout_sec = 10;
1879 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1880 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1881 "there might be racing in content\n", killing_timeout_sec);
1882 }
1883
1884 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1885 for (size_t i = 0; i < paths.size(); i++) {
1886 struct stat s;
1887 if (fstat(handle.get()->data[i], &s) == -1) {
1888 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1889 strerror(errno));
1890 file_sizes[i] = -1;
1891 continue;
1892 }
1893 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001894 }
1895
1896 for (size_t i = 0; i < paths.size(); i++) {
1897 if (file_sizes[i] == -1) {
1898 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001899 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001900 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001901 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001902 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001903 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001904 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001905 }
1906
Felipe Lemed8b94e52016-12-08 10:21:44 -08001907 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001908}
1909
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001910static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001911 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001912 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001913 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1914 " -h: display this help message\n"
1915 " -b: play sound file instead of vibrate, at beginning of job\n"
1916 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001917 " -d: append date to filename\n"
1918 " -p: capture screenshot to filename.png\n"
1919 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001920 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001921 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001922 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001923 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001924 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001925 "progress (requires -B)\n"
1926 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001927 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001928 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001929 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001930}
1931
Wei Liuf87959e2016-08-26 14:51:42 -07001932static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001933 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001934}
1935
Felipe Leme1d486fe2016-10-14 18:06:47 -07001936bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001937 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001938 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001939 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001940 // Final timestamp
1941 char date[80];
1942 time_t the_real_now_please_stand_up = time(nullptr);
1943 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001944 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001945 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001946
Felipe Leme9a523ae2016-10-20 15:10:33 -07001947 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001948 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001949 return false;
1950 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001951 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001952 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001953 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001954 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001955
Felipe Leme0f3fb202016-06-10 17:10:53 -07001956 // Add log file (which contains stderr output) to zip...
1957 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001958 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001959 MYLOGE("Failed to add dumpstate log to .zip file\n");
1960 return false;
1961 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001962 // TODO: Should truncate the existing file.
1963 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001964 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1965 return false;
1966 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001967 fprintf(stderr, "\n");
1968
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001969 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001970 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001971 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001972 return false;
1973 }
1974
Felipe Leme1d486fe2016-10-14 18:06:47 -07001975 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1976 ds.zip_file.reset(nullptr);
1977
Felipe Lemee9d2c542016-11-15 11:48:26 -08001978 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001979 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001980
Felipe Leme1e9edc62015-12-21 16:02:13 -08001981 return true;
1982}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001983
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001984static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001985 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1986 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001987 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001988 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001989 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001990 }
1991
1992 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001993 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001994
1995 std::vector<uint8_t> buffer(65536);
1996 while (1) {
1997 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1998 if (bytes_read == 0) {
1999 break;
2000 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08002001 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07002002 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002003 }
2004
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002005 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002006 }
2007
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002008 uint8_t hash[SHA256_DIGEST_LENGTH];
2009 SHA256_Final(hash, &ctx);
2010
2011 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
2012 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00002013 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002014 }
2015 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2016 return std::string(hash_buffer);
2017}
2018
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002019static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2020 // clang-format off
2021 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2022 "--receiver-foreground", "--receiver-include-background", "-a", action};
2023 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002024
2025 am.insert(am.end(), args.begin(), args.end());
2026
Felipe Leme8d2410e2017-02-08 09:46:08 -08002027 RunCommand("", am,
2028 CommandOptions::WithTimeout(20)
2029 .Log("Sending broadcast: '%s'\n")
2030 .Always()
2031 .DropRoot()
2032 .RedirectStderr()
2033 .Build());
2034}
2035
Felipe Leme35b8cf12017-02-10 15:47:29 -08002036static void Vibrate(int duration_ms) {
2037 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002038 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002039 CommandOptions::WithTimeout(10)
2040 .Log("Vibrate: '%s'\n")
2041 .Always()
2042 .Build());
2043 // clang-format on
2044}
2045
Nandana Dutt979388e2018-11-30 16:48:55 +00002046static void MaybeResolveSymlink(std::string* path) {
2047 std::string resolved_path;
2048 if (android::base::Readlink(*path, &resolved_path)) {
2049 *path = resolved_path;
2050 }
2051}
2052
Nandana Dutt4be45d12018-09-26 15:04:23 +01002053/*
2054 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2055 * if we are writing zip files and adds the version file.
2056 */
2057static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002058 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2059
Nandana Dutt4be45d12018-09-26 15:04:23 +01002060 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2061 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002062 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002063 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002064 char date[80];
2065 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2066 ds.name_ = date;
2067 } else {
2068 ds.name_ = "undated";
2069 }
2070
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002071 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002072 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002073 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 ds.base_name_ += "-wifi";
2075 }
2076
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002077 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002078 ds.screenshot_path_ = ds.GetPath(".png");
2079 }
2080 ds.tmp_path_ = ds.GetPath(".tmp");
2081 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2082
Nandana Dutt54dbd672019-01-11 12:58:05 +00002083 std::string destination = ds.options_->bugreport_fd.get() != -1
2084 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002085 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002086 MYLOGD(
2087 "Bugreport dir: %s\n"
2088 "Base name: %s\n"
2089 "Suffix: %s\n"
2090 "Log path: %s\n"
2091 "Temporary path: %s\n"
2092 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002093 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2094 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002095
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002096 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002097 ds.path_ = ds.GetPath(".zip");
2098 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2099 create_parent_dirs(ds.path_.c_str());
2100 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2101 if (ds.zip_file == nullptr) {
2102 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2103 } else {
2104 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2105 }
2106 ds.AddTextZipEntry("version.txt", ds.version_);
2107 }
2108}
2109
2110/*
2111 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2112 * printing zipped file status, etc.
2113 */
2114static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002115 /* check if user changed the suffix using system properties */
2116 std::string name =
2117 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2118 bool change_suffix = false;
2119 if (!name.empty()) {
2120 /* must whitelist which characters are allowed, otherwise it could cross directories */
2121 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2122 if (std::regex_match(name.c_str(), valid_regex)) {
2123 change_suffix = true;
2124 } else {
2125 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2126 }
2127 }
2128 if (change_suffix) {
2129 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2130 ds.name_ = name;
2131 if (!ds.screenshot_path_.empty()) {
2132 std::string new_screenshot_path = ds.GetPath(".png");
2133 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2134 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2135 new_screenshot_path.c_str(), strerror(errno));
2136 } else {
2137 ds.screenshot_path_ = new_screenshot_path;
2138 }
2139 }
2140 }
2141
2142 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002143 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002144 if (!ds.FinishZipFile()) {
2145 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2146 do_text_file = true;
2147 } else {
2148 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002149 // If the user has changed the suffix, we need to change the zip file name.
2150 std::string new_path = ds.GetPath(".zip");
2151 if (ds.path_ != new_path) {
2152 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2153 if (rename(ds.path_.c_str(), new_path.c_str())) {
2154 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2155 strerror(errno));
2156 } else {
2157 ds.path_ = new_path;
2158 }
2159 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002160 }
2161 }
2162 if (do_text_file) {
2163 ds.path_ = ds.GetPath(".txt");
2164 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2165 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2166 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2167 ds.path_.clear();
2168 }
2169 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002170 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002171 if (do_text_file) {
2172 dprintf(ds.control_socket_fd_,
2173 "FAIL:could not create zip file, check %s "
2174 "for more details\n",
2175 ds.log_path_.c_str());
2176 } else {
2177 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2178 }
2179 }
2180}
2181
2182/* Broadcasts that we are done with the bugreport */
2183static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002184 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002185 if (!ds.path_.empty()) {
2186 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002187 // clang-format off
2188
2189 std::vector<std::string> am_args = {
2190 "--receiver-permission", "android.permission.DUMP",
2191 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2192 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2193 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002194 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002195 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2196 };
2197 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002198 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002199 am_args.push_back("--es");
2200 am_args.push_back("android.intent.extra.SCREENSHOT");
2201 am_args.push_back(ds.screenshot_path_);
2202 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002203 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002204 am_args.push_back("--es");
2205 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002206 am_args.push_back(ds.options_->notification_title);
2207 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002208 am_args.push_back("--es");
2209 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002210 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002211 }
2212 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002213 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002214 am_args.push_back("--es");
2215 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002216 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002217 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2218 } else {
2219 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2220 }
2221 } else {
2222 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2223 }
2224}
2225
Nandana Dutt58d72e22018-11-16 10:30:48 +00002226static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2227 switch (mode) {
2228 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2229 return "BUGREPORT_FULL";
2230 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2231 return "BUGREPORT_INTERACTIVE";
2232 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2233 return "BUGREPORT_REMOTE";
2234 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2235 return "BUGREPORT_WEAR";
2236 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2237 return "BUGREPORT_TELEPHONY";
2238 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2239 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002240 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2241 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002242 }
2243}
2244
2245static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002246 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002247 switch (mode) {
2248 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2249 options->do_broadcast = true;
2250 options->do_fb = true;
2251 break;
2252 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002253 // Currently, the dumpstate binder is only used by Shell to update progress.
2254 options->do_start_service = true;
2255 options->do_progress_updates = true;
2256 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002257 options->do_broadcast = true;
2258 break;
2259 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002260 options->do_vibrate = false;
2261 options->is_remote_mode = true;
2262 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002263 options->do_broadcast = true;
2264 break;
2265 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002266 options->do_start_service = true;
2267 options->do_progress_updates = true;
2268 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002269 options->do_fb = true;
2270 options->do_broadcast = true;
2271 break;
2272 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002273 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002274 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002275 options->do_broadcast = true;
2276 break;
2277 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002278 options->wifi_only = true;
2279 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002280 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002281 options->do_broadcast = true;
2282 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002283 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2284 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002285 }
2286}
2287
2288static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002289 // If the system property is not set, it's assumed to be a default bugreport.
2290 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002291
2292 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2293 if (!extra_options.empty()) {
2294 // Framework uses a system property to override some command-line args.
2295 // Currently, it contains the type of the requested bugreport.
2296 if (extra_options == "bugreportplus") {
2297 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002298 } else if (extra_options == "bugreportfull") {
2299 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002300 } else if (extra_options == "bugreportremote") {
2301 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2302 } else if (extra_options == "bugreportwear") {
2303 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2304 } else if (extra_options == "bugreporttelephony") {
2305 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2306 } else if (extra_options == "bugreportwifi") {
2307 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002308 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002309 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002310 }
2311 // Reset the property
2312 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2313 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002314 return mode;
2315}
2316
2317// TODO: Move away from system properties when we have options passed via binder calls.
2318/* Sets runtime options from the system properties and then clears those properties. */
2319static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2320 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2321 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002322
2323 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2324 if (!options->notification_title.empty()) {
2325 // Reset the property
2326 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2327
Nandana Duttdd8cca32018-11-14 10:10:29 +00002328 options->notification_description =
2329 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002330 if (!options->notification_description.empty()) {
2331 // Reset the property
2332 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2333 }
2334 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2335 options->notification_description.c_str());
2336 }
2337}
2338
Nandana Dutt58d72e22018-11-16 10:30:48 +00002339static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2340 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2341 MYLOGI("do_add_date: %d\n", options.do_add_date);
2342 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2343 MYLOGI("use_socket: %d\n", options.use_socket);
2344 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2345 MYLOGI("do_fb: %d\n", options.do_fb);
2346 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2347 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2348 MYLOGI("show_header_only: %d\n", options.show_header_only);
2349 MYLOGI("do_start_service: %d\n", options.do_start_service);
2350 MYLOGI("telephony_only: %d\n", options.telephony_only);
2351 MYLOGI("wifi_only: %d\n", options.wifi_only);
2352 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002353 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002354 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2355 MYLOGI("args: %s\n", options.args.c_str());
2356 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2357 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2358}
2359
Nandana Dutt54dbd672019-01-11 12:58:05 +00002360void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2361 const android::base::unique_fd& bugreport_fd_in,
2362 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002363 // In the new API world, date is always added; output is always a zip file.
2364 // TODO(111441001): remove these options once they are obsolete.
2365 do_add_date = true;
2366 do_zip_file = true;
2367
Nandana Dutt54dbd672019-01-11 12:58:05 +00002368 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2369 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2370 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002371
2372 extra_options = ModeToString(bugreport_mode);
2373 SetOptionsFromMode(bugreport_mode, this);
2374}
2375
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002376Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2377 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002378 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002379 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002380 switch (c) {
2381 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002382 case 'd': do_add_date = true; break;
2383 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002384 // o=use_outfile not supported anymore.
2385 // TODO(b/111441001): Remove when all callers have migrated.
2386 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002387 case 's': use_socket = true; break;
2388 case 'S': use_control_socket = true; break;
2389 case 'v': show_header_only = true; break;
2390 case 'q': do_vibrate = false; break;
2391 case 'p': do_fb = true; break;
2392 case 'P': do_progress_updates = true; break;
2393 case 'R': is_remote_mode = true; break;
2394 case 'B': do_broadcast = true; break;
2395 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002396 case 'w':
2397 // This was already processed
2398 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002399 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002400 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002401 break;
2402 default:
2403 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002404 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002405 break;
2406 // clang-format on
2407 }
2408 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002409
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002410 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002411 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002412 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002413 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002414 }
2415 }
2416
2417 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2418 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002419
2420 SetOptionsFromProperties(this);
2421 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002422}
2423
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002424bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002425 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002426 return false;
2427 }
2428
Nandana Dutt9a76d202019-01-21 15:56:48 +00002429 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002430 return false;
2431 }
2432
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002433 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002434 return false;
2435 }
2436
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002437 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002438 return false;
2439 }
2440
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002441 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002442 return false;
2443 }
2444 return true;
2445}
2446
Nandana Dutt197661d2018-11-16 16:40:21 +00002447void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2448 options_ = std::move(options);
2449}
2450
Nandana Duttd2f5f082019-01-18 17:13:52 +00002451Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2452 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002453 if (listener_ != nullptr) {
2454 switch (status) {
2455 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002456 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002457 break;
2458 case Dumpstate::RunStatus::HELP:
2459 break;
2460 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002461 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002462 break;
2463 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002464 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2465 break;
2466 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2467 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2468 break;
2469 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2470 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002471 break;
2472 }
2473 }
2474 return status;
2475}
2476
Nandana Dutt979388e2018-11-30 16:48:55 +00002477/*
2478 * Dumps relevant information to a bugreport based on the given options.
2479 *
2480 * The bugreport can be dumped to a file or streamed to a socket.
2481 *
2482 * How dumping to file works:
2483 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2484 * stderr is redirected a log file.
2485 *
2486 * The temporary bugreport is then populated via printfs, dumping contents of files and
2487 * output of commands to stdout.
2488 *
2489 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2490 * text file.
2491 *
2492 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2493 * gets added to the archive.
2494 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002495 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2496 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002497 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002498Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2499 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002500 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002501 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002502 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002503 return RunStatus::INVALID_INPUT;
2504 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002505 /* set as high priority, and protect from OOM killer */
2506 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002507
Felipe Lemed071c682016-10-20 16:48:00 -07002508 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002509 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002510 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002511 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002512 } else {
2513 /* fallback to kernels <= 2.6.35 */
2514 oom_adj = fopen("/proc/self/oom_adj", "we");
2515 if (oom_adj) {
2516 fputs("-17", oom_adj);
2517 fclose(oom_adj);
2518 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002519 }
2520
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002521 if (version_ == VERSION_DEFAULT) {
2522 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002523 }
2524
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002525 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002526 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002527 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002528 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002529 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002530 }
2531
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002532 if (options_->show_header_only) {
2533 PrintHeader();
2534 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002535 }
2536
Nandana Duttd2f5f082019-01-18 17:13:52 +00002537 if (options_->bugreport_fd.get() != -1) {
2538 // If the output needs to be copied over to the caller's fd, get user consent.
2539 android::String16 package(calling_package.c_str());
2540 CheckUserConsent(calling_uid, package);
2541 }
2542
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002543 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002544 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002545
2546 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002547 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002548 is_redirecting
2549 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2550 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002551 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002552
Felipe Lemed071c682016-10-20 16:48:00 -07002553 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002554 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002555 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002556 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2557
2558 MYLOGI("begin\n");
2559
Sahana Raof35ed432019-07-12 10:47:52 +01002560 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2561 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2562 } else {
2563 // Wake lock will be released automatically on process death
2564 MYLOGD("Wake lock acquired.\n");
2565 }
2566
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002567 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002568
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002569 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002570 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002571 MYLOGI("Starting 'dumpstate' service\n");
2572 android::status_t ret;
2573 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2574 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2575 }
2576 }
2577
Felipe Lemef0292972016-11-22 13:57:05 -08002578 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002579 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2580 }
2581
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002582 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2583 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002584
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002585 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002586
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002587 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002588
Christopher Ferrised9354f2014-10-01 17:35:01 -07002589 // If we are going to use a socket, do it as early as possible
2590 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002591 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002592 if (!redirect_to_socket(stdout, "dumpstate")) {
2593 return ERROR;
2594 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002595 }
2596
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002597 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002598 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002599 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002600 if (control_socket_fd_ == -1) {
2601 return ERROR;
2602 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002603 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002604 }
2605
Felipe Leme71bbfc52015-11-23 14:14:51 -08002606 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002607 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002608
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002609 if (options_->do_progress_updates) {
2610 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002611 // clang-format off
2612 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002613 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002614 "--es", "android.intent.extra.NAME", name_,
2615 "--ei", "android.intent.extra.ID", std::to_string(id_),
2616 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2617 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002618 };
2619 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002620 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002621 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002622 if (options_->use_control_socket) {
2623 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002624 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002625 }
2626 }
2627
Nick Kralevichf3599b32016-01-25 15:05:16 -08002628 /* read /proc/cmdline before dropping root */
2629 FILE *cmdline = fopen("/proc/cmdline", "re");
2630 if (cmdline) {
2631 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2632 fclose(cmdline);
2633 }
2634
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002635 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002636 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002637 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002638
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002639 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002640 MYLOGI("taking early screenshot\n");
2641 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002642 }
2643
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002644 if (options_->do_zip_file && zip_file != nullptr) {
2645 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2646 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002647 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002648 }
2649 }
2650
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002651 int dup_stdout_fd;
2652 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002653 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002654 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002655 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002656 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2657 return ERROR;
2658 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002659 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2660 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2661 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002662 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002663
2664 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2665 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002666 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002667 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002668 /* TODO: rather than generating a text file now and zipping it later,
2669 it would be more efficient to redirect stdout to the zip entry
2670 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002671 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2672 return ERROR;
2673 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002674 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002675 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002676 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002677 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002678 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002679
2680 // Don't buffer stdout
2681 setvbuf(stdout, nullptr, _IONBF, 0);
2682
Felipe Leme608385d2016-02-01 10:35:38 -08002683 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2684 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002685 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002686 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002687
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002688 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002689 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002690 DumpstateBoard();
2691 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002692 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002693 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002694 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002695 RunStatus s = DumpstateDefault();
2696 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002697 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002698 HandleUserConsentDenied();
2699 }
2700 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002701 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002702 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002703
Felipe Leme55b42a62015-11-10 17:39:08 -08002704 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002705 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002706 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002707 }
2708
Nandana Duttd2f5f082019-01-18 17:13:52 +00002709 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002710 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002711 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002712 }
2713
Nandana Duttd2f5f082019-01-18 17:13:52 +00002714 // Share the final file with the caller if the user has consented.
2715 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2716 if (options_->bugreport_fd.get() != -1) {
2717 status = CopyBugreportIfUserConsented();
2718 if (status != Dumpstate::RunStatus::OK &&
2719 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2720 // Do an early return if there were errors. We make an exception for consent
2721 // timing out because it's possible the user got distracted. In this case the
2722 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002723 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002724 return status;
2725 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002726 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002727 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2728 options_->screenshot_fd.get());
2729 if (copy_succeeded) {
2730 android::os::UnlinkAndLogOnError(screenshot_path_);
2731 }
2732 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002733 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2734 MYLOGI(
2735 "Did not receive user consent yet."
2736 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002737 const String16 incidentcompanion("incidentcompanion");
2738 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2739 if (ics != nullptr) {
2740 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2741 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2742 consent_callback_.get());
2743 } else {
2744 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2745 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002746 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002747 }
2748
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002749 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002750 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002751 for (int i = 0; i < 3; i++) {
2752 Vibrate(75);
2753 usleep((75 + 50) * 1000);
2754 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002755 }
2756
Jeff Brown1dc94e32014-09-11 14:15:27 -07002757 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002758 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002759 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002760 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002761 }
2762
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002763 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2764 progress_->GetInitialMax());
2765 progress_->Save();
2766 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002767
Felipe Leme107a05f2016-03-08 15:11:15 -08002768 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002769 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002770 }
2771
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002772 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002773 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002774 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002775 }
2776
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002777 tombstone_data_.clear();
2778 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002779
Nandana Duttd2f5f082019-01-18 17:13:52 +00002780 return (consent_callback_ != nullptr &&
2781 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2782 ? USER_CONSENT_TIMED_OUT
2783 : RunStatus::OK;
2784}
2785
2786void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2787 consent_callback_ = new ConsentCallback();
2788 const String16 incidentcompanion("incidentcompanion");
2789 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2790 if (ics != nullptr) {
2791 MYLOGD("Checking user consent via incidentcompanion service\n");
2792 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002793 calling_uid, calling_package, String16(), String16(),
2794 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002795 } else {
2796 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2797 }
2798}
2799
Nandana Dutt5c390032019-03-12 10:52:56 +00002800bool Dumpstate::IsUserConsentDenied() const {
2801 return ds.consent_callback_ != nullptr &&
2802 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2803}
2804
Nandana Duttd2f5f082019-01-18 17:13:52 +00002805void Dumpstate::CleanupFiles() {
2806 android::os::UnlinkAndLogOnError(tmp_path_);
2807 android::os::UnlinkAndLogOnError(screenshot_path_);
2808 android::os::UnlinkAndLogOnError(path_);
2809}
2810
2811Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2812 MYLOGD("User denied consent; deleting files and returning\n");
2813 CleanupFiles();
2814 return USER_CONSENT_DENIED;
2815}
2816
2817Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2818 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2819 // user consent.
2820 UserConsentResult consent_result = consent_callback_->getResult();
2821 if (consent_result == UserConsentResult::UNAVAILABLE) {
2822 // User has not responded yet.
2823 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2824 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2825 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2826 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2827 sleep(delay_seconds);
2828 }
2829 consent_result = consent_callback_->getResult();
2830 }
2831 if (consent_result == UserConsentResult::DENIED) {
2832 // User has explicitly denied sharing with the app. To be safe delete the
2833 // internal bugreport & tmp files.
2834 return HandleUserConsentDenied();
2835 }
2836 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002837 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2838 if (copy_succeeded) {
2839 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002840 }
2841 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2842 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2843 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2844 // Since we do not have user consent to share the bugreport it does not get
2845 // copied over to the calling app but remains in the internal directory from
2846 // where the user can manually pull it.
2847 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2848 }
2849 // Unknown result; must be a programming error.
2850 MYLOGE("Unknown user consent result:%d\n", consent_result);
2851 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002852}
2853
Nandana Duttf02564e2019-02-15 15:24:24 +00002854Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002855 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2856 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2857 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002858 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002859 // When directly running dumpstate binary, the output is not expected to be written
2860 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002861 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002862
2863 // calling_uid and calling_package are for user consent to share the bugreport with
2864 // an app; they are irrelvant here because bugreport is only written to a local
2865 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002866 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002867 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002868 return status;
2869}
2870
2871/* Main entry point for dumpstate binary. */
2872int run_main(int argc, char* argv[]) {
2873 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002874
2875 switch (status) {
2876 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002877 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002878 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002879 ShowUsage();
2880 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002881 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002882 fprintf(stderr, "Invalid combination of args\n");
2883 ShowUsage();
2884 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002885 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002886 FALLTHROUGH_INTENDED;
2887 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2888 FALLTHROUGH_INTENDED;
2889 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002890 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002891 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002892}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002893
2894// TODO(111441001): Default DumpOptions to sensible values.
2895Dumpstate::Dumpstate(const std::string& version)
2896 : pid_(getpid()),
2897 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002898 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002899 version_(version),
2900 now_(time(nullptr)) {
2901}
2902
2903Dumpstate& Dumpstate::GetInstance() {
2904 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2905 return singleton_;
2906}
2907
Nandana Dutt8d945c02019-08-14 13:30:07 +01002908DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2909 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002910 if (!title_.empty()) {
2911 started_ = Nanotime();
2912 }
2913}
2914
2915DurationReporter::~DurationReporter() {
2916 if (!title_.empty()) {
2917 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
chenqiwuaf8b2d92019-12-12 18:53:51 +08002918 if (elapsed >= .5f || verbose_) {
2919 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002920 }
chenqiwuaf8b2d92019-12-12 18:53:51 +08002921 if (!logcat_only_) {
2922 // Use "Yoda grammar" to make it easier to grep|sort sections.
2923 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002924 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002925 }
2926}
2927
2928const int32_t Progress::kDefaultMax = 5000;
2929
2930Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2931}
2932
2933Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2934 : Progress(initial_max, growth_factor, "") {
2935 progress_ = progress;
2936}
2937
2938Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2939 : initial_max_(initial_max),
2940 progress_(0),
2941 max_(initial_max),
2942 growth_factor_(growth_factor),
2943 n_runs_(0),
2944 average_max_(0),
2945 path_(path) {
2946 if (!path_.empty()) {
2947 Load();
2948 }
2949}
2950
2951void Progress::Load() {
2952 MYLOGD("Loading stats from %s\n", path_.c_str());
2953 std::string content;
2954 if (!android::base::ReadFileToString(path_, &content)) {
2955 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2956 return;
2957 }
2958 if (content.empty()) {
2959 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2960 return;
2961 }
2962 std::vector<std::string> lines = android::base::Split(content, "\n");
2963
2964 if (lines.size() < 1) {
2965 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2966 (int)lines.size(), max_);
2967 return;
2968 }
2969 char* ptr;
2970 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2971 average_max_ = strtol(ptr, nullptr, 10);
2972 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2973 average_max_ > STATS_MAX_AVERAGE) {
2974 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2975 initial_max_ = Progress::kDefaultMax;
2976 } else {
2977 initial_max_ = average_max_;
2978 }
2979 max_ = initial_max_;
2980
2981 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2982}
2983
2984void Progress::Save() {
2985 int32_t total = n_runs_ * average_max_ + progress_;
2986 int32_t runs = n_runs_ + 1;
2987 int32_t average = floor(((float)total) / runs);
2988 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2989 path_.c_str());
2990 if (path_.empty()) {
2991 return;
2992 }
2993
2994 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2995 if (!android::base::WriteStringToFile(content, path_)) {
2996 MYLOGE("Could not save stats on %s\n", path_.c_str());
2997 }
2998}
2999
3000int32_t Progress::Get() const {
3001 return progress_;
3002}
3003
3004bool Progress::Inc(int32_t delta_sec) {
3005 bool changed = false;
3006 if (delta_sec >= 0) {
3007 progress_ += delta_sec;
3008 if (progress_ > max_) {
3009 int32_t old_max = max_;
3010 max_ = floor((float)progress_ * growth_factor_);
3011 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
3012 changed = true;
3013 }
3014 }
3015 return changed;
3016}
3017
3018int32_t Progress::GetMax() const {
3019 return max_;
3020}
3021
3022int32_t Progress::GetInitialMax() const {
3023 return initial_max_;
3024}
3025
3026void Progress::Dump(int fd, const std::string& prefix) const {
3027 const char* pr = prefix.c_str();
3028 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3029 dprintf(fd, "%smax: %d\n", pr, max_);
3030 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3031 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3032 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3033 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3034 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3035}
3036
3037bool Dumpstate::IsZipping() const {
3038 return zip_writer_ != nullptr;
3039}
3040
3041std::string Dumpstate::GetPath(const std::string& suffix) const {
3042 return GetPath(bugreport_internal_dir_, suffix);
3043}
3044
3045std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3046 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3047 name_.c_str(), suffix.c_str());
3048}
3049
3050void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3051 progress_ = std::move(progress);
3052}
3053
3054void for_each_userid(void (*func)(int), const char *header) {
3055 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3056 "for_each_userid(%s)", header);
3057 DurationReporter duration_reporter(title);
3058 if (PropertiesHelper::IsDryRun()) return;
3059
3060 DIR *d;
3061 struct dirent *de;
3062
3063 if (header) printf("\n------ %s ------\n", header);
3064 func(0);
3065
3066 if (!(d = opendir("/data/system/users"))) {
3067 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3068 return;
3069 }
3070
3071 while ((de = readdir(d))) {
3072 int userid;
3073 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3074 continue;
3075 }
3076 func(userid);
3077 }
3078
3079 closedir(d);
3080}
3081
3082static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3083 DIR *d;
3084 struct dirent *de;
3085
3086 if (!(d = opendir("/proc"))) {
3087 printf("Failed to open /proc (%s)\n", strerror(errno));
3088 return;
3089 }
3090
3091 if (header) printf("\n------ %s ------\n", header);
3092 while ((de = readdir(d))) {
3093 if (ds.IsUserConsentDenied()) {
3094 MYLOGE(
3095 "Returning early because user denied consent to share bugreport with calling app.");
3096 closedir(d);
3097 return;
3098 }
3099 int pid;
3100 int fd;
3101 char cmdpath[255];
3102 char cmdline[255];
3103
3104 if (!(pid = atoi(de->d_name))) {
3105 continue;
3106 }
3107
3108 memset(cmdline, 0, sizeof(cmdline));
3109
3110 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3111 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3112 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3113 close(fd);
3114 if (cmdline[0]) {
3115 helper(pid, cmdline, arg);
3116 continue;
3117 }
3118 }
3119
3120 // if no cmdline, a kernel thread has comm
3121 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3122 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3123 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3124 close(fd);
3125 if (cmdline[1]) {
3126 cmdline[0] = '[';
3127 size_t len = strcspn(cmdline, "\f\b\r\n");
3128 cmdline[len] = ']';
3129 cmdline[len+1] = '\0';
3130 }
3131 }
3132 if (!cmdline[0]) {
3133 strcpy(cmdline, "N/A");
3134 }
3135 helper(pid, cmdline, arg);
3136 }
3137
3138 closedir(d);
3139}
3140
3141static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3142 for_each_pid_func *func = (for_each_pid_func*) arg;
3143 func(pid, cmdline);
3144}
3145
3146void for_each_pid(for_each_pid_func func, const char *header) {
3147 std::string title = header == nullptr ? "for_each_pid"
3148 : android::base::StringPrintf("for_each_pid(%s)", header);
3149 DurationReporter duration_reporter(title);
3150 if (PropertiesHelper::IsDryRun()) return;
3151
3152 __for_each_pid(for_each_pid_helper, header, (void *) func);
3153}
3154
3155static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3156 DIR *d;
3157 struct dirent *de;
3158 char taskpath[255];
3159 for_each_tid_func *func = (for_each_tid_func *) arg;
3160
3161 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3162
3163 if (!(d = opendir(taskpath))) {
3164 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3165 return;
3166 }
3167
3168 func(pid, pid, cmdline);
3169
3170 while ((de = readdir(d))) {
3171 if (ds.IsUserConsentDenied()) {
3172 MYLOGE(
3173 "Returning early because user denied consent to share bugreport with calling app.");
3174 closedir(d);
3175 return;
3176 }
3177 int tid;
3178 int fd;
3179 char commpath[255];
3180 char comm[255];
3181
3182 if (!(tid = atoi(de->d_name))) {
3183 continue;
3184 }
3185
3186 if (tid == pid)
3187 continue;
3188
3189 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3190 memset(comm, 0, sizeof(comm));
3191 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3192 strcpy(comm, "N/A");
3193 } else {
3194 char *c;
3195 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3196 close(fd);
3197
3198 c = strrchr(comm, '\n');
3199 if (c) {
3200 *c = '\0';
3201 }
3202 }
3203 func(pid, tid, comm);
3204 }
3205
3206 closedir(d);
3207}
3208
3209void for_each_tid(for_each_tid_func func, const char *header) {
3210 std::string title = header == nullptr ? "for_each_tid"
3211 : android::base::StringPrintf("for_each_tid(%s)", header);
3212 DurationReporter duration_reporter(title);
3213
3214 if (PropertiesHelper::IsDryRun()) return;
3215
3216 __for_each_pid(for_each_tid_helper, header, (void *) func);
3217}
3218
3219void show_wchan(int pid, int tid, const char *name) {
3220 if (PropertiesHelper::IsDryRun()) return;
3221
3222 char path[255];
3223 char buffer[255];
3224 int fd, ret, save_errno;
3225 char name_buffer[255];
3226
3227 memset(buffer, 0, sizeof(buffer));
3228
3229 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3230 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3231 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3232 return;
3233 }
3234
3235 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3236 save_errno = errno;
3237 close(fd);
3238
3239 if (ret < 0) {
3240 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3241 return;
3242 }
3243
3244 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3245 pid == tid ? 0 : 3, "", name);
3246
3247 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3248
3249 return;
3250}
3251
3252// print time in centiseconds
3253static void snprcent(char *buffer, size_t len, size_t spc,
3254 unsigned long long time) {
3255 static long hz; // cache discovered hz
3256
3257 if (hz <= 0) {
3258 hz = sysconf(_SC_CLK_TCK);
3259 if (hz <= 0) {
3260 hz = 1000;
3261 }
3262 }
3263
3264 // convert to centiseconds
3265 time = (time * 100 + (hz / 2)) / hz;
3266
3267 char str[16];
3268
3269 snprintf(str, sizeof(str), " %llu.%02u",
3270 time / 100, (unsigned)(time % 100));
3271 size_t offset = strlen(buffer);
3272 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3273 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3274}
3275
3276// print permille as a percent
3277static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3278 char str[16];
3279
3280 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3281 size_t offset = strlen(buffer);
3282 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3283 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3284}
3285
3286void show_showtime(int pid, const char *name) {
3287 if (PropertiesHelper::IsDryRun()) return;
3288
3289 char path[255];
3290 char buffer[1023];
3291 int fd, ret, save_errno;
3292
3293 memset(buffer, 0, sizeof(buffer));
3294
3295 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3296 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3297 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3298 return;
3299 }
3300
3301 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3302 save_errno = errno;
3303 close(fd);
3304
3305 if (ret < 0) {
3306 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3307 return;
3308 }
3309
3310 // field 14 is utime
3311 // field 15 is stime
3312 // field 42 is iotime
3313 unsigned long long utime = 0, stime = 0, iotime = 0;
3314 if (sscanf(buffer,
3315 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3316 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3317 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3318 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3319 &utime, &stime, &iotime) != 3) {
3320 return;
3321 }
3322
3323 unsigned long long total = utime + stime;
3324 if (!total) {
3325 return;
3326 }
3327
3328 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3329 if (permille > 1000) {
3330 permille = 1000;
3331 }
3332
3333 // try to beautify and stabilize columns at <80 characters
3334 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3335 if ((name[0] != '[') || utime) {
3336 snprcent(buffer, sizeof(buffer), 57, utime);
3337 }
3338 snprcent(buffer, sizeof(buffer), 65, stime);
3339 if ((name[0] != '[') || iotime) {
3340 snprcent(buffer, sizeof(buffer), 73, iotime);
3341 }
3342 if (iotime) {
3343 snprdec(buffer, sizeof(buffer), 79, permille);
3344 }
3345 puts(buffer); // adds a trailing newline
3346
3347 return;
3348}
3349
3350void do_dmesg() {
3351 const char *title = "KERNEL LOG (dmesg)";
3352 DurationReporter duration_reporter(title);
3353 printf("------ %s ------\n", title);
3354
3355 if (PropertiesHelper::IsDryRun()) return;
3356
3357 /* Get size of kernel buffer */
3358 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3359 if (size <= 0) {
3360 printf("Unexpected klogctl return value: %d\n\n", size);
3361 return;
3362 }
3363 char *buf = (char *) malloc(size + 1);
3364 if (buf == nullptr) {
3365 printf("memory allocation failed\n\n");
3366 return;
3367 }
3368 int retval = klogctl(KLOG_READ_ALL, buf, size);
3369 if (retval < 0) {
3370 printf("klogctl failure\n\n");
3371 free(buf);
3372 return;
3373 }
3374 buf[retval] = '\0';
3375 printf("%s\n\n", buf);
3376 free(buf);
3377 return;
3378}
3379
3380void do_showmap(int pid, const char *name) {
3381 char title[255];
3382 char arg[255];
3383
3384 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3385 snprintf(arg, sizeof(arg), "%d", pid);
3386 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3387}
3388
3389int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3390 DurationReporter duration_reporter(title);
3391
3392 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3393
3394 UpdateProgress(WEIGHT_FILE);
3395
3396 return status;
3397}
3398
3399int read_file_as_long(const char *path, long int *output) {
3400 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3401 if (fd < 0) {
3402 int err = errno;
3403 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3404 return -1;
3405 }
3406 char buffer[50];
3407 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3408 if (bytes_read == -1) {
3409 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3410 return -2;
3411 }
3412 if (bytes_read == 0) {
3413 MYLOGE("File %s is empty\n", path);
3414 return -3;
3415 }
3416 *output = atoi(buffer);
3417 return 0;
3418}
3419
3420/* calls skip to gate calling dump_from_fd recursively
3421 * in the specified directory. dump_from_fd defaults to
3422 * dump_file_from_fd above when set to NULL. skip defaults
3423 * to false when set to NULL. dump_from_fd will always be
3424 * called with title NULL.
3425 */
3426int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3427 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3428 DurationReporter duration_reporter(title);
3429 DIR *dirp;
3430 struct dirent *d;
3431 char *newpath = nullptr;
3432 const char *slash = "/";
3433 int retval = 0;
3434
3435 if (!title.empty()) {
3436 printf("------ %s (%s) ------\n", title.c_str(), dir);
3437 }
3438 if (PropertiesHelper::IsDryRun()) return 0;
3439
3440 if (dir[strlen(dir) - 1] == '/') {
3441 ++slash;
3442 }
3443 dirp = opendir(dir);
3444 if (dirp == nullptr) {
3445 retval = -errno;
3446 MYLOGE("%s: %s\n", dir, strerror(errno));
3447 return retval;
3448 }
3449
3450 if (!dump_from_fd) {
3451 dump_from_fd = dump_file_from_fd;
3452 }
3453 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3454 if ((d->d_name[0] == '.')
3455 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3456 || (d->d_name[1] == '\0'))) {
3457 continue;
3458 }
3459 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3460 (d->d_type == DT_DIR) ? "/" : "");
3461 if (!newpath) {
3462 retval = -errno;
3463 continue;
3464 }
3465 if (skip && (*skip)(newpath)) {
3466 continue;
3467 }
3468 if (d->d_type == DT_DIR) {
3469 int ret = dump_files("", newpath, skip, dump_from_fd);
3470 if (ret < 0) {
3471 retval = ret;
3472 }
3473 continue;
3474 }
3475 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3476 if (fd.get() < 0) {
3477 retval = -1;
3478 printf("*** %s: %s\n", newpath, strerror(errno));
3479 continue;
3480 }
3481 (*dump_from_fd)(nullptr, newpath, fd.get());
3482 }
3483 closedir(dirp);
3484 if (!title.empty()) {
3485 printf("\n");
3486 }
3487 return retval;
3488}
3489
3490/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3491 * it's possible to avoid issues where opening the file itself can get
3492 * stuck.
3493 */
3494int dump_file_from_fd(const char *title, const char *path, int fd) {
3495 if (PropertiesHelper::IsDryRun()) return 0;
3496
3497 int flags = fcntl(fd, F_GETFL);
3498 if (flags == -1) {
3499 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3500 return -1;
3501 } else if (!(flags & O_NONBLOCK)) {
3502 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3503 return -1;
3504 }
3505 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3506}
3507
3508int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003509 const CommandOptions& options, bool verbose_duration) {
3510 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003511
3512 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3513
3514 /* TODO: for now we're simplifying the progress calculation by using the
3515 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3516 * where its weight should be much higher proportionally to its timeout.
3517 * Ideally, it should use a options.EstimatedDuration() instead...*/
3518 UpdateProgress(options.Timeout());
3519
3520 return status;
3521}
3522
3523void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3524 const CommandOptions& options, long dumpsysTimeoutMs) {
3525 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3526 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3527 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3528 RunCommand(title, dumpsys, options);
3529}
3530
3531int open_socket(const char *service) {
3532 int s = android_get_control_socket(service);
3533 if (s < 0) {
3534 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3535 return -1;
3536 }
3537 fcntl(s, F_SETFD, FD_CLOEXEC);
3538
3539 // Set backlog to 0 to make sure that queue size will be minimum.
3540 // In Linux, because the minimum queue will be 1, connect() will be blocked
3541 // if the other clients already called connect() and the connection request was not accepted.
3542 if (listen(s, 0) < 0) {
3543 MYLOGE("listen(control socket): %s\n", strerror(errno));
3544 return -1;
3545 }
3546
3547 struct sockaddr addr;
3548 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003549 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003550
3551 // Close socket just after accept(), to make sure that connect() by client will get error
3552 // when the socket is used by the other services.
3553 // There is still a race condition possibility between accept and close, but there is no way
3554 // to close-on-accept atomically.
3555 // See detail; b/123306389#comment25
3556 close(s);
3557
3558 if (fd < 0) {
3559 MYLOGE("accept(control socket): %s\n", strerror(errno));
3560 return -1;
3561 }
3562
3563 return fd;
3564}
3565
3566/* redirect output to a service control socket */
3567bool redirect_to_socket(FILE* redirect, const char* service) {
3568 int fd = open_socket(service);
3569 if (fd == -1) {
3570 return false;
3571 }
3572 fflush(redirect);
3573 // TODO: handle dup2 failure
3574 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3575 close(fd);
3576 return true;
3577}
3578
3579// TODO: should call is_valid_output_file and/or be merged into it.
3580void create_parent_dirs(const char *path) {
3581 char *chp = const_cast<char *> (path);
3582
3583 /* skip initial slash */
3584 if (chp[0] == '/')
3585 chp++;
3586
3587 /* create leading directories, if necessary */
3588 struct stat dir_stat;
3589 while (chp && chp[0]) {
3590 chp = strchr(chp, '/');
3591 if (chp) {
3592 *chp = 0;
3593 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3594 MYLOGI("Creating directory %s\n", path);
3595 if (mkdir(path, 0770)) { /* drwxrwx--- */
3596 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3597 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3598 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3599 }
3600 }
3601 *chp++ = '/';
3602 }
3603 }
3604}
3605
3606bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3607 create_parent_dirs(path);
3608
3609 int fd = TEMP_FAILURE_RETRY(open(path,
3610 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3611 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3612 if (fd < 0) {
3613 MYLOGE("%s: %s\n", path, strerror(errno));
3614 return false;
3615 }
3616
3617 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3618 close(fd);
3619 return true;
3620}
3621
3622bool redirect_to_file(FILE* redirect, char* path) {
3623 return _redirect_to_file(redirect, path, O_TRUNC);
3624}
3625
3626bool redirect_to_existing_file(FILE* redirect, char* path) {
3627 return _redirect_to_file(redirect, path, O_APPEND);
3628}
3629
3630void dump_route_tables() {
3631 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3632 if (PropertiesHelper::IsDryRun()) return;
3633 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3634 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3635 FILE* fp = fopen(RT_TABLES_PATH, "re");
3636 if (!fp) {
3637 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3638 return;
3639 }
3640 char table[16];
3641 // Each line has an integer (the table number), a space, and a string (the table name). We only
3642 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3643 // Add a fixed max limit so this doesn't go awry.
3644 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3645 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3646 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3647 }
3648 fclose(fp);
3649}
3650
3651// TODO: make this function thread safe if sections are generated in parallel.
3652void Dumpstate::UpdateProgress(int32_t delta_sec) {
3653 if (progress_ == nullptr) {
3654 MYLOGE("UpdateProgress: progress_ not set\n");
3655 return;
3656 }
3657
3658 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003659 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003660
3661 // ...but only notifiy listeners when necessary.
3662 if (!options_->do_progress_updates) return;
3663
3664 int progress = progress_->Get();
3665 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003666 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003667
Nandana Duttf02cd782019-06-14 14:25:13 +01003668 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003669 return;
3670 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003671 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003672
3673 if (control_socket_fd_ >= 0) {
3674 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3675 fsync(control_socket_fd_);
3676 }
3677
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003678 if (listener_ != nullptr) {
3679 if (percent % 5 == 0) {
3680 // We don't want to spam logcat, so only log multiples of 5.
3681 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3682 percent);
3683 } else {
3684 // stderr is ignored on normal invocations, but useful when calling
3685 // /system/bin/dumpstate directly for debuggging.
3686 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3687 progress, max, percent);
3688 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003689
3690 listener_->onProgress(percent);
3691 }
3692}
3693
3694void Dumpstate::TakeScreenshot(const std::string& path) {
3695 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3696 int status =
3697 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3698 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3699 if (status == 0) {
3700 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3701 } else {
3702 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3703 }
3704}
3705
3706bool is_dir(const char* pathname) {
3707 struct stat info;
3708 if (stat(pathname, &info) == -1) {
3709 return false;
3710 }
3711 return S_ISDIR(info.st_mode);
3712}
3713
3714time_t get_mtime(int fd, time_t default_mtime) {
3715 struct stat info;
3716 if (fstat(fd, &info) == -1) {
3717 return default_mtime;
3718 }
3719 return info.st_mtime;
3720}