blob: 141662904ec7dda2d6e948490e7434267e195077 [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>
Sahana Raof35ed432019-07-12 10:47:52 +010074#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080075#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010076#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070077#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070078#include <private/android_filesystem_config.h>
79#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080080#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070081#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080082#include "DumpstateInternal.h"
Vishnu Naire97d6122018-01-18 13:58:56 -080083#include "DumpstateSectionReporter.h"
Felipe Leme75876a22016-10-27 16:31:27 -070084#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070085#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080086
Steven Morelandcb7ef822016-11-29 13:20:37 -080087using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080088using ::std::literals::chrono_literals::operator""ms;
89using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080090
Felipe Leme47e9be22016-12-21 15:37:07 -080091// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080092using android::defaultServiceManager;
93using android::Dumpsys;
94using android::INVALID_OPERATION;
95using android::IServiceManager;
96using android::OK;
97using android::sp;
98using android::status_t;
99using android::String16;
100using android::String8;
101using android::TIMED_OUT;
102using android::UNKNOWN_ERROR;
103using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000104using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000105using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800106using android::os::dumpstate::CommandOptions;
107using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800108using android::os::dumpstate::DumpstateSectionReporter;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
121 const CommandOptions& options = CommandOptions::DEFAULT) {
122 return ds.RunCommand(title, full_command, options);
123}
124
125// Reasonable value for max stats.
126static const int STATS_MAX_N_RUNS = 1000;
127static const long STATS_MAX_AVERAGE = 100000;
128
129CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
130
Nandana Duttd2f5f082019-01-18 17:13:52 +0000131typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
132
Colin Crossf45fa6b2012-03-26 12:38:26 -0700133/* read before root is shed */
134static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700135static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000136static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700137
Felipe Leme1d486fe2016-10-14 18:06:47 -0700138// TODO: variables and functions below should be part of dumpstate object
139
Felipe Leme635ca312016-01-05 14:23:02 -0800140static std::set<std::string> mount_points;
141void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800142
Todd Poynor2a83daa2013-11-22 15:44:22 -0800143#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700144#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700145#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800146
Felipe Lemee82a27d2016-01-05 13:35:44 -0800147#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700148#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700149#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700150#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100151#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
152#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800153#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900154#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800155#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700156
Narayan Kamath8f788292017-05-25 13:20:39 +0100157// TODO(narayan): Since this information has to be kept in sync
158// with tombstoned, we should just put it in a common header.
159//
160// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100161static const std::string TOMBSTONE_DIR = "/data/tombstones/";
162static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
163static const std::string ANR_DIR = "/data/anr/";
164static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700165
Felipe Lemee844a9d2016-09-21 15:01:39 -0700166// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000167
Nandana Dutt5c390032019-03-12 10:52:56 +0000168#define RETURN_IF_USER_DENIED_CONSENT() \
169 if (ds.IsUserConsentDenied()) { \
170 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
171 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
172 }
173
174// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
175// if consent is found to be denied.
176#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
177 RETURN_IF_USER_DENIED_CONSENT(); \
178 func_ptr(__VA_ARGS__); \
179 RETURN_IF_USER_DENIED_CONSENT();
180
Sahana Raof35ed432019-07-12 10:47:52 +0100181static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
182
Nandana Dutt979388e2018-11-30 16:48:55 +0000183namespace android {
184namespace os {
185namespace {
186
187static int Open(std::string path, int flags, mode_t mode = 0) {
188 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
189 if (fd == -1) {
190 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
191 }
192 return fd;
193}
194
Nandana Dutt979388e2018-11-30 16:48:55 +0000195
196static int OpenForRead(std::string path) {
197 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
198}
199
200bool CopyFile(int in_fd, int out_fd) {
201 char buf[4096];
202 ssize_t byte_count;
203 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
204 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
205 return false;
206 }
207 }
208 return (byte_count != -1);
209}
210
211static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000212 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000213
214 // Obtain a handle to the source file.
215 android::base::unique_fd in_fd(OpenForRead(input_file));
216 if (out_fd != -1 && in_fd.get() != -1) {
217 if (CopyFile(in_fd.get(), out_fd)) {
218 return true;
219 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000220 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000221 }
222 return false;
223}
224
Nandana Duttd2f5f082019-01-18 17:13:52 +0000225static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000226 if (unlink(file.c_str())) {
227 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000228 return false;
229 }
230 return true;
231}
Nandana Dutt979388e2018-11-30 16:48:55 +0000232
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000233static bool IsFileEmpty(const std::string& file_path) {
234 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
235 if(file.bad()) {
236 MYLOGE("Cannot open file: %s\n", file_path.c_str());
237 return true;
238 }
239 return file.tellg() <= 0;
240}
241
Nikita Ioffea325a572019-05-16 19:49:47 +0100242int64_t GetModuleMetadataVersion() {
243 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
244 if (binder == nullptr) {
245 MYLOGE("Failed to retrieve package_native service");
246 return 0L;
247 }
248 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
249 std::string package_name;
250 auto status = package_service->getModuleMetadataPackageName(&package_name);
251 if (!status.isOk()) {
252 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
253 return 0L;
254 }
255 MYLOGD("Module metadata package name: %s", package_name.c_str());
256 int64_t version_code;
257 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
258 &version_code);
259 if (!status.isOk()) {
260 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
261 return 0L;
262 }
263 return version_code;
264}
265
Nandana Dutt979388e2018-11-30 16:48:55 +0000266} // namespace
267} // namespace os
268} // namespace android
269
Felipe Leme678727a2016-09-21 17:22:11 -0700270static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800271 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800272 long dumpsysTimeoutMs = 0) {
273 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700274}
275static int DumpFile(const std::string& title, const std::string& path) {
276 return ds.DumpFile(title, path);
277}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800278
Felipe Lemee844a9d2016-09-21 15:01:39 -0700279// Relative directory (inside the zip) for all files copied as-is into the bugreport.
280static const std::string ZIP_ROOT_DIR = "FS";
281
Vishnu Naire97d6122018-01-18 13:58:56 -0800282static const std::string kProtoPath = "proto/";
283static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700284static const std::string kDumpstateBoardFiles[] = {
285 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700286 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700287};
288static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
289
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700290static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700291static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700292static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700293static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
294static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700295
Felipe Lemef0292972016-11-22 13:57:05 -0800296static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
297
Narayan Kamath8f788292017-05-25 13:20:39 +0100298/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100299 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
300 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
301 * is set, the vector only contains files that were written in the last 30 minutes.
Andreas Gamped0d76952017-08-22 13:08:37 -0700302 * If |limit_by_count| is set, the vector only contains the ten latest files.
Narayan Kamath8f788292017-05-25 13:20:39 +0100303 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700304static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
305 const std::string& file_prefix,
306 bool limit_by_mtime,
307 bool limit_by_count = true) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100308 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
309
Narayan Kamathbd863722017-06-01 18:50:12 +0100310 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100311
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700312 if (dump_dir == nullptr) {
313 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700314 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700315 }
316
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700317 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100318 struct dirent* entry = nullptr;
319 while ((entry = readdir(dump_dir.get()))) {
320 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100321 continue;
322 }
323
Narayan Kamathbd863722017-06-01 18:50:12 +0100324 const std::string base_name(entry->d_name);
325 if (base_name.find(file_prefix) != 0) {
326 continue;
327 }
328
329 const std::string abs_path = dir_path + base_name;
330 android::base::unique_fd fd(
331 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
332 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700333 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100334 break;
335 }
336
337 struct stat st = {};
338 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700339 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100340 continue;
341 }
342
Narayan Kamath3f31b632018-02-22 19:42:36 +0000343 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100344 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100345 continue;
346 }
347
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700348 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700349 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100350
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700351 // Sort in descending modification time so that we only keep the newest
352 // reports if |limit_by_count| is true.
353 std::sort(dump_data.begin(), dump_data.end(),
354 [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
Narayan Kamath8f788292017-05-25 13:20:39 +0100355
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700356 if (limit_by_count && dump_data.size() > 10) {
357 dump_data.erase(dump_data.begin() + 10, dump_data.end());
Andreas Gamped0d76952017-08-22 13:08:37 -0700358 }
359
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700360 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100361}
362
Narayan Kamathbd863722017-06-01 18:50:12 +0100363static bool AddDumps(const std::vector<DumpData>::const_iterator start,
364 const std::vector<DumpData>::const_iterator end,
365 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100366 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100367 for (auto it = start; it != end; ++it) {
368 const std::string& name = it->name;
369 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100370 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100371
372 // Seek to the beginning of the file before dumping any data. A given
373 // DumpData entry might be dumped multiple times in the report.
374 //
375 // For example, the most recent ANR entry is dumped to the body of the
376 // main entry and it also shows up as a separate entry in the bugreport
377 // ZIP file.
378 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
379 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
380 strerror(errno));
381 }
382
Narayan Kamath8f788292017-05-25 13:20:39 +0100383 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800384 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100385 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100386 }
387 } else {
388 dump_file_from_fd(type_name, name.c_str(), fd);
389 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100390 }
391
392 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700393}
394
Felipe Leme635ca312016-01-05 14:23:02 -0800395// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700396void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800397 char path[PATH_MAX];
398
399 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
400 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700401 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800402 char linkname[PATH_MAX];
403 ssize_t r = readlink(path, linkname, PATH_MAX);
404 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800405 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800406 return;
407 }
408 linkname[r] = '\0';
409
410 if (mount_points.find(linkname) == mount_points.end()) {
411 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700412 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700413 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800414 mount_points.insert(linkname);
415 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800416 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800417 }
418 }
419}
420
421void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700422 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700423 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800424 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800425 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700426 for_each_pid(do_mountinfo, nullptr);
427 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800428}
429
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700430static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
431{
432 DIR *d;
433 struct dirent *de;
434 char path[PATH_MAX];
435
436 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700437 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700438 return;
439 }
440
441 while ((de = readdir(d))) {
442 if (de->d_type != DT_LNK) {
443 continue;
444 }
445 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700446 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700447 }
448
449 closedir(d);
450}
451
Mark Salyzyn326842f2015-04-30 09:49:41 -0700452static bool skip_not_stat(const char *path) {
453 static const char stat[] = "/stat";
454 size_t len = strlen(path);
455 if (path[len - 1] == '/') { /* Directory? */
456 return false;
457 }
458 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
459}
460
Felipe Leme4c2d6632016-09-28 14:32:00 -0700461static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800462 return false;
463}
464
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700465unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700466
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800467//
468// stat offsets
469// Name units description
470// ---- ----- -----------
471// read I/Os requests number of read I/Os processed
472#define __STAT_READ_IOS 0
473// read merges requests number of read I/Os merged with in-queue I/O
474#define __STAT_READ_MERGES 1
475// read sectors sectors number of sectors read
476#define __STAT_READ_SECTORS 2
477// read ticks milliseconds total wait time for read requests
478#define __STAT_READ_TICKS 3
479// write I/Os requests number of write I/Os processed
480#define __STAT_WRITE_IOS 4
481// write merges requests number of write I/Os merged with in-queue I/O
482#define __STAT_WRITE_MERGES 5
483// write sectors sectors number of sectors written
484#define __STAT_WRITE_SECTORS 6
485// write ticks milliseconds total wait time for write requests
486#define __STAT_WRITE_TICKS 7
487// in_flight requests number of I/Os currently in flight
488#define __STAT_IN_FLIGHT 8
489// io_ticks milliseconds total time this block device has been active
490#define __STAT_IO_TICKS 9
491// time_in_queue milliseconds total wait time for all requests
492#define __STAT_IN_QUEUE 10
493#define __STAT_NUMBER_FIELD 11
494//
495// read I/Os, write I/Os
496// =====================
497//
498// These values increment when an I/O request completes.
499//
500// read merges, write merges
501// =========================
502//
503// These values increment when an I/O request is merged with an
504// already-queued I/O request.
505//
506// read sectors, write sectors
507// ===========================
508//
509// These values count the number of sectors read from or written to this
510// block device. The "sectors" in question are the standard UNIX 512-byte
511// sectors, not any device- or filesystem-specific block size. The
512// counters are incremented when the I/O completes.
513#define SECTOR_SIZE 512
514//
515// read ticks, write ticks
516// =======================
517//
518// These values count the number of milliseconds that I/O requests have
519// waited on this block device. If there are multiple I/O requests waiting,
520// these values will increase at a rate greater than 1000/second; for
521// example, if 60 read requests wait for an average of 30 ms, the read_ticks
522// field will increase by 60*30 = 1800.
523//
524// in_flight
525// =========
526//
527// This value counts the number of I/O requests that have been issued to
528// the device driver but have not yet completed. It does not include I/O
529// requests that are in the queue but not yet issued to the device driver.
530//
531// io_ticks
532// ========
533//
534// This value counts the number of milliseconds during which the device has
535// had I/O requests queued.
536//
537// time_in_queue
538// =============
539//
540// This value counts the number of milliseconds that I/O requests have waited
541// on this block device. If there are multiple I/O requests waiting, this
542// value will increase as the product of the number of milliseconds times the
543// number of requests waiting (see "read ticks" above for an example).
544#define S_TO_MS 1000
545//
546
Mark Salyzyn326842f2015-04-30 09:49:41 -0700547static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800548 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700549 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700550 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700551 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700552 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700553 getline(&buffer, &i, fp);
554 fclose(fp);
555 if (!buffer) {
556 return -errno;
557 }
558 i = strlen(buffer);
559 while ((i > 0) && (buffer[i - 1] == '\n')) {
560 buffer[--i] = '\0';
561 }
562 if (!*buffer) {
563 free(buffer);
564 return 0;
565 }
566 z = true;
567 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800568 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700569 if (fields[i] != 0) {
570 z = false;
571 }
572 }
573 if (z) { /* never accessed */
574 free(buffer);
575 return 0;
576 }
577
Wei Wang509bb5d2017-06-09 14:42:12 -0700578 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
579 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700580 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700581
582 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
583 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
584 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700585 free(buffer);
586
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800587 if (fields[__STAT_IO_TICKS]) {
588 unsigned long read_perf = 0;
589 unsigned long read_ios = 0;
590 if (fields[__STAT_READ_TICKS]) {
591 unsigned long long divisor = fields[__STAT_READ_TICKS]
592 * fields[__STAT_IO_TICKS];
593 read_perf = ((unsigned long long)SECTOR_SIZE
594 * fields[__STAT_READ_SECTORS]
595 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
596 / divisor;
597 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
598 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
599 / divisor;
600 }
601
602 unsigned long write_perf = 0;
603 unsigned long write_ios = 0;
604 if (fields[__STAT_WRITE_TICKS]) {
605 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
606 * fields[__STAT_IO_TICKS];
607 write_perf = ((unsigned long long)SECTOR_SIZE
608 * fields[__STAT_WRITE_SECTORS]
609 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
610 / divisor;
611 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
612 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
613 / divisor;
614 }
615
616 unsigned queue = (fields[__STAT_IN_QUEUE]
617 + (fields[__STAT_IO_TICKS] >> 1))
618 / fields[__STAT_IO_TICKS];
619
620 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700621 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 -0800622 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700623 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 -0800624 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800625 }
626
627 /* bugreport timeout factor adjustment */
628 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
629 worst_write_perf = write_perf;
630 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700631 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700632 return 0;
633}
634
Yao Chenbe3bbc12018-01-17 16:31:10 -0800635static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
636
637/* timeout in ms to read a list of buffers */
638static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
639 unsigned long timeout_ms = 0;
640 for (const auto& buffer : buffers) {
641 log_id_t id = android_name_to_log_id(buffer.c_str());
642 unsigned long property_size = __android_logger_get_buffer_size(id);
643 /* Engineering margin is ten-fold our guess */
644 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
645 }
646 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700647}
648
Nandana Duttd2f5f082019-01-18 17:13:52 +0000649Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
650}
651
652android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
653 std::lock_guard<std::mutex> lock(lock_);
654 result_ = APPROVED;
655 MYLOGD("User approved consent to share bugreport\n");
656 return android::binder::Status::ok();
657}
658
659android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
660 std::lock_guard<std::mutex> lock(lock_);
661 result_ = DENIED;
662 MYLOGW("User denied consent to share bugreport\n");
663 return android::binder::Status::ok();
664}
665
666UserConsentResult Dumpstate::ConsentCallback::getResult() {
667 std::lock_guard<std::mutex> lock(lock_);
668 return result_;
669}
670
671uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
672 return Nanotime() - start_time_;
673}
674
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700675void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700676 std::string build, fingerprint, radio, bootloader, network;
677 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700678
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700679 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
680 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700681 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
682 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
683 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700684 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700685
Felipe Lemed8b94e52016-12-08 10:21:44 -0800686 printf("========================================================\n");
687 printf("== dumpstate: %s\n", date);
688 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700689
Felipe Lemed8b94e52016-12-08 10:21:44 -0800690 printf("\n");
691 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700692 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800693 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
694 printf("Bootloader: %s\n", bootloader.c_str());
695 printf("Radio: %s\n", radio.c_str());
696 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100697 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
698 if (module_metadata_version != 0) {
699 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
700 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700701
Felipe Lemed8b94e52016-12-08 10:21:44 -0800702 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800703 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800704 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800705 printf("Uptime: ");
706 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
707 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800708 printf("Bugreport format version: %s\n", version_.c_str());
709 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 +0100710 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800711 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800712}
713
Felipe Leme24b66ee2016-06-16 10:55:26 -0700714// List of file extensions that can cause a zip file attachment to be rejected by some email
715// service providers.
716static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
717 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
718 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
719 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
720};
721
Vishnu Naire97d6122018-01-18 13:58:56 -0800722status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
723 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700724 if (!IsZipping()) {
725 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
726 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800727 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800728 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700729 std::string valid_name = entry_name;
730
731 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700732 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700733 if (idx != std::string::npos) {
734 std::string extension = entry_name.substr(idx);
735 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
736 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
737 valid_name = entry_name + ".renamed";
738 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
739 }
740 }
741
Felipe Leme6fe9db62016-02-12 09:04:16 -0800742 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
743 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700744 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
745 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700746 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700747 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700748 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800749 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800750 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000751 bool finished_entry = false;
752 auto finish_entry = [this, &finished_entry] {
753 if (!finished_entry) {
754 // This should only be called when we're going to return an earlier error,
755 // which would've been logged. This may imply the file is already corrupt
756 // and any further logging from FinishEntry is more likely to mislead than
757 // not.
758 this->zip_writer_->FinishEntry();
759 }
760 };
761 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800762 auto start = std::chrono::steady_clock::now();
763 auto end = start + timeout;
764 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800765
Felipe Leme770410d2016-01-26 17:07:14 -0800766 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800767 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800768 if (timeout.count() > 0) {
769 // lambda to recalculate the timeout.
770 auto time_left_ms = [end]() {
771 auto now = std::chrono::steady_clock::now();
772 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
773 return std::max(diff.count(), 0LL);
774 };
775
776 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
777 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000778 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
779 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800780 return -errno;
781 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000782 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800783 entry_name.c_str(), strerror(errno), timeout.count());
784 return TIMED_OUT;
785 }
786 }
787
Zach Riggle22200402016-08-18 01:01:24 -0400788 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800789 if (bytes_read == 0) {
790 break;
791 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800792 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800793 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800794 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700795 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800796 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700797 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800798 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800799 }
800 }
801
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700802 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000803 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700804 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700805 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800806 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800807 }
808
Vishnu Naire97d6122018-01-18 13:58:56 -0800809 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800810}
811
Felipe Leme1d486fe2016-10-14 18:06:47 -0700812bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
813 android::base::unique_fd fd(
814 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700815 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800816 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800817 return false;
818 }
819
Vishnu Naire97d6122018-01-18 13:58:56 -0800820 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800821}
822
823/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700824static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800825 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800826}
827
Felipe Leme1d486fe2016-10-14 18:06:47 -0700828void Dumpstate::AddDir(const std::string& dir, bool recursive) {
829 if (!IsZipping()) {
830 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800831 return;
832 }
Felipe Leme678727a2016-09-21 17:22:11 -0700833 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800834 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700835 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800836}
837
Felipe Leme1d486fe2016-10-14 18:06:47 -0700838bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
839 if (!IsZipping()) {
840 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
841 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800842 return false;
843 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800844 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700845 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700846 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700847 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700848 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800849 return false;
850 }
851
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700852 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700853 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700854 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700855 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800856 return false;
857 }
858
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700859 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700860 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700861 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800862 return false;
863 }
864
865 return true;
866}
867
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800868static void DoKmsg() {
869 struct stat st;
870 if (!stat(PSTORE_LAST_KMSG, &st)) {
871 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
872 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
873 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
874 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
875 } else {
876 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
877 DumpFile("LAST KMSG", "/proc/last_kmsg");
878 }
879}
880
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800881static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800882 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800883 RunCommand(
884 "KERNEL LOG",
885 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
886 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
887}
888
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800889static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800890 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800891 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
892 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800893 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100894 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800895 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
896 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800897 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800898 RunCommand(
899 "EVENT LOG",
900 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
901 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800902 timeout_ms = logcat_timeout({"stats"});
903 RunCommand(
904 "STATS LOG",
905 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
906 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
907 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800908 RunCommand(
909 "RADIO LOG",
910 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
911 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800912
913 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
914
915 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800916 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
917 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800918}
919
Jayachandran Ca94c7172017-06-10 15:08:12 -0700920static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700921 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
922 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900923 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700924 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900925 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
926 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
927 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
928 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700929}
930
Narayan Kamath8f788292017-05-25 13:20:39 +0100931static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
932 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
933 anr_traces_dir.c_str());
934
935 // If we're here, dump_traces_path will always be a temporary file
936 // (created with mkostemp or similar) that contains dumps taken earlier
937 // on in the process.
938 if (dump_traces_path != nullptr) {
939 if (add_to_zip) {
940 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
941 } else {
942 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
943 dump_traces_path);
944 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
945 }
946
947 const int ret = unlink(dump_traces_path);
948 if (ret == -1) {
949 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
950 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700951 }
952 }
953
Narayan Kamathbd863722017-06-01 18:50:12 +0100954 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700955 if (ds.anr_data_.size() > 0) {
956 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100957 "VM TRACES AT LAST ANR", add_to_zip);
958
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100959 // The "last" ANR will always be included as separate entry in the zip file. In addition,
960 // it will be present in the body of the main entry if |add_to_zip| == false.
961 //
962 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700963 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100964 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100965 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100966 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
967 }
968}
969
970static void AddAnrTraceFiles() {
971 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
972
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700973 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100974
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700975 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100976
Makoto Onuki83ec63f2019-01-31 17:08:59 -0800977 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
978
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700979 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -0700980 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700981 int i = 0;
982 while (true) {
983 const std::string slow_trace_path =
984 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
985 if (stat(slow_trace_path.c_str(), &st)) {
986 // No traces file at this index, done with the files.
987 break;
Felipe Lemee184f662016-10-27 10:04:47 -0700988 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700989 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
990 i++;
Felipe Lemee184f662016-10-27 10:04:47 -0700991 }
992}
993
Wei Wang509bb5d2017-06-09 14:42:12 -0700994static void DumpBlockStatFiles() {
995 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -0700996
Wei Wang1dc1ef52017-06-12 11:28:37 -0700997 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
998
999 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001000 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1001 return;
1002 }
1003
1004 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001005 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001006 if ((d->d_name[0] == '.')
1007 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1008 || (d->d_name[1] == '\0'))) {
1009 continue;
1010 }
1011 const std::string new_path =
1012 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1013 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1014 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1015 printf("\n");
1016 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001017 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001018}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001019
1020static void DumpPacketStats() {
1021 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1022 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1023 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1024 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1025 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1026}
1027
1028static void DumpIpAddrAndRules() {
1029 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1030 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1031 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1032 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1033 RunCommand("IP RULES", {"ip", "rule", "show"});
1034 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1035}
1036
Nandana Dutt5c390032019-03-12 10:52:56 +00001037static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1038 std::chrono::milliseconds timeout,
1039 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001040 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001041 sp<android::IServiceManager> sm = defaultServiceManager();
1042 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001043 Vector<String16> args;
1044 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001045 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1046 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001047 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001048 std::string path(title);
1049 path.append(" - ").append(String8(service).c_str());
1050 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1051 size_t bytes_written = 0;
1052 status_t status = dumpsys.startDumpThread(service, args);
1053 if (status == OK) {
1054 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1055 std::chrono::duration<double> elapsed_seconds;
1056 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1057 /* as_proto = */ false, elapsed_seconds, bytes_written);
1058 section_reporter.setSize(bytes_written);
1059 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1060 bool dump_complete = (status == OK);
1061 dumpsys.stopDumpThread(dump_complete);
1062 }
1063 section_reporter.setStatus(status);
1064
1065 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1066 std::chrono::steady_clock::now() - start);
1067 if (elapsed_duration > timeout) {
1068 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1069 elapsed_duration.count());
1070 break;
1071 }
1072 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001073 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001074}
1075
Vishnu Nair64afc022018-02-01 15:29:34 -08001076static void RunDumpsysText(const std::string& title, int priority,
1077 std::chrono::milliseconds timeout,
1078 std::chrono::milliseconds service_timeout) {
1079 DurationReporter duration_reporter(title);
1080 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1081 fsync(STDOUT_FILENO);
1082 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1083}
1084
1085/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001086static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1087 std::chrono::milliseconds timeout,
1088 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001089 DurationReporter duration_reporter(title);
1090 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1091 fsync(STDOUT_FILENO);
1092 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1093 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001094
1095 RETURN_IF_USER_DENIED_CONSENT();
1096
1097 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1098 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001099}
1100
Nandana Dutt5c390032019-03-12 10:52:56 +00001101static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1102 std::chrono::milliseconds timeout,
1103 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001104 if (!ds.IsZipping()) {
1105 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001106 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001107 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001108 sp<android::IServiceManager> sm = defaultServiceManager();
1109 Dumpsys dumpsys(sm.get());
1110 Vector<String16> args;
1111 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1112 DurationReporter duration_reporter(title);
1113
1114 auto start = std::chrono::steady_clock::now();
1115 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1116 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001117 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001118 std::string path(kProtoPath);
1119 path.append(String8(service).c_str());
1120 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1121 path.append("_CRITICAL");
1122 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1123 path.append("_HIGH");
1124 }
1125 path.append(kProtoExt);
1126 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1127 status_t status = dumpsys.startDumpThread(service, args);
1128 if (status == OK) {
1129 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1130 bool dumpTerminated = (status == OK);
1131 dumpsys.stopDumpThread(dumpTerminated);
1132 }
1133 ZipWriter::FileEntry file_entry;
1134 ds.zip_writer_->GetLastEntry(&file_entry);
1135 section_reporter.setSize(file_entry.compressed_size);
1136 section_reporter.setStatus(status);
1137
1138 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1139 std::chrono::steady_clock::now() - start);
1140 if (elapsed_duration > timeout) {
1141 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1142 elapsed_duration.count());
1143 break;
1144 }
1145 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001146 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001147}
1148
Nandana Dutta7db6342018-11-21 14:53:34 +00001149// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001150static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001151 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1152 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001153
1154 RETURN_IF_USER_DENIED_CONSENT();
1155
1156 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1157 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001158}
1159
1160// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001161static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001162 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1163 // high priority. Reduce timeout once they are able to dump in a shorter time or
1164 // moved to a parallel task.
1165 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1166 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001167
1168 RETURN_IF_USER_DENIED_CONSENT();
1169
1170 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1171 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001172}
1173
1174// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001175static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001176 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001177
1178 RETURN_IF_USER_DENIED_CONSENT();
1179
1180 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1181 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001182}
1183
Steven Moreland44cd9482018-01-04 16:24:13 -08001184static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001185 if (!ds.IsZipping()) {
1186 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1187 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1188 return;
1189 }
1190 DurationReporter duration_reporter("DUMP HALS");
1191 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001192 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001193
Steven Moreland44cd9482018-01-04 16:24:13 -08001194 using android::hidl::manager::V1_0::IServiceManager;
1195 using android::hardware::defaultServiceManager;
1196
1197 sp<IServiceManager> sm = defaultServiceManager();
1198 if (sm == nullptr) {
1199 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1200 return;
1201 }
1202
1203 auto ret = sm->list([&](const auto& interfaces) {
1204 for (const std::string& interface : interfaces) {
1205 std::string cleanName = interface;
1206 std::replace_if(cleanName.begin(),
1207 cleanName.end(),
1208 [](char c) {
1209 return !isalnum(c) &&
1210 std::string("@-_:.").find(c) == std::string::npos;
1211 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001212 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001213
1214 {
1215 auto fd = android::base::unique_fd(
1216 TEMP_FAILURE_RETRY(open(path.c_str(),
1217 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1218 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1219 if (fd < 0) {
1220 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1221 continue;
1222 }
1223 RunCommandToFd(fd,
1224 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001225 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001226 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1227
1228 bool empty = 0 == lseek(fd, 0, SEEK_END);
1229 if (!empty) {
1230 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1231 }
1232 }
1233
1234 unlink(path.c_str());
1235 }
1236 });
1237
1238 if (!ret.isOk()) {
1239 MYLOGE("Could not list hals from hwservicemanager.\n");
1240 }
1241}
1242
Nandana Dutt5c390032019-03-12 10:52:56 +00001243// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1244// via the consent they are shown. Ignores other errors that occur while running various
1245// commands. The consent checking is currently done around long running tasks, which happen to
1246// be distributed fairly evenly throughout the function.
1247static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001248 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001249
Nandana Dutt5c390032019-03-12 10:52:56 +00001250 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1251 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1252 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001253 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001254 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001255 DumpBlockStatFiles();
Mark Salyzyn8c8130e2015-12-09 11:21:28 -08001256 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001257 DumpFile("MEMORY INFO", "/proc/meminfo");
1258 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001259 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001260
1261 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1262
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001263 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1264 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1265 DumpFile("SLAB INFO", "/proc/slabinfo");
1266 DumpFile("ZONEINFO", "/proc/zoneinfo");
1267 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1268 DumpFile("BUDDYINFO", "/proc/buddyinfo");
1269 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001270
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001271 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1272 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
1273 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001274
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001275 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001276 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001277
1278 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1279 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001280
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001281 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001282
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001283 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001284 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001285 struct stat s;
1286 if (stat("/proc/modules", &s) != 0) {
1287 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1288 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001289 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001290 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001291
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001292 if (__android_logger_property_get_bool(
1293 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1294 DoKernelLogcat();
1295 } else {
1296 do_dmesg();
1297 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001298
Felipe Lemef0292972016-11-22 13:57:05 -08001299 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001300
1301 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1302
Jeff Brown1dc94e32014-09-11 14:15:27 -07001303 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001304 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001305
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001306 /* Dump Bluetooth HCI logs */
1307 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001308
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001309 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001310 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001311 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001312 }
1313
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001314 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001315
Felipe Lemee184f662016-10-27 10:04:47 -07001316 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001317
Narayan Kamath8f788292017-05-25 13:20:39 +01001318 // NOTE: tombstones are always added as separate entries in the zip archive
1319 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001320 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001321 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001322 if (!tombstones_dumped) {
1323 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001324 }
1325
Jayachandran Ca94c7172017-06-10 15:08:12 -07001326 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001327
Chenbo Feng276a3b62018-08-07 11:44:49 -07001328 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1329
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001330 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001331
Jayachandran Ca94c7172017-06-10 15:08:12 -07001332 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001333
1334 dump_route_tables();
1335
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001336 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1337 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1338 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001339
Nandana Dutt5c390032019-03-12 10:52:56 +00001340 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001341
Elliott Hughes23ccc622017-02-28 10:14:22 -08001342 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001343
Jin Qianf334d662017-10-10 14:41:37 -07001344 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001345
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001346 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001347
Colin Crossf45fa6b2012-03-26 12:38:26 -07001348 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001349 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1350 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1351 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1352 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1353 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001354
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001355 /* Add window and surface trace files. */
1356 if (!PropertiesHelper::IsUserBuild()) {
1357 ds.AddDir(WMTRACE_DATA_DIR, false);
1358 }
1359
Nandana Dutt5c390032019-03-12 10:52:56 +00001360 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001361
Steven Moreland7440ddb2016-12-15 16:13:39 -08001362 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001363 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1364 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001365 // su does not exist on user builds, so try running without it.
1366 // This way any implementations of vril-dump that do not require
1367 // root can run on user builds.
1368 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001369 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001370 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001371 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001372 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001373 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001374 }
1375
Felipe Lemed8b94e52016-12-08 10:21:44 -08001376 printf("========================================================\n");
1377 printf("== Android Framework Services\n");
1378 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001379
Nandana Dutt5c390032019-03-12 10:52:56 +00001380 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001381
Felipe Lemed8b94e52016-12-08 10:21:44 -08001382 printf("========================================================\n");
1383 printf("== Checkins\n");
1384 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001385
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001386 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001387
1388 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1389
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001390 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1391 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1392 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1393 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001394
Felipe Lemed8b94e52016-12-08 10:21:44 -08001395 printf("========================================================\n");
1396 printf("== Running Application Activities\n");
1397 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001398
Makoto Onuki60780982018-04-16 15:34:00 -07001399 // The following dumpsys internally collects output from running apps, so it can take a long
1400 // time. So let's extend the timeout.
1401
1402 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1403
1404 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001405
Felipe Lemed8b94e52016-12-08 10:21:44 -08001406 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001407 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001408 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001409
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001410 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001411 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001412
Felipe Lemed8b94e52016-12-08 10:21:44 -08001413 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001414 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001415 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001416
Makoto Onuki60780982018-04-16 15:34:00 -07001417 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1418 DUMPSYS_COMPONENTS_OPTIONS);
1419
1420 printf("========================================================\n");
1421 printf("== Running Application Providers (platform)\n");
1422 printf("========================================================\n");
1423
1424 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1425 DUMPSYS_COMPONENTS_OPTIONS);
1426
1427 printf("========================================================\n");
1428 printf("== Running Application Providers (non-platform)\n");
1429 printf("========================================================\n");
1430
1431 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1432 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001433
Adrian Roos8b397ab2017-04-04 16:35:44 -07001434 printf("========================================================\n");
1435 printf("== Dropbox crashes\n");
1436 printf("========================================================\n");
1437
1438 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1439 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1440
Felipe Lemed8b94e52016-12-08 10:21:44 -08001441 printf("========================================================\n");
1442 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1443 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1444 printf("========================================================\n");
1445 printf("== dumpstate: done (id %d)\n", ds.id_);
1446 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001447
1448 printf("========================================================\n");
1449 printf("== Obtaining statsd metadata\n");
1450 printf("========================================================\n");
1451 // This differs from the usual dumpsys stats, which is the stats report data.
1452 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001453 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001454}
1455
Nandana Dutt5c390032019-03-12 10:52:56 +00001456/*
1457 * Dumps state for the default case; drops root after it's no longer necessary.
1458 *
1459 * Returns RunStatus::OK if everything went fine.
1460 * Returns RunStatus::ERROR if there was an error.
1461 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1462 * with the caller.
1463 */
1464static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001465 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001466 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001467 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001468
1469 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001470 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001471
1472 /* Run some operations that require root. */
1473 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1474 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1475
1476 ds.AddDir(RECOVERY_DIR, true);
1477 ds.AddDir(RECOVERY_DATA_DIR, true);
1478 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1479 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1480 if (!PropertiesHelper::IsUserBuild()) {
1481 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1482 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1483 }
1484 add_mountinfo();
1485 DumpIpTablesAsRoot();
1486
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001487 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001488 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1489
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001490 // Dump IPsec stats. No keys are exposed here.
1491 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1492
Nandana Dutt4be45d12018-09-26 15:04:23 +01001493 // Run ss as root so we can see socket marks.
1494 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1495
1496 // Run iotop as root to show top 100 IO threads
1497 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1498
Erick Reyese68df822019-02-11 14:46:36 -08001499 // Gather shared memory buffer info if the product implements it
1500 struct stat st;
1501 if (!stat("/product/bin/dmabuf_dump", &st)) {
1502 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1503 }
1504
Nandana Dutt4be45d12018-09-26 15:04:23 +01001505 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001506 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001507 }
1508
Nandana Dutt5c390032019-03-12 10:52:56 +00001509 RETURN_IF_USER_DENIED_CONSENT();
1510 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001511}
1512
mukesh agrawal253dad42018-01-23 21:59:59 -08001513// This method collects common dumpsys for telephony and wifi
1514static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001515 DumpIpTablesAsRoot();
1516
1517 if (!DropRootUser()) {
1518 return;
1519 }
1520
1521 do_dmesg();
1522 DoLogcat();
1523 DumpPacketStats();
1524 DoKmsg();
1525 DumpIpAddrAndRules();
1526 dump_route_tables();
1527
1528 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1529 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001530}
1531
1532// This method collects dumpsys for telephony debugging only
1533static void DumpstateTelephonyOnly() {
1534 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001535 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001536
1537 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001538
1539 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1540
1541 printf("========================================================\n");
1542 printf("== Android Framework Services\n");
1543 printf("========================================================\n");
1544
Vishnu Nair652cc802017-11-30 15:18:30 -08001545 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1546 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001547 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1548 SEC_TO_MSEC(10));
1549 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001550 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1551 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001552 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1553 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001554 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1555 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001556
1557 printf("========================================================\n");
1558 printf("== Running Application Services\n");
1559 printf("========================================================\n");
1560
1561 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1562
1563 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001564 printf("== Running Application Services (non-platform)\n");
1565 printf("========================================================\n");
1566
1567 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1568 DUMPSYS_COMPONENTS_OPTIONS);
1569
1570 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001571 printf("== Checkins\n");
1572 printf("========================================================\n");
1573
1574 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1575
1576 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001577 printf("== dumpstate: done (id %d)\n", ds.id_);
1578 printf("========================================================\n");
1579}
1580
mukesh agrawal253dad42018-01-23 21:59:59 -08001581// This method collects dumpsys for wifi debugging only
1582static void DumpstateWifiOnly() {
1583 DurationReporter duration_reporter("DUMPSTATE");
1584
1585 DumpstateRadioCommon();
1586
1587 printf("========================================================\n");
1588 printf("== Android Framework Services\n");
1589 printf("========================================================\n");
1590
1591 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1592 SEC_TO_MSEC(10));
1593 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1594 SEC_TO_MSEC(10));
1595
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001596 DumpHals();
Roger Wang70399032019-01-08 16:10:37 +08001597
mukesh agrawal253dad42018-01-23 21:59:59 -08001598 printf("========================================================\n");
1599 printf("== dumpstate: done (id %d)\n", ds.id_);
1600 printf("========================================================\n");
1601}
1602
Nandana Duttcf419a72019-03-14 10:40:17 +00001603Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001604 DurationReporter duration_reporter("DUMP TRACES");
1605
1606 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1607 const size_t buf_size = temp_file_pattern.length() + 1;
1608 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1609 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1610
1611 // Create a new, empty file to receive all trace dumps.
1612 //
1613 // TODO: This can be simplified once we remove support for the old style
1614 // dumps. We can have a file descriptor passed in to dump_traces instead
1615 // of creating a file, closing it and then reopening it again.
1616 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1617 if (fd < 0) {
1618 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001619 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001620 }
1621
1622 // Nobody should have access to this temporary file except dumpstate, but we
1623 // temporarily grant 'read' to 'others' here because this file is created
1624 // when tombstoned is still running as root, but dumped after dropping. This
1625 // can go away once support for old style dumping has.
1626 const int chmod_ret = fchmod(fd, 0666);
1627 if (chmod_ret < 0) {
1628 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001629 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001630 }
1631
1632 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1633 if (proc.get() == nullptr) {
1634 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001635 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001636 }
1637
1638 // Number of times process dumping has timed out. If we encounter too many
1639 // failures, we'll give up.
1640 int timeout_failures = 0;
1641 bool dalvik_found = false;
1642
1643 const std::set<int> hal_pids = get_interesting_hal_pids();
1644
1645 struct dirent* d;
1646 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001647 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001648 int pid = atoi(d->d_name);
1649 if (pid <= 0) {
1650 continue;
1651 }
1652
1653 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1654 std::string exe;
1655 if (!android::base::Readlink(link_name, &exe)) {
1656 continue;
1657 }
1658
1659 bool is_java_process;
1660 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1661 // Don't bother dumping backtraces for the zygote.
1662 if (IsZygote(pid)) {
1663 continue;
1664 }
1665
1666 dalvik_found = true;
1667 is_java_process = true;
1668 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1669 is_java_process = false;
1670 } else {
1671 // Probably a native process we don't care about, continue.
1672 continue;
1673 }
1674
1675 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1676 if (timeout_failures == 3) {
1677 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1678 break;
1679 }
1680
1681 const uint64_t start = Nanotime();
1682 const int ret = dump_backtrace_to_file_timeout(
1683 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1684 is_java_process ? 5 : 20, fd);
1685
1686 if (ret == -1) {
1687 // For consistency, the header and footer to this message match those
1688 // dumped by debuggerd in the success case.
1689 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1690 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1691 dprintf(fd, "---- end %d ----", pid);
1692 timeout_failures++;
1693 continue;
1694 }
1695
1696 // We've successfully dumped stack traces, reset the failure count
1697 // and write a summary of the elapsed time to the file and continue with the
1698 // next process.
1699 timeout_failures = 0;
1700
1701 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1702 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1703 }
1704
1705 if (!dalvik_found) {
1706 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1707 }
1708
Nandana Duttcf419a72019-03-14 10:40:17 +00001709 *path = file_name_buf.release();
1710 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001711}
1712
Felipe Leme6f674ae2016-11-18 17:10:33 -08001713void Dumpstate::DumpstateBoard() {
1714 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001715 printf("========================================================\n");
1716 printf("== Board\n");
1717 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001718
Felipe Leme6f674ae2016-11-18 17:10:33 -08001719 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001720 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001721 return;
1722 }
1723
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001724 std::vector<std::string> paths;
1725 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001726 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001727 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1728 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001729 remover.emplace_back(android::base::make_scope_guard(
1730 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001731 }
Jie Song9fbfad02017-06-20 16:29:42 -07001732
Wei Wang587eac92018-04-05 12:17:20 -07001733 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1734 if (dumpstate_device == nullptr) {
1735 MYLOGE("No IDumpstateDevice implementation\n");
1736 return;
1737 }
1738
1739 using ScopedNativeHandle =
1740 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1741 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1742 [](native_handle_t* handle) {
1743 native_handle_close(handle);
1744 native_handle_delete(handle);
1745 });
1746 if (handle == nullptr) {
1747 MYLOGE("Could not create native_handle\n");
1748 return;
1749 }
1750
Nandana Dutt5c390032019-03-12 10:52:56 +00001751 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001752 for (size_t i = 0; i < paths.size(); i++) {
1753 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1754
1755 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1756 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1757 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1758 if (fd < 0) {
1759 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1760 return;
1761 }
1762 handle.get()->data[i] = fd.release();
1763 }
1764
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001765 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001766 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1767 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1768 // and grab whatever dumped
1769 std::packaged_task<bool()>
1770 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001771 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1772 if (!status.isOk()) {
1773 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001774 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001775 }
Wei Wang587eac92018-04-05 12:17:20 -07001776 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001777 });
Wei Wang587eac92018-04-05 12:17:20 -07001778
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001779 auto result = dumpstate_task.get_future();
1780 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001781
1782 constexpr size_t timeout_sec = 30;
1783 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1784 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1785 if (!android::base::SetProperty("ctl.interface_restart",
1786 android::base::StringPrintf("%s/default",
1787 IDumpstateDevice::descriptor))) {
1788 MYLOGE("Couldn't restart dumpstate HAL\n");
1789 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001790 }
Wei Wang587eac92018-04-05 12:17:20 -07001791 // Wait some time for init to kill dumpstate vendor HAL
1792 constexpr size_t killing_timeout_sec = 10;
1793 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1794 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1795 "there might be racing in content\n", killing_timeout_sec);
1796 }
1797
1798 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1799 for (size_t i = 0; i < paths.size(); i++) {
1800 struct stat s;
1801 if (fstat(handle.get()->data[i], &s) == -1) {
1802 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1803 strerror(errno));
1804 file_sizes[i] = -1;
1805 continue;
1806 }
1807 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001808 }
1809
1810 for (size_t i = 0; i < paths.size(); i++) {
1811 if (file_sizes[i] == -1) {
1812 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001813 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001814 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001815 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001816 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001817 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001818 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001819 }
1820
Felipe Lemed8b94e52016-12-08 10:21:44 -08001821 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001822}
1823
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001824static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001825 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001826 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001827 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1828 " -h: display this help message\n"
1829 " -b: play sound file instead of vibrate, at beginning of job\n"
1830 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001831 " -d: append date to filename\n"
1832 " -p: capture screenshot to filename.png\n"
1833 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001834 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001835 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001836 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001837 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001838 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001839 "progress (requires -B)\n"
1840 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001841 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001842 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001843 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001844}
1845
Wei Liuf87959e2016-08-26 14:51:42 -07001846static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001847 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001848}
1849
Felipe Leme1d486fe2016-10-14 18:06:47 -07001850bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001851 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001852 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001853 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001854 // Final timestamp
1855 char date[80];
1856 time_t the_real_now_please_stand_up = time(nullptr);
1857 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001858 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001859 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001860
Felipe Leme9a523ae2016-10-20 15:10:33 -07001861 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001862 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001863 return false;
1864 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001865 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001866 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001867 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001868 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001869
Felipe Leme0f3fb202016-06-10 17:10:53 -07001870 // Add log file (which contains stderr output) to zip...
1871 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001872 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001873 MYLOGE("Failed to add dumpstate log to .zip file\n");
1874 return false;
1875 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001876 // TODO: Should truncate the existing file.
1877 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001878 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1879 return false;
1880 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001881 fprintf(stderr, "\n");
1882
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001883 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001884 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001885 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001886 return false;
1887 }
1888
Felipe Leme1d486fe2016-10-14 18:06:47 -07001889 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1890 ds.zip_file.reset(nullptr);
1891
Felipe Lemee9d2c542016-11-15 11:48:26 -08001892 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001893 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001894
Felipe Leme1e9edc62015-12-21 16:02:13 -08001895 return true;
1896}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001897
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001898static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001899 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1900 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001901 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001902 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001903 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001904 }
1905
1906 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001907 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001908
1909 std::vector<uint8_t> buffer(65536);
1910 while (1) {
1911 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1912 if (bytes_read == 0) {
1913 break;
1914 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001915 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001916 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001917 }
1918
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001919 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001920 }
1921
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001922 uint8_t hash[SHA256_DIGEST_LENGTH];
1923 SHA256_Final(hash, &ctx);
1924
1925 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1926 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001927 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001928 }
1929 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1930 return std::string(hash_buffer);
1931}
1932
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001933static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1934 // clang-format off
1935 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1936 "--receiver-foreground", "--receiver-include-background", "-a", action};
1937 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001938
1939 am.insert(am.end(), args.begin(), args.end());
1940
Felipe Leme8d2410e2017-02-08 09:46:08 -08001941 RunCommand("", am,
1942 CommandOptions::WithTimeout(20)
1943 .Log("Sending broadcast: '%s'\n")
1944 .Always()
1945 .DropRoot()
1946 .RedirectStderr()
1947 .Build());
1948}
1949
Felipe Leme35b8cf12017-02-10 15:47:29 -08001950static void Vibrate(int duration_ms) {
1951 // clang-format off
Chris Friese7e95fb2019-06-14 14:47:59 +00001952 RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001953 CommandOptions::WithTimeout(10)
1954 .Log("Vibrate: '%s'\n")
1955 .Always()
1956 .Build());
1957 // clang-format on
1958}
1959
Nandana Dutt979388e2018-11-30 16:48:55 +00001960static void MaybeResolveSymlink(std::string* path) {
1961 std::string resolved_path;
1962 if (android::base::Readlink(*path, &resolved_path)) {
1963 *path = resolved_path;
1964 }
1965}
1966
Nandana Dutt4be45d12018-09-26 15:04:23 +01001967/*
1968 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
1969 * if we are writing zip files and adds the version file.
1970 */
1971static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00001972 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
1973
Nandana Dutt4be45d12018-09-26 15:04:23 +01001974 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1975 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00001976 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001977 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001978 char date[80];
1979 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
1980 ds.name_ = date;
1981 } else {
1982 ds.name_ = "undated";
1983 }
1984
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001985 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001986 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001987 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001988 ds.base_name_ += "-wifi";
1989 }
1990
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001991 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001992 ds.screenshot_path_ = ds.GetPath(".png");
1993 }
1994 ds.tmp_path_ = ds.GetPath(".tmp");
1995 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1996
Nandana Dutt54dbd672019-01-11 12:58:05 +00001997 std::string destination = ds.options_->bugreport_fd.get() != -1
1998 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00001999 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002000 MYLOGD(
2001 "Bugreport dir: %s\n"
2002 "Base name: %s\n"
2003 "Suffix: %s\n"
2004 "Log path: %s\n"
2005 "Temporary path: %s\n"
2006 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002007 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2008 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002009
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002010 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002011 ds.path_ = ds.GetPath(".zip");
2012 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2013 create_parent_dirs(ds.path_.c_str());
2014 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2015 if (ds.zip_file == nullptr) {
2016 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2017 } else {
2018 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2019 }
2020 ds.AddTextZipEntry("version.txt", ds.version_);
2021 }
2022}
2023
2024/*
2025 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2026 * printing zipped file status, etc.
2027 */
2028static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002029 /* check if user changed the suffix using system properties */
2030 std::string name =
2031 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2032 bool change_suffix = false;
2033 if (!name.empty()) {
2034 /* must whitelist which characters are allowed, otherwise it could cross directories */
2035 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2036 if (std::regex_match(name.c_str(), valid_regex)) {
2037 change_suffix = true;
2038 } else {
2039 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2040 }
2041 }
2042 if (change_suffix) {
2043 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2044 ds.name_ = name;
2045 if (!ds.screenshot_path_.empty()) {
2046 std::string new_screenshot_path = ds.GetPath(".png");
2047 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2048 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2049 new_screenshot_path.c_str(), strerror(errno));
2050 } else {
2051 ds.screenshot_path_ = new_screenshot_path;
2052 }
2053 }
2054 }
2055
2056 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002057 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002058 if (!ds.FinishZipFile()) {
2059 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2060 do_text_file = true;
2061 } else {
2062 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002063 // If the user has changed the suffix, we need to change the zip file name.
2064 std::string new_path = ds.GetPath(".zip");
2065 if (ds.path_ != new_path) {
2066 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2067 if (rename(ds.path_.c_str(), new_path.c_str())) {
2068 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2069 strerror(errno));
2070 } else {
2071 ds.path_ = new_path;
2072 }
2073 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 }
2075 }
2076 if (do_text_file) {
2077 ds.path_ = ds.GetPath(".txt");
2078 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2079 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2080 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2081 ds.path_.clear();
2082 }
2083 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002084 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002085 if (do_text_file) {
2086 dprintf(ds.control_socket_fd_,
2087 "FAIL:could not create zip file, check %s "
2088 "for more details\n",
2089 ds.log_path_.c_str());
2090 } else {
2091 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2092 }
2093 }
2094}
2095
2096/* Broadcasts that we are done with the bugreport */
2097static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002098 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002099 if (!ds.path_.empty()) {
2100 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002101 // clang-format off
2102
2103 std::vector<std::string> am_args = {
2104 "--receiver-permission", "android.permission.DUMP",
2105 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2106 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2107 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002108 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002109 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2110 };
2111 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002112 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002113 am_args.push_back("--es");
2114 am_args.push_back("android.intent.extra.SCREENSHOT");
2115 am_args.push_back(ds.screenshot_path_);
2116 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002117 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002118 am_args.push_back("--es");
2119 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002120 am_args.push_back(ds.options_->notification_title);
2121 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002122 am_args.push_back("--es");
2123 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002124 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002125 }
2126 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002127 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002128 am_args.push_back("--es");
2129 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002130 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002131 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2132 } else {
2133 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2134 }
2135 } else {
2136 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2137 }
2138}
2139
Nandana Dutt58d72e22018-11-16 10:30:48 +00002140static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2141 switch (mode) {
2142 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2143 return "BUGREPORT_FULL";
2144 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2145 return "BUGREPORT_INTERACTIVE";
2146 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2147 return "BUGREPORT_REMOTE";
2148 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2149 return "BUGREPORT_WEAR";
2150 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2151 return "BUGREPORT_TELEPHONY";
2152 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2153 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002154 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2155 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002156 }
2157}
2158
2159static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002160 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002161 switch (mode) {
2162 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2163 options->do_broadcast = true;
2164 options->do_fb = true;
2165 break;
2166 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002167 // Currently, the dumpstate binder is only used by Shell to update progress.
2168 options->do_start_service = true;
2169 options->do_progress_updates = true;
2170 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002171 options->do_broadcast = true;
2172 break;
2173 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002174 options->do_vibrate = false;
2175 options->is_remote_mode = true;
2176 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002177 options->do_broadcast = true;
2178 break;
2179 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002180 options->do_start_service = true;
2181 options->do_progress_updates = true;
2182 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002183 options->do_fb = true;
2184 options->do_broadcast = true;
2185 break;
2186 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002187 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002188 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002189 options->do_broadcast = true;
2190 break;
2191 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002192 options->wifi_only = true;
2193 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002194 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002195 options->do_broadcast = true;
2196 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002197 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2198 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002199 }
2200}
2201
2202static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002203 // If the system property is not set, it's assumed to be a default bugreport.
2204 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002205
2206 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2207 if (!extra_options.empty()) {
2208 // Framework uses a system property to override some command-line args.
2209 // Currently, it contains the type of the requested bugreport.
2210 if (extra_options == "bugreportplus") {
2211 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002212 } else if (extra_options == "bugreportfull") {
2213 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002214 } else if (extra_options == "bugreportremote") {
2215 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2216 } else if (extra_options == "bugreportwear") {
2217 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2218 } else if (extra_options == "bugreporttelephony") {
2219 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2220 } else if (extra_options == "bugreportwifi") {
2221 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002222 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002223 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002224 }
2225 // Reset the property
2226 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2227 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002228 return mode;
2229}
2230
2231// TODO: Move away from system properties when we have options passed via binder calls.
2232/* Sets runtime options from the system properties and then clears those properties. */
2233static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2234 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2235 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002236
2237 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2238 if (!options->notification_title.empty()) {
2239 // Reset the property
2240 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2241
Nandana Duttdd8cca32018-11-14 10:10:29 +00002242 options->notification_description =
2243 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002244 if (!options->notification_description.empty()) {
2245 // Reset the property
2246 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2247 }
2248 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2249 options->notification_description.c_str());
2250 }
2251}
2252
Nandana Dutt58d72e22018-11-16 10:30:48 +00002253static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2254 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2255 MYLOGI("do_add_date: %d\n", options.do_add_date);
2256 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2257 MYLOGI("use_socket: %d\n", options.use_socket);
2258 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2259 MYLOGI("do_fb: %d\n", options.do_fb);
2260 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2261 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2262 MYLOGI("show_header_only: %d\n", options.show_header_only);
2263 MYLOGI("do_start_service: %d\n", options.do_start_service);
2264 MYLOGI("telephony_only: %d\n", options.telephony_only);
2265 MYLOGI("wifi_only: %d\n", options.wifi_only);
2266 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002267 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002268 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2269 MYLOGI("args: %s\n", options.args.c_str());
2270 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2271 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2272}
2273
Nandana Dutt54dbd672019-01-11 12:58:05 +00002274void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2275 const android::base::unique_fd& bugreport_fd_in,
2276 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002277 // In the new API world, date is always added; output is always a zip file.
2278 // TODO(111441001): remove these options once they are obsolete.
2279 do_add_date = true;
2280 do_zip_file = true;
2281
Nandana Dutt54dbd672019-01-11 12:58:05 +00002282 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2283 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2284 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002285
2286 extra_options = ModeToString(bugreport_mode);
2287 SetOptionsFromMode(bugreport_mode, this);
2288}
2289
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002290Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2291 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002292 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002293 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002294 switch (c) {
2295 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002296 case 'd': do_add_date = true; break;
2297 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002298 // o=use_outfile not supported anymore.
2299 // TODO(b/111441001): Remove when all callers have migrated.
2300 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002301 case 's': use_socket = true; break;
2302 case 'S': use_control_socket = true; break;
2303 case 'v': show_header_only = true; break;
2304 case 'q': do_vibrate = false; break;
2305 case 'p': do_fb = true; break;
2306 case 'P': do_progress_updates = true; break;
2307 case 'R': is_remote_mode = true; break;
2308 case 'B': do_broadcast = true; break;
2309 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002310 case 'w':
2311 // This was already processed
2312 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002313 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002314 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002315 break;
2316 default:
2317 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002318 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002319 break;
2320 // clang-format on
2321 }
2322 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002323
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002324 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002325 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002326 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002327 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002328 }
2329 }
2330
2331 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2332 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002333
2334 SetOptionsFromProperties(this);
2335 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002336}
2337
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002338bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002339 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002340 return false;
2341 }
2342
Nandana Dutt9a76d202019-01-21 15:56:48 +00002343 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002344 return false;
2345 }
2346
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002347 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002348 return false;
2349 }
2350
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002351 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002352 return false;
2353 }
2354
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002355 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002356 return false;
2357 }
2358 return true;
2359}
2360
Nandana Dutt197661d2018-11-16 16:40:21 +00002361void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2362 options_ = std::move(options);
2363}
2364
Nandana Duttd2f5f082019-01-18 17:13:52 +00002365Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2366 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002367 if (listener_ != nullptr) {
2368 switch (status) {
2369 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002370 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002371 break;
2372 case Dumpstate::RunStatus::HELP:
2373 break;
2374 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002375 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002376 break;
2377 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002378 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2379 break;
2380 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2381 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2382 break;
2383 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2384 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002385 break;
2386 }
2387 }
2388 return status;
2389}
2390
Nandana Dutt979388e2018-11-30 16:48:55 +00002391/*
2392 * Dumps relevant information to a bugreport based on the given options.
2393 *
2394 * The bugreport can be dumped to a file or streamed to a socket.
2395 *
2396 * How dumping to file works:
2397 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2398 * stderr is redirected a log file.
2399 *
2400 * The temporary bugreport is then populated via printfs, dumping contents of files and
2401 * output of commands to stdout.
2402 *
2403 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2404 * text file.
2405 *
2406 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2407 * gets added to the archive.
2408 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002409 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2410 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002411 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002412Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2413 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002414 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002415 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002416 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002417 return RunStatus::INVALID_INPUT;
2418 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002419 /* set as high priority, and protect from OOM killer */
2420 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002421
Felipe Lemed071c682016-10-20 16:48:00 -07002422 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002423 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002424 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002425 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002426 } else {
2427 /* fallback to kernels <= 2.6.35 */
2428 oom_adj = fopen("/proc/self/oom_adj", "we");
2429 if (oom_adj) {
2430 fputs("-17", oom_adj);
2431 fclose(oom_adj);
2432 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002433 }
2434
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002435 if (version_ == VERSION_DEFAULT) {
2436 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002437 }
2438
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002439 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002440 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002441 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002442 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002443 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002444 }
2445
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002446 if (options_->show_header_only) {
2447 PrintHeader();
2448 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002449 }
2450
Nandana Duttd2f5f082019-01-18 17:13:52 +00002451 if (options_->bugreport_fd.get() != -1) {
2452 // If the output needs to be copied over to the caller's fd, get user consent.
2453 android::String16 package(calling_package.c_str());
2454 CheckUserConsent(calling_uid, package);
2455 }
2456
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002457 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002458 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002459
2460 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002461 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002462 is_redirecting
2463 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2464 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002465 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002466
Felipe Lemed071c682016-10-20 16:48:00 -07002467 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002468 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002469 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002470 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2471
2472 MYLOGI("begin\n");
2473
Sahana Raof35ed432019-07-12 10:47:52 +01002474 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2475 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2476 } else {
2477 // Wake lock will be released automatically on process death
2478 MYLOGD("Wake lock acquired.\n");
2479 }
2480
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002481 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002482
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002483 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002484 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002485 MYLOGI("Starting 'dumpstate' service\n");
2486 android::status_t ret;
2487 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2488 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2489 }
2490 }
2491
Felipe Lemef0292972016-11-22 13:57:05 -08002492 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002493 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2494 }
2495
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002496 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2497 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002498
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002499 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002500
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002501 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002502
Christopher Ferrised9354f2014-10-01 17:35:01 -07002503 // If we are going to use a socket, do it as early as possible
2504 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002505 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002506 if (!redirect_to_socket(stdout, "dumpstate")) {
2507 return ERROR;
2508 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002509 }
2510
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002511 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002512 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002513 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002514 if (control_socket_fd_ == -1) {
2515 return ERROR;
2516 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002517 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002518 }
2519
Felipe Leme71bbfc52015-11-23 14:14:51 -08002520 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002521 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002522
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002523 if (options_->do_progress_updates) {
2524 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002525 // clang-format off
2526 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002527 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002528 "--es", "android.intent.extra.NAME", name_,
2529 "--ei", "android.intent.extra.ID", std::to_string(id_),
2530 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2531 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002532 };
2533 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002534 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002535 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002536 if (options_->use_control_socket) {
2537 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002538 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002539 }
2540 }
2541
Nick Kralevichf3599b32016-01-25 15:05:16 -08002542 /* read /proc/cmdline before dropping root */
2543 FILE *cmdline = fopen("/proc/cmdline", "re");
2544 if (cmdline) {
2545 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2546 fclose(cmdline);
2547 }
2548
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002549 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002550 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002551 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002552
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002553 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002554 MYLOGI("taking early screenshot\n");
2555 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002556 }
2557
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002558 if (options_->do_zip_file && zip_file != nullptr) {
2559 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2560 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002561 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002562 }
2563 }
2564
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002565 int dup_stdout_fd;
2566 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002567 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002568 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002569 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002570 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2571 return ERROR;
2572 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002573 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2574 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2575 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002576 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002577
2578 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2579 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002580 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002581 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002582 /* TODO: rather than generating a text file now and zipping it later,
2583 it would be more efficient to redirect stdout to the zip entry
2584 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002585 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2586 return ERROR;
2587 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002588 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002589 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002590 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002591 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002592 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002593
2594 // Don't buffer stdout
2595 setvbuf(stdout, nullptr, _IONBF, 0);
2596
Felipe Leme608385d2016-02-01 10:35:38 -08002597 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2598 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002599 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002600 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002601
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002602 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002603 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002604 DumpstateBoard();
2605 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002606 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002607 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002608 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002609 RunStatus s = DumpstateDefault();
2610 if (s != RunStatus::OK) {
2611 if (s == RunStatus::USER_CONSENT_TIMED_OUT) {
2612 HandleUserConsentDenied();
2613 }
2614 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002615 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002616 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002617
Felipe Leme55b42a62015-11-10 17:39:08 -08002618 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002619 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002620 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002621 }
2622
Nandana Duttd2f5f082019-01-18 17:13:52 +00002623 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002624 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002625 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002626 }
2627
Nandana Duttd2f5f082019-01-18 17:13:52 +00002628 // Share the final file with the caller if the user has consented.
2629 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2630 if (options_->bugreport_fd.get() != -1) {
2631 status = CopyBugreportIfUserConsented();
2632 if (status != Dumpstate::RunStatus::OK &&
2633 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2634 // Do an early return if there were errors. We make an exception for consent
2635 // timing out because it's possible the user got distracted. In this case the
2636 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002637 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002638 return status;
2639 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002640 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002641 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2642 options_->screenshot_fd.get());
2643 if (copy_succeeded) {
2644 android::os::UnlinkAndLogOnError(screenshot_path_);
2645 }
2646 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002647 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2648 MYLOGI(
2649 "Did not receive user consent yet."
2650 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002651 const String16 incidentcompanion("incidentcompanion");
2652 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2653 if (ics != nullptr) {
2654 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2655 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2656 consent_callback_.get());
2657 } else {
2658 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2659 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002660 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002661 }
2662
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002663 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002664 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002665 for (int i = 0; i < 3; i++) {
2666 Vibrate(75);
2667 usleep((75 + 50) * 1000);
2668 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002669 }
2670
Jeff Brown1dc94e32014-09-11 14:15:27 -07002671 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002672 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002673 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002674 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002675 }
2676
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002677 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2678 progress_->GetInitialMax());
2679 progress_->Save();
2680 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002681
Felipe Leme107a05f2016-03-08 15:11:15 -08002682 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002683 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002684 }
2685
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002686 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002687 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002688 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002689 }
2690
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002691 tombstone_data_.clear();
2692 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002693
Nandana Duttd2f5f082019-01-18 17:13:52 +00002694 return (consent_callback_ != nullptr &&
2695 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2696 ? USER_CONSENT_TIMED_OUT
2697 : RunStatus::OK;
2698}
2699
2700void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2701 consent_callback_ = new ConsentCallback();
2702 const String16 incidentcompanion("incidentcompanion");
2703 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2704 if (ics != nullptr) {
2705 MYLOGD("Checking user consent via incidentcompanion service\n");
2706 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002707 calling_uid, calling_package, String16(), String16(),
2708 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002709 } else {
2710 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2711 }
2712}
2713
Nandana Dutt5c390032019-03-12 10:52:56 +00002714bool Dumpstate::IsUserConsentDenied() const {
2715 return ds.consent_callback_ != nullptr &&
2716 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2717}
2718
Nandana Duttd2f5f082019-01-18 17:13:52 +00002719void Dumpstate::CleanupFiles() {
2720 android::os::UnlinkAndLogOnError(tmp_path_);
2721 android::os::UnlinkAndLogOnError(screenshot_path_);
2722 android::os::UnlinkAndLogOnError(path_);
2723}
2724
2725Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2726 MYLOGD("User denied consent; deleting files and returning\n");
2727 CleanupFiles();
2728 return USER_CONSENT_DENIED;
2729}
2730
2731Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2732 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2733 // user consent.
2734 UserConsentResult consent_result = consent_callback_->getResult();
2735 if (consent_result == UserConsentResult::UNAVAILABLE) {
2736 // User has not responded yet.
2737 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2738 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2739 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2740 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2741 sleep(delay_seconds);
2742 }
2743 consent_result = consent_callback_->getResult();
2744 }
2745 if (consent_result == UserConsentResult::DENIED) {
2746 // User has explicitly denied sharing with the app. To be safe delete the
2747 // internal bugreport & tmp files.
2748 return HandleUserConsentDenied();
2749 }
2750 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002751 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2752 if (copy_succeeded) {
2753 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002754 }
2755 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2756 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2757 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2758 // Since we do not have user consent to share the bugreport it does not get
2759 // copied over to the calling app but remains in the internal directory from
2760 // where the user can manually pull it.
2761 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2762 }
2763 // Unknown result; must be a programming error.
2764 MYLOGE("Unknown user consent result:%d\n", consent_result);
2765 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002766}
2767
Nandana Duttf02564e2019-02-15 15:24:24 +00002768Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002769 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2770 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2771 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002772 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002773 // When directly running dumpstate binary, the output is not expected to be written
2774 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002775 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002776
2777 // calling_uid and calling_package are for user consent to share the bugreport with
2778 // an app; they are irrelvant here because bugreport is only written to a local
2779 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002780 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002781 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002782 return status;
2783}
2784
2785/* Main entry point for dumpstate binary. */
2786int run_main(int argc, char* argv[]) {
2787 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002788
2789 switch (status) {
2790 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002791 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002792 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002793 ShowUsage();
2794 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002795 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002796 fprintf(stderr, "Invalid combination of args\n");
2797 ShowUsage();
2798 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002799 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002800 FALLTHROUGH_INTENDED;
2801 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2802 FALLTHROUGH_INTENDED;
2803 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002804 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002805 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002806}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002807
2808// TODO(111441001): Default DumpOptions to sensible values.
2809Dumpstate::Dumpstate(const std::string& version)
2810 : pid_(getpid()),
2811 options_(new Dumpstate::DumpOptions()),
2812 version_(version),
2813 now_(time(nullptr)) {
2814}
2815
2816Dumpstate& Dumpstate::GetInstance() {
2817 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2818 return singleton_;
2819}
2820
2821DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
2822 : title_(title), logcat_only_(logcat_only) {
2823 if (!title_.empty()) {
2824 started_ = Nanotime();
2825 }
2826}
2827
2828DurationReporter::~DurationReporter() {
2829 if (!title_.empty()) {
2830 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2831 if (elapsed < .5f) {
2832 return;
2833 }
2834 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2835 if (logcat_only_) {
2836 return;
2837 }
2838 // Use "Yoda grammar" to make it easier to grep|sort sections.
2839 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2840 }
2841}
2842
2843const int32_t Progress::kDefaultMax = 5000;
2844
2845Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2846}
2847
2848Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2849 : Progress(initial_max, growth_factor, "") {
2850 progress_ = progress;
2851}
2852
2853Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2854 : initial_max_(initial_max),
2855 progress_(0),
2856 max_(initial_max),
2857 growth_factor_(growth_factor),
2858 n_runs_(0),
2859 average_max_(0),
2860 path_(path) {
2861 if (!path_.empty()) {
2862 Load();
2863 }
2864}
2865
2866void Progress::Load() {
2867 MYLOGD("Loading stats from %s\n", path_.c_str());
2868 std::string content;
2869 if (!android::base::ReadFileToString(path_, &content)) {
2870 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2871 return;
2872 }
2873 if (content.empty()) {
2874 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2875 return;
2876 }
2877 std::vector<std::string> lines = android::base::Split(content, "\n");
2878
2879 if (lines.size() < 1) {
2880 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2881 (int)lines.size(), max_);
2882 return;
2883 }
2884 char* ptr;
2885 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2886 average_max_ = strtol(ptr, nullptr, 10);
2887 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2888 average_max_ > STATS_MAX_AVERAGE) {
2889 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2890 initial_max_ = Progress::kDefaultMax;
2891 } else {
2892 initial_max_ = average_max_;
2893 }
2894 max_ = initial_max_;
2895
2896 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2897}
2898
2899void Progress::Save() {
2900 int32_t total = n_runs_ * average_max_ + progress_;
2901 int32_t runs = n_runs_ + 1;
2902 int32_t average = floor(((float)total) / runs);
2903 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2904 path_.c_str());
2905 if (path_.empty()) {
2906 return;
2907 }
2908
2909 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2910 if (!android::base::WriteStringToFile(content, path_)) {
2911 MYLOGE("Could not save stats on %s\n", path_.c_str());
2912 }
2913}
2914
2915int32_t Progress::Get() const {
2916 return progress_;
2917}
2918
2919bool Progress::Inc(int32_t delta_sec) {
2920 bool changed = false;
2921 if (delta_sec >= 0) {
2922 progress_ += delta_sec;
2923 if (progress_ > max_) {
2924 int32_t old_max = max_;
2925 max_ = floor((float)progress_ * growth_factor_);
2926 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2927 changed = true;
2928 }
2929 }
2930 return changed;
2931}
2932
2933int32_t Progress::GetMax() const {
2934 return max_;
2935}
2936
2937int32_t Progress::GetInitialMax() const {
2938 return initial_max_;
2939}
2940
2941void Progress::Dump(int fd, const std::string& prefix) const {
2942 const char* pr = prefix.c_str();
2943 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2944 dprintf(fd, "%smax: %d\n", pr, max_);
2945 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2946 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2947 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2948 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2949 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2950}
2951
2952bool Dumpstate::IsZipping() const {
2953 return zip_writer_ != nullptr;
2954}
2955
2956std::string Dumpstate::GetPath(const std::string& suffix) const {
2957 return GetPath(bugreport_internal_dir_, suffix);
2958}
2959
2960std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2961 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2962 name_.c_str(), suffix.c_str());
2963}
2964
2965void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2966 progress_ = std::move(progress);
2967}
2968
2969void for_each_userid(void (*func)(int), const char *header) {
2970 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2971 "for_each_userid(%s)", header);
2972 DurationReporter duration_reporter(title);
2973 if (PropertiesHelper::IsDryRun()) return;
2974
2975 DIR *d;
2976 struct dirent *de;
2977
2978 if (header) printf("\n------ %s ------\n", header);
2979 func(0);
2980
2981 if (!(d = opendir("/data/system/users"))) {
2982 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2983 return;
2984 }
2985
2986 while ((de = readdir(d))) {
2987 int userid;
2988 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2989 continue;
2990 }
2991 func(userid);
2992 }
2993
2994 closedir(d);
2995}
2996
2997static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2998 DIR *d;
2999 struct dirent *de;
3000
3001 if (!(d = opendir("/proc"))) {
3002 printf("Failed to open /proc (%s)\n", strerror(errno));
3003 return;
3004 }
3005
3006 if (header) printf("\n------ %s ------\n", header);
3007 while ((de = readdir(d))) {
3008 if (ds.IsUserConsentDenied()) {
3009 MYLOGE(
3010 "Returning early because user denied consent to share bugreport with calling app.");
3011 closedir(d);
3012 return;
3013 }
3014 int pid;
3015 int fd;
3016 char cmdpath[255];
3017 char cmdline[255];
3018
3019 if (!(pid = atoi(de->d_name))) {
3020 continue;
3021 }
3022
3023 memset(cmdline, 0, sizeof(cmdline));
3024
3025 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3026 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3027 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3028 close(fd);
3029 if (cmdline[0]) {
3030 helper(pid, cmdline, arg);
3031 continue;
3032 }
3033 }
3034
3035 // if no cmdline, a kernel thread has comm
3036 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3037 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3038 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3039 close(fd);
3040 if (cmdline[1]) {
3041 cmdline[0] = '[';
3042 size_t len = strcspn(cmdline, "\f\b\r\n");
3043 cmdline[len] = ']';
3044 cmdline[len+1] = '\0';
3045 }
3046 }
3047 if (!cmdline[0]) {
3048 strcpy(cmdline, "N/A");
3049 }
3050 helper(pid, cmdline, arg);
3051 }
3052
3053 closedir(d);
3054}
3055
3056static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3057 for_each_pid_func *func = (for_each_pid_func*) arg;
3058 func(pid, cmdline);
3059}
3060
3061void for_each_pid(for_each_pid_func func, const char *header) {
3062 std::string title = header == nullptr ? "for_each_pid"
3063 : android::base::StringPrintf("for_each_pid(%s)", header);
3064 DurationReporter duration_reporter(title);
3065 if (PropertiesHelper::IsDryRun()) return;
3066
3067 __for_each_pid(for_each_pid_helper, header, (void *) func);
3068}
3069
3070static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3071 DIR *d;
3072 struct dirent *de;
3073 char taskpath[255];
3074 for_each_tid_func *func = (for_each_tid_func *) arg;
3075
3076 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3077
3078 if (!(d = opendir(taskpath))) {
3079 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3080 return;
3081 }
3082
3083 func(pid, pid, cmdline);
3084
3085 while ((de = readdir(d))) {
3086 if (ds.IsUserConsentDenied()) {
3087 MYLOGE(
3088 "Returning early because user denied consent to share bugreport with calling app.");
3089 closedir(d);
3090 return;
3091 }
3092 int tid;
3093 int fd;
3094 char commpath[255];
3095 char comm[255];
3096
3097 if (!(tid = atoi(de->d_name))) {
3098 continue;
3099 }
3100
3101 if (tid == pid)
3102 continue;
3103
3104 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3105 memset(comm, 0, sizeof(comm));
3106 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3107 strcpy(comm, "N/A");
3108 } else {
3109 char *c;
3110 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3111 close(fd);
3112
3113 c = strrchr(comm, '\n');
3114 if (c) {
3115 *c = '\0';
3116 }
3117 }
3118 func(pid, tid, comm);
3119 }
3120
3121 closedir(d);
3122}
3123
3124void for_each_tid(for_each_tid_func func, const char *header) {
3125 std::string title = header == nullptr ? "for_each_tid"
3126 : android::base::StringPrintf("for_each_tid(%s)", header);
3127 DurationReporter duration_reporter(title);
3128
3129 if (PropertiesHelper::IsDryRun()) return;
3130
3131 __for_each_pid(for_each_tid_helper, header, (void *) func);
3132}
3133
3134void show_wchan(int pid, int tid, const char *name) {
3135 if (PropertiesHelper::IsDryRun()) return;
3136
3137 char path[255];
3138 char buffer[255];
3139 int fd, ret, save_errno;
3140 char name_buffer[255];
3141
3142 memset(buffer, 0, sizeof(buffer));
3143
3144 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3145 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3146 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3147 return;
3148 }
3149
3150 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3151 save_errno = errno;
3152 close(fd);
3153
3154 if (ret < 0) {
3155 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3156 return;
3157 }
3158
3159 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3160 pid == tid ? 0 : 3, "", name);
3161
3162 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3163
3164 return;
3165}
3166
3167// print time in centiseconds
3168static void snprcent(char *buffer, size_t len, size_t spc,
3169 unsigned long long time) {
3170 static long hz; // cache discovered hz
3171
3172 if (hz <= 0) {
3173 hz = sysconf(_SC_CLK_TCK);
3174 if (hz <= 0) {
3175 hz = 1000;
3176 }
3177 }
3178
3179 // convert to centiseconds
3180 time = (time * 100 + (hz / 2)) / hz;
3181
3182 char str[16];
3183
3184 snprintf(str, sizeof(str), " %llu.%02u",
3185 time / 100, (unsigned)(time % 100));
3186 size_t offset = strlen(buffer);
3187 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3188 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3189}
3190
3191// print permille as a percent
3192static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3193 char str[16];
3194
3195 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3196 size_t offset = strlen(buffer);
3197 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3198 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3199}
3200
3201void show_showtime(int pid, const char *name) {
3202 if (PropertiesHelper::IsDryRun()) return;
3203
3204 char path[255];
3205 char buffer[1023];
3206 int fd, ret, save_errno;
3207
3208 memset(buffer, 0, sizeof(buffer));
3209
3210 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3211 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3212 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3213 return;
3214 }
3215
3216 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3217 save_errno = errno;
3218 close(fd);
3219
3220 if (ret < 0) {
3221 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3222 return;
3223 }
3224
3225 // field 14 is utime
3226 // field 15 is stime
3227 // field 42 is iotime
3228 unsigned long long utime = 0, stime = 0, iotime = 0;
3229 if (sscanf(buffer,
3230 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3231 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3232 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3233 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3234 &utime, &stime, &iotime) != 3) {
3235 return;
3236 }
3237
3238 unsigned long long total = utime + stime;
3239 if (!total) {
3240 return;
3241 }
3242
3243 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3244 if (permille > 1000) {
3245 permille = 1000;
3246 }
3247
3248 // try to beautify and stabilize columns at <80 characters
3249 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3250 if ((name[0] != '[') || utime) {
3251 snprcent(buffer, sizeof(buffer), 57, utime);
3252 }
3253 snprcent(buffer, sizeof(buffer), 65, stime);
3254 if ((name[0] != '[') || iotime) {
3255 snprcent(buffer, sizeof(buffer), 73, iotime);
3256 }
3257 if (iotime) {
3258 snprdec(buffer, sizeof(buffer), 79, permille);
3259 }
3260 puts(buffer); // adds a trailing newline
3261
3262 return;
3263}
3264
3265void do_dmesg() {
3266 const char *title = "KERNEL LOG (dmesg)";
3267 DurationReporter duration_reporter(title);
3268 printf("------ %s ------\n", title);
3269
3270 if (PropertiesHelper::IsDryRun()) return;
3271
3272 /* Get size of kernel buffer */
3273 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3274 if (size <= 0) {
3275 printf("Unexpected klogctl return value: %d\n\n", size);
3276 return;
3277 }
3278 char *buf = (char *) malloc(size + 1);
3279 if (buf == nullptr) {
3280 printf("memory allocation failed\n\n");
3281 return;
3282 }
3283 int retval = klogctl(KLOG_READ_ALL, buf, size);
3284 if (retval < 0) {
3285 printf("klogctl failure\n\n");
3286 free(buf);
3287 return;
3288 }
3289 buf[retval] = '\0';
3290 printf("%s\n\n", buf);
3291 free(buf);
3292 return;
3293}
3294
3295void do_showmap(int pid, const char *name) {
3296 char title[255];
3297 char arg[255];
3298
3299 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3300 snprintf(arg, sizeof(arg), "%d", pid);
3301 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3302}
3303
3304int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3305 DurationReporter duration_reporter(title);
3306
3307 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3308
3309 UpdateProgress(WEIGHT_FILE);
3310
3311 return status;
3312}
3313
3314int read_file_as_long(const char *path, long int *output) {
3315 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3316 if (fd < 0) {
3317 int err = errno;
3318 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3319 return -1;
3320 }
3321 char buffer[50];
3322 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3323 if (bytes_read == -1) {
3324 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3325 return -2;
3326 }
3327 if (bytes_read == 0) {
3328 MYLOGE("File %s is empty\n", path);
3329 return -3;
3330 }
3331 *output = atoi(buffer);
3332 return 0;
3333}
3334
3335/* calls skip to gate calling dump_from_fd recursively
3336 * in the specified directory. dump_from_fd defaults to
3337 * dump_file_from_fd above when set to NULL. skip defaults
3338 * to false when set to NULL. dump_from_fd will always be
3339 * called with title NULL.
3340 */
3341int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3342 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3343 DurationReporter duration_reporter(title);
3344 DIR *dirp;
3345 struct dirent *d;
3346 char *newpath = nullptr;
3347 const char *slash = "/";
3348 int retval = 0;
3349
3350 if (!title.empty()) {
3351 printf("------ %s (%s) ------\n", title.c_str(), dir);
3352 }
3353 if (PropertiesHelper::IsDryRun()) return 0;
3354
3355 if (dir[strlen(dir) - 1] == '/') {
3356 ++slash;
3357 }
3358 dirp = opendir(dir);
3359 if (dirp == nullptr) {
3360 retval = -errno;
3361 MYLOGE("%s: %s\n", dir, strerror(errno));
3362 return retval;
3363 }
3364
3365 if (!dump_from_fd) {
3366 dump_from_fd = dump_file_from_fd;
3367 }
3368 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3369 if ((d->d_name[0] == '.')
3370 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3371 || (d->d_name[1] == '\0'))) {
3372 continue;
3373 }
3374 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3375 (d->d_type == DT_DIR) ? "/" : "");
3376 if (!newpath) {
3377 retval = -errno;
3378 continue;
3379 }
3380 if (skip && (*skip)(newpath)) {
3381 continue;
3382 }
3383 if (d->d_type == DT_DIR) {
3384 int ret = dump_files("", newpath, skip, dump_from_fd);
3385 if (ret < 0) {
3386 retval = ret;
3387 }
3388 continue;
3389 }
3390 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3391 if (fd.get() < 0) {
3392 retval = -1;
3393 printf("*** %s: %s\n", newpath, strerror(errno));
3394 continue;
3395 }
3396 (*dump_from_fd)(nullptr, newpath, fd.get());
3397 }
3398 closedir(dirp);
3399 if (!title.empty()) {
3400 printf("\n");
3401 }
3402 return retval;
3403}
3404
3405/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3406 * it's possible to avoid issues where opening the file itself can get
3407 * stuck.
3408 */
3409int dump_file_from_fd(const char *title, const char *path, int fd) {
3410 if (PropertiesHelper::IsDryRun()) return 0;
3411
3412 int flags = fcntl(fd, F_GETFL);
3413 if (flags == -1) {
3414 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3415 return -1;
3416 } else if (!(flags & O_NONBLOCK)) {
3417 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3418 return -1;
3419 }
3420 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3421}
3422
3423int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3424 const CommandOptions& options) {
3425 DurationReporter duration_reporter(title);
3426
3427 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3428
3429 /* TODO: for now we're simplifying the progress calculation by using the
3430 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3431 * where its weight should be much higher proportionally to its timeout.
3432 * Ideally, it should use a options.EstimatedDuration() instead...*/
3433 UpdateProgress(options.Timeout());
3434
3435 return status;
3436}
3437
3438void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3439 const CommandOptions& options, long dumpsysTimeoutMs) {
3440 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3441 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3442 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3443 RunCommand(title, dumpsys, options);
3444}
3445
3446int open_socket(const char *service) {
3447 int s = android_get_control_socket(service);
3448 if (s < 0) {
3449 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3450 return -1;
3451 }
3452 fcntl(s, F_SETFD, FD_CLOEXEC);
3453
3454 // Set backlog to 0 to make sure that queue size will be minimum.
3455 // In Linux, because the minimum queue will be 1, connect() will be blocked
3456 // if the other clients already called connect() and the connection request was not accepted.
3457 if (listen(s, 0) < 0) {
3458 MYLOGE("listen(control socket): %s\n", strerror(errno));
3459 return -1;
3460 }
3461
3462 struct sockaddr addr;
3463 socklen_t alen = sizeof(addr);
3464 int fd = accept(s, &addr, &alen);
3465
3466 // Close socket just after accept(), to make sure that connect() by client will get error
3467 // when the socket is used by the other services.
3468 // There is still a race condition possibility between accept and close, but there is no way
3469 // to close-on-accept atomically.
3470 // See detail; b/123306389#comment25
3471 close(s);
3472
3473 if (fd < 0) {
3474 MYLOGE("accept(control socket): %s\n", strerror(errno));
3475 return -1;
3476 }
3477
3478 return fd;
3479}
3480
3481/* redirect output to a service control socket */
3482bool redirect_to_socket(FILE* redirect, const char* service) {
3483 int fd = open_socket(service);
3484 if (fd == -1) {
3485 return false;
3486 }
3487 fflush(redirect);
3488 // TODO: handle dup2 failure
3489 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3490 close(fd);
3491 return true;
3492}
3493
3494// TODO: should call is_valid_output_file and/or be merged into it.
3495void create_parent_dirs(const char *path) {
3496 char *chp = const_cast<char *> (path);
3497
3498 /* skip initial slash */
3499 if (chp[0] == '/')
3500 chp++;
3501
3502 /* create leading directories, if necessary */
3503 struct stat dir_stat;
3504 while (chp && chp[0]) {
3505 chp = strchr(chp, '/');
3506 if (chp) {
3507 *chp = 0;
3508 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3509 MYLOGI("Creating directory %s\n", path);
3510 if (mkdir(path, 0770)) { /* drwxrwx--- */
3511 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3512 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3513 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3514 }
3515 }
3516 *chp++ = '/';
3517 }
3518 }
3519}
3520
3521bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3522 create_parent_dirs(path);
3523
3524 int fd = TEMP_FAILURE_RETRY(open(path,
3525 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3526 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3527 if (fd < 0) {
3528 MYLOGE("%s: %s\n", path, strerror(errno));
3529 return false;
3530 }
3531
3532 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3533 close(fd);
3534 return true;
3535}
3536
3537bool redirect_to_file(FILE* redirect, char* path) {
3538 return _redirect_to_file(redirect, path, O_TRUNC);
3539}
3540
3541bool redirect_to_existing_file(FILE* redirect, char* path) {
3542 return _redirect_to_file(redirect, path, O_APPEND);
3543}
3544
3545void dump_route_tables() {
3546 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3547 if (PropertiesHelper::IsDryRun()) return;
3548 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3549 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3550 FILE* fp = fopen(RT_TABLES_PATH, "re");
3551 if (!fp) {
3552 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3553 return;
3554 }
3555 char table[16];
3556 // Each line has an integer (the table number), a space, and a string (the table name). We only
3557 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3558 // Add a fixed max limit so this doesn't go awry.
3559 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3560 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3561 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3562 }
3563 fclose(fp);
3564}
3565
3566// TODO: make this function thread safe if sections are generated in parallel.
3567void Dumpstate::UpdateProgress(int32_t delta_sec) {
3568 if (progress_ == nullptr) {
3569 MYLOGE("UpdateProgress: progress_ not set\n");
3570 return;
3571 }
3572
3573 // Always update progess so stats can be tuned...
3574 bool max_changed = progress_->Inc(delta_sec);
3575
3576 // ...but only notifiy listeners when necessary.
3577 if (!options_->do_progress_updates) return;
3578
3579 int progress = progress_->Get();
3580 int max = progress_->GetMax();
3581
3582 // adjusts max on the fly
3583 if (max_changed && listener_ != nullptr) {
3584 listener_->onMaxProgressUpdated(max);
3585 }
3586
3587 int32_t last_update_delta = progress - last_updated_progress_;
3588 if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
3589 return;
3590 }
3591 last_updated_progress_ = progress;
3592
3593 if (control_socket_fd_ >= 0) {
3594 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3595 fsync(control_socket_fd_);
3596 }
3597
3598 int percent = 100 * progress / max;
3599 if (listener_ != nullptr) {
3600 if (percent % 5 == 0) {
3601 // We don't want to spam logcat, so only log multiples of 5.
3602 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3603 percent);
3604 } else {
3605 // stderr is ignored on normal invocations, but useful when calling
3606 // /system/bin/dumpstate directly for debuggging.
3607 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3608 progress, max, percent);
3609 }
3610 // TODO(b/111441001): Remove in favor of onProgress
3611 listener_->onProgressUpdated(progress);
3612
3613 listener_->onProgress(percent);
3614 }
3615}
3616
3617void Dumpstate::TakeScreenshot(const std::string& path) {
3618 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3619 int status =
3620 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3621 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3622 if (status == 0) {
3623 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3624 } else {
3625 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3626 }
3627}
3628
3629bool is_dir(const char* pathname) {
3630 struct stat info;
3631 if (stat(pathname, &info) == -1) {
3632 return false;
3633 }
3634 return S_ISDIR(info.st_mode);
3635}
3636
3637time_t get_mtime(int fd, time_t default_mtime) {
3638 struct stat info;
3639 if (fstat(fd, &info) == -1) {
3640 return default_mtime;
3641 }
3642 return info.st_mtime;
3643}
3644
3645void dump_emmc_ecsd(const char *ext_csd_path) {
3646 // List of interesting offsets
3647 struct hex {
3648 char str[2];
3649 };
3650 static const size_t EXT_CSD_REV = 192 * sizeof(hex);
3651 static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
3652 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
3653 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
3654
3655 std::string buffer;
3656 if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
3657 return;
3658 }
3659
3660 printf("------ %s Extended CSD ------\n", ext_csd_path);
3661
3662 if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
3663 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3664 return;
3665 }
3666
3667 int ext_csd_rev = 0;
3668 std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
3669 if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
3670 printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3671 return;
3672 }
3673
3674 static const char *ver_str[] = {
3675 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
3676 };
3677 printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
3678 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
3679 : "Unknown");
3680 if (ext_csd_rev < 7) {
3681 printf("\n");
3682 return;
3683 }
3684
3685 if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
3686 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3687 return;
3688 }
3689
3690 int ext_pre_eol_info = 0;
3691 sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
3692 if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
3693 printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3694 return;
3695 }
3696
3697 static const char *eol_str[] = {
3698 "Undefined",
3699 "Normal",
3700 "Warning (consumed 80% of reserve)",
3701 "Urgent (consumed 90% of reserve)"
3702 };
3703 printf(
3704 "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
3705 eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
3706 : 0]);
3707
3708 for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
3709 lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
3710 lifetime += sizeof(hex)) {
3711 int ext_device_life_time_est;
3712 static const char *est_str[] = {
3713 "Undefined",
3714 "0-10% of device lifetime used",
3715 "10-20% of device lifetime used",
3716 "20-30% of device lifetime used",
3717 "30-40% of device lifetime used",
3718 "40-50% of device lifetime used",
3719 "50-60% of device lifetime used",
3720 "60-70% of device lifetime used",
3721 "70-80% of device lifetime used",
3722 "80-90% of device lifetime used",
3723 "90-100% of device lifetime used",
3724 "Exceeded the maximum estimated device lifetime",
3725 };
3726
3727 if (buffer.length() < (lifetime + sizeof(hex))) {
3728 printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
3729 break;
3730 }
3731
3732 ext_device_life_time_est = 0;
3733 sub = buffer.substr(lifetime, sizeof(hex));
3734 if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
3735 printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
3736 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3737 sub.c_str());
3738 continue;
3739 }
3740 printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
3741 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3742 ext_device_life_time_est,
3743 est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
3744 ? ext_device_life_time_est
3745 : 0]);
3746 }
3747
3748 printf("\n");
3749}
3750