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