blob: 76580c5e730f0670eff0d42dc0d0fa2b8f73110f [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>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000047#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070048#include <functional>
49#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010050#include <memory>
51#include <regex>
52#include <set>
53#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070054#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010055#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070056
Felipe Leme96c2bbb2016-09-26 09:21:21 -070057#include <android-base/file.h>
58#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070059#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080060#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070061#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070062#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010063#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080064#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080065#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000066#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010067#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080068#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070069#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010070#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000071#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080072#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <dumputils/dump_utils.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080074#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010075#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070076#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070077#include <private/android_filesystem_config.h>
78#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080079#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070080#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080081#include "DumpstateInternal.h"
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include "DumpstateSectionReporter.h"
Felipe Leme75876a22016-10-27 16:31:27 -070083#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070084#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080085
Steven Morelandcb7ef822016-11-29 13:20:37 -080086using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080087using ::std::literals::chrono_literals::operator""ms;
88using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080089
Felipe Leme47e9be22016-12-21 15:37:07 -080090// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080091using android::defaultServiceManager;
92using android::Dumpsys;
93using android::INVALID_OPERATION;
94using android::IServiceManager;
95using android::OK;
96using android::sp;
97using android::status_t;
98using android::String16;
99using android::String8;
100using android::TIMED_OUT;
101using android::UNKNOWN_ERROR;
102using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000103using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000104using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800105using android::os::dumpstate::CommandOptions;
106using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800107using android::os::dumpstate::DumpstateSectionReporter;
Vishnu Naire97d6122018-01-18 13:58:56 -0800108using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800109
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100110// Keep in sync with
111// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
112static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
113
114/* Most simple commands have 10 as timeout, so 5 is a good estimate */
115static const int32_t WEIGHT_FILE = 5;
116
117// TODO: temporary variables and functions used during C++ refactoring
118static Dumpstate& ds = Dumpstate::GetInstance();
119static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
120 const CommandOptions& options = CommandOptions::DEFAULT) {
121 return ds.RunCommand(title, full_command, options);
122}
123
124// Reasonable value for max stats.
125static const int STATS_MAX_N_RUNS = 1000;
126static const long STATS_MAX_AVERAGE = 100000;
127
128CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
129
Nandana Duttd2f5f082019-01-18 17:13:52 +0000130typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
131
Colin Crossf45fa6b2012-03-26 12:38:26 -0700132/* read before root is shed */
133static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700134static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000135static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700136
Felipe Leme1d486fe2016-10-14 18:06:47 -0700137// TODO: variables and functions below should be part of dumpstate object
138
Felipe Leme635ca312016-01-05 14:23:02 -0800139static std::set<std::string> mount_points;
140void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800141
Todd Poynor2a83daa2013-11-22 15:44:22 -0800142#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700143#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700144#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800145
Felipe Lemee82a27d2016-01-05 13:35:44 -0800146#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700147#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700148#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700149#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100150#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
151#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800152#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900153#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800154#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700155
Narayan Kamath8f788292017-05-25 13:20:39 +0100156// TODO(narayan): Since this information has to be kept in sync
157// with tombstoned, we should just put it in a common header.
158//
159// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100160static const std::string TOMBSTONE_DIR = "/data/tombstones/";
161static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
162static const std::string ANR_DIR = "/data/anr/";
163static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700164
Felipe Lemee844a9d2016-09-21 15:01:39 -0700165// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000166
Nandana Dutt5c390032019-03-12 10:52:56 +0000167#define RETURN_IF_USER_DENIED_CONSENT() \
168 if (ds.IsUserConsentDenied()) { \
169 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
170 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
171 }
172
173// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
174// if consent is found to be denied.
175#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
176 RETURN_IF_USER_DENIED_CONSENT(); \
177 func_ptr(__VA_ARGS__); \
178 RETURN_IF_USER_DENIED_CONSENT();
179
Nandana Dutt979388e2018-11-30 16:48:55 +0000180namespace android {
181namespace os {
182namespace {
183
184static int Open(std::string path, int flags, mode_t mode = 0) {
185 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
186 if (fd == -1) {
187 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
188 }
189 return fd;
190}
191
Nandana Dutt979388e2018-11-30 16:48:55 +0000192
193static int OpenForRead(std::string path) {
194 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
195}
196
197bool CopyFile(int in_fd, int out_fd) {
198 char buf[4096];
199 ssize_t byte_count;
200 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
201 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
202 return false;
203 }
204 }
205 return (byte_count != -1);
206}
207
208static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000209 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000210
211 // Obtain a handle to the source file.
212 android::base::unique_fd in_fd(OpenForRead(input_file));
213 if (out_fd != -1 && in_fd.get() != -1) {
214 if (CopyFile(in_fd.get(), out_fd)) {
215 return true;
216 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000217 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000218 }
219 return false;
220}
221
Nandana Duttd2f5f082019-01-18 17:13:52 +0000222static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000223 if (unlink(file.c_str())) {
224 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000225 return false;
226 }
227 return true;
228}
Nandana Dutt979388e2018-11-30 16:48:55 +0000229
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000230static bool IsFileEmpty(const std::string& file_path) {
231 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
232 if(file.bad()) {
233 MYLOGE("Cannot open file: %s\n", file_path.c_str());
234 return true;
235 }
236 return file.tellg() <= 0;
237}
238
Nikita Ioffea325a572019-05-16 19:49:47 +0100239int64_t GetModuleMetadataVersion() {
240 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
241 if (binder == nullptr) {
242 MYLOGE("Failed to retrieve package_native service");
243 return 0L;
244 }
245 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
246 std::string package_name;
247 auto status = package_service->getModuleMetadataPackageName(&package_name);
248 if (!status.isOk()) {
249 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
250 return 0L;
251 }
252 MYLOGD("Module metadata package name: %s", package_name.c_str());
253 int64_t version_code;
254 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
255 &version_code);
256 if (!status.isOk()) {
257 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
258 return 0L;
259 }
260 return version_code;
261}
262
Nandana Dutt979388e2018-11-30 16:48:55 +0000263} // namespace
264} // namespace os
265} // namespace android
266
Felipe Leme678727a2016-09-21 17:22:11 -0700267static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800268 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800269 long dumpsysTimeoutMs = 0) {
270 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700271}
272static int DumpFile(const std::string& title, const std::string& path) {
273 return ds.DumpFile(title, path);
274}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800275
Felipe Lemee844a9d2016-09-21 15:01:39 -0700276// Relative directory (inside the zip) for all files copied as-is into the bugreport.
277static const std::string ZIP_ROOT_DIR = "FS";
278
Vishnu Naire97d6122018-01-18 13:58:56 -0800279static const std::string kProtoPath = "proto/";
280static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700281static const std::string kDumpstateBoardFiles[] = {
282 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700283 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700284};
285static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
286
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700287static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700288static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700289static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700290static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
291static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700292
Felipe Lemef0292972016-11-22 13:57:05 -0800293static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
294
Narayan Kamath8f788292017-05-25 13:20:39 +0100295/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100296 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
297 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
298 * is set, the vector only contains files that were written in the last 30 minutes.
Andreas Gamped0d76952017-08-22 13:08:37 -0700299 * If |limit_by_count| is set, the vector only contains the ten latest files.
Narayan Kamath8f788292017-05-25 13:20:39 +0100300 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700301static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
302 const std::string& file_prefix,
303 bool limit_by_mtime,
304 bool limit_by_count = true) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100305 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
306
Narayan Kamathbd863722017-06-01 18:50:12 +0100307 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100308
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700309 if (dump_dir == nullptr) {
310 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700311 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700312 }
313
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700314 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100315 struct dirent* entry = nullptr;
316 while ((entry = readdir(dump_dir.get()))) {
317 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100318 continue;
319 }
320
Narayan Kamathbd863722017-06-01 18:50:12 +0100321 const std::string base_name(entry->d_name);
322 if (base_name.find(file_prefix) != 0) {
323 continue;
324 }
325
326 const std::string abs_path = dir_path + base_name;
327 android::base::unique_fd fd(
328 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
329 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700330 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100331 break;
332 }
333
334 struct stat st = {};
335 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700336 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100337 continue;
338 }
339
Narayan Kamath3f31b632018-02-22 19:42:36 +0000340 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100341 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100342 continue;
343 }
344
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700345 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700346 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100347
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700348 // Sort in descending modification time so that we only keep the newest
349 // reports if |limit_by_count| is true.
350 std::sort(dump_data.begin(), dump_data.end(),
351 [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
Narayan Kamath8f788292017-05-25 13:20:39 +0100352
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700353 if (limit_by_count && dump_data.size() > 10) {
354 dump_data.erase(dump_data.begin() + 10, dump_data.end());
Andreas Gamped0d76952017-08-22 13:08:37 -0700355 }
356
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700357 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100358}
359
Narayan Kamathbd863722017-06-01 18:50:12 +0100360static bool AddDumps(const std::vector<DumpData>::const_iterator start,
361 const std::vector<DumpData>::const_iterator end,
362 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100363 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100364 for (auto it = start; it != end; ++it) {
365 const std::string& name = it->name;
366 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100367 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100368
369 // Seek to the beginning of the file before dumping any data. A given
370 // DumpData entry might be dumped multiple times in the report.
371 //
372 // For example, the most recent ANR entry is dumped to the body of the
373 // main entry and it also shows up as a separate entry in the bugreport
374 // ZIP file.
375 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
376 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
377 strerror(errno));
378 }
379
Narayan Kamath8f788292017-05-25 13:20:39 +0100380 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800381 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100382 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100383 }
384 } else {
385 dump_file_from_fd(type_name, name.c_str(), fd);
386 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100387 }
388
389 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700390}
391
Felipe Leme635ca312016-01-05 14:23:02 -0800392// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700393void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800394 char path[PATH_MAX];
395
396 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
397 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700398 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800399 char linkname[PATH_MAX];
400 ssize_t r = readlink(path, linkname, PATH_MAX);
401 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800402 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800403 return;
404 }
405 linkname[r] = '\0';
406
407 if (mount_points.find(linkname) == mount_points.end()) {
408 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700409 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700410 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800411 mount_points.insert(linkname);
412 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800413 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800414 }
415 }
416}
417
418void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700419 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700420 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800421 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800422 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700423 for_each_pid(do_mountinfo, nullptr);
424 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800425}
426
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700427static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
428{
429 DIR *d;
430 struct dirent *de;
431 char path[PATH_MAX];
432
433 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700434 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700435 return;
436 }
437
438 while ((de = readdir(d))) {
439 if (de->d_type != DT_LNK) {
440 continue;
441 }
442 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700443 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700444 }
445
446 closedir(d);
447}
448
Mark Salyzyn326842f2015-04-30 09:49:41 -0700449static bool skip_not_stat(const char *path) {
450 static const char stat[] = "/stat";
451 size_t len = strlen(path);
452 if (path[len - 1] == '/') { /* Directory? */
453 return false;
454 }
455 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
456}
457
Felipe Leme4c2d6632016-09-28 14:32:00 -0700458static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800459 return false;
460}
461
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700462unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700463
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800464//
465// stat offsets
466// Name units description
467// ---- ----- -----------
468// read I/Os requests number of read I/Os processed
469#define __STAT_READ_IOS 0
470// read merges requests number of read I/Os merged with in-queue I/O
471#define __STAT_READ_MERGES 1
472// read sectors sectors number of sectors read
473#define __STAT_READ_SECTORS 2
474// read ticks milliseconds total wait time for read requests
475#define __STAT_READ_TICKS 3
476// write I/Os requests number of write I/Os processed
477#define __STAT_WRITE_IOS 4
478// write merges requests number of write I/Os merged with in-queue I/O
479#define __STAT_WRITE_MERGES 5
480// write sectors sectors number of sectors written
481#define __STAT_WRITE_SECTORS 6
482// write ticks milliseconds total wait time for write requests
483#define __STAT_WRITE_TICKS 7
484// in_flight requests number of I/Os currently in flight
485#define __STAT_IN_FLIGHT 8
486// io_ticks milliseconds total time this block device has been active
487#define __STAT_IO_TICKS 9
488// time_in_queue milliseconds total wait time for all requests
489#define __STAT_IN_QUEUE 10
490#define __STAT_NUMBER_FIELD 11
491//
492// read I/Os, write I/Os
493// =====================
494//
495// These values increment when an I/O request completes.
496//
497// read merges, write merges
498// =========================
499//
500// These values increment when an I/O request is merged with an
501// already-queued I/O request.
502//
503// read sectors, write sectors
504// ===========================
505//
506// These values count the number of sectors read from or written to this
507// block device. The "sectors" in question are the standard UNIX 512-byte
508// sectors, not any device- or filesystem-specific block size. The
509// counters are incremented when the I/O completes.
510#define SECTOR_SIZE 512
511//
512// read ticks, write ticks
513// =======================
514//
515// These values count the number of milliseconds that I/O requests have
516// waited on this block device. If there are multiple I/O requests waiting,
517// these values will increase at a rate greater than 1000/second; for
518// example, if 60 read requests wait for an average of 30 ms, the read_ticks
519// field will increase by 60*30 = 1800.
520//
521// in_flight
522// =========
523//
524// This value counts the number of I/O requests that have been issued to
525// the device driver but have not yet completed. It does not include I/O
526// requests that are in the queue but not yet issued to the device driver.
527//
528// io_ticks
529// ========
530//
531// This value counts the number of milliseconds during which the device has
532// had I/O requests queued.
533//
534// time_in_queue
535// =============
536//
537// This value counts the number of milliseconds that I/O requests have waited
538// on this block device. If there are multiple I/O requests waiting, this
539// value will increase as the product of the number of milliseconds times the
540// number of requests waiting (see "read ticks" above for an example).
541#define S_TO_MS 1000
542//
543
Mark Salyzyn326842f2015-04-30 09:49:41 -0700544static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800545 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700546 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700547 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700548 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700549 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700550 getline(&buffer, &i, fp);
551 fclose(fp);
552 if (!buffer) {
553 return -errno;
554 }
555 i = strlen(buffer);
556 while ((i > 0) && (buffer[i - 1] == '\n')) {
557 buffer[--i] = '\0';
558 }
559 if (!*buffer) {
560 free(buffer);
561 return 0;
562 }
563 z = true;
564 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800565 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700566 if (fields[i] != 0) {
567 z = false;
568 }
569 }
570 if (z) { /* never accessed */
571 free(buffer);
572 return 0;
573 }
574
Wei Wang509bb5d2017-06-09 14:42:12 -0700575 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
576 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700577 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700578
579 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
580 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
581 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700582 free(buffer);
583
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800584 if (fields[__STAT_IO_TICKS]) {
585 unsigned long read_perf = 0;
586 unsigned long read_ios = 0;
587 if (fields[__STAT_READ_TICKS]) {
588 unsigned long long divisor = fields[__STAT_READ_TICKS]
589 * fields[__STAT_IO_TICKS];
590 read_perf = ((unsigned long long)SECTOR_SIZE
591 * fields[__STAT_READ_SECTORS]
592 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
593 / divisor;
594 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
595 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
596 / divisor;
597 }
598
599 unsigned long write_perf = 0;
600 unsigned long write_ios = 0;
601 if (fields[__STAT_WRITE_TICKS]) {
602 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
603 * fields[__STAT_IO_TICKS];
604 write_perf = ((unsigned long long)SECTOR_SIZE
605 * fields[__STAT_WRITE_SECTORS]
606 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
607 / divisor;
608 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
609 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
610 / divisor;
611 }
612
613 unsigned queue = (fields[__STAT_IN_QUEUE]
614 + (fields[__STAT_IO_TICKS] >> 1))
615 / fields[__STAT_IO_TICKS];
616
617 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700618 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 -0800619 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700620 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 -0800621 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800622 }
623
624 /* bugreport timeout factor adjustment */
625 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
626 worst_write_perf = write_perf;
627 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700628 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700629 return 0;
630}
631
Yao Chenbe3bbc12018-01-17 16:31:10 -0800632static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
633
634/* timeout in ms to read a list of buffers */
635static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
636 unsigned long timeout_ms = 0;
637 for (const auto& buffer : buffers) {
638 log_id_t id = android_name_to_log_id(buffer.c_str());
639 unsigned long property_size = __android_logger_get_buffer_size(id);
640 /* Engineering margin is ten-fold our guess */
641 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
642 }
643 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700644}
645
Nandana Duttd2f5f082019-01-18 17:13:52 +0000646Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
647}
648
649android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
650 std::lock_guard<std::mutex> lock(lock_);
651 result_ = APPROVED;
652 MYLOGD("User approved consent to share bugreport\n");
653 return android::binder::Status::ok();
654}
655
656android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
657 std::lock_guard<std::mutex> lock(lock_);
658 result_ = DENIED;
659 MYLOGW("User denied consent to share bugreport\n");
660 return android::binder::Status::ok();
661}
662
663UserConsentResult Dumpstate::ConsentCallback::getResult() {
664 std::lock_guard<std::mutex> lock(lock_);
665 return result_;
666}
667
668uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
669 return Nanotime() - start_time_;
670}
671
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700672void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700673 std::string build, fingerprint, radio, bootloader, network;
674 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700675
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700676 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
677 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700678 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
679 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
680 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700681 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700682
Felipe Lemed8b94e52016-12-08 10:21:44 -0800683 printf("========================================================\n");
684 printf("== dumpstate: %s\n", date);
685 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700686
Felipe Lemed8b94e52016-12-08 10:21:44 -0800687 printf("\n");
688 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700689 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800690 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
691 printf("Bootloader: %s\n", bootloader.c_str());
692 printf("Radio: %s\n", radio.c_str());
693 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100694 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
695 if (module_metadata_version != 0) {
696 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
697 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700698
Felipe Lemed8b94e52016-12-08 10:21:44 -0800699 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800700 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800701 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800702 printf("Uptime: ");
703 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
704 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800705 printf("Bugreport format version: %s\n", version_.c_str());
706 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 +0100707 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800708 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800709}
710
Felipe Leme24b66ee2016-06-16 10:55:26 -0700711// List of file extensions that can cause a zip file attachment to be rejected by some email
712// service providers.
713static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
714 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
715 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
716 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
717};
718
Vishnu Naire97d6122018-01-18 13:58:56 -0800719status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
720 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700721 if (!IsZipping()) {
722 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
723 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800724 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800725 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700726 std::string valid_name = entry_name;
727
728 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700729 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700730 if (idx != std::string::npos) {
731 std::string extension = entry_name.substr(idx);
732 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
733 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
734 valid_name = entry_name + ".renamed";
735 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
736 }
737 }
738
Felipe Leme6fe9db62016-02-12 09:04:16 -0800739 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
740 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700741 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
742 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700743 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700744 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700745 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800746 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800747 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000748 bool finished_entry = false;
749 auto finish_entry = [this, &finished_entry] {
750 if (!finished_entry) {
751 // This should only be called when we're going to return an earlier error,
752 // which would've been logged. This may imply the file is already corrupt
753 // and any further logging from FinishEntry is more likely to mislead than
754 // not.
755 this->zip_writer_->FinishEntry();
756 }
757 };
758 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800759 auto start = std::chrono::steady_clock::now();
760 auto end = start + timeout;
761 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800762
Felipe Leme770410d2016-01-26 17:07:14 -0800763 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800764 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800765 if (timeout.count() > 0) {
766 // lambda to recalculate the timeout.
767 auto time_left_ms = [end]() {
768 auto now = std::chrono::steady_clock::now();
769 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
770 return std::max(diff.count(), 0LL);
771 };
772
773 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
774 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000775 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
776 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800777 return -errno;
778 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000779 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800780 entry_name.c_str(), strerror(errno), timeout.count());
781 return TIMED_OUT;
782 }
783 }
784
Zach Riggle22200402016-08-18 01:01:24 -0400785 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 if (bytes_read == 0) {
787 break;
788 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800789 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800790 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800791 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700792 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800793 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700794 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800795 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800796 }
797 }
798
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700799 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000800 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700801 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700802 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800803 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800804 }
805
Vishnu Naire97d6122018-01-18 13:58:56 -0800806 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800807}
808
Felipe Leme1d486fe2016-10-14 18:06:47 -0700809bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
810 android::base::unique_fd fd(
811 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700812 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800813 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800814 return false;
815 }
816
Vishnu Naire97d6122018-01-18 13:58:56 -0800817 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800818}
819
820/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700821static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800822 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800823}
824
Felipe Leme1d486fe2016-10-14 18:06:47 -0700825void Dumpstate::AddDir(const std::string& dir, bool recursive) {
826 if (!IsZipping()) {
827 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800828 return;
829 }
Felipe Leme678727a2016-09-21 17:22:11 -0700830 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800831 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700832 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800833}
834
Felipe Leme1d486fe2016-10-14 18:06:47 -0700835bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
836 if (!IsZipping()) {
837 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
838 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800839 return false;
840 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800841 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700842 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700843 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700844 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700845 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800846 return false;
847 }
848
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700849 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700850 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700851 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700852 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800853 return false;
854 }
855
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700856 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700857 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700858 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800859 return false;
860 }
861
862 return true;
863}
864
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800865static void DoKmsg() {
866 struct stat st;
867 if (!stat(PSTORE_LAST_KMSG, &st)) {
868 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
869 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
870 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
871 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
872 } else {
873 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
874 DumpFile("LAST KMSG", "/proc/last_kmsg");
875 }
876}
877
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800878static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800879 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800880 RunCommand(
881 "KERNEL LOG",
882 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
883 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
884}
885
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800886static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800887 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800888 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
889 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800890 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100891 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800892 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
893 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800894 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800895 RunCommand(
896 "EVENT LOG",
897 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
898 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800899 timeout_ms = logcat_timeout({"stats"});
900 RunCommand(
901 "STATS LOG",
902 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
903 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
904 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800905 RunCommand(
906 "RADIO LOG",
907 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
908 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800909
910 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
911
912 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800913 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
914 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800915}
916
Jayachandran Ca94c7172017-06-10 15:08:12 -0700917static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700918 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
919 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900920 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700921 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900922 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
923 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
924 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
925 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700926}
927
Narayan Kamath8f788292017-05-25 13:20:39 +0100928static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
929 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
930 anr_traces_dir.c_str());
931
932 // If we're here, dump_traces_path will always be a temporary file
933 // (created with mkostemp or similar) that contains dumps taken earlier
934 // on in the process.
935 if (dump_traces_path != nullptr) {
936 if (add_to_zip) {
937 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
938 } else {
939 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
940 dump_traces_path);
941 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
942 }
943
944 const int ret = unlink(dump_traces_path);
945 if (ret == -1) {
946 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
947 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700948 }
949 }
950
Narayan Kamathbd863722017-06-01 18:50:12 +0100951 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700952 if (ds.anr_data_.size() > 0) {
953 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100954 "VM TRACES AT LAST ANR", add_to_zip);
955
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100956 // The "last" ANR will always be included as separate entry in the zip file. In addition,
957 // it will be present in the body of the main entry if |add_to_zip| == false.
958 //
959 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700960 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100961 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100962 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100963 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
964 }
965}
966
967static void AddAnrTraceFiles() {
968 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
969
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700970 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100971
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700972 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100973
Makoto Onuki83ec63f2019-01-31 17:08:59 -0800974 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
975
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700976 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -0700977 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700978 int i = 0;
979 while (true) {
980 const std::string slow_trace_path =
981 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
982 if (stat(slow_trace_path.c_str(), &st)) {
983 // No traces file at this index, done with the files.
984 break;
Felipe Lemee184f662016-10-27 10:04:47 -0700985 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700986 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
987 i++;
Felipe Lemee184f662016-10-27 10:04:47 -0700988 }
989}
990
Wei Wang509bb5d2017-06-09 14:42:12 -0700991static void DumpBlockStatFiles() {
992 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -0700993
Wei Wang1dc1ef52017-06-12 11:28:37 -0700994 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
995
996 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -0700997 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
998 return;
999 }
1000
1001 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001002 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001003 if ((d->d_name[0] == '.')
1004 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1005 || (d->d_name[1] == '\0'))) {
1006 continue;
1007 }
1008 const std::string new_path =
1009 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1010 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1011 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1012 printf("\n");
1013 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001014 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001015}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001016
1017static void DumpPacketStats() {
1018 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1019 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1020 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1021 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1022 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1023}
1024
1025static void DumpIpAddrAndRules() {
1026 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1027 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1028 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1029 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1030 RunCommand("IP RULES", {"ip", "rule", "show"});
1031 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1032}
1033
Nandana Dutt5c390032019-03-12 10:52:56 +00001034static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1035 std::chrono::milliseconds timeout,
1036 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001037 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001038 sp<android::IServiceManager> sm = defaultServiceManager();
1039 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001040 Vector<String16> args;
1041 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001042 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1043 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001044 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001045 std::string path(title);
1046 path.append(" - ").append(String8(service).c_str());
1047 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1048 size_t bytes_written = 0;
1049 status_t status = dumpsys.startDumpThread(service, args);
1050 if (status == OK) {
1051 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1052 std::chrono::duration<double> elapsed_seconds;
1053 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1054 /* as_proto = */ false, elapsed_seconds, bytes_written);
1055 section_reporter.setSize(bytes_written);
1056 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1057 bool dump_complete = (status == OK);
1058 dumpsys.stopDumpThread(dump_complete);
1059 }
1060 section_reporter.setStatus(status);
1061
1062 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1063 std::chrono::steady_clock::now() - start);
1064 if (elapsed_duration > timeout) {
1065 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1066 elapsed_duration.count());
1067 break;
1068 }
1069 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001070 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001071}
1072
Vishnu Nair64afc022018-02-01 15:29:34 -08001073static void RunDumpsysText(const std::string& title, int priority,
1074 std::chrono::milliseconds timeout,
1075 std::chrono::milliseconds service_timeout) {
1076 DurationReporter duration_reporter(title);
1077 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1078 fsync(STDOUT_FILENO);
1079 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1080}
1081
1082/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001083static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1084 std::chrono::milliseconds timeout,
1085 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001086 DurationReporter duration_reporter(title);
1087 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1088 fsync(STDOUT_FILENO);
1089 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1090 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001091
1092 RETURN_IF_USER_DENIED_CONSENT();
1093
1094 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1095 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001096}
1097
Nandana Dutt5c390032019-03-12 10:52:56 +00001098static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1099 std::chrono::milliseconds timeout,
1100 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001101 if (!ds.IsZipping()) {
1102 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001103 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001104 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001105 sp<android::IServiceManager> sm = defaultServiceManager();
1106 Dumpsys dumpsys(sm.get());
1107 Vector<String16> args;
1108 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1109 DurationReporter duration_reporter(title);
1110
1111 auto start = std::chrono::steady_clock::now();
1112 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1113 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001114 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001115 std::string path(kProtoPath);
1116 path.append(String8(service).c_str());
1117 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1118 path.append("_CRITICAL");
1119 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1120 path.append("_HIGH");
1121 }
1122 path.append(kProtoExt);
1123 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1124 status_t status = dumpsys.startDumpThread(service, args);
1125 if (status == OK) {
1126 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1127 bool dumpTerminated = (status == OK);
1128 dumpsys.stopDumpThread(dumpTerminated);
1129 }
1130 ZipWriter::FileEntry file_entry;
1131 ds.zip_writer_->GetLastEntry(&file_entry);
1132 section_reporter.setSize(file_entry.compressed_size);
1133 section_reporter.setStatus(status);
1134
1135 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1136 std::chrono::steady_clock::now() - start);
1137 if (elapsed_duration > timeout) {
1138 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1139 elapsed_duration.count());
1140 break;
1141 }
1142 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001143 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001144}
1145
Nandana Dutta7db6342018-11-21 14:53:34 +00001146// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001147static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001148 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1149 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001150
1151 RETURN_IF_USER_DENIED_CONSENT();
1152
1153 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1154 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001155}
1156
1157// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001158static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001159 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1160 // high priority. Reduce timeout once they are able to dump in a shorter time or
1161 // moved to a parallel task.
1162 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1163 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001164
1165 RETURN_IF_USER_DENIED_CONSENT();
1166
1167 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1168 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001169}
1170
1171// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001172static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001173 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001174
1175 RETURN_IF_USER_DENIED_CONSENT();
1176
1177 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1178 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001179}
1180
Steven Moreland44cd9482018-01-04 16:24:13 -08001181static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001182 if (!ds.IsZipping()) {
1183 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1184 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1185 return;
1186 }
1187 DurationReporter duration_reporter("DUMP HALS");
1188 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001189 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001190
Steven Moreland44cd9482018-01-04 16:24:13 -08001191 using android::hidl::manager::V1_0::IServiceManager;
1192 using android::hardware::defaultServiceManager;
1193
1194 sp<IServiceManager> sm = defaultServiceManager();
1195 if (sm == nullptr) {
1196 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1197 return;
1198 }
1199
1200 auto ret = sm->list([&](const auto& interfaces) {
1201 for (const std::string& interface : interfaces) {
1202 std::string cleanName = interface;
1203 std::replace_if(cleanName.begin(),
1204 cleanName.end(),
1205 [](char c) {
1206 return !isalnum(c) &&
1207 std::string("@-_:.").find(c) == std::string::npos;
1208 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001209 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001210
1211 {
1212 auto fd = android::base::unique_fd(
1213 TEMP_FAILURE_RETRY(open(path.c_str(),
1214 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1215 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1216 if (fd < 0) {
1217 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1218 continue;
1219 }
1220 RunCommandToFd(fd,
1221 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001222 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001223 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1224
1225 bool empty = 0 == lseek(fd, 0, SEEK_END);
1226 if (!empty) {
1227 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1228 }
1229 }
1230
1231 unlink(path.c_str());
1232 }
1233 });
1234
1235 if (!ret.isOk()) {
1236 MYLOGE("Could not list hals from hwservicemanager.\n");
1237 }
1238}
1239
Nandana Dutt5c390032019-03-12 10:52:56 +00001240// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1241// via the consent they are shown. Ignores other errors that occur while running various
1242// commands. The consent checking is currently done around long running tasks, which happen to
1243// be distributed fairly evenly throughout the function.
1244static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001245 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001246
Nandana Dutt5c390032019-03-12 10:52:56 +00001247 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1248 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1249 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001250 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001251 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001252 DumpBlockStatFiles();
Mark Salyzyn8c8130e2015-12-09 11:21:28 -08001253 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001254 DumpFile("MEMORY INFO", "/proc/meminfo");
1255 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001256 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001257
1258 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1259
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001260 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1261 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1262 DumpFile("SLAB INFO", "/proc/slabinfo");
1263 DumpFile("ZONEINFO", "/proc/zoneinfo");
1264 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1265 DumpFile("BUDDYINFO", "/proc/buddyinfo");
1266 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001267
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001268 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1269 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
1270 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001271
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001272 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001273 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001274
1275 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1276 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001277
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001278 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001279
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001280 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001281 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001282 struct stat s;
1283 if (stat("/proc/modules", &s) != 0) {
1284 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1285 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001286 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001287 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001288
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001289 if (__android_logger_property_get_bool(
1290 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1291 DoKernelLogcat();
1292 } else {
1293 do_dmesg();
1294 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001295
Felipe Lemef0292972016-11-22 13:57:05 -08001296 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001297
1298 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1299
Jeff Brown1dc94e32014-09-11 14:15:27 -07001300 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001301 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001302
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001303 /* Dump Bluetooth HCI logs */
1304 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001305
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001306 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001307 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001308 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001309 }
1310
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001311 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001312
Felipe Lemee184f662016-10-27 10:04:47 -07001313 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001314
Narayan Kamath8f788292017-05-25 13:20:39 +01001315 // NOTE: tombstones are always added as separate entries in the zip archive
1316 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001317 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001318 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001319 if (!tombstones_dumped) {
1320 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001321 }
1322
Jayachandran Ca94c7172017-06-10 15:08:12 -07001323 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001324
Chenbo Feng276a3b62018-08-07 11:44:49 -07001325 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1326
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001327 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001328
Jayachandran Ca94c7172017-06-10 15:08:12 -07001329 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001330
1331 dump_route_tables();
1332
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001333 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1334 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1335 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001336
Nandana Dutt5c390032019-03-12 10:52:56 +00001337 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001338
Elliott Hughes23ccc622017-02-28 10:14:22 -08001339 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001340
Jin Qianf334d662017-10-10 14:41:37 -07001341 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001342
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001343 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001344
Colin Crossf45fa6b2012-03-26 12:38:26 -07001345 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001346 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1347 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1348 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1349 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1350 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001351
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001352 /* Add window and surface trace files. */
1353 if (!PropertiesHelper::IsUserBuild()) {
1354 ds.AddDir(WMTRACE_DATA_DIR, false);
1355 }
1356
Nandana Dutt5c390032019-03-12 10:52:56 +00001357 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001358
Steven Moreland7440ddb2016-12-15 16:13:39 -08001359 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001360 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1361 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001362 // su does not exist on user builds, so try running without it.
1363 // This way any implementations of vril-dump that do not require
1364 // root can run on user builds.
1365 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001366 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001367 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001368 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001369 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001370 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371 }
1372
Felipe Lemed8b94e52016-12-08 10:21:44 -08001373 printf("========================================================\n");
1374 printf("== Android Framework Services\n");
1375 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001376
Nandana Dutt5c390032019-03-12 10:52:56 +00001377 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001378
Felipe Lemed8b94e52016-12-08 10:21:44 -08001379 printf("========================================================\n");
1380 printf("== Checkins\n");
1381 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001382
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001383 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001384
1385 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1386
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001387 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1388 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1389 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1390 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001391
Felipe Lemed8b94e52016-12-08 10:21:44 -08001392 printf("========================================================\n");
1393 printf("== Running Application Activities\n");
1394 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001395
Makoto Onuki60780982018-04-16 15:34:00 -07001396 // The following dumpsys internally collects output from running apps, so it can take a long
1397 // time. So let's extend the timeout.
1398
1399 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1400
1401 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001402
Felipe Lemed8b94e52016-12-08 10:21:44 -08001403 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001404 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001405 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001406
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001407 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001408 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001409
Felipe Lemed8b94e52016-12-08 10:21:44 -08001410 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001411 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001412 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001413
Makoto Onuki60780982018-04-16 15:34:00 -07001414 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1415 DUMPSYS_COMPONENTS_OPTIONS);
1416
1417 printf("========================================================\n");
1418 printf("== Running Application Providers (platform)\n");
1419 printf("========================================================\n");
1420
1421 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1422 DUMPSYS_COMPONENTS_OPTIONS);
1423
1424 printf("========================================================\n");
1425 printf("== Running Application Providers (non-platform)\n");
1426 printf("========================================================\n");
1427
1428 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1429 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001430
Adrian Roos8b397ab2017-04-04 16:35:44 -07001431 printf("========================================================\n");
1432 printf("== Dropbox crashes\n");
1433 printf("========================================================\n");
1434
1435 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1436 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1437
Felipe Lemed8b94e52016-12-08 10:21:44 -08001438 printf("========================================================\n");
1439 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1440 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1441 printf("========================================================\n");
1442 printf("== dumpstate: done (id %d)\n", ds.id_);
1443 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001444
1445 printf("========================================================\n");
1446 printf("== Obtaining statsd metadata\n");
1447 printf("========================================================\n");
1448 // This differs from the usual dumpsys stats, which is the stats report data.
1449 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001450 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001451}
1452
Nandana Dutt5c390032019-03-12 10:52:56 +00001453/*
1454 * Dumps state for the default case; drops root after it's no longer necessary.
1455 *
1456 * Returns RunStatus::OK if everything went fine.
1457 * Returns RunStatus::ERROR if there was an error.
1458 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1459 * with the caller.
1460 */
1461static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001462 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001463 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001464 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001465
1466 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001467 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001468
1469 /* Run some operations that require root. */
1470 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1471 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1472
1473 ds.AddDir(RECOVERY_DIR, true);
1474 ds.AddDir(RECOVERY_DATA_DIR, true);
1475 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1476 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1477 if (!PropertiesHelper::IsUserBuild()) {
1478 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1479 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1480 }
1481 add_mountinfo();
1482 DumpIpTablesAsRoot();
1483
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001484 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001485 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1486
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001487 // Dump IPsec stats. No keys are exposed here.
1488 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1489
Nandana Dutt4be45d12018-09-26 15:04:23 +01001490 // Run ss as root so we can see socket marks.
1491 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1492
1493 // Run iotop as root to show top 100 IO threads
1494 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1495
Erick Reyese68df822019-02-11 14:46:36 -08001496 // Gather shared memory buffer info if the product implements it
1497 struct stat st;
1498 if (!stat("/product/bin/dmabuf_dump", &st)) {
1499 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1500 }
1501
Nandana Dutt4be45d12018-09-26 15:04:23 +01001502 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001503 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001504 }
1505
Nandana Dutt5c390032019-03-12 10:52:56 +00001506 RETURN_IF_USER_DENIED_CONSENT();
1507 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001508}
1509
mukesh agrawal253dad42018-01-23 21:59:59 -08001510// This method collects common dumpsys for telephony and wifi
1511static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001512 DumpIpTablesAsRoot();
1513
1514 if (!DropRootUser()) {
1515 return;
1516 }
1517
1518 do_dmesg();
1519 DoLogcat();
1520 DumpPacketStats();
1521 DoKmsg();
1522 DumpIpAddrAndRules();
1523 dump_route_tables();
1524
1525 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1526 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001527}
1528
1529// This method collects dumpsys for telephony debugging only
1530static void DumpstateTelephonyOnly() {
1531 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001532 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001533
1534 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001535
1536 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1537
1538 printf("========================================================\n");
1539 printf("== Android Framework Services\n");
1540 printf("========================================================\n");
1541
Vishnu Nair652cc802017-11-30 15:18:30 -08001542 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1543 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001544 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1545 SEC_TO_MSEC(10));
1546 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001547 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1548 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001549 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1550 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001551 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1552 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001553
1554 printf("========================================================\n");
1555 printf("== Running Application Services\n");
1556 printf("========================================================\n");
1557
1558 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1559
1560 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001561 printf("== Running Application Services (non-platform)\n");
1562 printf("========================================================\n");
1563
1564 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1565 DUMPSYS_COMPONENTS_OPTIONS);
1566
1567 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001568 printf("== Checkins\n");
1569 printf("========================================================\n");
1570
1571 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1572
1573 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001574 printf("== dumpstate: done (id %d)\n", ds.id_);
1575 printf("========================================================\n");
1576}
1577
mukesh agrawal253dad42018-01-23 21:59:59 -08001578// This method collects dumpsys for wifi debugging only
1579static void DumpstateWifiOnly() {
1580 DurationReporter duration_reporter("DUMPSTATE");
1581
1582 DumpstateRadioCommon();
1583
1584 printf("========================================================\n");
1585 printf("== Android Framework Services\n");
1586 printf("========================================================\n");
1587
1588 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1589 SEC_TO_MSEC(10));
1590 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1591 SEC_TO_MSEC(10));
1592
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001593 DumpHals();
Roger Wang70399032019-01-08 16:10:37 +08001594
mukesh agrawal253dad42018-01-23 21:59:59 -08001595 printf("========================================================\n");
1596 printf("== dumpstate: done (id %d)\n", ds.id_);
1597 printf("========================================================\n");
1598}
1599
Nandana Duttcf419a72019-03-14 10:40:17 +00001600Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001601 DurationReporter duration_reporter("DUMP TRACES");
1602
1603 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1604 const size_t buf_size = temp_file_pattern.length() + 1;
1605 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1606 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1607
1608 // Create a new, empty file to receive all trace dumps.
1609 //
1610 // TODO: This can be simplified once we remove support for the old style
1611 // dumps. We can have a file descriptor passed in to dump_traces instead
1612 // of creating a file, closing it and then reopening it again.
1613 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1614 if (fd < 0) {
1615 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001616 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001617 }
1618
1619 // Nobody should have access to this temporary file except dumpstate, but we
1620 // temporarily grant 'read' to 'others' here because this file is created
1621 // when tombstoned is still running as root, but dumped after dropping. This
1622 // can go away once support for old style dumping has.
1623 const int chmod_ret = fchmod(fd, 0666);
1624 if (chmod_ret < 0) {
1625 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001626 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001627 }
1628
1629 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1630 if (proc.get() == nullptr) {
1631 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001632 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001633 }
1634
1635 // Number of times process dumping has timed out. If we encounter too many
1636 // failures, we'll give up.
1637 int timeout_failures = 0;
1638 bool dalvik_found = false;
1639
1640 const std::set<int> hal_pids = get_interesting_hal_pids();
1641
1642 struct dirent* d;
1643 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001644 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001645 int pid = atoi(d->d_name);
1646 if (pid <= 0) {
1647 continue;
1648 }
1649
1650 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1651 std::string exe;
1652 if (!android::base::Readlink(link_name, &exe)) {
1653 continue;
1654 }
1655
1656 bool is_java_process;
1657 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1658 // Don't bother dumping backtraces for the zygote.
1659 if (IsZygote(pid)) {
1660 continue;
1661 }
1662
1663 dalvik_found = true;
1664 is_java_process = true;
1665 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1666 is_java_process = false;
1667 } else {
1668 // Probably a native process we don't care about, continue.
1669 continue;
1670 }
1671
1672 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1673 if (timeout_failures == 3) {
1674 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1675 break;
1676 }
1677
1678 const uint64_t start = Nanotime();
1679 const int ret = dump_backtrace_to_file_timeout(
1680 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1681 is_java_process ? 5 : 20, fd);
1682
1683 if (ret == -1) {
1684 // For consistency, the header and footer to this message match those
1685 // dumped by debuggerd in the success case.
1686 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1687 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1688 dprintf(fd, "---- end %d ----", pid);
1689 timeout_failures++;
1690 continue;
1691 }
1692
1693 // We've successfully dumped stack traces, reset the failure count
1694 // and write a summary of the elapsed time to the file and continue with the
1695 // next process.
1696 timeout_failures = 0;
1697
1698 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1699 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1700 }
1701
1702 if (!dalvik_found) {
1703 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1704 }
1705
Nandana Duttcf419a72019-03-14 10:40:17 +00001706 *path = file_name_buf.release();
1707 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001708}
1709
Felipe Leme6f674ae2016-11-18 17:10:33 -08001710void Dumpstate::DumpstateBoard() {
1711 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001712 printf("========================================================\n");
1713 printf("== Board\n");
1714 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001715
Felipe Leme6f674ae2016-11-18 17:10:33 -08001716 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001717 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001718 return;
1719 }
1720
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001721 std::vector<std::string> paths;
1722 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001723 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001724 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1725 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001726 remover.emplace_back(android::base::make_scope_guard(
1727 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001728 }
Jie Song9fbfad02017-06-20 16:29:42 -07001729
Wei Wang587eac92018-04-05 12:17:20 -07001730 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1731 if (dumpstate_device == nullptr) {
1732 MYLOGE("No IDumpstateDevice implementation\n");
1733 return;
1734 }
1735
1736 using ScopedNativeHandle =
1737 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1738 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1739 [](native_handle_t* handle) {
1740 native_handle_close(handle);
1741 native_handle_delete(handle);
1742 });
1743 if (handle == nullptr) {
1744 MYLOGE("Could not create native_handle\n");
1745 return;
1746 }
1747
Nandana Dutt5c390032019-03-12 10:52:56 +00001748 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001749 for (size_t i = 0; i < paths.size(); i++) {
1750 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1751
1752 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1753 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1754 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1755 if (fd < 0) {
1756 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1757 return;
1758 }
1759 handle.get()->data[i] = fd.release();
1760 }
1761
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001762 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001763 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1764 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1765 // and grab whatever dumped
1766 std::packaged_task<bool()>
1767 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001768 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1769 if (!status.isOk()) {
1770 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001771 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001772 }
Wei Wang587eac92018-04-05 12:17:20 -07001773 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001774 });
Wei Wang587eac92018-04-05 12:17:20 -07001775
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001776 auto result = dumpstate_task.get_future();
1777 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001778
1779 constexpr size_t timeout_sec = 30;
1780 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1781 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1782 if (!android::base::SetProperty("ctl.interface_restart",
1783 android::base::StringPrintf("%s/default",
1784 IDumpstateDevice::descriptor))) {
1785 MYLOGE("Couldn't restart dumpstate HAL\n");
1786 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001787 }
Wei Wang587eac92018-04-05 12:17:20 -07001788 // Wait some time for init to kill dumpstate vendor HAL
1789 constexpr size_t killing_timeout_sec = 10;
1790 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1791 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1792 "there might be racing in content\n", killing_timeout_sec);
1793 }
1794
1795 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1796 for (size_t i = 0; i < paths.size(); i++) {
1797 struct stat s;
1798 if (fstat(handle.get()->data[i], &s) == -1) {
1799 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1800 strerror(errno));
1801 file_sizes[i] = -1;
1802 continue;
1803 }
1804 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001805 }
1806
1807 for (size_t i = 0; i < paths.size(); i++) {
1808 if (file_sizes[i] == -1) {
1809 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001810 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001811 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001812 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001813 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001814 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001815 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001816 }
1817
Felipe Lemed8b94e52016-12-08 10:21:44 -08001818 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001819}
1820
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001821static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001822 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001823 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001824 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1825 " -h: display this help message\n"
1826 " -b: play sound file instead of vibrate, at beginning of job\n"
1827 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001828 " -d: append date to filename\n"
1829 " -p: capture screenshot to filename.png\n"
1830 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001831 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001832 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001833 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001834 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001835 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001836 "progress (requires -B)\n"
1837 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001838 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001839 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001840 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001841}
1842
Wei Liuf87959e2016-08-26 14:51:42 -07001843static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001844 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001845}
1846
Felipe Leme1d486fe2016-10-14 18:06:47 -07001847bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001848 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001849 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001850 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001851 // Final timestamp
1852 char date[80];
1853 time_t the_real_now_please_stand_up = time(nullptr);
1854 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001855 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001856 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001857
Felipe Leme9a523ae2016-10-20 15:10:33 -07001858 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001859 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001860 return false;
1861 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001862 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001863 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001864 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001865 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001866
Felipe Leme0f3fb202016-06-10 17:10:53 -07001867 // Add log file (which contains stderr output) to zip...
1868 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001869 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001870 MYLOGE("Failed to add dumpstate log to .zip file\n");
1871 return false;
1872 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001873 // TODO: Should truncate the existing file.
1874 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001875 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1876 return false;
1877 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001878 fprintf(stderr, "\n");
1879
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001880 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001881 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001882 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001883 return false;
1884 }
1885
Felipe Leme1d486fe2016-10-14 18:06:47 -07001886 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1887 ds.zip_file.reset(nullptr);
1888
Felipe Lemee9d2c542016-11-15 11:48:26 -08001889 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001890 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001891
Felipe Leme1e9edc62015-12-21 16:02:13 -08001892 return true;
1893}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001894
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001895static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001896 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1897 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001898 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001899 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001900 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001901 }
1902
1903 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001904 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001905
1906 std::vector<uint8_t> buffer(65536);
1907 while (1) {
1908 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1909 if (bytes_read == 0) {
1910 break;
1911 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001912 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001913 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001914 }
1915
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001916 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001917 }
1918
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001919 uint8_t hash[SHA256_DIGEST_LENGTH];
1920 SHA256_Final(hash, &ctx);
1921
1922 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1923 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001924 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001925 }
1926 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1927 return std::string(hash_buffer);
1928}
1929
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001930static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1931 // clang-format off
1932 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1933 "--receiver-foreground", "--receiver-include-background", "-a", action};
1934 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001935
1936 am.insert(am.end(), args.begin(), args.end());
1937
Felipe Leme8d2410e2017-02-08 09:46:08 -08001938 RunCommand("", am,
1939 CommandOptions::WithTimeout(20)
1940 .Log("Sending broadcast: '%s'\n")
1941 .Always()
1942 .DropRoot()
1943 .RedirectStderr()
1944 .Build());
1945}
1946
Felipe Leme35b8cf12017-02-10 15:47:29 -08001947static void Vibrate(int duration_ms) {
1948 // clang-format off
Chris Friese7e95fb2019-06-14 14:47:59 +00001949 RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001950 CommandOptions::WithTimeout(10)
1951 .Log("Vibrate: '%s'\n")
1952 .Always()
1953 .Build());
1954 // clang-format on
1955}
1956
Nandana Dutt979388e2018-11-30 16:48:55 +00001957static void MaybeResolveSymlink(std::string* path) {
1958 std::string resolved_path;
1959 if (android::base::Readlink(*path, &resolved_path)) {
1960 *path = resolved_path;
1961 }
1962}
1963
Nandana Dutt4be45d12018-09-26 15:04:23 +01001964/*
1965 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
1966 * if we are writing zip files and adds the version file.
1967 */
1968static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00001969 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
1970
Nandana Dutt4be45d12018-09-26 15:04:23 +01001971 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1972 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00001973 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001974 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001975 char date[80];
1976 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
1977 ds.name_ = date;
1978 } else {
1979 ds.name_ = "undated";
1980 }
1981
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001982 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001983 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001984 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001985 ds.base_name_ += "-wifi";
1986 }
1987
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001988 if (ds.options_->do_fb) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01001989 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01001990 }
1991 ds.tmp_path_ = ds.GetPath(".tmp");
1992 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1993
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01001994 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00001995 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00001996 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001997 MYLOGD(
1998 "Bugreport dir: %s\n"
1999 "Base name: %s\n"
2000 "Suffix: %s\n"
2001 "Log path: %s\n"
2002 "Temporary path: %s\n"
2003 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002004 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2005 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002006
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002007 if (ds.options_->do_zip_file) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002008 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002009 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2010 create_parent_dirs(ds.path_.c_str());
2011 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2012 if (ds.zip_file == nullptr) {
2013 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2014 } else {
2015 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2016 }
2017 ds.AddTextZipEntry("version.txt", ds.version_);
2018 }
2019}
2020
2021/*
2022 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2023 * printing zipped file status, etc.
2024 */
2025static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002026 /* check if user changed the suffix using system properties */
2027 std::string name =
2028 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2029 bool change_suffix = false;
2030 if (!name.empty()) {
2031 /* must whitelist which characters are allowed, otherwise it could cross directories */
2032 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2033 if (std::regex_match(name.c_str(), valid_regex)) {
2034 change_suffix = true;
2035 } else {
2036 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2037 }
2038 }
2039 if (change_suffix) {
2040 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2041 ds.name_ = name;
2042 if (!ds.screenshot_path_.empty()) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002043 std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002044 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2045 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2046 new_screenshot_path.c_str(), strerror(errno));
2047 } else {
2048 ds.screenshot_path_ = new_screenshot_path;
2049 }
2050 }
2051 }
2052
2053 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002054 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002055 if (!ds.FinishZipFile()) {
2056 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2057 do_text_file = true;
2058 } else {
2059 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002060 // If the user has changed the suffix, we need to change the zip file name.
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002061 std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt383d0c12018-11-30 15:54:56 +00002062 if (ds.path_ != new_path) {
2063 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2064 if (rename(ds.path_.c_str(), new_path.c_str())) {
2065 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2066 strerror(errno));
2067 } else {
2068 ds.path_ = new_path;
2069 }
2070 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002071 }
2072 }
2073 if (do_text_file) {
2074 ds.path_ = ds.GetPath(".txt");
2075 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2076 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2077 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2078 ds.path_.clear();
2079 }
2080 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002081 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002082 if (do_text_file) {
2083 dprintf(ds.control_socket_fd_,
2084 "FAIL:could not create zip file, check %s "
2085 "for more details\n",
2086 ds.log_path_.c_str());
2087 } else {
2088 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2089 }
2090 }
2091}
2092
2093/* Broadcasts that we are done with the bugreport */
2094static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002095 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002096 if (!ds.path_.empty()) {
2097 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002098 // clang-format off
2099
2100 std::vector<std::string> am_args = {
2101 "--receiver-permission", "android.permission.DUMP",
2102 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2103 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2104 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002105 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002106 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2107 };
2108 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002109 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002110 am_args.push_back("--es");
2111 am_args.push_back("android.intent.extra.SCREENSHOT");
2112 am_args.push_back(ds.screenshot_path_);
2113 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002114 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002115 am_args.push_back("--es");
2116 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002117 am_args.push_back(ds.options_->notification_title);
2118 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002119 am_args.push_back("--es");
2120 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002121 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002122 }
2123 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002124 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002125 am_args.push_back("--es");
2126 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002127 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002128 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2129 } else {
2130 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2131 }
2132 } else {
2133 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2134 }
2135}
2136
Nandana Dutt58d72e22018-11-16 10:30:48 +00002137static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2138 switch (mode) {
2139 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2140 return "BUGREPORT_FULL";
2141 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2142 return "BUGREPORT_INTERACTIVE";
2143 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2144 return "BUGREPORT_REMOTE";
2145 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2146 return "BUGREPORT_WEAR";
2147 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2148 return "BUGREPORT_TELEPHONY";
2149 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2150 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002151 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2152 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002153 }
2154}
2155
2156static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002157 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002158 switch (mode) {
2159 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2160 options->do_broadcast = true;
2161 options->do_fb = true;
2162 break;
2163 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002164 // Currently, the dumpstate binder is only used by Shell to update progress.
2165 options->do_start_service = true;
2166 options->do_progress_updates = true;
2167 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002168 options->do_broadcast = true;
2169 break;
2170 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002171 options->do_vibrate = false;
2172 options->is_remote_mode = true;
2173 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002174 options->do_broadcast = true;
2175 break;
2176 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002177 options->do_start_service = true;
2178 options->do_progress_updates = true;
2179 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002180 options->do_fb = true;
2181 options->do_broadcast = true;
2182 break;
2183 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002184 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002185 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002186 options->do_broadcast = true;
2187 break;
2188 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002189 options->wifi_only = true;
2190 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002191 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002192 options->do_broadcast = true;
2193 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002194 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2195 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002196 }
2197}
2198
2199static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002200 // If the system property is not set, it's assumed to be a default bugreport.
2201 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002202
2203 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2204 if (!extra_options.empty()) {
2205 // Framework uses a system property to override some command-line args.
2206 // Currently, it contains the type of the requested bugreport.
2207 if (extra_options == "bugreportplus") {
2208 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002209 } else if (extra_options == "bugreportfull") {
2210 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002211 } else if (extra_options == "bugreportremote") {
2212 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2213 } else if (extra_options == "bugreportwear") {
2214 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2215 } else if (extra_options == "bugreporttelephony") {
2216 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2217 } else if (extra_options == "bugreportwifi") {
2218 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002219 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002220 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002221 }
2222 // Reset the property
2223 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2224 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002225 return mode;
2226}
2227
2228// TODO: Move away from system properties when we have options passed via binder calls.
2229/* Sets runtime options from the system properties and then clears those properties. */
2230static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2231 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2232 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002233
2234 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2235 if (!options->notification_title.empty()) {
2236 // Reset the property
2237 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2238
Nandana Duttdd8cca32018-11-14 10:10:29 +00002239 options->notification_description =
2240 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002241 if (!options->notification_description.empty()) {
2242 // Reset the property
2243 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2244 }
2245 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2246 options->notification_description.c_str());
2247 }
2248}
2249
Nandana Dutt58d72e22018-11-16 10:30:48 +00002250static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2251 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2252 MYLOGI("do_add_date: %d\n", options.do_add_date);
2253 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2254 MYLOGI("use_socket: %d\n", options.use_socket);
2255 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2256 MYLOGI("do_fb: %d\n", options.do_fb);
2257 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2258 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2259 MYLOGI("show_header_only: %d\n", options.show_header_only);
2260 MYLOGI("do_start_service: %d\n", options.do_start_service);
2261 MYLOGI("telephony_only: %d\n", options.telephony_only);
2262 MYLOGI("wifi_only: %d\n", options.wifi_only);
2263 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002264 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002265 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2266 MYLOGI("args: %s\n", options.args.c_str());
2267 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2268 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2269}
2270
Nandana Dutt54dbd672019-01-11 12:58:05 +00002271void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2272 const android::base::unique_fd& bugreport_fd_in,
2273 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002274 // In the new API world, date is always added; output is always a zip file.
2275 // TODO(111441001): remove these options once they are obsolete.
2276 do_add_date = true;
2277 do_zip_file = true;
2278
Nandana Dutt54dbd672019-01-11 12:58:05 +00002279 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2280 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2281 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002282
2283 extra_options = ModeToString(bugreport_mode);
2284 SetOptionsFromMode(bugreport_mode, this);
2285}
2286
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002287Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2288 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002289 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002290 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002291 switch (c) {
2292 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002293 case 'd': do_add_date = true; break;
2294 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002295 // o=use_outfile not supported anymore.
2296 // TODO(b/111441001): Remove when all callers have migrated.
2297 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002298 case 's': use_socket = true; break;
2299 case 'S': use_control_socket = true; break;
2300 case 'v': show_header_only = true; break;
2301 case 'q': do_vibrate = false; break;
2302 case 'p': do_fb = true; break;
2303 case 'P': do_progress_updates = true; break;
2304 case 'R': is_remote_mode = true; break;
2305 case 'B': do_broadcast = true; break;
2306 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002307 case 'w':
2308 // This was already processed
2309 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002310 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002311 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002312 break;
2313 default:
2314 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002315 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002316 break;
2317 // clang-format on
2318 }
2319 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002320
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002321 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002322 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002323 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002324 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002325 }
2326 }
2327
2328 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2329 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002330
2331 SetOptionsFromProperties(this);
2332 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002333}
2334
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002335bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002336 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002337 return false;
2338 }
2339
Nandana Dutt9a76d202019-01-21 15:56:48 +00002340 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002341 return false;
2342 }
2343
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002344 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002345 return false;
2346 }
2347
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002348 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002349 return false;
2350 }
2351
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002352 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002353 return false;
2354 }
2355 return true;
2356}
2357
Nandana Dutt197661d2018-11-16 16:40:21 +00002358void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2359 options_ = std::move(options);
2360}
2361
Nandana Duttd2f5f082019-01-18 17:13:52 +00002362Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2363 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002364 if (listener_ != nullptr) {
2365 switch (status) {
2366 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002367 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002368 break;
2369 case Dumpstate::RunStatus::HELP:
2370 break;
2371 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002372 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002373 break;
2374 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002375 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2376 break;
2377 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2378 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2379 break;
2380 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2381 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002382 break;
2383 }
2384 }
2385 return status;
2386}
2387
Nandana Dutt979388e2018-11-30 16:48:55 +00002388/*
2389 * Dumps relevant information to a bugreport based on the given options.
2390 *
2391 * The bugreport can be dumped to a file or streamed to a socket.
2392 *
2393 * How dumping to file works:
2394 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2395 * stderr is redirected a log file.
2396 *
2397 * The temporary bugreport is then populated via printfs, dumping contents of files and
2398 * output of commands to stdout.
2399 *
2400 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2401 * text file.
2402 *
2403 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2404 * gets added to the archive.
2405 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002406 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2407 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002408 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002409Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2410 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002411 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002412 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002413 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002414 return RunStatus::INVALID_INPUT;
2415 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002416 /* set as high priority, and protect from OOM killer */
2417 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002418
Felipe Lemed071c682016-10-20 16:48:00 -07002419 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002420 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002421 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002422 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002423 } else {
2424 /* fallback to kernels <= 2.6.35 */
2425 oom_adj = fopen("/proc/self/oom_adj", "we");
2426 if (oom_adj) {
2427 fputs("-17", oom_adj);
2428 fclose(oom_adj);
2429 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002430 }
2431
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002432 if (version_ == VERSION_DEFAULT) {
2433 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002434 }
2435
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002436 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002437 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002438 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002439 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002440 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002441 }
2442
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002443 if (options_->show_header_only) {
2444 PrintHeader();
2445 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002446 }
2447
Nandana Duttd2f5f082019-01-18 17:13:52 +00002448 if (options_->bugreport_fd.get() != -1) {
2449 // If the output needs to be copied over to the caller's fd, get user consent.
2450 android::String16 package(calling_package.c_str());
2451 CheckUserConsent(calling_uid, package);
2452 }
2453
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002454 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002455 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002456
2457 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002458 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002459 is_redirecting
2460 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2461 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002462 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002463
Felipe Lemed071c682016-10-20 16:48:00 -07002464 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002465 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002466 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002467 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2468
2469 MYLOGI("begin\n");
2470
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002471 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002472
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002473 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002474 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002475 MYLOGI("Starting 'dumpstate' service\n");
2476 android::status_t ret;
2477 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2478 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2479 }
2480 }
2481
Felipe Lemef0292972016-11-22 13:57:05 -08002482 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002483 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2484 }
2485
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002486 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2487 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002488
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002489 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002490
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002491 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002492
Christopher Ferrised9354f2014-10-01 17:35:01 -07002493 // If we are going to use a socket, do it as early as possible
2494 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002495 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002496 if (!redirect_to_socket(stdout, "dumpstate")) {
2497 return ERROR;
2498 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002499 }
2500
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002501 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002502 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002503 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002504 if (control_socket_fd_ == -1) {
2505 return ERROR;
2506 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002507 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002508 }
2509
Felipe Leme71bbfc52015-11-23 14:14:51 -08002510 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002511 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002512
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002513 if (options_->do_progress_updates) {
2514 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002515 // clang-format off
2516 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002517 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002518 "--es", "android.intent.extra.NAME", name_,
2519 "--ei", "android.intent.extra.ID", std::to_string(id_),
2520 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2521 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002522 };
2523 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002524 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002525 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002526 if (options_->use_control_socket) {
2527 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002528 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002529 }
2530 }
2531
Nick Kralevichf3599b32016-01-25 15:05:16 -08002532 /* read /proc/cmdline before dropping root */
2533 FILE *cmdline = fopen("/proc/cmdline", "re");
2534 if (cmdline) {
2535 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2536 fclose(cmdline);
2537 }
2538
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002539 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002540 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002541 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002542
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002543 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002544 MYLOGI("taking early screenshot\n");
2545 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002546 }
2547
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002548 if (options_->do_zip_file && zip_file != nullptr) {
2549 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2550 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002551 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002552 }
2553 }
2554
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002555 int dup_stdout_fd;
2556 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002557 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002558 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002559 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002560 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2561 return ERROR;
2562 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002563 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2564 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2565 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002566 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002567
2568 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2569 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002570 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002571 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002572 /* TODO: rather than generating a text file now and zipping it later,
2573 it would be more efficient to redirect stdout to the zip entry
2574 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002575 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2576 return ERROR;
2577 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002578 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002579 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002580 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002581 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002582 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002583
2584 // Don't buffer stdout
2585 setvbuf(stdout, nullptr, _IONBF, 0);
2586
Felipe Leme608385d2016-02-01 10:35:38 -08002587 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2588 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002589 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002590 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002591
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002592 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002593 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002594 DumpstateBoard();
2595 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002596 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002597 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002598 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002599 RunStatus s = DumpstateDefault();
2600 if (s != RunStatus::OK) {
2601 if (s == RunStatus::USER_CONSENT_TIMED_OUT) {
2602 HandleUserConsentDenied();
2603 }
2604 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002605 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002606 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002607
Felipe Leme55b42a62015-11-10 17:39:08 -08002608 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002609 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002610 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002611 }
2612
Nandana Duttd2f5f082019-01-18 17:13:52 +00002613 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002614 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002615 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002616 }
2617
Nandana Duttd2f5f082019-01-18 17:13:52 +00002618 // Share the final file with the caller if the user has consented.
2619 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2620 if (options_->bugreport_fd.get() != -1) {
2621 status = CopyBugreportIfUserConsented();
2622 if (status != Dumpstate::RunStatus::OK &&
2623 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2624 // Do an early return if there were errors. We make an exception for consent
2625 // timing out because it's possible the user got distracted. In this case the
2626 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002627 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002628 return status;
2629 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002630 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002631 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2632 options_->screenshot_fd.get());
2633 if (copy_succeeded) {
2634 android::os::UnlinkAndLogOnError(screenshot_path_);
2635 }
2636 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002637 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2638 MYLOGI(
2639 "Did not receive user consent yet."
2640 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002641 const String16 incidentcompanion("incidentcompanion");
2642 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2643 if (ics != nullptr) {
2644 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2645 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2646 consent_callback_.get());
2647 } else {
2648 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2649 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002650 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002651 }
2652
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002653 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002654 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002655 for (int i = 0; i < 3; i++) {
2656 Vibrate(75);
2657 usleep((75 + 50) * 1000);
2658 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002659 }
2660
Jeff Brown1dc94e32014-09-11 14:15:27 -07002661 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002662 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002663 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002664 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002665 }
2666
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002667 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2668 progress_->GetInitialMax());
2669 progress_->Save();
2670 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002671
Felipe Leme107a05f2016-03-08 15:11:15 -08002672 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002673 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002674 }
2675
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002676 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002677 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002678 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002679 }
2680
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002681 tombstone_data_.clear();
2682 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002683
Nandana Duttd2f5f082019-01-18 17:13:52 +00002684 return (consent_callback_ != nullptr &&
2685 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2686 ? USER_CONSENT_TIMED_OUT
2687 : RunStatus::OK;
2688}
2689
2690void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2691 consent_callback_ = new ConsentCallback();
2692 const String16 incidentcompanion("incidentcompanion");
2693 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2694 if (ics != nullptr) {
2695 MYLOGD("Checking user consent via incidentcompanion service\n");
2696 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002697 calling_uid, calling_package, String16(), String16(),
2698 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002699 } else {
2700 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2701 }
2702}
2703
Nandana Dutt5c390032019-03-12 10:52:56 +00002704bool Dumpstate::IsUserConsentDenied() const {
2705 return ds.consent_callback_ != nullptr &&
2706 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2707}
2708
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002709bool Dumpstate::CalledByApi() const {
2710 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2711}
2712
Nandana Duttd2f5f082019-01-18 17:13:52 +00002713void Dumpstate::CleanupFiles() {
2714 android::os::UnlinkAndLogOnError(tmp_path_);
2715 android::os::UnlinkAndLogOnError(screenshot_path_);
2716 android::os::UnlinkAndLogOnError(path_);
2717}
2718
2719Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2720 MYLOGD("User denied consent; deleting files and returning\n");
2721 CleanupFiles();
2722 return USER_CONSENT_DENIED;
2723}
2724
2725Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2726 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2727 // user consent.
2728 UserConsentResult consent_result = consent_callback_->getResult();
2729 if (consent_result == UserConsentResult::UNAVAILABLE) {
2730 // User has not responded yet.
2731 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2732 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2733 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2734 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2735 sleep(delay_seconds);
2736 }
2737 consent_result = consent_callback_->getResult();
2738 }
2739 if (consent_result == UserConsentResult::DENIED) {
2740 // User has explicitly denied sharing with the app. To be safe delete the
2741 // internal bugreport & tmp files.
2742 return HandleUserConsentDenied();
2743 }
2744 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002745 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2746 if (copy_succeeded) {
2747 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002748 }
2749 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2750 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2751 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2752 // Since we do not have user consent to share the bugreport it does not get
2753 // copied over to the calling app but remains in the internal directory from
2754 // where the user can manually pull it.
2755 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2756 }
2757 // Unknown result; must be a programming error.
2758 MYLOGE("Unknown user consent result:%d\n", consent_result);
2759 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002760}
2761
Nandana Duttf02564e2019-02-15 15:24:24 +00002762Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002763 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2764 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2765 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002766 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002767 // When directly running dumpstate binary, the output is not expected to be written
2768 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002769 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002770
2771 // calling_uid and calling_package are for user consent to share the bugreport with
2772 // an app; they are irrelvant here because bugreport is only written to a local
2773 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002774 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002775 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002776 return status;
2777}
2778
2779/* Main entry point for dumpstate binary. */
2780int run_main(int argc, char* argv[]) {
2781 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002782
2783 switch (status) {
2784 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002785 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002786 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002787 ShowUsage();
2788 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002789 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002790 fprintf(stderr, "Invalid combination of args\n");
2791 ShowUsage();
2792 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002793 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002794 FALLTHROUGH_INTENDED;
2795 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2796 FALLTHROUGH_INTENDED;
2797 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002798 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002799 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002800}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002801
2802// TODO(111441001): Default DumpOptions to sensible values.
2803Dumpstate::Dumpstate(const std::string& version)
2804 : pid_(getpid()),
2805 options_(new Dumpstate::DumpOptions()),
2806 version_(version),
2807 now_(time(nullptr)) {
2808}
2809
2810Dumpstate& Dumpstate::GetInstance() {
2811 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2812 return singleton_;
2813}
2814
2815DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
2816 : title_(title), logcat_only_(logcat_only) {
2817 if (!title_.empty()) {
2818 started_ = Nanotime();
2819 }
2820}
2821
2822DurationReporter::~DurationReporter() {
2823 if (!title_.empty()) {
2824 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2825 if (elapsed < .5f) {
2826 return;
2827 }
2828 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2829 if (logcat_only_) {
2830 return;
2831 }
2832 // Use "Yoda grammar" to make it easier to grep|sort sections.
2833 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2834 }
2835}
2836
2837const int32_t Progress::kDefaultMax = 5000;
2838
2839Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2840}
2841
2842Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2843 : Progress(initial_max, growth_factor, "") {
2844 progress_ = progress;
2845}
2846
2847Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2848 : initial_max_(initial_max),
2849 progress_(0),
2850 max_(initial_max),
2851 growth_factor_(growth_factor),
2852 n_runs_(0),
2853 average_max_(0),
2854 path_(path) {
2855 if (!path_.empty()) {
2856 Load();
2857 }
2858}
2859
2860void Progress::Load() {
2861 MYLOGD("Loading stats from %s\n", path_.c_str());
2862 std::string content;
2863 if (!android::base::ReadFileToString(path_, &content)) {
2864 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2865 return;
2866 }
2867 if (content.empty()) {
2868 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2869 return;
2870 }
2871 std::vector<std::string> lines = android::base::Split(content, "\n");
2872
2873 if (lines.size() < 1) {
2874 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2875 (int)lines.size(), max_);
2876 return;
2877 }
2878 char* ptr;
2879 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2880 average_max_ = strtol(ptr, nullptr, 10);
2881 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2882 average_max_ > STATS_MAX_AVERAGE) {
2883 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2884 initial_max_ = Progress::kDefaultMax;
2885 } else {
2886 initial_max_ = average_max_;
2887 }
2888 max_ = initial_max_;
2889
2890 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2891}
2892
2893void Progress::Save() {
2894 int32_t total = n_runs_ * average_max_ + progress_;
2895 int32_t runs = n_runs_ + 1;
2896 int32_t average = floor(((float)total) / runs);
2897 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2898 path_.c_str());
2899 if (path_.empty()) {
2900 return;
2901 }
2902
2903 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2904 if (!android::base::WriteStringToFile(content, path_)) {
2905 MYLOGE("Could not save stats on %s\n", path_.c_str());
2906 }
2907}
2908
2909int32_t Progress::Get() const {
2910 return progress_;
2911}
2912
2913bool Progress::Inc(int32_t delta_sec) {
2914 bool changed = false;
2915 if (delta_sec >= 0) {
2916 progress_ += delta_sec;
2917 if (progress_ > max_) {
2918 int32_t old_max = max_;
2919 max_ = floor((float)progress_ * growth_factor_);
2920 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2921 changed = true;
2922 }
2923 }
2924 return changed;
2925}
2926
2927int32_t Progress::GetMax() const {
2928 return max_;
2929}
2930
2931int32_t Progress::GetInitialMax() const {
2932 return initial_max_;
2933}
2934
2935void Progress::Dump(int fd, const std::string& prefix) const {
2936 const char* pr = prefix.c_str();
2937 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2938 dprintf(fd, "%smax: %d\n", pr, max_);
2939 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2940 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2941 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2942 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2943 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2944}
2945
2946bool Dumpstate::IsZipping() const {
2947 return zip_writer_ != nullptr;
2948}
2949
2950std::string Dumpstate::GetPath(const std::string& suffix) const {
2951 return GetPath(bugreport_internal_dir_, suffix);
2952}
2953
2954std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2955 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2956 name_.c_str(), suffix.c_str());
2957}
2958
2959void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2960 progress_ = std::move(progress);
2961}
2962
2963void for_each_userid(void (*func)(int), const char *header) {
2964 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2965 "for_each_userid(%s)", header);
2966 DurationReporter duration_reporter(title);
2967 if (PropertiesHelper::IsDryRun()) return;
2968
2969 DIR *d;
2970 struct dirent *de;
2971
2972 if (header) printf("\n------ %s ------\n", header);
2973 func(0);
2974
2975 if (!(d = opendir("/data/system/users"))) {
2976 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2977 return;
2978 }
2979
2980 while ((de = readdir(d))) {
2981 int userid;
2982 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2983 continue;
2984 }
2985 func(userid);
2986 }
2987
2988 closedir(d);
2989}
2990
2991static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2992 DIR *d;
2993 struct dirent *de;
2994
2995 if (!(d = opendir("/proc"))) {
2996 printf("Failed to open /proc (%s)\n", strerror(errno));
2997 return;
2998 }
2999
3000 if (header) printf("\n------ %s ------\n", header);
3001 while ((de = readdir(d))) {
3002 if (ds.IsUserConsentDenied()) {
3003 MYLOGE(
3004 "Returning early because user denied consent to share bugreport with calling app.");
3005 closedir(d);
3006 return;
3007 }
3008 int pid;
3009 int fd;
3010 char cmdpath[255];
3011 char cmdline[255];
3012
3013 if (!(pid = atoi(de->d_name))) {
3014 continue;
3015 }
3016
3017 memset(cmdline, 0, sizeof(cmdline));
3018
3019 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3020 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3021 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3022 close(fd);
3023 if (cmdline[0]) {
3024 helper(pid, cmdline, arg);
3025 continue;
3026 }
3027 }
3028
3029 // if no cmdline, a kernel thread has comm
3030 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3031 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3032 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3033 close(fd);
3034 if (cmdline[1]) {
3035 cmdline[0] = '[';
3036 size_t len = strcspn(cmdline, "\f\b\r\n");
3037 cmdline[len] = ']';
3038 cmdline[len+1] = '\0';
3039 }
3040 }
3041 if (!cmdline[0]) {
3042 strcpy(cmdline, "N/A");
3043 }
3044 helper(pid, cmdline, arg);
3045 }
3046
3047 closedir(d);
3048}
3049
3050static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3051 for_each_pid_func *func = (for_each_pid_func*) arg;
3052 func(pid, cmdline);
3053}
3054
3055void for_each_pid(for_each_pid_func func, const char *header) {
3056 std::string title = header == nullptr ? "for_each_pid"
3057 : android::base::StringPrintf("for_each_pid(%s)", header);
3058 DurationReporter duration_reporter(title);
3059 if (PropertiesHelper::IsDryRun()) return;
3060
3061 __for_each_pid(for_each_pid_helper, header, (void *) func);
3062}
3063
3064static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3065 DIR *d;
3066 struct dirent *de;
3067 char taskpath[255];
3068 for_each_tid_func *func = (for_each_tid_func *) arg;
3069
3070 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3071
3072 if (!(d = opendir(taskpath))) {
3073 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3074 return;
3075 }
3076
3077 func(pid, pid, cmdline);
3078
3079 while ((de = readdir(d))) {
3080 if (ds.IsUserConsentDenied()) {
3081 MYLOGE(
3082 "Returning early because user denied consent to share bugreport with calling app.");
3083 closedir(d);
3084 return;
3085 }
3086 int tid;
3087 int fd;
3088 char commpath[255];
3089 char comm[255];
3090
3091 if (!(tid = atoi(de->d_name))) {
3092 continue;
3093 }
3094
3095 if (tid == pid)
3096 continue;
3097
3098 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3099 memset(comm, 0, sizeof(comm));
3100 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3101 strcpy(comm, "N/A");
3102 } else {
3103 char *c;
3104 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3105 close(fd);
3106
3107 c = strrchr(comm, '\n');
3108 if (c) {
3109 *c = '\0';
3110 }
3111 }
3112 func(pid, tid, comm);
3113 }
3114
3115 closedir(d);
3116}
3117
3118void for_each_tid(for_each_tid_func func, const char *header) {
3119 std::string title = header == nullptr ? "for_each_tid"
3120 : android::base::StringPrintf("for_each_tid(%s)", header);
3121 DurationReporter duration_reporter(title);
3122
3123 if (PropertiesHelper::IsDryRun()) return;
3124
3125 __for_each_pid(for_each_tid_helper, header, (void *) func);
3126}
3127
3128void show_wchan(int pid, int tid, const char *name) {
3129 if (PropertiesHelper::IsDryRun()) return;
3130
3131 char path[255];
3132 char buffer[255];
3133 int fd, ret, save_errno;
3134 char name_buffer[255];
3135
3136 memset(buffer, 0, sizeof(buffer));
3137
3138 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3139 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3140 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3141 return;
3142 }
3143
3144 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3145 save_errno = errno;
3146 close(fd);
3147
3148 if (ret < 0) {
3149 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3150 return;
3151 }
3152
3153 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3154 pid == tid ? 0 : 3, "", name);
3155
3156 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3157
3158 return;
3159}
3160
3161// print time in centiseconds
3162static void snprcent(char *buffer, size_t len, size_t spc,
3163 unsigned long long time) {
3164 static long hz; // cache discovered hz
3165
3166 if (hz <= 0) {
3167 hz = sysconf(_SC_CLK_TCK);
3168 if (hz <= 0) {
3169 hz = 1000;
3170 }
3171 }
3172
3173 // convert to centiseconds
3174 time = (time * 100 + (hz / 2)) / hz;
3175
3176 char str[16];
3177
3178 snprintf(str, sizeof(str), " %llu.%02u",
3179 time / 100, (unsigned)(time % 100));
3180 size_t offset = strlen(buffer);
3181 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3182 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3183}
3184
3185// print permille as a percent
3186static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3187 char str[16];
3188
3189 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3190 size_t offset = strlen(buffer);
3191 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3192 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3193}
3194
3195void show_showtime(int pid, const char *name) {
3196 if (PropertiesHelper::IsDryRun()) return;
3197
3198 char path[255];
3199 char buffer[1023];
3200 int fd, ret, save_errno;
3201
3202 memset(buffer, 0, sizeof(buffer));
3203
3204 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3205 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3206 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3207 return;
3208 }
3209
3210 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3211 save_errno = errno;
3212 close(fd);
3213
3214 if (ret < 0) {
3215 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3216 return;
3217 }
3218
3219 // field 14 is utime
3220 // field 15 is stime
3221 // field 42 is iotime
3222 unsigned long long utime = 0, stime = 0, iotime = 0;
3223 if (sscanf(buffer,
3224 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3225 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3226 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3227 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3228 &utime, &stime, &iotime) != 3) {
3229 return;
3230 }
3231
3232 unsigned long long total = utime + stime;
3233 if (!total) {
3234 return;
3235 }
3236
3237 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3238 if (permille > 1000) {
3239 permille = 1000;
3240 }
3241
3242 // try to beautify and stabilize columns at <80 characters
3243 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3244 if ((name[0] != '[') || utime) {
3245 snprcent(buffer, sizeof(buffer), 57, utime);
3246 }
3247 snprcent(buffer, sizeof(buffer), 65, stime);
3248 if ((name[0] != '[') || iotime) {
3249 snprcent(buffer, sizeof(buffer), 73, iotime);
3250 }
3251 if (iotime) {
3252 snprdec(buffer, sizeof(buffer), 79, permille);
3253 }
3254 puts(buffer); // adds a trailing newline
3255
3256 return;
3257}
3258
3259void do_dmesg() {
3260 const char *title = "KERNEL LOG (dmesg)";
3261 DurationReporter duration_reporter(title);
3262 printf("------ %s ------\n", title);
3263
3264 if (PropertiesHelper::IsDryRun()) return;
3265
3266 /* Get size of kernel buffer */
3267 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3268 if (size <= 0) {
3269 printf("Unexpected klogctl return value: %d\n\n", size);
3270 return;
3271 }
3272 char *buf = (char *) malloc(size + 1);
3273 if (buf == nullptr) {
3274 printf("memory allocation failed\n\n");
3275 return;
3276 }
3277 int retval = klogctl(KLOG_READ_ALL, buf, size);
3278 if (retval < 0) {
3279 printf("klogctl failure\n\n");
3280 free(buf);
3281 return;
3282 }
3283 buf[retval] = '\0';
3284 printf("%s\n\n", buf);
3285 free(buf);
3286 return;
3287}
3288
3289void do_showmap(int pid, const char *name) {
3290 char title[255];
3291 char arg[255];
3292
3293 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3294 snprintf(arg, sizeof(arg), "%d", pid);
3295 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3296}
3297
3298int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3299 DurationReporter duration_reporter(title);
3300
3301 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3302
3303 UpdateProgress(WEIGHT_FILE);
3304
3305 return status;
3306}
3307
3308int read_file_as_long(const char *path, long int *output) {
3309 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3310 if (fd < 0) {
3311 int err = errno;
3312 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3313 return -1;
3314 }
3315 char buffer[50];
3316 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3317 if (bytes_read == -1) {
3318 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3319 return -2;
3320 }
3321 if (bytes_read == 0) {
3322 MYLOGE("File %s is empty\n", path);
3323 return -3;
3324 }
3325 *output = atoi(buffer);
3326 return 0;
3327}
3328
3329/* calls skip to gate calling dump_from_fd recursively
3330 * in the specified directory. dump_from_fd defaults to
3331 * dump_file_from_fd above when set to NULL. skip defaults
3332 * to false when set to NULL. dump_from_fd will always be
3333 * called with title NULL.
3334 */
3335int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3336 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3337 DurationReporter duration_reporter(title);
3338 DIR *dirp;
3339 struct dirent *d;
3340 char *newpath = nullptr;
3341 const char *slash = "/";
3342 int retval = 0;
3343
3344 if (!title.empty()) {
3345 printf("------ %s (%s) ------\n", title.c_str(), dir);
3346 }
3347 if (PropertiesHelper::IsDryRun()) return 0;
3348
3349 if (dir[strlen(dir) - 1] == '/') {
3350 ++slash;
3351 }
3352 dirp = opendir(dir);
3353 if (dirp == nullptr) {
3354 retval = -errno;
3355 MYLOGE("%s: %s\n", dir, strerror(errno));
3356 return retval;
3357 }
3358
3359 if (!dump_from_fd) {
3360 dump_from_fd = dump_file_from_fd;
3361 }
3362 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3363 if ((d->d_name[0] == '.')
3364 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3365 || (d->d_name[1] == '\0'))) {
3366 continue;
3367 }
3368 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3369 (d->d_type == DT_DIR) ? "/" : "");
3370 if (!newpath) {
3371 retval = -errno;
3372 continue;
3373 }
3374 if (skip && (*skip)(newpath)) {
3375 continue;
3376 }
3377 if (d->d_type == DT_DIR) {
3378 int ret = dump_files("", newpath, skip, dump_from_fd);
3379 if (ret < 0) {
3380 retval = ret;
3381 }
3382 continue;
3383 }
3384 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3385 if (fd.get() < 0) {
3386 retval = -1;
3387 printf("*** %s: %s\n", newpath, strerror(errno));
3388 continue;
3389 }
3390 (*dump_from_fd)(nullptr, newpath, fd.get());
3391 }
3392 closedir(dirp);
3393 if (!title.empty()) {
3394 printf("\n");
3395 }
3396 return retval;
3397}
3398
3399/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3400 * it's possible to avoid issues where opening the file itself can get
3401 * stuck.
3402 */
3403int dump_file_from_fd(const char *title, const char *path, int fd) {
3404 if (PropertiesHelper::IsDryRun()) return 0;
3405
3406 int flags = fcntl(fd, F_GETFL);
3407 if (flags == -1) {
3408 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3409 return -1;
3410 } else if (!(flags & O_NONBLOCK)) {
3411 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3412 return -1;
3413 }
3414 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3415}
3416
3417int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3418 const CommandOptions& options) {
3419 DurationReporter duration_reporter(title);
3420
3421 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3422
3423 /* TODO: for now we're simplifying the progress calculation by using the
3424 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3425 * where its weight should be much higher proportionally to its timeout.
3426 * Ideally, it should use a options.EstimatedDuration() instead...*/
3427 UpdateProgress(options.Timeout());
3428
3429 return status;
3430}
3431
3432void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3433 const CommandOptions& options, long dumpsysTimeoutMs) {
3434 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3435 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3436 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3437 RunCommand(title, dumpsys, options);
3438}
3439
3440int open_socket(const char *service) {
3441 int s = android_get_control_socket(service);
3442 if (s < 0) {
3443 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3444 return -1;
3445 }
3446 fcntl(s, F_SETFD, FD_CLOEXEC);
3447
3448 // Set backlog to 0 to make sure that queue size will be minimum.
3449 // In Linux, because the minimum queue will be 1, connect() will be blocked
3450 // if the other clients already called connect() and the connection request was not accepted.
3451 if (listen(s, 0) < 0) {
3452 MYLOGE("listen(control socket): %s\n", strerror(errno));
3453 return -1;
3454 }
3455
3456 struct sockaddr addr;
3457 socklen_t alen = sizeof(addr);
3458 int fd = accept(s, &addr, &alen);
3459
3460 // Close socket just after accept(), to make sure that connect() by client will get error
3461 // when the socket is used by the other services.
3462 // There is still a race condition possibility between accept and close, but there is no way
3463 // to close-on-accept atomically.
3464 // See detail; b/123306389#comment25
3465 close(s);
3466
3467 if (fd < 0) {
3468 MYLOGE("accept(control socket): %s\n", strerror(errno));
3469 return -1;
3470 }
3471
3472 return fd;
3473}
3474
3475/* redirect output to a service control socket */
3476bool redirect_to_socket(FILE* redirect, const char* service) {
3477 int fd = open_socket(service);
3478 if (fd == -1) {
3479 return false;
3480 }
3481 fflush(redirect);
3482 // TODO: handle dup2 failure
3483 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3484 close(fd);
3485 return true;
3486}
3487
3488// TODO: should call is_valid_output_file and/or be merged into it.
3489void create_parent_dirs(const char *path) {
3490 char *chp = const_cast<char *> (path);
3491
3492 /* skip initial slash */
3493 if (chp[0] == '/')
3494 chp++;
3495
3496 /* create leading directories, if necessary */
3497 struct stat dir_stat;
3498 while (chp && chp[0]) {
3499 chp = strchr(chp, '/');
3500 if (chp) {
3501 *chp = 0;
3502 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3503 MYLOGI("Creating directory %s\n", path);
3504 if (mkdir(path, 0770)) { /* drwxrwx--- */
3505 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3506 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3507 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3508 }
3509 }
3510 *chp++ = '/';
3511 }
3512 }
3513}
3514
3515bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3516 create_parent_dirs(path);
3517
3518 int fd = TEMP_FAILURE_RETRY(open(path,
3519 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3520 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3521 if (fd < 0) {
3522 MYLOGE("%s: %s\n", path, strerror(errno));
3523 return false;
3524 }
3525
3526 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3527 close(fd);
3528 return true;
3529}
3530
3531bool redirect_to_file(FILE* redirect, char* path) {
3532 return _redirect_to_file(redirect, path, O_TRUNC);
3533}
3534
3535bool redirect_to_existing_file(FILE* redirect, char* path) {
3536 return _redirect_to_file(redirect, path, O_APPEND);
3537}
3538
3539void dump_route_tables() {
3540 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3541 if (PropertiesHelper::IsDryRun()) return;
3542 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3543 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3544 FILE* fp = fopen(RT_TABLES_PATH, "re");
3545 if (!fp) {
3546 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3547 return;
3548 }
3549 char table[16];
3550 // Each line has an integer (the table number), a space, and a string (the table name). We only
3551 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3552 // Add a fixed max limit so this doesn't go awry.
3553 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3554 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3555 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3556 }
3557 fclose(fp);
3558}
3559
3560// TODO: make this function thread safe if sections are generated in parallel.
3561void Dumpstate::UpdateProgress(int32_t delta_sec) {
3562 if (progress_ == nullptr) {
3563 MYLOGE("UpdateProgress: progress_ not set\n");
3564 return;
3565 }
3566
3567 // Always update progess so stats can be tuned...
3568 bool max_changed = progress_->Inc(delta_sec);
3569
3570 // ...but only notifiy listeners when necessary.
3571 if (!options_->do_progress_updates) return;
3572
3573 int progress = progress_->Get();
3574 int max = progress_->GetMax();
3575
3576 // adjusts max on the fly
3577 if (max_changed && listener_ != nullptr) {
3578 listener_->onMaxProgressUpdated(max);
3579 }
3580
3581 int32_t last_update_delta = progress - last_updated_progress_;
3582 if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
3583 return;
3584 }
3585 last_updated_progress_ = progress;
3586
3587 if (control_socket_fd_ >= 0) {
3588 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3589 fsync(control_socket_fd_);
3590 }
3591
3592 int percent = 100 * progress / max;
3593 if (listener_ != nullptr) {
3594 if (percent % 5 == 0) {
3595 // We don't want to spam logcat, so only log multiples of 5.
3596 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3597 percent);
3598 } else {
3599 // stderr is ignored on normal invocations, but useful when calling
3600 // /system/bin/dumpstate directly for debuggging.
3601 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3602 progress, max, percent);
3603 }
3604 // TODO(b/111441001): Remove in favor of onProgress
3605 listener_->onProgressUpdated(progress);
3606
3607 listener_->onProgress(percent);
3608 }
3609}
3610
3611void Dumpstate::TakeScreenshot(const std::string& path) {
3612 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3613 int status =
3614 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3615 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3616 if (status == 0) {
3617 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3618 } else {
3619 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3620 }
3621}
3622
3623bool is_dir(const char* pathname) {
3624 struct stat info;
3625 if (stat(pathname, &info) == -1) {
3626 return false;
3627 }
3628 return S_ISDIR(info.st_mode);
3629}
3630
3631time_t get_mtime(int fd, time_t default_mtime) {
3632 struct stat info;
3633 if (fstat(fd, &info) == -1) {
3634 return default_mtime;
3635 }
3636 return info.st_mtime;
3637}
3638
3639void dump_emmc_ecsd(const char *ext_csd_path) {
3640 // List of interesting offsets
3641 struct hex {
3642 char str[2];
3643 };
3644 static const size_t EXT_CSD_REV = 192 * sizeof(hex);
3645 static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
3646 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
3647 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
3648
3649 std::string buffer;
3650 if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
3651 return;
3652 }
3653
3654 printf("------ %s Extended CSD ------\n", ext_csd_path);
3655
3656 if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
3657 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3658 return;
3659 }
3660
3661 int ext_csd_rev = 0;
3662 std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
3663 if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
3664 printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3665 return;
3666 }
3667
3668 static const char *ver_str[] = {
3669 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
3670 };
3671 printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
3672 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
3673 : "Unknown");
3674 if (ext_csd_rev < 7) {
3675 printf("\n");
3676 return;
3677 }
3678
3679 if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
3680 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3681 return;
3682 }
3683
3684 int ext_pre_eol_info = 0;
3685 sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
3686 if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
3687 printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3688 return;
3689 }
3690
3691 static const char *eol_str[] = {
3692 "Undefined",
3693 "Normal",
3694 "Warning (consumed 80% of reserve)",
3695 "Urgent (consumed 90% of reserve)"
3696 };
3697 printf(
3698 "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
3699 eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
3700 : 0]);
3701
3702 for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
3703 lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
3704 lifetime += sizeof(hex)) {
3705 int ext_device_life_time_est;
3706 static const char *est_str[] = {
3707 "Undefined",
3708 "0-10% of device lifetime used",
3709 "10-20% of device lifetime used",
3710 "20-30% of device lifetime used",
3711 "30-40% of device lifetime used",
3712 "40-50% of device lifetime used",
3713 "50-60% of device lifetime used",
3714 "60-70% of device lifetime used",
3715 "70-80% of device lifetime used",
3716 "80-90% of device lifetime used",
3717 "90-100% of device lifetime used",
3718 "Exceeded the maximum estimated device lifetime",
3719 };
3720
3721 if (buffer.length() < (lifetime + sizeof(hex))) {
3722 printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
3723 break;
3724 }
3725
3726 ext_device_life_time_est = 0;
3727 sub = buffer.substr(lifetime, sizeof(hex));
3728 if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
3729 printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
3730 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3731 sub.c_str());
3732 continue;
3733 }
3734 printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
3735 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3736 ext_device_life_time_est,
3737 est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
3738 ? ext_device_life_time_est
3739 : 0]);
3740 }
3741
3742 printf("\n");
3743}
3744