blob: fe55fe7d4b14a9456ed66978c0c5ab307a285693 [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) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01001992 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01001993 }
1994 ds.tmp_path_ = ds.GetPath(".tmp");
1995 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1996
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01001997 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00001998 ? 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) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002011 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002012 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()) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002046 std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002047 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.
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002064 std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt383d0c12018-11-30 15:54:56 +00002065 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) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002611 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002612 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
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002719bool Dumpstate::CalledByApi() const {
2720 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2721}
2722
Nandana Duttd2f5f082019-01-18 17:13:52 +00002723void Dumpstate::CleanupFiles() {
2724 android::os::UnlinkAndLogOnError(tmp_path_);
2725 android::os::UnlinkAndLogOnError(screenshot_path_);
2726 android::os::UnlinkAndLogOnError(path_);
2727}
2728
2729Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2730 MYLOGD("User denied consent; deleting files and returning\n");
2731 CleanupFiles();
2732 return USER_CONSENT_DENIED;
2733}
2734
2735Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2736 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2737 // user consent.
2738 UserConsentResult consent_result = consent_callback_->getResult();
2739 if (consent_result == UserConsentResult::UNAVAILABLE) {
2740 // User has not responded yet.
2741 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2742 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2743 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2744 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2745 sleep(delay_seconds);
2746 }
2747 consent_result = consent_callback_->getResult();
2748 }
2749 if (consent_result == UserConsentResult::DENIED) {
2750 // User has explicitly denied sharing with the app. To be safe delete the
2751 // internal bugreport & tmp files.
2752 return HandleUserConsentDenied();
2753 }
2754 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002755 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2756 if (copy_succeeded) {
2757 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002758 }
2759 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2760 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2761 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2762 // Since we do not have user consent to share the bugreport it does not get
2763 // copied over to the calling app but remains in the internal directory from
2764 // where the user can manually pull it.
2765 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2766 }
2767 // Unknown result; must be a programming error.
2768 MYLOGE("Unknown user consent result:%d\n", consent_result);
2769 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002770}
2771
Nandana Duttf02564e2019-02-15 15:24:24 +00002772Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002773 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2774 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2775 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002776 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002777 // When directly running dumpstate binary, the output is not expected to be written
2778 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002779 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002780
2781 // calling_uid and calling_package are for user consent to share the bugreport with
2782 // an app; they are irrelvant here because bugreport is only written to a local
2783 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002784 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002785 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002786 return status;
2787}
2788
2789/* Main entry point for dumpstate binary. */
2790int run_main(int argc, char* argv[]) {
2791 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002792
2793 switch (status) {
2794 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002795 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002796 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002797 ShowUsage();
2798 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002799 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002800 fprintf(stderr, "Invalid combination of args\n");
2801 ShowUsage();
2802 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002803 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002804 FALLTHROUGH_INTENDED;
2805 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2806 FALLTHROUGH_INTENDED;
2807 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002808 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002809 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002810}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002811
2812// TODO(111441001): Default DumpOptions to sensible values.
2813Dumpstate::Dumpstate(const std::string& version)
2814 : pid_(getpid()),
2815 options_(new Dumpstate::DumpOptions()),
2816 version_(version),
2817 now_(time(nullptr)) {
2818}
2819
2820Dumpstate& Dumpstate::GetInstance() {
2821 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2822 return singleton_;
2823}
2824
2825DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
2826 : title_(title), logcat_only_(logcat_only) {
2827 if (!title_.empty()) {
2828 started_ = Nanotime();
2829 }
2830}
2831
2832DurationReporter::~DurationReporter() {
2833 if (!title_.empty()) {
2834 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2835 if (elapsed < .5f) {
2836 return;
2837 }
2838 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2839 if (logcat_only_) {
2840 return;
2841 }
2842 // Use "Yoda grammar" to make it easier to grep|sort sections.
2843 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2844 }
2845}
2846
2847const int32_t Progress::kDefaultMax = 5000;
2848
2849Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2850}
2851
2852Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2853 : Progress(initial_max, growth_factor, "") {
2854 progress_ = progress;
2855}
2856
2857Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2858 : initial_max_(initial_max),
2859 progress_(0),
2860 max_(initial_max),
2861 growth_factor_(growth_factor),
2862 n_runs_(0),
2863 average_max_(0),
2864 path_(path) {
2865 if (!path_.empty()) {
2866 Load();
2867 }
2868}
2869
2870void Progress::Load() {
2871 MYLOGD("Loading stats from %s\n", path_.c_str());
2872 std::string content;
2873 if (!android::base::ReadFileToString(path_, &content)) {
2874 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2875 return;
2876 }
2877 if (content.empty()) {
2878 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2879 return;
2880 }
2881 std::vector<std::string> lines = android::base::Split(content, "\n");
2882
2883 if (lines.size() < 1) {
2884 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2885 (int)lines.size(), max_);
2886 return;
2887 }
2888 char* ptr;
2889 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2890 average_max_ = strtol(ptr, nullptr, 10);
2891 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2892 average_max_ > STATS_MAX_AVERAGE) {
2893 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2894 initial_max_ = Progress::kDefaultMax;
2895 } else {
2896 initial_max_ = average_max_;
2897 }
2898 max_ = initial_max_;
2899
2900 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2901}
2902
2903void Progress::Save() {
2904 int32_t total = n_runs_ * average_max_ + progress_;
2905 int32_t runs = n_runs_ + 1;
2906 int32_t average = floor(((float)total) / runs);
2907 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2908 path_.c_str());
2909 if (path_.empty()) {
2910 return;
2911 }
2912
2913 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2914 if (!android::base::WriteStringToFile(content, path_)) {
2915 MYLOGE("Could not save stats on %s\n", path_.c_str());
2916 }
2917}
2918
2919int32_t Progress::Get() const {
2920 return progress_;
2921}
2922
2923bool Progress::Inc(int32_t delta_sec) {
2924 bool changed = false;
2925 if (delta_sec >= 0) {
2926 progress_ += delta_sec;
2927 if (progress_ > max_) {
2928 int32_t old_max = max_;
2929 max_ = floor((float)progress_ * growth_factor_);
2930 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2931 changed = true;
2932 }
2933 }
2934 return changed;
2935}
2936
2937int32_t Progress::GetMax() const {
2938 return max_;
2939}
2940
2941int32_t Progress::GetInitialMax() const {
2942 return initial_max_;
2943}
2944
2945void Progress::Dump(int fd, const std::string& prefix) const {
2946 const char* pr = prefix.c_str();
2947 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2948 dprintf(fd, "%smax: %d\n", pr, max_);
2949 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2950 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2951 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2952 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2953 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2954}
2955
2956bool Dumpstate::IsZipping() const {
2957 return zip_writer_ != nullptr;
2958}
2959
2960std::string Dumpstate::GetPath(const std::string& suffix) const {
2961 return GetPath(bugreport_internal_dir_, suffix);
2962}
2963
2964std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2965 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2966 name_.c_str(), suffix.c_str());
2967}
2968
2969void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2970 progress_ = std::move(progress);
2971}
2972
2973void for_each_userid(void (*func)(int), const char *header) {
2974 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2975 "for_each_userid(%s)", header);
2976 DurationReporter duration_reporter(title);
2977 if (PropertiesHelper::IsDryRun()) return;
2978
2979 DIR *d;
2980 struct dirent *de;
2981
2982 if (header) printf("\n------ %s ------\n", header);
2983 func(0);
2984
2985 if (!(d = opendir("/data/system/users"))) {
2986 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2987 return;
2988 }
2989
2990 while ((de = readdir(d))) {
2991 int userid;
2992 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2993 continue;
2994 }
2995 func(userid);
2996 }
2997
2998 closedir(d);
2999}
3000
3001static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3002 DIR *d;
3003 struct dirent *de;
3004
3005 if (!(d = opendir("/proc"))) {
3006 printf("Failed to open /proc (%s)\n", strerror(errno));
3007 return;
3008 }
3009
3010 if (header) printf("\n------ %s ------\n", header);
3011 while ((de = readdir(d))) {
3012 if (ds.IsUserConsentDenied()) {
3013 MYLOGE(
3014 "Returning early because user denied consent to share bugreport with calling app.");
3015 closedir(d);
3016 return;
3017 }
3018 int pid;
3019 int fd;
3020 char cmdpath[255];
3021 char cmdline[255];
3022
3023 if (!(pid = atoi(de->d_name))) {
3024 continue;
3025 }
3026
3027 memset(cmdline, 0, sizeof(cmdline));
3028
3029 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3030 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3031 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3032 close(fd);
3033 if (cmdline[0]) {
3034 helper(pid, cmdline, arg);
3035 continue;
3036 }
3037 }
3038
3039 // if no cmdline, a kernel thread has comm
3040 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3041 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3042 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3043 close(fd);
3044 if (cmdline[1]) {
3045 cmdline[0] = '[';
3046 size_t len = strcspn(cmdline, "\f\b\r\n");
3047 cmdline[len] = ']';
3048 cmdline[len+1] = '\0';
3049 }
3050 }
3051 if (!cmdline[0]) {
3052 strcpy(cmdline, "N/A");
3053 }
3054 helper(pid, cmdline, arg);
3055 }
3056
3057 closedir(d);
3058}
3059
3060static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3061 for_each_pid_func *func = (for_each_pid_func*) arg;
3062 func(pid, cmdline);
3063}
3064
3065void for_each_pid(for_each_pid_func func, const char *header) {
3066 std::string title = header == nullptr ? "for_each_pid"
3067 : android::base::StringPrintf("for_each_pid(%s)", header);
3068 DurationReporter duration_reporter(title);
3069 if (PropertiesHelper::IsDryRun()) return;
3070
3071 __for_each_pid(for_each_pid_helper, header, (void *) func);
3072}
3073
3074static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3075 DIR *d;
3076 struct dirent *de;
3077 char taskpath[255];
3078 for_each_tid_func *func = (for_each_tid_func *) arg;
3079
3080 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3081
3082 if (!(d = opendir(taskpath))) {
3083 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3084 return;
3085 }
3086
3087 func(pid, pid, cmdline);
3088
3089 while ((de = readdir(d))) {
3090 if (ds.IsUserConsentDenied()) {
3091 MYLOGE(
3092 "Returning early because user denied consent to share bugreport with calling app.");
3093 closedir(d);
3094 return;
3095 }
3096 int tid;
3097 int fd;
3098 char commpath[255];
3099 char comm[255];
3100
3101 if (!(tid = atoi(de->d_name))) {
3102 continue;
3103 }
3104
3105 if (tid == pid)
3106 continue;
3107
3108 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3109 memset(comm, 0, sizeof(comm));
3110 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3111 strcpy(comm, "N/A");
3112 } else {
3113 char *c;
3114 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3115 close(fd);
3116
3117 c = strrchr(comm, '\n');
3118 if (c) {
3119 *c = '\0';
3120 }
3121 }
3122 func(pid, tid, comm);
3123 }
3124
3125 closedir(d);
3126}
3127
3128void for_each_tid(for_each_tid_func func, const char *header) {
3129 std::string title = header == nullptr ? "for_each_tid"
3130 : android::base::StringPrintf("for_each_tid(%s)", header);
3131 DurationReporter duration_reporter(title);
3132
3133 if (PropertiesHelper::IsDryRun()) return;
3134
3135 __for_each_pid(for_each_tid_helper, header, (void *) func);
3136}
3137
3138void show_wchan(int pid, int tid, const char *name) {
3139 if (PropertiesHelper::IsDryRun()) return;
3140
3141 char path[255];
3142 char buffer[255];
3143 int fd, ret, save_errno;
3144 char name_buffer[255];
3145
3146 memset(buffer, 0, sizeof(buffer));
3147
3148 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3149 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3150 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3151 return;
3152 }
3153
3154 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3155 save_errno = errno;
3156 close(fd);
3157
3158 if (ret < 0) {
3159 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3160 return;
3161 }
3162
3163 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3164 pid == tid ? 0 : 3, "", name);
3165
3166 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3167
3168 return;
3169}
3170
3171// print time in centiseconds
3172static void snprcent(char *buffer, size_t len, size_t spc,
3173 unsigned long long time) {
3174 static long hz; // cache discovered hz
3175
3176 if (hz <= 0) {
3177 hz = sysconf(_SC_CLK_TCK);
3178 if (hz <= 0) {
3179 hz = 1000;
3180 }
3181 }
3182
3183 // convert to centiseconds
3184 time = (time * 100 + (hz / 2)) / hz;
3185
3186 char str[16];
3187
3188 snprintf(str, sizeof(str), " %llu.%02u",
3189 time / 100, (unsigned)(time % 100));
3190 size_t offset = strlen(buffer);
3191 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3192 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3193}
3194
3195// print permille as a percent
3196static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3197 char str[16];
3198
3199 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3200 size_t offset = strlen(buffer);
3201 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3202 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3203}
3204
3205void show_showtime(int pid, const char *name) {
3206 if (PropertiesHelper::IsDryRun()) return;
3207
3208 char path[255];
3209 char buffer[1023];
3210 int fd, ret, save_errno;
3211
3212 memset(buffer, 0, sizeof(buffer));
3213
3214 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3215 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3216 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3217 return;
3218 }
3219
3220 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3221 save_errno = errno;
3222 close(fd);
3223
3224 if (ret < 0) {
3225 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3226 return;
3227 }
3228
3229 // field 14 is utime
3230 // field 15 is stime
3231 // field 42 is iotime
3232 unsigned long long utime = 0, stime = 0, iotime = 0;
3233 if (sscanf(buffer,
3234 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3235 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3236 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3237 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3238 &utime, &stime, &iotime) != 3) {
3239 return;
3240 }
3241
3242 unsigned long long total = utime + stime;
3243 if (!total) {
3244 return;
3245 }
3246
3247 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3248 if (permille > 1000) {
3249 permille = 1000;
3250 }
3251
3252 // try to beautify and stabilize columns at <80 characters
3253 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3254 if ((name[0] != '[') || utime) {
3255 snprcent(buffer, sizeof(buffer), 57, utime);
3256 }
3257 snprcent(buffer, sizeof(buffer), 65, stime);
3258 if ((name[0] != '[') || iotime) {
3259 snprcent(buffer, sizeof(buffer), 73, iotime);
3260 }
3261 if (iotime) {
3262 snprdec(buffer, sizeof(buffer), 79, permille);
3263 }
3264 puts(buffer); // adds a trailing newline
3265
3266 return;
3267}
3268
3269void do_dmesg() {
3270 const char *title = "KERNEL LOG (dmesg)";
3271 DurationReporter duration_reporter(title);
3272 printf("------ %s ------\n", title);
3273
3274 if (PropertiesHelper::IsDryRun()) return;
3275
3276 /* Get size of kernel buffer */
3277 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3278 if (size <= 0) {
3279 printf("Unexpected klogctl return value: %d\n\n", size);
3280 return;
3281 }
3282 char *buf = (char *) malloc(size + 1);
3283 if (buf == nullptr) {
3284 printf("memory allocation failed\n\n");
3285 return;
3286 }
3287 int retval = klogctl(KLOG_READ_ALL, buf, size);
3288 if (retval < 0) {
3289 printf("klogctl failure\n\n");
3290 free(buf);
3291 return;
3292 }
3293 buf[retval] = '\0';
3294 printf("%s\n\n", buf);
3295 free(buf);
3296 return;
3297}
3298
3299void do_showmap(int pid, const char *name) {
3300 char title[255];
3301 char arg[255];
3302
3303 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3304 snprintf(arg, sizeof(arg), "%d", pid);
3305 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3306}
3307
3308int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3309 DurationReporter duration_reporter(title);
3310
3311 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3312
3313 UpdateProgress(WEIGHT_FILE);
3314
3315 return status;
3316}
3317
3318int read_file_as_long(const char *path, long int *output) {
3319 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3320 if (fd < 0) {
3321 int err = errno;
3322 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3323 return -1;
3324 }
3325 char buffer[50];
3326 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3327 if (bytes_read == -1) {
3328 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3329 return -2;
3330 }
3331 if (bytes_read == 0) {
3332 MYLOGE("File %s is empty\n", path);
3333 return -3;
3334 }
3335 *output = atoi(buffer);
3336 return 0;
3337}
3338
3339/* calls skip to gate calling dump_from_fd recursively
3340 * in the specified directory. dump_from_fd defaults to
3341 * dump_file_from_fd above when set to NULL. skip defaults
3342 * to false when set to NULL. dump_from_fd will always be
3343 * called with title NULL.
3344 */
3345int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3346 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3347 DurationReporter duration_reporter(title);
3348 DIR *dirp;
3349 struct dirent *d;
3350 char *newpath = nullptr;
3351 const char *slash = "/";
3352 int retval = 0;
3353
3354 if (!title.empty()) {
3355 printf("------ %s (%s) ------\n", title.c_str(), dir);
3356 }
3357 if (PropertiesHelper::IsDryRun()) return 0;
3358
3359 if (dir[strlen(dir) - 1] == '/') {
3360 ++slash;
3361 }
3362 dirp = opendir(dir);
3363 if (dirp == nullptr) {
3364 retval = -errno;
3365 MYLOGE("%s: %s\n", dir, strerror(errno));
3366 return retval;
3367 }
3368
3369 if (!dump_from_fd) {
3370 dump_from_fd = dump_file_from_fd;
3371 }
3372 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3373 if ((d->d_name[0] == '.')
3374 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3375 || (d->d_name[1] == '\0'))) {
3376 continue;
3377 }
3378 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3379 (d->d_type == DT_DIR) ? "/" : "");
3380 if (!newpath) {
3381 retval = -errno;
3382 continue;
3383 }
3384 if (skip && (*skip)(newpath)) {
3385 continue;
3386 }
3387 if (d->d_type == DT_DIR) {
3388 int ret = dump_files("", newpath, skip, dump_from_fd);
3389 if (ret < 0) {
3390 retval = ret;
3391 }
3392 continue;
3393 }
3394 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3395 if (fd.get() < 0) {
3396 retval = -1;
3397 printf("*** %s: %s\n", newpath, strerror(errno));
3398 continue;
3399 }
3400 (*dump_from_fd)(nullptr, newpath, fd.get());
3401 }
3402 closedir(dirp);
3403 if (!title.empty()) {
3404 printf("\n");
3405 }
3406 return retval;
3407}
3408
3409/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3410 * it's possible to avoid issues where opening the file itself can get
3411 * stuck.
3412 */
3413int dump_file_from_fd(const char *title, const char *path, int fd) {
3414 if (PropertiesHelper::IsDryRun()) return 0;
3415
3416 int flags = fcntl(fd, F_GETFL);
3417 if (flags == -1) {
3418 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3419 return -1;
3420 } else if (!(flags & O_NONBLOCK)) {
3421 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3422 return -1;
3423 }
3424 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3425}
3426
3427int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3428 const CommandOptions& options) {
3429 DurationReporter duration_reporter(title);
3430
3431 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3432
3433 /* TODO: for now we're simplifying the progress calculation by using the
3434 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3435 * where its weight should be much higher proportionally to its timeout.
3436 * Ideally, it should use a options.EstimatedDuration() instead...*/
3437 UpdateProgress(options.Timeout());
3438
3439 return status;
3440}
3441
3442void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3443 const CommandOptions& options, long dumpsysTimeoutMs) {
3444 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3445 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3446 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3447 RunCommand(title, dumpsys, options);
3448}
3449
3450int open_socket(const char *service) {
3451 int s = android_get_control_socket(service);
3452 if (s < 0) {
3453 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3454 return -1;
3455 }
3456 fcntl(s, F_SETFD, FD_CLOEXEC);
3457
3458 // Set backlog to 0 to make sure that queue size will be minimum.
3459 // In Linux, because the minimum queue will be 1, connect() will be blocked
3460 // if the other clients already called connect() and the connection request was not accepted.
3461 if (listen(s, 0) < 0) {
3462 MYLOGE("listen(control socket): %s\n", strerror(errno));
3463 return -1;
3464 }
3465
3466 struct sockaddr addr;
3467 socklen_t alen = sizeof(addr);
3468 int fd = accept(s, &addr, &alen);
3469
3470 // Close socket just after accept(), to make sure that connect() by client will get error
3471 // when the socket is used by the other services.
3472 // There is still a race condition possibility between accept and close, but there is no way
3473 // to close-on-accept atomically.
3474 // See detail; b/123306389#comment25
3475 close(s);
3476
3477 if (fd < 0) {
3478 MYLOGE("accept(control socket): %s\n", strerror(errno));
3479 return -1;
3480 }
3481
3482 return fd;
3483}
3484
3485/* redirect output to a service control socket */
3486bool redirect_to_socket(FILE* redirect, const char* service) {
3487 int fd = open_socket(service);
3488 if (fd == -1) {
3489 return false;
3490 }
3491 fflush(redirect);
3492 // TODO: handle dup2 failure
3493 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3494 close(fd);
3495 return true;
3496}
3497
3498// TODO: should call is_valid_output_file and/or be merged into it.
3499void create_parent_dirs(const char *path) {
3500 char *chp = const_cast<char *> (path);
3501
3502 /* skip initial slash */
3503 if (chp[0] == '/')
3504 chp++;
3505
3506 /* create leading directories, if necessary */
3507 struct stat dir_stat;
3508 while (chp && chp[0]) {
3509 chp = strchr(chp, '/');
3510 if (chp) {
3511 *chp = 0;
3512 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3513 MYLOGI("Creating directory %s\n", path);
3514 if (mkdir(path, 0770)) { /* drwxrwx--- */
3515 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3516 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3517 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3518 }
3519 }
3520 *chp++ = '/';
3521 }
3522 }
3523}
3524
3525bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3526 create_parent_dirs(path);
3527
3528 int fd = TEMP_FAILURE_RETRY(open(path,
3529 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3530 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3531 if (fd < 0) {
3532 MYLOGE("%s: %s\n", path, strerror(errno));
3533 return false;
3534 }
3535
3536 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3537 close(fd);
3538 return true;
3539}
3540
3541bool redirect_to_file(FILE* redirect, char* path) {
3542 return _redirect_to_file(redirect, path, O_TRUNC);
3543}
3544
3545bool redirect_to_existing_file(FILE* redirect, char* path) {
3546 return _redirect_to_file(redirect, path, O_APPEND);
3547}
3548
3549void dump_route_tables() {
3550 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3551 if (PropertiesHelper::IsDryRun()) return;
3552 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3553 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3554 FILE* fp = fopen(RT_TABLES_PATH, "re");
3555 if (!fp) {
3556 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3557 return;
3558 }
3559 char table[16];
3560 // Each line has an integer (the table number), a space, and a string (the table name). We only
3561 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3562 // Add a fixed max limit so this doesn't go awry.
3563 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3564 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3565 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3566 }
3567 fclose(fp);
3568}
3569
3570// TODO: make this function thread safe if sections are generated in parallel.
3571void Dumpstate::UpdateProgress(int32_t delta_sec) {
3572 if (progress_ == nullptr) {
3573 MYLOGE("UpdateProgress: progress_ not set\n");
3574 return;
3575 }
3576
3577 // Always update progess so stats can be tuned...
3578 bool max_changed = progress_->Inc(delta_sec);
3579
3580 // ...but only notifiy listeners when necessary.
3581 if (!options_->do_progress_updates) return;
3582
3583 int progress = progress_->Get();
3584 int max = progress_->GetMax();
3585
3586 // adjusts max on the fly
3587 if (max_changed && listener_ != nullptr) {
3588 listener_->onMaxProgressUpdated(max);
3589 }
3590
3591 int32_t last_update_delta = progress - last_updated_progress_;
3592 if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
3593 return;
3594 }
3595 last_updated_progress_ = progress;
3596
3597 if (control_socket_fd_ >= 0) {
3598 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3599 fsync(control_socket_fd_);
3600 }
3601
3602 int percent = 100 * progress / max;
3603 if (listener_ != nullptr) {
3604 if (percent % 5 == 0) {
3605 // We don't want to spam logcat, so only log multiples of 5.
3606 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3607 percent);
3608 } else {
3609 // stderr is ignored on normal invocations, but useful when calling
3610 // /system/bin/dumpstate directly for debuggging.
3611 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3612 progress, max, percent);
3613 }
3614 // TODO(b/111441001): Remove in favor of onProgress
3615 listener_->onProgressUpdated(progress);
3616
3617 listener_->onProgress(percent);
3618 }
3619}
3620
3621void Dumpstate::TakeScreenshot(const std::string& path) {
3622 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3623 int status =
3624 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3625 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3626 if (status == 0) {
3627 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3628 } else {
3629 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3630 }
3631}
3632
3633bool is_dir(const char* pathname) {
3634 struct stat info;
3635 if (stat(pathname, &info) == -1) {
3636 return false;
3637 }
3638 return S_ISDIR(info.st_mode);
3639}
3640
3641time_t get_mtime(int fd, time_t default_mtime) {
3642 struct stat info;
3643 if (fstat(fd, &info) == -1) {
3644 return default_mtime;
3645 }
3646 return info.st_mtime;
3647}
3648
3649void dump_emmc_ecsd(const char *ext_csd_path) {
3650 // List of interesting offsets
3651 struct hex {
3652 char str[2];
3653 };
3654 static const size_t EXT_CSD_REV = 192 * sizeof(hex);
3655 static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
3656 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
3657 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
3658
3659 std::string buffer;
3660 if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
3661 return;
3662 }
3663
3664 printf("------ %s Extended CSD ------\n", ext_csd_path);
3665
3666 if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
3667 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3668 return;
3669 }
3670
3671 int ext_csd_rev = 0;
3672 std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
3673 if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
3674 printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3675 return;
3676 }
3677
3678 static const char *ver_str[] = {
3679 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
3680 };
3681 printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
3682 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
3683 : "Unknown");
3684 if (ext_csd_rev < 7) {
3685 printf("\n");
3686 return;
3687 }
3688
3689 if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
3690 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3691 return;
3692 }
3693
3694 int ext_pre_eol_info = 0;
3695 sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
3696 if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
3697 printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3698 return;
3699 }
3700
3701 static const char *eol_str[] = {
3702 "Undefined",
3703 "Normal",
3704 "Warning (consumed 80% of reserve)",
3705 "Urgent (consumed 90% of reserve)"
3706 };
3707 printf(
3708 "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
3709 eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
3710 : 0]);
3711
3712 for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
3713 lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
3714 lifetime += sizeof(hex)) {
3715 int ext_device_life_time_est;
3716 static const char *est_str[] = {
3717 "Undefined",
3718 "0-10% of device lifetime used",
3719 "10-20% of device lifetime used",
3720 "20-30% of device lifetime used",
3721 "30-40% of device lifetime used",
3722 "40-50% of device lifetime used",
3723 "50-60% of device lifetime used",
3724 "60-70% of device lifetime used",
3725 "70-80% of device lifetime used",
3726 "80-90% of device lifetime used",
3727 "90-100% of device lifetime used",
3728 "Exceeded the maximum estimated device lifetime",
3729 };
3730
3731 if (buffer.length() < (lifetime + sizeof(hex))) {
3732 printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
3733 break;
3734 }
3735
3736 ext_device_life_time_est = 0;
3737 sub = buffer.substr(lifetime, sizeof(hex));
3738 if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
3739 printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
3740 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3741 sub.c_str());
3742 continue;
3743 }
3744 printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
3745 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3746 ext_device_life_time_est,
3747 est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
3748 ? ext_device_life_time_est
3749 : 0]);
3750 }
3751
3752 printf("\n");
3753}
3754