blob: bdb13634f2d12a9e4890b12c4b9b586ff7537ade [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>
Felipe Lemead5f6c42015-11-30 14:26:46 -080022#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070023#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010024#include <math.h>
25#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070026#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080030#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070031#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032#include <sys/resource.h>
33#include <sys/stat.h>
34#include <sys/time.h>
35#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010036#include <signal.h>
37#include <stdarg.h>
38#include <string.h>
39#include <sys/capability.h>
40#include <sys/inotify.h>
41#include <sys/klog.h>
42#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070043#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070044
45#include <chrono>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000046#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070047#include <functional>
48#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010049#include <memory>
50#include <regex>
51#include <set>
52#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070053#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010054#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070055
Felipe Leme96c2bbb2016-09-26 09:21:21 -070056#include <android-base/file.h>
57#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070058#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080059#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070060#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070061#include <android-base/unique_fd.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080062#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080063#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000064#include <android/os/IIncidentCompanion.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080065#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070066#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010067#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000068#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080069#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000070#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010071#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080072#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010073#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070074#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070075#include <private/android_filesystem_config.h>
76#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080077#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070078#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080079#include "DumpstateInternal.h"
Vishnu Naire97d6122018-01-18 13:58:56 -080080#include "DumpstateSectionReporter.h"
Felipe Leme75876a22016-10-27 16:31:27 -070081#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070082#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080083
Steven Morelandcb7ef822016-11-29 13:20:37 -080084using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080085using ::std::literals::chrono_literals::operator""ms;
86using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080087
Felipe Leme47e9be22016-12-21 15:37:07 -080088// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080089using android::defaultServiceManager;
90using android::Dumpsys;
91using android::INVALID_OPERATION;
92using android::IServiceManager;
93using android::OK;
94using android::sp;
95using android::status_t;
96using android::String16;
97using android::String8;
98using android::TIMED_OUT;
99using android::UNKNOWN_ERROR;
100using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000101using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000102using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800103using android::os::dumpstate::CommandOptions;
104using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800105using android::os::dumpstate::DumpstateSectionReporter;
Vishnu Naire97d6122018-01-18 13:58:56 -0800106using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100108// Keep in sync with
109// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
110static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
111
112/* Most simple commands have 10 as timeout, so 5 is a good estimate */
113static const int32_t WEIGHT_FILE = 5;
114
115// TODO: temporary variables and functions used during C++ refactoring
116static Dumpstate& ds = Dumpstate::GetInstance();
117static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
118 const CommandOptions& options = CommandOptions::DEFAULT) {
119 return ds.RunCommand(title, full_command, options);
120}
121
122// Reasonable value for max stats.
123static const int STATS_MAX_N_RUNS = 1000;
124static const long STATS_MAX_AVERAGE = 100000;
125
126CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
127
Nandana Duttd2f5f082019-01-18 17:13:52 +0000128typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
129
Colin Crossf45fa6b2012-03-26 12:38:26 -0700130/* read before root is shed */
131static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700132static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000133static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134
Felipe Leme1d486fe2016-10-14 18:06:47 -0700135// TODO: variables and functions below should be part of dumpstate object
136
Felipe Leme635ca312016-01-05 14:23:02 -0800137static std::set<std::string> mount_points;
138void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800139
Todd Poynor2a83daa2013-11-22 15:44:22 -0800140#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700141#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700142#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800143
Felipe Lemee82a27d2016-01-05 13:35:44 -0800144#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700145#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700146#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700147#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100148#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
149#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800150#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900151#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800152#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700153
Narayan Kamath8f788292017-05-25 13:20:39 +0100154// TODO(narayan): Since this information has to be kept in sync
155// with tombstoned, we should just put it in a common header.
156//
157// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100158static const std::string TOMBSTONE_DIR = "/data/tombstones/";
159static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
160static const std::string ANR_DIR = "/data/anr/";
161static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700162
Felipe Lemee844a9d2016-09-21 15:01:39 -0700163// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000164
Nandana Duttbbdb5b42019-03-12 10:52:56 +0000165#define RETURN_IF_USER_DENIED_CONSENT() \
166 if (ds.IsUserConsentDenied()) { \
167 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
168 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
169 }
170
171// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
172// if consent is found to be denied.
173#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
174 RETURN_IF_USER_DENIED_CONSENT(); \
175 func_ptr(__VA_ARGS__); \
176 RETURN_IF_USER_DENIED_CONSENT();
177
Sahana Raof35ed432019-07-12 10:47:52 +0100178static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
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
Nandana Dutt979388e2018-11-30 16:48:55 +0000239} // namespace
240} // namespace os
241} // namespace android
242
Felipe Leme678727a2016-09-21 17:22:11 -0700243static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800244 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800245 long dumpsysTimeoutMs = 0) {
246 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700247}
248static int DumpFile(const std::string& title, const std::string& path) {
249 return ds.DumpFile(title, path);
250}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800251
Felipe Lemee844a9d2016-09-21 15:01:39 -0700252// Relative directory (inside the zip) for all files copied as-is into the bugreport.
253static const std::string ZIP_ROOT_DIR = "FS";
254
Vishnu Naire97d6122018-01-18 13:58:56 -0800255static const std::string kProtoPath = "proto/";
256static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700257static const std::string kDumpstateBoardFiles[] = {
258 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700259 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700260};
261static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
262
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700263static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700264static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700265static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700266static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
267static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700268
Felipe Lemef0292972016-11-22 13:57:05 -0800269static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
270
Narayan Kamath8f788292017-05-25 13:20:39 +0100271/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100272 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
273 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
274 * is set, the vector only contains files that were written in the last 30 minutes.
Andreas Gamped0d76952017-08-22 13:08:37 -0700275 * If |limit_by_count| is set, the vector only contains the ten latest files.
Narayan Kamath8f788292017-05-25 13:20:39 +0100276 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700277static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
278 const std::string& file_prefix,
279 bool limit_by_mtime,
280 bool limit_by_count = true) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100281 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
282
Narayan Kamathbd863722017-06-01 18:50:12 +0100283 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100284
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700285 if (dump_dir == nullptr) {
286 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700287 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700288 }
289
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700290 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100291 struct dirent* entry = nullptr;
292 while ((entry = readdir(dump_dir.get()))) {
293 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100294 continue;
295 }
296
Narayan Kamathbd863722017-06-01 18:50:12 +0100297 const std::string base_name(entry->d_name);
298 if (base_name.find(file_prefix) != 0) {
299 continue;
300 }
301
302 const std::string abs_path = dir_path + base_name;
303 android::base::unique_fd fd(
304 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
305 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700306 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100307 break;
308 }
309
310 struct stat st = {};
311 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700312 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100313 continue;
314 }
315
Narayan Kamath3f31b632018-02-22 19:42:36 +0000316 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100317 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100318 continue;
319 }
320
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700321 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700322 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100323
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700324 // Sort in descending modification time so that we only keep the newest
325 // reports if |limit_by_count| is true.
326 std::sort(dump_data.begin(), dump_data.end(),
327 [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
Narayan Kamath8f788292017-05-25 13:20:39 +0100328
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700329 if (limit_by_count && dump_data.size() > 10) {
330 dump_data.erase(dump_data.begin() + 10, dump_data.end());
Andreas Gamped0d76952017-08-22 13:08:37 -0700331 }
332
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700333 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100334}
335
Narayan Kamathbd863722017-06-01 18:50:12 +0100336static bool AddDumps(const std::vector<DumpData>::const_iterator start,
337 const std::vector<DumpData>::const_iterator end,
338 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100339 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100340 for (auto it = start; it != end; ++it) {
341 const std::string& name = it->name;
342 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100343 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100344
345 // Seek to the beginning of the file before dumping any data. A given
346 // DumpData entry might be dumped multiple times in the report.
347 //
348 // For example, the most recent ANR entry is dumped to the body of the
349 // main entry and it also shows up as a separate entry in the bugreport
350 // ZIP file.
351 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
352 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
353 strerror(errno));
354 }
355
Narayan Kamath8f788292017-05-25 13:20:39 +0100356 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800357 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100358 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100359 }
360 } else {
361 dump_file_from_fd(type_name, name.c_str(), fd);
362 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100363 }
364
365 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700366}
367
Felipe Leme635ca312016-01-05 14:23:02 -0800368// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700369void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800370 char path[PATH_MAX];
371
372 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
373 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700374 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800375 char linkname[PATH_MAX];
376 ssize_t r = readlink(path, linkname, PATH_MAX);
377 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800378 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800379 return;
380 }
381 linkname[r] = '\0';
382
383 if (mount_points.find(linkname) == mount_points.end()) {
384 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700385 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700386 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800387 mount_points.insert(linkname);
388 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800389 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800390 }
391 }
392}
393
394void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700395 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700396 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800397 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800398 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700399 for_each_pid(do_mountinfo, nullptr);
400 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800401}
402
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700403static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
404{
405 DIR *d;
406 struct dirent *de;
407 char path[PATH_MAX];
408
409 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700410 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700411 return;
412 }
413
414 while ((de = readdir(d))) {
415 if (de->d_type != DT_LNK) {
416 continue;
417 }
418 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700419 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700420 }
421
422 closedir(d);
423}
424
Mark Salyzyn326842f2015-04-30 09:49:41 -0700425static bool skip_not_stat(const char *path) {
426 static const char stat[] = "/stat";
427 size_t len = strlen(path);
428 if (path[len - 1] == '/') { /* Directory? */
429 return false;
430 }
431 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
432}
433
Felipe Leme4c2d6632016-09-28 14:32:00 -0700434static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800435 return false;
436}
437
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700438unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700439
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800440//
441// stat offsets
442// Name units description
443// ---- ----- -----------
444// read I/Os requests number of read I/Os processed
445#define __STAT_READ_IOS 0
446// read merges requests number of read I/Os merged with in-queue I/O
447#define __STAT_READ_MERGES 1
448// read sectors sectors number of sectors read
449#define __STAT_READ_SECTORS 2
450// read ticks milliseconds total wait time for read requests
451#define __STAT_READ_TICKS 3
452// write I/Os requests number of write I/Os processed
453#define __STAT_WRITE_IOS 4
454// write merges requests number of write I/Os merged with in-queue I/O
455#define __STAT_WRITE_MERGES 5
456// write sectors sectors number of sectors written
457#define __STAT_WRITE_SECTORS 6
458// write ticks milliseconds total wait time for write requests
459#define __STAT_WRITE_TICKS 7
460// in_flight requests number of I/Os currently in flight
461#define __STAT_IN_FLIGHT 8
462// io_ticks milliseconds total time this block device has been active
463#define __STAT_IO_TICKS 9
464// time_in_queue milliseconds total wait time for all requests
465#define __STAT_IN_QUEUE 10
466#define __STAT_NUMBER_FIELD 11
467//
468// read I/Os, write I/Os
469// =====================
470//
471// These values increment when an I/O request completes.
472//
473// read merges, write merges
474// =========================
475//
476// These values increment when an I/O request is merged with an
477// already-queued I/O request.
478//
479// read sectors, write sectors
480// ===========================
481//
482// These values count the number of sectors read from or written to this
483// block device. The "sectors" in question are the standard UNIX 512-byte
484// sectors, not any device- or filesystem-specific block size. The
485// counters are incremented when the I/O completes.
486#define SECTOR_SIZE 512
487//
488// read ticks, write ticks
489// =======================
490//
491// These values count the number of milliseconds that I/O requests have
492// waited on this block device. If there are multiple I/O requests waiting,
493// these values will increase at a rate greater than 1000/second; for
494// example, if 60 read requests wait for an average of 30 ms, the read_ticks
495// field will increase by 60*30 = 1800.
496//
497// in_flight
498// =========
499//
500// This value counts the number of I/O requests that have been issued to
501// the device driver but have not yet completed. It does not include I/O
502// requests that are in the queue but not yet issued to the device driver.
503//
504// io_ticks
505// ========
506//
507// This value counts the number of milliseconds during which the device has
508// had I/O requests queued.
509//
510// time_in_queue
511// =============
512//
513// This value counts the number of milliseconds that I/O requests have waited
514// on this block device. If there are multiple I/O requests waiting, this
515// value will increase as the product of the number of milliseconds times the
516// number of requests waiting (see "read ticks" above for an example).
517#define S_TO_MS 1000
518//
519
Mark Salyzyn326842f2015-04-30 09:49:41 -0700520static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800521 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700522 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700523 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700524 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700525 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700526 getline(&buffer, &i, fp);
527 fclose(fp);
528 if (!buffer) {
529 return -errno;
530 }
531 i = strlen(buffer);
532 while ((i > 0) && (buffer[i - 1] == '\n')) {
533 buffer[--i] = '\0';
534 }
535 if (!*buffer) {
536 free(buffer);
537 return 0;
538 }
539 z = true;
540 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800541 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700542 if (fields[i] != 0) {
543 z = false;
544 }
545 }
546 if (z) { /* never accessed */
547 free(buffer);
548 return 0;
549 }
550
Wei Wang509bb5d2017-06-09 14:42:12 -0700551 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
552 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700553 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700554
555 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
556 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
557 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700558 free(buffer);
559
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800560 if (fields[__STAT_IO_TICKS]) {
561 unsigned long read_perf = 0;
562 unsigned long read_ios = 0;
563 if (fields[__STAT_READ_TICKS]) {
564 unsigned long long divisor = fields[__STAT_READ_TICKS]
565 * fields[__STAT_IO_TICKS];
566 read_perf = ((unsigned long long)SECTOR_SIZE
567 * fields[__STAT_READ_SECTORS]
568 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
569 / divisor;
570 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
571 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
572 / divisor;
573 }
574
575 unsigned long write_perf = 0;
576 unsigned long write_ios = 0;
577 if (fields[__STAT_WRITE_TICKS]) {
578 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
579 * fields[__STAT_IO_TICKS];
580 write_perf = ((unsigned long long)SECTOR_SIZE
581 * fields[__STAT_WRITE_SECTORS]
582 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
583 / divisor;
584 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
585 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
586 / divisor;
587 }
588
589 unsigned queue = (fields[__STAT_IN_QUEUE]
590 + (fields[__STAT_IO_TICKS] >> 1))
591 / fields[__STAT_IO_TICKS];
592
593 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700594 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 -0800595 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700596 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 -0800597 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800598 }
599
600 /* bugreport timeout factor adjustment */
601 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
602 worst_write_perf = write_perf;
603 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700604 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700605 return 0;
606}
607
Yao Chenbe3bbc12018-01-17 16:31:10 -0800608static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
609
610/* timeout in ms to read a list of buffers */
611static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
612 unsigned long timeout_ms = 0;
613 for (const auto& buffer : buffers) {
614 log_id_t id = android_name_to_log_id(buffer.c_str());
615 unsigned long property_size = __android_logger_get_buffer_size(id);
616 /* Engineering margin is ten-fold our guess */
617 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
618 }
619 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700620}
621
Nandana Duttd2f5f082019-01-18 17:13:52 +0000622Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
623}
624
625android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
626 std::lock_guard<std::mutex> lock(lock_);
627 result_ = APPROVED;
628 MYLOGD("User approved consent to share bugreport\n");
629 return android::binder::Status::ok();
630}
631
632android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
633 std::lock_guard<std::mutex> lock(lock_);
634 result_ = DENIED;
635 MYLOGW("User denied consent to share bugreport\n");
636 return android::binder::Status::ok();
637}
638
639UserConsentResult Dumpstate::ConsentCallback::getResult() {
640 std::lock_guard<std::mutex> lock(lock_);
641 return result_;
642}
643
644uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
645 return Nanotime() - start_time_;
646}
647
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700648void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700649 std::string build, fingerprint, radio, bootloader, network;
650 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700651
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700652 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
653 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700654 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
655 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
656 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700657 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700658
Felipe Lemed8b94e52016-12-08 10:21:44 -0800659 printf("========================================================\n");
660 printf("== dumpstate: %s\n", date);
661 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700662
Felipe Lemed8b94e52016-12-08 10:21:44 -0800663 printf("\n");
664 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700665 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800666 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
667 printf("Bootloader: %s\n", bootloader.c_str());
668 printf("Radio: %s\n", radio.c_str());
669 printf("Network: %s\n", network.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700670
Felipe Lemed8b94e52016-12-08 10:21:44 -0800671 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800672 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800673 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800674 printf("Uptime: ");
675 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
676 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800677 printf("Bugreport format version: %s\n", version_.c_str());
678 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 +0100679 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800680 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800681}
682
Felipe Leme24b66ee2016-06-16 10:55:26 -0700683// List of file extensions that can cause a zip file attachment to be rejected by some email
684// service providers.
685static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
686 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
687 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
688 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
689};
690
Vishnu Naire97d6122018-01-18 13:58:56 -0800691status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
692 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700693 if (!IsZipping()) {
694 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
695 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800696 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800697 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700698 std::string valid_name = entry_name;
699
700 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700701 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700702 if (idx != std::string::npos) {
703 std::string extension = entry_name.substr(idx);
704 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
705 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
706 valid_name = entry_name + ".renamed";
707 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
708 }
709 }
710
Felipe Leme6fe9db62016-02-12 09:04:16 -0800711 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
712 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700713 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
714 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700715 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700716 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700717 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800718 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800719 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000720 bool finished_entry = false;
721 auto finish_entry = [this, &finished_entry] {
722 if (!finished_entry) {
723 // This should only be called when we're going to return an earlier error,
724 // which would've been logged. This may imply the file is already corrupt
725 // and any further logging from FinishEntry is more likely to mislead than
726 // not.
727 this->zip_writer_->FinishEntry();
728 }
729 };
730 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800731 auto start = std::chrono::steady_clock::now();
732 auto end = start + timeout;
733 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800734
Felipe Leme770410d2016-01-26 17:07:14 -0800735 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800736 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800737 if (timeout.count() > 0) {
738 // lambda to recalculate the timeout.
739 auto time_left_ms = [end]() {
740 auto now = std::chrono::steady_clock::now();
741 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
742 return std::max(diff.count(), 0LL);
743 };
744
745 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
746 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000747 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
748 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800749 return -errno;
750 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000751 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800752 entry_name.c_str(), strerror(errno), timeout.count());
753 return TIMED_OUT;
754 }
755 }
756
Zach Riggle22200402016-08-18 01:01:24 -0400757 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800758 if (bytes_read == 0) {
759 break;
760 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800761 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800762 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800763 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700764 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800765 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700766 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800767 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800768 }
769 }
770
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700771 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000772 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700773 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700774 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800775 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800776 }
777
Vishnu Naire97d6122018-01-18 13:58:56 -0800778 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800779}
780
Felipe Leme1d486fe2016-10-14 18:06:47 -0700781bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
782 android::base::unique_fd fd(
783 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700784 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800785 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 return false;
787 }
788
Vishnu Naire97d6122018-01-18 13:58:56 -0800789 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800790}
791
792/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700793static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800794 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800795}
796
Felipe Leme1d486fe2016-10-14 18:06:47 -0700797void Dumpstate::AddDir(const std::string& dir, bool recursive) {
798 if (!IsZipping()) {
799 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800800 return;
801 }
Felipe Leme678727a2016-09-21 17:22:11 -0700802 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800803 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700804 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800805}
806
Felipe Leme1d486fe2016-10-14 18:06:47 -0700807bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
808 if (!IsZipping()) {
809 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
810 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800811 return false;
812 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800813 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700814 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700815 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700816 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700817 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800818 return false;
819 }
820
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700821 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700822 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700823 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700824 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800825 return false;
826 }
827
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700828 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700829 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700830 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800831 return false;
832 }
833
834 return true;
835}
836
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800837static void DoKmsg() {
838 struct stat st;
839 if (!stat(PSTORE_LAST_KMSG, &st)) {
840 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
841 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
842 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
843 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
844 } else {
845 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
846 DumpFile("LAST KMSG", "/proc/last_kmsg");
847 }
848}
849
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800850static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800851 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800852 RunCommand(
853 "KERNEL LOG",
854 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
855 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
856}
857
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800858static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800859 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800860 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
861 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800862 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100863 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800864 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
865 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800866 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800867 RunCommand(
868 "EVENT LOG",
869 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
870 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800871 timeout_ms = logcat_timeout({"stats"});
872 RunCommand(
873 "STATS LOG",
874 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
875 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
876 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800877 RunCommand(
878 "RADIO LOG",
879 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
880 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800881
882 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
883
884 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800885 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
886 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800887}
888
Jayachandran Ca94c7172017-06-10 15:08:12 -0700889static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700890 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
891 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900892 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700893 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900894 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
895 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
896 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
897 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700898}
899
Narayan Kamath8f788292017-05-25 13:20:39 +0100900static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
901 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
902 anr_traces_dir.c_str());
903
904 // If we're here, dump_traces_path will always be a temporary file
905 // (created with mkostemp or similar) that contains dumps taken earlier
906 // on in the process.
907 if (dump_traces_path != nullptr) {
908 if (add_to_zip) {
909 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
910 } else {
911 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
912 dump_traces_path);
913 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
914 }
915
916 const int ret = unlink(dump_traces_path);
917 if (ret == -1) {
918 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
919 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700920 }
921 }
922
Narayan Kamathbd863722017-06-01 18:50:12 +0100923 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700924 if (ds.anr_data_.size() > 0) {
925 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100926 "VM TRACES AT LAST ANR", add_to_zip);
927
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100928 // The "last" ANR will always be included as separate entry in the zip file. In addition,
929 // it will be present in the body of the main entry if |add_to_zip| == false.
930 //
931 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700932 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100933 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100934 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100935 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
936 }
937}
938
939static void AddAnrTraceFiles() {
940 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
941
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700942 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100943
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700944 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100945
Makoto Onuki83ec63f2019-01-31 17:08:59 -0800946 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
947
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700948 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -0700949 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700950 int i = 0;
951 while (true) {
952 const std::string slow_trace_path =
953 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
954 if (stat(slow_trace_path.c_str(), &st)) {
955 // No traces file at this index, done with the files.
956 break;
Felipe Lemee184f662016-10-27 10:04:47 -0700957 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700958 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
959 i++;
Felipe Lemee184f662016-10-27 10:04:47 -0700960 }
961}
962
Wei Wang509bb5d2017-06-09 14:42:12 -0700963static void DumpBlockStatFiles() {
964 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -0700965
Wei Wang1dc1ef52017-06-12 11:28:37 -0700966 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
967
968 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -0700969 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
970 return;
971 }
972
973 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -0700974 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -0700975 if ((d->d_name[0] == '.')
976 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
977 || (d->d_name[1] == '\0'))) {
978 continue;
979 }
980 const std::string new_path =
981 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
982 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
983 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
984 printf("\n");
985 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700986 return;
Wei Wang509bb5d2017-06-09 14:42:12 -0700987}
Jayachandran Ca94c7172017-06-10 15:08:12 -0700988
989static void DumpPacketStats() {
990 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
991 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
992 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
993 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
994 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
995}
996
997static void DumpIpAddrAndRules() {
998 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
999 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1000 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1001 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1002 RunCommand("IP RULES", {"ip", "rule", "show"});
1003 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1004}
1005
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001006static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1007 std::chrono::milliseconds timeout,
1008 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001009 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001010 sp<android::IServiceManager> sm = defaultServiceManager();
1011 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001012 Vector<String16> args;
1013 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001014 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1015 for (const String16& service : services) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001016 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001017 std::string path(title);
1018 path.append(" - ").append(String8(service).c_str());
1019 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1020 size_t bytes_written = 0;
1021 status_t status = dumpsys.startDumpThread(service, args);
1022 if (status == OK) {
1023 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1024 std::chrono::duration<double> elapsed_seconds;
1025 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1026 /* as_proto = */ false, elapsed_seconds, bytes_written);
1027 section_reporter.setSize(bytes_written);
1028 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1029 bool dump_complete = (status == OK);
1030 dumpsys.stopDumpThread(dump_complete);
1031 }
1032 section_reporter.setStatus(status);
1033
1034 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1035 std::chrono::steady_clock::now() - start);
1036 if (elapsed_duration > timeout) {
1037 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1038 elapsed_duration.count());
1039 break;
1040 }
1041 }
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001042 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001043}
1044
Vishnu Nair64afc022018-02-01 15:29:34 -08001045static void RunDumpsysText(const std::string& title, int priority,
1046 std::chrono::milliseconds timeout,
1047 std::chrono::milliseconds service_timeout) {
1048 DurationReporter duration_reporter(title);
1049 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1050 fsync(STDOUT_FILENO);
1051 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1052}
1053
1054/* Dump all services registered with Normal or Default priority. */
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001055static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1056 std::chrono::milliseconds timeout,
1057 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001058 DurationReporter duration_reporter(title);
1059 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1060 fsync(STDOUT_FILENO);
1061 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1062 service_timeout);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001063
1064 RETURN_IF_USER_DENIED_CONSENT();
1065
1066 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1067 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001068}
1069
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001070static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1071 std::chrono::milliseconds timeout,
1072 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001073 if (!ds.IsZipping()) {
1074 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001075 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001076 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001077 sp<android::IServiceManager> sm = defaultServiceManager();
1078 Dumpsys dumpsys(sm.get());
1079 Vector<String16> args;
1080 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1081 DurationReporter duration_reporter(title);
1082
1083 auto start = std::chrono::steady_clock::now();
1084 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1085 for (const String16& service : services) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001086 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001087 std::string path(kProtoPath);
1088 path.append(String8(service).c_str());
1089 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1090 path.append("_CRITICAL");
1091 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1092 path.append("_HIGH");
1093 }
1094 path.append(kProtoExt);
1095 DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
1096 status_t status = dumpsys.startDumpThread(service, args);
1097 if (status == OK) {
1098 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1099 bool dumpTerminated = (status == OK);
1100 dumpsys.stopDumpThread(dumpTerminated);
1101 }
1102 ZipWriter::FileEntry file_entry;
1103 ds.zip_writer_->GetLastEntry(&file_entry);
1104 section_reporter.setSize(file_entry.compressed_size);
1105 section_reporter.setStatus(status);
1106
1107 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1108 std::chrono::steady_clock::now() - start);
1109 if (elapsed_duration > timeout) {
1110 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1111 elapsed_duration.count());
1112 break;
1113 }
1114 }
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001115 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001116}
1117
Nandana Dutta7db6342018-11-21 14:53:34 +00001118// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001119static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001120 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1121 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001122
1123 RETURN_IF_USER_DENIED_CONSENT();
1124
1125 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1126 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001127}
1128
1129// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001130static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001131 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1132 // high priority. Reduce timeout once they are able to dump in a shorter time or
1133 // moved to a parallel task.
1134 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1135 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001136
1137 RETURN_IF_USER_DENIED_CONSENT();
1138
1139 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1140 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001141}
1142
1143// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001144static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001145 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001146
1147 RETURN_IF_USER_DENIED_CONSENT();
1148
1149 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1150 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001151}
1152
Steven Moreland44cd9482018-01-04 16:24:13 -08001153static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001154 if (!ds.IsZipping()) {
1155 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1156 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1157 return;
1158 }
1159 DurationReporter duration_reporter("DUMP HALS");
1160 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001161 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001162
Steven Moreland44cd9482018-01-04 16:24:13 -08001163 using android::hidl::manager::V1_0::IServiceManager;
1164 using android::hardware::defaultServiceManager;
1165
1166 sp<IServiceManager> sm = defaultServiceManager();
1167 if (sm == nullptr) {
1168 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1169 return;
1170 }
1171
1172 auto ret = sm->list([&](const auto& interfaces) {
1173 for (const std::string& interface : interfaces) {
1174 std::string cleanName = interface;
1175 std::replace_if(cleanName.begin(),
1176 cleanName.end(),
1177 [](char c) {
1178 return !isalnum(c) &&
1179 std::string("@-_:.").find(c) == std::string::npos;
1180 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001181 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001182
1183 {
1184 auto fd = android::base::unique_fd(
1185 TEMP_FAILURE_RETRY(open(path.c_str(),
1186 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1187 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1188 if (fd < 0) {
1189 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1190 continue;
1191 }
1192 RunCommandToFd(fd,
1193 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001194 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001195 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1196
1197 bool empty = 0 == lseek(fd, 0, SEEK_END);
1198 if (!empty) {
1199 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1200 }
1201 }
1202
1203 unlink(path.c_str());
1204 }
1205 });
1206
1207 if (!ret.isOk()) {
1208 MYLOGE("Could not list hals from hwservicemanager.\n");
1209 }
1210}
1211
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001212// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1213// via the consent they are shown. Ignores other errors that occur while running various
1214// commands. The consent checking is currently done around long running tasks, which happen to
1215// be distributed fairly evenly throughout the function.
1216static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001217 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001218
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001219 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1220 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1221 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001222 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001223 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001224 DumpBlockStatFiles();
Mark Salyzyn8c8130e2015-12-09 11:21:28 -08001225 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001226 DumpFile("MEMORY INFO", "/proc/meminfo");
1227 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001228 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001229
1230 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1231
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001232 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1233 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1234 DumpFile("SLAB INFO", "/proc/slabinfo");
1235 DumpFile("ZONEINFO", "/proc/zoneinfo");
1236 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1237 DumpFile("BUDDYINFO", "/proc/buddyinfo");
1238 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001239
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001240 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1241 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
1242 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001243
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001244 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001245 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001246
1247 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1248 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001249
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001250 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001251
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001252 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001253 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001254 struct stat s;
1255 if (stat("/proc/modules", &s) != 0) {
1256 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1257 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001258 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001259 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001260
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001261 if (__android_logger_property_get_bool(
1262 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1263 DoKernelLogcat();
1264 } else {
1265 do_dmesg();
1266 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001267
Felipe Lemef0292972016-11-22 13:57:05 -08001268 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001269
1270 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1271
Jeff Brown1dc94e32014-09-11 14:15:27 -07001272 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001273 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001274
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001275 /* Dump Bluetooth HCI logs */
1276 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001277
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001278 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001279 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001280 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001281 }
1282
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001283 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001284
Felipe Lemee184f662016-10-27 10:04:47 -07001285 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001286
Narayan Kamath8f788292017-05-25 13:20:39 +01001287 // NOTE: tombstones are always added as separate entries in the zip archive
1288 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001289 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001290 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001291 if (!tombstones_dumped) {
1292 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001293 }
1294
Jayachandran Ca94c7172017-06-10 15:08:12 -07001295 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001296
Chenbo Feng276a3b62018-08-07 11:44:49 -07001297 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1298
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001299 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001300
Jayachandran Ca94c7172017-06-10 15:08:12 -07001301 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001302
1303 dump_route_tables();
1304
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001305 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1306 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1307 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001308
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001309 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001310
Elliott Hughes23ccc622017-02-28 10:14:22 -08001311 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001312
Jin Qianf334d662017-10-10 14:41:37 -07001313 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001314
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001315 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001316
Colin Crossf45fa6b2012-03-26 12:38:26 -07001317 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001318 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1319 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1320 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1321 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1322 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001323
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001324 /* Add window and surface trace files. */
1325 if (!PropertiesHelper::IsUserBuild()) {
1326 ds.AddDir(WMTRACE_DATA_DIR, false);
1327 }
1328
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001329 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001330
Steven Moreland7440ddb2016-12-15 16:13:39 -08001331 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001332 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1333 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001334 // su does not exist on user builds, so try running without it.
1335 // This way any implementations of vril-dump that do not require
1336 // root can run on user builds.
1337 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001338 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001339 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001340 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001341 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001342 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001343 }
1344
Felipe Lemed8b94e52016-12-08 10:21:44 -08001345 printf("========================================================\n");
1346 printf("== Android Framework Services\n");
1347 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001348
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001349 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001350
Felipe Lemed8b94e52016-12-08 10:21:44 -08001351 printf("========================================================\n");
1352 printf("== Checkins\n");
1353 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001354
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001355 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001356
1357 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1358
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001359 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1360 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1361 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1362 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001363
Felipe Lemed8b94e52016-12-08 10:21:44 -08001364 printf("========================================================\n");
1365 printf("== Running Application Activities\n");
1366 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001367
Makoto Onuki60780982018-04-16 15:34:00 -07001368 // The following dumpsys internally collects output from running apps, so it can take a long
1369 // time. So let's extend the timeout.
1370
1371 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1372
1373 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001374
Felipe Lemed8b94e52016-12-08 10:21:44 -08001375 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001376 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001377 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001378
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001379 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001380 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001381
Felipe Lemed8b94e52016-12-08 10:21:44 -08001382 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001383 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001384 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001385
Makoto Onuki60780982018-04-16 15:34:00 -07001386 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1387 DUMPSYS_COMPONENTS_OPTIONS);
1388
1389 printf("========================================================\n");
1390 printf("== Running Application Providers (platform)\n");
1391 printf("========================================================\n");
1392
1393 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1394 DUMPSYS_COMPONENTS_OPTIONS);
1395
1396 printf("========================================================\n");
1397 printf("== Running Application Providers (non-platform)\n");
1398 printf("========================================================\n");
1399
1400 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1401 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001402
Adrian Roos8b397ab2017-04-04 16:35:44 -07001403 printf("========================================================\n");
1404 printf("== Dropbox crashes\n");
1405 printf("========================================================\n");
1406
1407 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1408 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1409
Felipe Lemed8b94e52016-12-08 10:21:44 -08001410 printf("========================================================\n");
1411 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1412 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1413 printf("========================================================\n");
1414 printf("== dumpstate: done (id %d)\n", ds.id_);
1415 printf("========================================================\n");
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001416 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001417}
1418
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001419/*
1420 * Dumps state for the default case; drops root after it's no longer necessary.
1421 *
1422 * Returns RunStatus::OK if everything went fine.
1423 * Returns RunStatus::ERROR if there was an error.
1424 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1425 * with the caller.
1426 */
1427static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001428 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001429 // keep the system stats as close to its initial state as possible.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001430 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001431
1432 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001433 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001434
1435 /* Run some operations that require root. */
1436 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1437 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1438
1439 ds.AddDir(RECOVERY_DIR, true);
1440 ds.AddDir(RECOVERY_DATA_DIR, true);
1441 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1442 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1443 if (!PropertiesHelper::IsUserBuild()) {
1444 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1445 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1446 }
1447 add_mountinfo();
1448 DumpIpTablesAsRoot();
1449
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001450 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001451 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1452
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001453 // Dump IPsec stats. No keys are exposed here.
1454 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1455
Nandana Dutt4be45d12018-09-26 15:04:23 +01001456 // Run ss as root so we can see socket marks.
1457 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1458
1459 // Run iotop as root to show top 100 IO threads
1460 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1461
Erick Reyese68df822019-02-11 14:46:36 -08001462 // Gather shared memory buffer info if the product implements it
1463 struct stat st;
1464 if (!stat("/product/bin/dmabuf_dump", &st)) {
1465 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1466 }
1467
Nandana Dutt4be45d12018-09-26 15:04:23 +01001468 if (!DropRootUser()) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001469 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001470 }
1471
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001472 RETURN_IF_USER_DENIED_CONSENT();
1473 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001474}
1475
mukesh agrawal253dad42018-01-23 21:59:59 -08001476// This method collects common dumpsys for telephony and wifi
1477static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001478 DumpIpTablesAsRoot();
1479
1480 if (!DropRootUser()) {
1481 return;
1482 }
1483
1484 do_dmesg();
1485 DoLogcat();
1486 DumpPacketStats();
1487 DoKmsg();
1488 DumpIpAddrAndRules();
1489 dump_route_tables();
1490
1491 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1492 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001493}
1494
1495// This method collects dumpsys for telephony debugging only
1496static void DumpstateTelephonyOnly() {
1497 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001498 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001499
1500 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001501
1502 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1503
1504 printf("========================================================\n");
1505 printf("== Android Framework Services\n");
1506 printf("========================================================\n");
1507
Vishnu Nair652cc802017-11-30 15:18:30 -08001508 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1509 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001510 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1511 SEC_TO_MSEC(10));
1512 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001513 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1514 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001515 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1516 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001517 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1518 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001519
1520 printf("========================================================\n");
1521 printf("== Running Application Services\n");
1522 printf("========================================================\n");
1523
1524 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1525
1526 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001527 printf("== Running Application Services (non-platform)\n");
1528 printf("========================================================\n");
1529
1530 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1531 DUMPSYS_COMPONENTS_OPTIONS);
1532
1533 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001534 printf("== Checkins\n");
1535 printf("========================================================\n");
1536
1537 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1538
1539 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001540 printf("== dumpstate: done (id %d)\n", ds.id_);
1541 printf("========================================================\n");
1542}
1543
mukesh agrawal253dad42018-01-23 21:59:59 -08001544// This method collects dumpsys for wifi debugging only
1545static void DumpstateWifiOnly() {
1546 DurationReporter duration_reporter("DUMPSTATE");
1547
1548 DumpstateRadioCommon();
1549
1550 printf("========================================================\n");
1551 printf("== Android Framework Services\n");
1552 printf("========================================================\n");
1553
1554 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1555 SEC_TO_MSEC(10));
1556 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1557 SEC_TO_MSEC(10));
1558
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001559 DumpHals();
Roger Wang70399032019-01-08 16:10:37 +08001560
mukesh agrawal253dad42018-01-23 21:59:59 -08001561 printf("========================================================\n");
1562 printf("== dumpstate: done (id %d)\n", ds.id_);
1563 printf("========================================================\n");
1564}
1565
Nandana Duttcf419a72019-03-14 10:40:17 +00001566Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001567 DurationReporter duration_reporter("DUMP TRACES");
1568
1569 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1570 const size_t buf_size = temp_file_pattern.length() + 1;
1571 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1572 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1573
1574 // Create a new, empty file to receive all trace dumps.
1575 //
1576 // TODO: This can be simplified once we remove support for the old style
1577 // dumps. We can have a file descriptor passed in to dump_traces instead
1578 // of creating a file, closing it and then reopening it again.
1579 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1580 if (fd < 0) {
1581 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001582 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001583 }
1584
1585 // Nobody should have access to this temporary file except dumpstate, but we
1586 // temporarily grant 'read' to 'others' here because this file is created
1587 // when tombstoned is still running as root, but dumped after dropping. This
1588 // can go away once support for old style dumping has.
1589 const int chmod_ret = fchmod(fd, 0666);
1590 if (chmod_ret < 0) {
1591 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001592 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001593 }
1594
1595 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1596 if (proc.get() == nullptr) {
1597 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001598 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001599 }
1600
1601 // Number of times process dumping has timed out. If we encounter too many
1602 // failures, we'll give up.
1603 int timeout_failures = 0;
1604 bool dalvik_found = false;
1605
1606 const std::set<int> hal_pids = get_interesting_hal_pids();
1607
1608 struct dirent* d;
1609 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001610 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001611 int pid = atoi(d->d_name);
1612 if (pid <= 0) {
1613 continue;
1614 }
1615
1616 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1617 std::string exe;
1618 if (!android::base::Readlink(link_name, &exe)) {
1619 continue;
1620 }
1621
1622 bool is_java_process;
1623 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1624 // Don't bother dumping backtraces for the zygote.
1625 if (IsZygote(pid)) {
1626 continue;
1627 }
1628
1629 dalvik_found = true;
1630 is_java_process = true;
1631 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1632 is_java_process = false;
1633 } else {
1634 // Probably a native process we don't care about, continue.
1635 continue;
1636 }
1637
1638 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1639 if (timeout_failures == 3) {
1640 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1641 break;
1642 }
1643
1644 const uint64_t start = Nanotime();
1645 const int ret = dump_backtrace_to_file_timeout(
1646 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1647 is_java_process ? 5 : 20, fd);
1648
1649 if (ret == -1) {
1650 // For consistency, the header and footer to this message match those
1651 // dumped by debuggerd in the success case.
1652 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1653 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1654 dprintf(fd, "---- end %d ----", pid);
1655 timeout_failures++;
1656 continue;
1657 }
1658
1659 // We've successfully dumped stack traces, reset the failure count
1660 // and write a summary of the elapsed time to the file and continue with the
1661 // next process.
1662 timeout_failures = 0;
1663
1664 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1665 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1666 }
1667
1668 if (!dalvik_found) {
1669 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1670 }
1671
Nandana Duttcf419a72019-03-14 10:40:17 +00001672 *path = file_name_buf.release();
1673 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001674}
1675
Felipe Leme6f674ae2016-11-18 17:10:33 -08001676void Dumpstate::DumpstateBoard() {
1677 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001678 printf("========================================================\n");
1679 printf("== Board\n");
1680 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001681
Felipe Leme6f674ae2016-11-18 17:10:33 -08001682 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001683 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001684 return;
1685 }
1686
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001687 std::vector<std::string> paths;
1688 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001689 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001690 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1691 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001692 remover.emplace_back(android::base::make_scope_guard(
1693 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001694 }
Jie Song9fbfad02017-06-20 16:29:42 -07001695
Wei Wang587eac92018-04-05 12:17:20 -07001696 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1697 if (dumpstate_device == nullptr) {
1698 MYLOGE("No IDumpstateDevice implementation\n");
1699 return;
1700 }
1701
1702 using ScopedNativeHandle =
1703 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1704 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1705 [](native_handle_t* handle) {
1706 native_handle_close(handle);
1707 native_handle_delete(handle);
1708 });
1709 if (handle == nullptr) {
1710 MYLOGE("Could not create native_handle\n");
1711 return;
1712 }
1713
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001714 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001715 for (size_t i = 0; i < paths.size(); i++) {
1716 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1717
1718 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1719 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1720 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1721 if (fd < 0) {
1722 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1723 return;
1724 }
1725 handle.get()->data[i] = fd.release();
1726 }
1727
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001728 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001729 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1730 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1731 // and grab whatever dumped
1732 std::packaged_task<bool()>
1733 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001734 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1735 if (!status.isOk()) {
1736 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001737 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001738 }
Wei Wang587eac92018-04-05 12:17:20 -07001739 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001740 });
Wei Wang587eac92018-04-05 12:17:20 -07001741
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001742 auto result = dumpstate_task.get_future();
1743 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001744
1745 constexpr size_t timeout_sec = 30;
1746 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1747 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1748 if (!android::base::SetProperty("ctl.interface_restart",
1749 android::base::StringPrintf("%s/default",
1750 IDumpstateDevice::descriptor))) {
1751 MYLOGE("Couldn't restart dumpstate HAL\n");
1752 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001753 }
Wei Wang587eac92018-04-05 12:17:20 -07001754 // Wait some time for init to kill dumpstate vendor HAL
1755 constexpr size_t killing_timeout_sec = 10;
1756 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1757 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1758 "there might be racing in content\n", killing_timeout_sec);
1759 }
1760
1761 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1762 for (size_t i = 0; i < paths.size(); i++) {
1763 struct stat s;
1764 if (fstat(handle.get()->data[i], &s) == -1) {
1765 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1766 strerror(errno));
1767 file_sizes[i] = -1;
1768 continue;
1769 }
1770 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001771 }
1772
1773 for (size_t i = 0; i < paths.size(); i++) {
1774 if (file_sizes[i] == -1) {
1775 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001776 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001777 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001778 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001779 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001780 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001781 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001782 }
1783
Felipe Lemed8b94e52016-12-08 10:21:44 -08001784 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001785}
1786
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001787static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001788 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001789 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001790 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1791 " -h: display this help message\n"
1792 " -b: play sound file instead of vibrate, at beginning of job\n"
1793 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001794 " -d: append date to filename\n"
1795 " -p: capture screenshot to filename.png\n"
1796 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001797 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001798 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001799 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001800 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001801 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001802 "progress (requires -B)\n"
1803 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001804 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001805 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001806 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001807}
1808
Wei Liuf87959e2016-08-26 14:51:42 -07001809static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001810 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001811}
1812
Felipe Leme1d486fe2016-10-14 18:06:47 -07001813bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001814 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001815 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001816 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001817 // Final timestamp
1818 char date[80];
1819 time_t the_real_now_please_stand_up = time(nullptr);
1820 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001821 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001822 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001823
Felipe Leme9a523ae2016-10-20 15:10:33 -07001824 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001825 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001826 return false;
1827 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001828 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001829 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001830 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001831 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001832
Felipe Leme0f3fb202016-06-10 17:10:53 -07001833 // Add log file (which contains stderr output) to zip...
1834 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001835 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001836 MYLOGE("Failed to add dumpstate log to .zip file\n");
1837 return false;
1838 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001839 // TODO: Should truncate the existing file.
1840 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001841 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1842 return false;
1843 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001844 fprintf(stderr, "\n");
1845
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001846 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001847 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001848 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001849 return false;
1850 }
1851
Felipe Leme1d486fe2016-10-14 18:06:47 -07001852 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1853 ds.zip_file.reset(nullptr);
1854
Felipe Lemee9d2c542016-11-15 11:48:26 -08001855 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001856 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001857
Felipe Leme1e9edc62015-12-21 16:02:13 -08001858 return true;
1859}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001860
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001861static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001862 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1863 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001864 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001865 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001866 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001867 }
1868
1869 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001870 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001871
1872 std::vector<uint8_t> buffer(65536);
1873 while (1) {
1874 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1875 if (bytes_read == 0) {
1876 break;
1877 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001878 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001879 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001880 }
1881
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001882 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001883 }
1884
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001885 uint8_t hash[SHA256_DIGEST_LENGTH];
1886 SHA256_Final(hash, &ctx);
1887
1888 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1889 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001890 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001891 }
1892 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1893 return std::string(hash_buffer);
1894}
1895
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001896static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1897 // clang-format off
1898 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1899 "--receiver-foreground", "--receiver-include-background", "-a", action};
1900 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001901
1902 am.insert(am.end(), args.begin(), args.end());
1903
Felipe Leme8d2410e2017-02-08 09:46:08 -08001904 RunCommand("", am,
1905 CommandOptions::WithTimeout(20)
1906 .Log("Sending broadcast: '%s'\n")
1907 .Always()
1908 .DropRoot()
1909 .RedirectStderr()
1910 .Build());
1911}
1912
Felipe Leme35b8cf12017-02-10 15:47:29 -08001913static void Vibrate(int duration_ms) {
1914 // clang-format off
Chris Friese7e95fb2019-06-14 14:47:59 +00001915 RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001916 CommandOptions::WithTimeout(10)
1917 .Log("Vibrate: '%s'\n")
1918 .Always()
1919 .Build());
1920 // clang-format on
1921}
1922
Nandana Dutt979388e2018-11-30 16:48:55 +00001923static void MaybeResolveSymlink(std::string* path) {
1924 std::string resolved_path;
1925 if (android::base::Readlink(*path, &resolved_path)) {
1926 *path = resolved_path;
1927 }
1928}
1929
Nandana Dutt4be45d12018-09-26 15:04:23 +01001930/*
1931 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
1932 * if we are writing zip files and adds the version file.
1933 */
1934static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00001935 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
1936
Nandana Dutt4be45d12018-09-26 15:04:23 +01001937 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1938 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00001939 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001940 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001941 char date[80];
1942 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
1943 ds.name_ = date;
1944 } else {
1945 ds.name_ = "undated";
1946 }
1947
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001948 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001949 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001950 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001951 ds.base_name_ += "-wifi";
1952 }
1953
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001954 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001955 ds.screenshot_path_ = ds.GetPath(".png");
1956 }
1957 ds.tmp_path_ = ds.GetPath(".tmp");
1958 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1959
Nandana Dutt54dbd672019-01-11 12:58:05 +00001960 std::string destination = ds.options_->bugreport_fd.get() != -1
1961 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00001962 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001963 MYLOGD(
1964 "Bugreport dir: %s\n"
1965 "Base name: %s\n"
1966 "Suffix: %s\n"
1967 "Log path: %s\n"
1968 "Temporary path: %s\n"
1969 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00001970 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
1971 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01001972
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001973 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001974 ds.path_ = ds.GetPath(".zip");
1975 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
1976 create_parent_dirs(ds.path_.c_str());
1977 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
1978 if (ds.zip_file == nullptr) {
1979 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
1980 } else {
1981 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
1982 }
1983 ds.AddTextZipEntry("version.txt", ds.version_);
1984 }
1985}
1986
1987/*
1988 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
1989 * printing zipped file status, etc.
1990 */
1991static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001992 /* check if user changed the suffix using system properties */
1993 std::string name =
1994 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
1995 bool change_suffix = false;
1996 if (!name.empty()) {
1997 /* must whitelist which characters are allowed, otherwise it could cross directories */
1998 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1999 if (std::regex_match(name.c_str(), valid_regex)) {
2000 change_suffix = true;
2001 } else {
2002 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2003 }
2004 }
2005 if (change_suffix) {
2006 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2007 ds.name_ = name;
2008 if (!ds.screenshot_path_.empty()) {
2009 std::string new_screenshot_path = ds.GetPath(".png");
2010 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2011 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2012 new_screenshot_path.c_str(), strerror(errno));
2013 } else {
2014 ds.screenshot_path_ = new_screenshot_path;
2015 }
2016 }
2017 }
2018
2019 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002020 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002021 if (!ds.FinishZipFile()) {
2022 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2023 do_text_file = true;
2024 } else {
2025 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002026 // If the user has changed the suffix, we need to change the zip file name.
2027 std::string new_path = ds.GetPath(".zip");
2028 if (ds.path_ != new_path) {
2029 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2030 if (rename(ds.path_.c_str(), new_path.c_str())) {
2031 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2032 strerror(errno));
2033 } else {
2034 ds.path_ = new_path;
2035 }
2036 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002037 }
2038 }
2039 if (do_text_file) {
2040 ds.path_ = ds.GetPath(".txt");
2041 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2042 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2043 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2044 ds.path_.clear();
2045 }
2046 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002047 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002048 if (do_text_file) {
2049 dprintf(ds.control_socket_fd_,
2050 "FAIL:could not create zip file, check %s "
2051 "for more details\n",
2052 ds.log_path_.c_str());
2053 } else {
2054 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2055 }
2056 }
2057}
2058
2059/* Broadcasts that we are done with the bugreport */
2060static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002061 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002062 if (!ds.path_.empty()) {
2063 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002064 // clang-format off
2065
2066 std::vector<std::string> am_args = {
2067 "--receiver-permission", "android.permission.DUMP",
2068 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2069 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2070 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002071 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002072 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2073 };
2074 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002075 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002076 am_args.push_back("--es");
2077 am_args.push_back("android.intent.extra.SCREENSHOT");
2078 am_args.push_back(ds.screenshot_path_);
2079 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002080 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002081 am_args.push_back("--es");
2082 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002083 am_args.push_back(ds.options_->notification_title);
2084 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002085 am_args.push_back("--es");
2086 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002087 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002088 }
2089 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002090 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002091 am_args.push_back("--es");
2092 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002093 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002094 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2095 } else {
2096 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2097 }
2098 } else {
2099 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2100 }
2101}
2102
Nandana Dutt58d72e22018-11-16 10:30:48 +00002103static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2104 switch (mode) {
2105 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2106 return "BUGREPORT_FULL";
2107 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2108 return "BUGREPORT_INTERACTIVE";
2109 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2110 return "BUGREPORT_REMOTE";
2111 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2112 return "BUGREPORT_WEAR";
2113 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2114 return "BUGREPORT_TELEPHONY";
2115 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2116 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002117 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2118 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002119 }
2120}
2121
2122static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002123 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002124 switch (mode) {
2125 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2126 options->do_broadcast = true;
2127 options->do_fb = true;
2128 break;
2129 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002130 // Currently, the dumpstate binder is only used by Shell to update progress.
2131 options->do_start_service = true;
2132 options->do_progress_updates = true;
2133 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002134 options->do_broadcast = true;
2135 break;
2136 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002137 options->do_vibrate = false;
2138 options->is_remote_mode = true;
2139 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002140 options->do_broadcast = true;
2141 break;
2142 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002143 options->do_start_service = true;
2144 options->do_progress_updates = true;
2145 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002146 options->do_fb = true;
2147 options->do_broadcast = true;
2148 break;
2149 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002150 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002151 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002152 options->do_broadcast = true;
2153 break;
2154 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002155 options->wifi_only = true;
2156 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002157 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002158 options->do_broadcast = true;
2159 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002160 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2161 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002162 }
2163}
2164
2165static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002166 // If the system property is not set, it's assumed to be a default bugreport.
2167 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002168
2169 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2170 if (!extra_options.empty()) {
2171 // Framework uses a system property to override some command-line args.
2172 // Currently, it contains the type of the requested bugreport.
2173 if (extra_options == "bugreportplus") {
2174 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002175 } else if (extra_options == "bugreportfull") {
2176 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002177 } else if (extra_options == "bugreportremote") {
2178 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2179 } else if (extra_options == "bugreportwear") {
2180 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2181 } else if (extra_options == "bugreporttelephony") {
2182 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2183 } else if (extra_options == "bugreportwifi") {
2184 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002185 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002186 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002187 }
2188 // Reset the property
2189 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2190 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002191 return mode;
2192}
2193
2194// TODO: Move away from system properties when we have options passed via binder calls.
2195/* Sets runtime options from the system properties and then clears those properties. */
2196static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2197 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2198 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002199
2200 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2201 if (!options->notification_title.empty()) {
2202 // Reset the property
2203 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2204
Nandana Duttdd8cca32018-11-14 10:10:29 +00002205 options->notification_description =
2206 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002207 if (!options->notification_description.empty()) {
2208 // Reset the property
2209 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2210 }
2211 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2212 options->notification_description.c_str());
2213 }
2214}
2215
Nandana Dutt58d72e22018-11-16 10:30:48 +00002216static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2217 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2218 MYLOGI("do_add_date: %d\n", options.do_add_date);
2219 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2220 MYLOGI("use_socket: %d\n", options.use_socket);
2221 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2222 MYLOGI("do_fb: %d\n", options.do_fb);
2223 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2224 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2225 MYLOGI("show_header_only: %d\n", options.show_header_only);
2226 MYLOGI("do_start_service: %d\n", options.do_start_service);
2227 MYLOGI("telephony_only: %d\n", options.telephony_only);
2228 MYLOGI("wifi_only: %d\n", options.wifi_only);
2229 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002230 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002231 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2232 MYLOGI("args: %s\n", options.args.c_str());
2233 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2234 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2235}
2236
Nandana Dutt54dbd672019-01-11 12:58:05 +00002237void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2238 const android::base::unique_fd& bugreport_fd_in,
2239 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002240 // In the new API world, date is always added; output is always a zip file.
2241 // TODO(111441001): remove these options once they are obsolete.
2242 do_add_date = true;
2243 do_zip_file = true;
2244
Nandana Dutt54dbd672019-01-11 12:58:05 +00002245 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2246 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2247 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002248
2249 extra_options = ModeToString(bugreport_mode);
2250 SetOptionsFromMode(bugreport_mode, this);
2251}
2252
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002253Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2254 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002255 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002256 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002257 switch (c) {
2258 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002259 case 'd': do_add_date = true; break;
2260 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002261 // o=use_outfile not supported anymore.
2262 // TODO(b/111441001): Remove when all callers have migrated.
2263 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002264 case 's': use_socket = true; break;
2265 case 'S': use_control_socket = true; break;
2266 case 'v': show_header_only = true; break;
2267 case 'q': do_vibrate = false; break;
2268 case 'p': do_fb = true; break;
2269 case 'P': do_progress_updates = true; break;
2270 case 'R': is_remote_mode = true; break;
2271 case 'B': do_broadcast = true; break;
2272 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002273 case 'w':
2274 // This was already processed
2275 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002276 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002277 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002278 break;
2279 default:
2280 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002281 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002282 break;
2283 // clang-format on
2284 }
2285 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002286
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002287 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002288 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002289 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002290 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002291 }
2292 }
2293
2294 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2295 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002296
2297 SetOptionsFromProperties(this);
2298 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002299}
2300
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002301bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002302 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002303 return false;
2304 }
2305
Nandana Dutt9a76d202019-01-21 15:56:48 +00002306 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002307 return false;
2308 }
2309
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002310 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002311 return false;
2312 }
2313
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002314 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002315 return false;
2316 }
2317
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002318 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002319 return false;
2320 }
2321 return true;
2322}
2323
Nandana Dutt197661d2018-11-16 16:40:21 +00002324void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2325 options_ = std::move(options);
2326}
2327
Nandana Duttd2f5f082019-01-18 17:13:52 +00002328Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2329 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002330 if (listener_ != nullptr) {
2331 switch (status) {
2332 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002333 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002334 break;
2335 case Dumpstate::RunStatus::HELP:
2336 break;
2337 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002338 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002339 break;
2340 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002341 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2342 break;
2343 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2344 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2345 break;
2346 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2347 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002348 break;
2349 }
2350 }
2351 return status;
2352}
2353
Nandana Dutt979388e2018-11-30 16:48:55 +00002354/*
2355 * Dumps relevant information to a bugreport based on the given options.
2356 *
2357 * The bugreport can be dumped to a file or streamed to a socket.
2358 *
2359 * How dumping to file works:
2360 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2361 * stderr is redirected a log file.
2362 *
2363 * The temporary bugreport is then populated via printfs, dumping contents of files and
2364 * output of commands to stdout.
2365 *
2366 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2367 * text file.
2368 *
2369 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2370 * gets added to the archive.
2371 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002372 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2373 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002374 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002375Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2376 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002377 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002378 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002379 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002380 return RunStatus::INVALID_INPUT;
2381 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002382 /* set as high priority, and protect from OOM killer */
2383 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002384
Felipe Lemed071c682016-10-20 16:48:00 -07002385 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002386 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002387 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002388 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002389 } else {
2390 /* fallback to kernels <= 2.6.35 */
2391 oom_adj = fopen("/proc/self/oom_adj", "we");
2392 if (oom_adj) {
2393 fputs("-17", oom_adj);
2394 fclose(oom_adj);
2395 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002396 }
2397
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002398 if (version_ == VERSION_DEFAULT) {
2399 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002400 }
2401
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002402 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002403 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002404 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002405 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002406 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002407 }
2408
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002409 if (options_->show_header_only) {
2410 PrintHeader();
2411 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002412 }
2413
Nandana Duttd2f5f082019-01-18 17:13:52 +00002414 if (options_->bugreport_fd.get() != -1) {
2415 // If the output needs to be copied over to the caller's fd, get user consent.
2416 android::String16 package(calling_package.c_str());
2417 CheckUserConsent(calling_uid, package);
2418 }
2419
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002420 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002421 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002422
2423 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002424 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002425 is_redirecting
2426 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2427 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002428 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002429
Felipe Lemed071c682016-10-20 16:48:00 -07002430 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002431 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002432 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002433 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2434
2435 MYLOGI("begin\n");
2436
Sahana Raof35ed432019-07-12 10:47:52 +01002437 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2438 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2439 } else {
2440 // Wake lock will be released automatically on process death
2441 MYLOGD("Wake lock acquired.\n");
2442 }
2443
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002444 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002445
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002446 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002447 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002448 MYLOGI("Starting 'dumpstate' service\n");
2449 android::status_t ret;
2450 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2451 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2452 }
2453 }
2454
Felipe Lemef0292972016-11-22 13:57:05 -08002455 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002456 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2457 }
2458
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002459 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2460 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002461
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002462 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002463
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002464 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002465
Christopher Ferrised9354f2014-10-01 17:35:01 -07002466 // If we are going to use a socket, do it as early as possible
2467 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002468 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002469 if (!redirect_to_socket(stdout, "dumpstate")) {
2470 return ERROR;
2471 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002472 }
2473
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002474 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002475 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002476 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002477 if (control_socket_fd_ == -1) {
2478 return ERROR;
2479 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002480 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002481 }
2482
Felipe Leme71bbfc52015-11-23 14:14:51 -08002483 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002484 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002485
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002486 if (options_->do_progress_updates) {
2487 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002488 // clang-format off
2489 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002490 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002491 "--es", "android.intent.extra.NAME", name_,
2492 "--ei", "android.intent.extra.ID", std::to_string(id_),
2493 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2494 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002495 };
2496 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002497 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002498 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002499 if (options_->use_control_socket) {
2500 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002501 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002502 }
2503 }
2504
Nick Kralevichf3599b32016-01-25 15:05:16 -08002505 /* read /proc/cmdline before dropping root */
2506 FILE *cmdline = fopen("/proc/cmdline", "re");
2507 if (cmdline) {
2508 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2509 fclose(cmdline);
2510 }
2511
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002512 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002513 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002514 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002515
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002516 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002517 MYLOGI("taking early screenshot\n");
2518 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002519 }
2520
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002521 if (options_->do_zip_file && zip_file != nullptr) {
2522 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2523 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002524 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002525 }
2526 }
2527
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002528 int dup_stdout_fd;
2529 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002530 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002531 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002532 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002533 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2534 return ERROR;
2535 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002536 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2537 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2538 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002539 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002540
2541 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2542 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002543 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002544 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002545 /* TODO: rather than generating a text file now and zipping it later,
2546 it would be more efficient to redirect stdout to the zip entry
2547 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002548 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2549 return ERROR;
2550 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002551 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002552 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002553 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002554 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002555 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002556
2557 // Don't buffer stdout
2558 setvbuf(stdout, nullptr, _IONBF, 0);
2559
Felipe Leme608385d2016-02-01 10:35:38 -08002560 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2561 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002562 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002563 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002564
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002565 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002566 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002567 DumpstateBoard();
2568 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002569 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002570 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002571 // Dump state for the default case. This also drops root.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002572 RunStatus s = DumpstateDefault();
2573 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002574 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002575 HandleUserConsentDenied();
2576 }
2577 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002578 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002579 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002580
Felipe Leme55b42a62015-11-10 17:39:08 -08002581 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002582 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002583 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002584 }
2585
Nandana Duttd2f5f082019-01-18 17:13:52 +00002586 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002587 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002588 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002589 }
2590
Nandana Duttd2f5f082019-01-18 17:13:52 +00002591 // Share the final file with the caller if the user has consented.
2592 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2593 if (options_->bugreport_fd.get() != -1) {
2594 status = CopyBugreportIfUserConsented();
2595 if (status != Dumpstate::RunStatus::OK &&
2596 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2597 // Do an early return if there were errors. We make an exception for consent
2598 // timing out because it's possible the user got distracted. In this case the
2599 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002600 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002601 return status;
2602 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002603 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002604 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2605 options_->screenshot_fd.get());
2606 if (copy_succeeded) {
2607 android::os::UnlinkAndLogOnError(screenshot_path_);
2608 }
2609 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002610 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2611 MYLOGI(
2612 "Did not receive user consent yet."
2613 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002614 const String16 incidentcompanion("incidentcompanion");
2615 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2616 if (ics != nullptr) {
2617 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2618 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2619 consent_callback_.get());
2620 } else {
2621 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2622 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002623 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002624 }
2625
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002626 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002627 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002628 for (int i = 0; i < 3; i++) {
2629 Vibrate(75);
2630 usleep((75 + 50) * 1000);
2631 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002632 }
2633
Jeff Brown1dc94e32014-09-11 14:15:27 -07002634 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002635 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002636 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002637 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002638 }
2639
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002640 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2641 progress_->GetInitialMax());
2642 progress_->Save();
2643 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002644
Felipe Leme107a05f2016-03-08 15:11:15 -08002645 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002646 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002647 }
2648
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002649 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002650 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002651 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002652 }
2653
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002654 tombstone_data_.clear();
2655 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002656
Nandana Duttd2f5f082019-01-18 17:13:52 +00002657 return (consent_callback_ != nullptr &&
2658 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2659 ? USER_CONSENT_TIMED_OUT
2660 : RunStatus::OK;
2661}
2662
2663void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2664 consent_callback_ = new ConsentCallback();
2665 const String16 incidentcompanion("incidentcompanion");
2666 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2667 if (ics != nullptr) {
2668 MYLOGD("Checking user consent via incidentcompanion service\n");
2669 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
2670 calling_uid, calling_package, 0x1 /* FLAG_CONFIRMATION_DIALOG */,
2671 consent_callback_.get());
2672 } else {
2673 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2674 }
2675}
2676
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002677bool Dumpstate::IsUserConsentDenied() const {
2678 return ds.consent_callback_ != nullptr &&
2679 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2680}
2681
Nandana Duttd2f5f082019-01-18 17:13:52 +00002682void Dumpstate::CleanupFiles() {
2683 android::os::UnlinkAndLogOnError(tmp_path_);
2684 android::os::UnlinkAndLogOnError(screenshot_path_);
2685 android::os::UnlinkAndLogOnError(path_);
2686}
2687
2688Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2689 MYLOGD("User denied consent; deleting files and returning\n");
2690 CleanupFiles();
2691 return USER_CONSENT_DENIED;
2692}
2693
2694Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2695 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2696 // user consent.
2697 UserConsentResult consent_result = consent_callback_->getResult();
2698 if (consent_result == UserConsentResult::UNAVAILABLE) {
2699 // User has not responded yet.
2700 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2701 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2702 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2703 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2704 sleep(delay_seconds);
2705 }
2706 consent_result = consent_callback_->getResult();
2707 }
2708 if (consent_result == UserConsentResult::DENIED) {
2709 // User has explicitly denied sharing with the app. To be safe delete the
2710 // internal bugreport & tmp files.
2711 return HandleUserConsentDenied();
2712 }
2713 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002714 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2715 if (copy_succeeded) {
2716 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002717 }
2718 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2719 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2720 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2721 // Since we do not have user consent to share the bugreport it does not get
2722 // copied over to the calling app but remains in the internal directory from
2723 // where the user can manually pull it.
2724 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2725 }
2726 // Unknown result; must be a programming error.
2727 MYLOGE("Unknown user consent result:%d\n", consent_result);
2728 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002729}
2730
Nandana Duttf02564e2019-02-15 15:24:24 +00002731Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002732 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2733 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2734 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002735 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002736 // When directly running dumpstate binary, the output is not expected to be written
2737 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002738 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002739
2740 // calling_uid and calling_package are for user consent to share the bugreport with
2741 // an app; they are irrelvant here because bugreport is only written to a local
2742 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002743 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002744 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002745 return status;
2746}
2747
2748/* Main entry point for dumpstate binary. */
2749int run_main(int argc, char* argv[]) {
2750 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002751
2752 switch (status) {
2753 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002754 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002755 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002756 ShowUsage();
2757 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002758 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002759 fprintf(stderr, "Invalid combination of args\n");
2760 ShowUsage();
2761 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002762 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002763 FALLTHROUGH_INTENDED;
2764 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2765 FALLTHROUGH_INTENDED;
2766 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002767 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002768 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002769}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002770
2771// TODO(111441001): Default DumpOptions to sensible values.
2772Dumpstate::Dumpstate(const std::string& version)
2773 : pid_(getpid()),
2774 options_(new Dumpstate::DumpOptions()),
2775 version_(version),
2776 now_(time(nullptr)) {
2777}
2778
2779Dumpstate& Dumpstate::GetInstance() {
2780 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2781 return singleton_;
2782}
2783
2784DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
2785 : title_(title), logcat_only_(logcat_only) {
2786 if (!title_.empty()) {
2787 started_ = Nanotime();
2788 }
2789}
2790
2791DurationReporter::~DurationReporter() {
2792 if (!title_.empty()) {
2793 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2794 if (elapsed < .5f) {
2795 return;
2796 }
2797 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2798 if (logcat_only_) {
2799 return;
2800 }
2801 // Use "Yoda grammar" to make it easier to grep|sort sections.
2802 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2803 }
2804}
2805
2806const int32_t Progress::kDefaultMax = 5000;
2807
2808Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2809}
2810
2811Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2812 : Progress(initial_max, growth_factor, "") {
2813 progress_ = progress;
2814}
2815
2816Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2817 : initial_max_(initial_max),
2818 progress_(0),
2819 max_(initial_max),
2820 growth_factor_(growth_factor),
2821 n_runs_(0),
2822 average_max_(0),
2823 path_(path) {
2824 if (!path_.empty()) {
2825 Load();
2826 }
2827}
2828
2829void Progress::Load() {
2830 MYLOGD("Loading stats from %s\n", path_.c_str());
2831 std::string content;
2832 if (!android::base::ReadFileToString(path_, &content)) {
2833 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2834 return;
2835 }
2836 if (content.empty()) {
2837 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2838 return;
2839 }
2840 std::vector<std::string> lines = android::base::Split(content, "\n");
2841
2842 if (lines.size() < 1) {
2843 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2844 (int)lines.size(), max_);
2845 return;
2846 }
2847 char* ptr;
2848 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2849 average_max_ = strtol(ptr, nullptr, 10);
2850 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2851 average_max_ > STATS_MAX_AVERAGE) {
2852 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2853 initial_max_ = Progress::kDefaultMax;
2854 } else {
2855 initial_max_ = average_max_;
2856 }
2857 max_ = initial_max_;
2858
2859 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2860}
2861
2862void Progress::Save() {
2863 int32_t total = n_runs_ * average_max_ + progress_;
2864 int32_t runs = n_runs_ + 1;
2865 int32_t average = floor(((float)total) / runs);
2866 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2867 path_.c_str());
2868 if (path_.empty()) {
2869 return;
2870 }
2871
2872 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2873 if (!android::base::WriteStringToFile(content, path_)) {
2874 MYLOGE("Could not save stats on %s\n", path_.c_str());
2875 }
2876}
2877
2878int32_t Progress::Get() const {
2879 return progress_;
2880}
2881
2882bool Progress::Inc(int32_t delta_sec) {
2883 bool changed = false;
2884 if (delta_sec >= 0) {
2885 progress_ += delta_sec;
2886 if (progress_ > max_) {
2887 int32_t old_max = max_;
2888 max_ = floor((float)progress_ * growth_factor_);
2889 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2890 changed = true;
2891 }
2892 }
2893 return changed;
2894}
2895
2896int32_t Progress::GetMax() const {
2897 return max_;
2898}
2899
2900int32_t Progress::GetInitialMax() const {
2901 return initial_max_;
2902}
2903
2904void Progress::Dump(int fd, const std::string& prefix) const {
2905 const char* pr = prefix.c_str();
2906 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2907 dprintf(fd, "%smax: %d\n", pr, max_);
2908 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2909 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2910 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2911 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2912 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2913}
2914
2915bool Dumpstate::IsZipping() const {
2916 return zip_writer_ != nullptr;
2917}
2918
2919std::string Dumpstate::GetPath(const std::string& suffix) const {
2920 return GetPath(bugreport_internal_dir_, suffix);
2921}
2922
2923std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2924 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2925 name_.c_str(), suffix.c_str());
2926}
2927
2928void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2929 progress_ = std::move(progress);
2930}
2931
2932void for_each_userid(void (*func)(int), const char *header) {
2933 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2934 "for_each_userid(%s)", header);
2935 DurationReporter duration_reporter(title);
2936 if (PropertiesHelper::IsDryRun()) return;
2937
2938 DIR *d;
2939 struct dirent *de;
2940
2941 if (header) printf("\n------ %s ------\n", header);
2942 func(0);
2943
2944 if (!(d = opendir("/data/system/users"))) {
2945 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2946 return;
2947 }
2948
2949 while ((de = readdir(d))) {
2950 int userid;
2951 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2952 continue;
2953 }
2954 func(userid);
2955 }
2956
2957 closedir(d);
2958}
2959
2960static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2961 DIR *d;
2962 struct dirent *de;
2963
2964 if (!(d = opendir("/proc"))) {
2965 printf("Failed to open /proc (%s)\n", strerror(errno));
2966 return;
2967 }
2968
2969 if (header) printf("\n------ %s ------\n", header);
2970 while ((de = readdir(d))) {
2971 if (ds.IsUserConsentDenied()) {
2972 MYLOGE(
2973 "Returning early because user denied consent to share bugreport with calling app.");
2974 closedir(d);
2975 return;
2976 }
2977 int pid;
2978 int fd;
2979 char cmdpath[255];
2980 char cmdline[255];
2981
2982 if (!(pid = atoi(de->d_name))) {
2983 continue;
2984 }
2985
2986 memset(cmdline, 0, sizeof(cmdline));
2987
2988 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
2989 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2990 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
2991 close(fd);
2992 if (cmdline[0]) {
2993 helper(pid, cmdline, arg);
2994 continue;
2995 }
2996 }
2997
2998 // if no cmdline, a kernel thread has comm
2999 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3000 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3001 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3002 close(fd);
3003 if (cmdline[1]) {
3004 cmdline[0] = '[';
3005 size_t len = strcspn(cmdline, "\f\b\r\n");
3006 cmdline[len] = ']';
3007 cmdline[len+1] = '\0';
3008 }
3009 }
3010 if (!cmdline[0]) {
3011 strcpy(cmdline, "N/A");
3012 }
3013 helper(pid, cmdline, arg);
3014 }
3015
3016 closedir(d);
3017}
3018
3019static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3020 for_each_pid_func *func = (for_each_pid_func*) arg;
3021 func(pid, cmdline);
3022}
3023
3024void for_each_pid(for_each_pid_func func, const char *header) {
3025 std::string title = header == nullptr ? "for_each_pid"
3026 : android::base::StringPrintf("for_each_pid(%s)", header);
3027 DurationReporter duration_reporter(title);
3028 if (PropertiesHelper::IsDryRun()) return;
3029
3030 __for_each_pid(for_each_pid_helper, header, (void *) func);
3031}
3032
3033static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3034 DIR *d;
3035 struct dirent *de;
3036 char taskpath[255];
3037 for_each_tid_func *func = (for_each_tid_func *) arg;
3038
3039 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3040
3041 if (!(d = opendir(taskpath))) {
3042 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3043 return;
3044 }
3045
3046 func(pid, pid, cmdline);
3047
3048 while ((de = readdir(d))) {
3049 if (ds.IsUserConsentDenied()) {
3050 MYLOGE(
3051 "Returning early because user denied consent to share bugreport with calling app.");
3052 closedir(d);
3053 return;
3054 }
3055 int tid;
3056 int fd;
3057 char commpath[255];
3058 char comm[255];
3059
3060 if (!(tid = atoi(de->d_name))) {
3061 continue;
3062 }
3063
3064 if (tid == pid)
3065 continue;
3066
3067 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3068 memset(comm, 0, sizeof(comm));
3069 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3070 strcpy(comm, "N/A");
3071 } else {
3072 char *c;
3073 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3074 close(fd);
3075
3076 c = strrchr(comm, '\n');
3077 if (c) {
3078 *c = '\0';
3079 }
3080 }
3081 func(pid, tid, comm);
3082 }
3083
3084 closedir(d);
3085}
3086
3087void for_each_tid(for_each_tid_func func, const char *header) {
3088 std::string title = header == nullptr ? "for_each_tid"
3089 : android::base::StringPrintf("for_each_tid(%s)", header);
3090 DurationReporter duration_reporter(title);
3091
3092 if (PropertiesHelper::IsDryRun()) return;
3093
3094 __for_each_pid(for_each_tid_helper, header, (void *) func);
3095}
3096
3097void show_wchan(int pid, int tid, const char *name) {
3098 if (PropertiesHelper::IsDryRun()) return;
3099
3100 char path[255];
3101 char buffer[255];
3102 int fd, ret, save_errno;
3103 char name_buffer[255];
3104
3105 memset(buffer, 0, sizeof(buffer));
3106
3107 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3108 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3109 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3110 return;
3111 }
3112
3113 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3114 save_errno = errno;
3115 close(fd);
3116
3117 if (ret < 0) {
3118 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3119 return;
3120 }
3121
3122 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3123 pid == tid ? 0 : 3, "", name);
3124
3125 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3126
3127 return;
3128}
3129
3130// print time in centiseconds
3131static void snprcent(char *buffer, size_t len, size_t spc,
3132 unsigned long long time) {
3133 static long hz; // cache discovered hz
3134
3135 if (hz <= 0) {
3136 hz = sysconf(_SC_CLK_TCK);
3137 if (hz <= 0) {
3138 hz = 1000;
3139 }
3140 }
3141
3142 // convert to centiseconds
3143 time = (time * 100 + (hz / 2)) / hz;
3144
3145 char str[16];
3146
3147 snprintf(str, sizeof(str), " %llu.%02u",
3148 time / 100, (unsigned)(time % 100));
3149 size_t offset = strlen(buffer);
3150 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3151 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3152}
3153
3154// print permille as a percent
3155static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3156 char str[16];
3157
3158 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3159 size_t offset = strlen(buffer);
3160 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3161 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3162}
3163
3164void show_showtime(int pid, const char *name) {
3165 if (PropertiesHelper::IsDryRun()) return;
3166
3167 char path[255];
3168 char buffer[1023];
3169 int fd, ret, save_errno;
3170
3171 memset(buffer, 0, sizeof(buffer));
3172
3173 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3174 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3175 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3176 return;
3177 }
3178
3179 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3180 save_errno = errno;
3181 close(fd);
3182
3183 if (ret < 0) {
3184 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3185 return;
3186 }
3187
3188 // field 14 is utime
3189 // field 15 is stime
3190 // field 42 is iotime
3191 unsigned long long utime = 0, stime = 0, iotime = 0;
3192 if (sscanf(buffer,
3193 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3194 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3195 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3196 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3197 &utime, &stime, &iotime) != 3) {
3198 return;
3199 }
3200
3201 unsigned long long total = utime + stime;
3202 if (!total) {
3203 return;
3204 }
3205
3206 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3207 if (permille > 1000) {
3208 permille = 1000;
3209 }
3210
3211 // try to beautify and stabilize columns at <80 characters
3212 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3213 if ((name[0] != '[') || utime) {
3214 snprcent(buffer, sizeof(buffer), 57, utime);
3215 }
3216 snprcent(buffer, sizeof(buffer), 65, stime);
3217 if ((name[0] != '[') || iotime) {
3218 snprcent(buffer, sizeof(buffer), 73, iotime);
3219 }
3220 if (iotime) {
3221 snprdec(buffer, sizeof(buffer), 79, permille);
3222 }
3223 puts(buffer); // adds a trailing newline
3224
3225 return;
3226}
3227
3228void do_dmesg() {
3229 const char *title = "KERNEL LOG (dmesg)";
3230 DurationReporter duration_reporter(title);
3231 printf("------ %s ------\n", title);
3232
3233 if (PropertiesHelper::IsDryRun()) return;
3234
3235 /* Get size of kernel buffer */
3236 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3237 if (size <= 0) {
3238 printf("Unexpected klogctl return value: %d\n\n", size);
3239 return;
3240 }
3241 char *buf = (char *) malloc(size + 1);
3242 if (buf == nullptr) {
3243 printf("memory allocation failed\n\n");
3244 return;
3245 }
3246 int retval = klogctl(KLOG_READ_ALL, buf, size);
3247 if (retval < 0) {
3248 printf("klogctl failure\n\n");
3249 free(buf);
3250 return;
3251 }
3252 buf[retval] = '\0';
3253 printf("%s\n\n", buf);
3254 free(buf);
3255 return;
3256}
3257
3258void do_showmap(int pid, const char *name) {
3259 char title[255];
3260 char arg[255];
3261
3262 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3263 snprintf(arg, sizeof(arg), "%d", pid);
3264 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3265}
3266
3267int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3268 DurationReporter duration_reporter(title);
3269
3270 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3271
3272 UpdateProgress(WEIGHT_FILE);
3273
3274 return status;
3275}
3276
3277int read_file_as_long(const char *path, long int *output) {
3278 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3279 if (fd < 0) {
3280 int err = errno;
3281 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3282 return -1;
3283 }
3284 char buffer[50];
3285 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3286 if (bytes_read == -1) {
3287 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3288 return -2;
3289 }
3290 if (bytes_read == 0) {
3291 MYLOGE("File %s is empty\n", path);
3292 return -3;
3293 }
3294 *output = atoi(buffer);
3295 return 0;
3296}
3297
3298/* calls skip to gate calling dump_from_fd recursively
3299 * in the specified directory. dump_from_fd defaults to
3300 * dump_file_from_fd above when set to NULL. skip defaults
3301 * to false when set to NULL. dump_from_fd will always be
3302 * called with title NULL.
3303 */
3304int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3305 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3306 DurationReporter duration_reporter(title);
3307 DIR *dirp;
3308 struct dirent *d;
3309 char *newpath = nullptr;
3310 const char *slash = "/";
3311 int retval = 0;
3312
3313 if (!title.empty()) {
3314 printf("------ %s (%s) ------\n", title.c_str(), dir);
3315 }
3316 if (PropertiesHelper::IsDryRun()) return 0;
3317
3318 if (dir[strlen(dir) - 1] == '/') {
3319 ++slash;
3320 }
3321 dirp = opendir(dir);
3322 if (dirp == nullptr) {
3323 retval = -errno;
3324 MYLOGE("%s: %s\n", dir, strerror(errno));
3325 return retval;
3326 }
3327
3328 if (!dump_from_fd) {
3329 dump_from_fd = dump_file_from_fd;
3330 }
3331 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3332 if ((d->d_name[0] == '.')
3333 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3334 || (d->d_name[1] == '\0'))) {
3335 continue;
3336 }
3337 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3338 (d->d_type == DT_DIR) ? "/" : "");
3339 if (!newpath) {
3340 retval = -errno;
3341 continue;
3342 }
3343 if (skip && (*skip)(newpath)) {
3344 continue;
3345 }
3346 if (d->d_type == DT_DIR) {
3347 int ret = dump_files("", newpath, skip, dump_from_fd);
3348 if (ret < 0) {
3349 retval = ret;
3350 }
3351 continue;
3352 }
3353 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3354 if (fd.get() < 0) {
3355 retval = -1;
3356 printf("*** %s: %s\n", newpath, strerror(errno));
3357 continue;
3358 }
3359 (*dump_from_fd)(nullptr, newpath, fd.get());
3360 }
3361 closedir(dirp);
3362 if (!title.empty()) {
3363 printf("\n");
3364 }
3365 return retval;
3366}
3367
3368/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3369 * it's possible to avoid issues where opening the file itself can get
3370 * stuck.
3371 */
3372int dump_file_from_fd(const char *title, const char *path, int fd) {
3373 if (PropertiesHelper::IsDryRun()) return 0;
3374
3375 int flags = fcntl(fd, F_GETFL);
3376 if (flags == -1) {
3377 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3378 return -1;
3379 } else if (!(flags & O_NONBLOCK)) {
3380 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3381 return -1;
3382 }
3383 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3384}
3385
3386int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3387 const CommandOptions& options) {
3388 DurationReporter duration_reporter(title);
3389
3390 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3391
3392 /* TODO: for now we're simplifying the progress calculation by using the
3393 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3394 * where its weight should be much higher proportionally to its timeout.
3395 * Ideally, it should use a options.EstimatedDuration() instead...*/
3396 UpdateProgress(options.Timeout());
3397
3398 return status;
3399}
3400
3401void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3402 const CommandOptions& options, long dumpsysTimeoutMs) {
3403 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3404 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3405 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3406 RunCommand(title, dumpsys, options);
3407}
3408
3409int open_socket(const char *service) {
3410 int s = android_get_control_socket(service);
3411 if (s < 0) {
3412 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3413 return -1;
3414 }
3415 fcntl(s, F_SETFD, FD_CLOEXEC);
3416
3417 // Set backlog to 0 to make sure that queue size will be minimum.
3418 // In Linux, because the minimum queue will be 1, connect() will be blocked
3419 // if the other clients already called connect() and the connection request was not accepted.
3420 if (listen(s, 0) < 0) {
3421 MYLOGE("listen(control socket): %s\n", strerror(errno));
3422 return -1;
3423 }
3424
3425 struct sockaddr addr;
3426 socklen_t alen = sizeof(addr);
3427 int fd = accept(s, &addr, &alen);
3428
3429 // Close socket just after accept(), to make sure that connect() by client will get error
3430 // when the socket is used by the other services.
3431 // There is still a race condition possibility between accept and close, but there is no way
3432 // to close-on-accept atomically.
3433 // See detail; b/123306389#comment25
3434 close(s);
3435
3436 if (fd < 0) {
3437 MYLOGE("accept(control socket): %s\n", strerror(errno));
3438 return -1;
3439 }
3440
3441 return fd;
3442}
3443
3444/* redirect output to a service control socket */
3445bool redirect_to_socket(FILE* redirect, const char* service) {
3446 int fd = open_socket(service);
3447 if (fd == -1) {
3448 return false;
3449 }
3450 fflush(redirect);
3451 // TODO: handle dup2 failure
3452 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3453 close(fd);
3454 return true;
3455}
3456
3457// TODO: should call is_valid_output_file and/or be merged into it.
3458void create_parent_dirs(const char *path) {
3459 char *chp = const_cast<char *> (path);
3460
3461 /* skip initial slash */
3462 if (chp[0] == '/')
3463 chp++;
3464
3465 /* create leading directories, if necessary */
3466 struct stat dir_stat;
3467 while (chp && chp[0]) {
3468 chp = strchr(chp, '/');
3469 if (chp) {
3470 *chp = 0;
3471 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3472 MYLOGI("Creating directory %s\n", path);
3473 if (mkdir(path, 0770)) { /* drwxrwx--- */
3474 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3475 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3476 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3477 }
3478 }
3479 *chp++ = '/';
3480 }
3481 }
3482}
3483
3484bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3485 create_parent_dirs(path);
3486
3487 int fd = TEMP_FAILURE_RETRY(open(path,
3488 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3489 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3490 if (fd < 0) {
3491 MYLOGE("%s: %s\n", path, strerror(errno));
3492 return false;
3493 }
3494
3495 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3496 close(fd);
3497 return true;
3498}
3499
3500bool redirect_to_file(FILE* redirect, char* path) {
3501 return _redirect_to_file(redirect, path, O_TRUNC);
3502}
3503
3504bool redirect_to_existing_file(FILE* redirect, char* path) {
3505 return _redirect_to_file(redirect, path, O_APPEND);
3506}
3507
3508void dump_route_tables() {
3509 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3510 if (PropertiesHelper::IsDryRun()) return;
3511 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3512 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3513 FILE* fp = fopen(RT_TABLES_PATH, "re");
3514 if (!fp) {
3515 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3516 return;
3517 }
3518 char table[16];
3519 // Each line has an integer (the table number), a space, and a string (the table name). We only
3520 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3521 // Add a fixed max limit so this doesn't go awry.
3522 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3523 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3524 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3525 }
3526 fclose(fp);
3527}
3528
3529// TODO: make this function thread safe if sections are generated in parallel.
3530void Dumpstate::UpdateProgress(int32_t delta_sec) {
3531 if (progress_ == nullptr) {
3532 MYLOGE("UpdateProgress: progress_ not set\n");
3533 return;
3534 }
3535
3536 // Always update progess so stats can be tuned...
3537 bool max_changed = progress_->Inc(delta_sec);
3538
3539 // ...but only notifiy listeners when necessary.
3540 if (!options_->do_progress_updates) return;
3541
3542 int progress = progress_->Get();
3543 int max = progress_->GetMax();
3544
3545 // adjusts max on the fly
3546 if (max_changed && listener_ != nullptr) {
3547 listener_->onMaxProgressUpdated(max);
3548 }
3549
3550 int32_t last_update_delta = progress - last_updated_progress_;
3551 if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
3552 return;
3553 }
3554 last_updated_progress_ = progress;
3555
3556 if (control_socket_fd_ >= 0) {
3557 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3558 fsync(control_socket_fd_);
3559 }
3560
3561 int percent = 100 * progress / max;
3562 if (listener_ != nullptr) {
3563 if (percent % 5 == 0) {
3564 // We don't want to spam logcat, so only log multiples of 5.
3565 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3566 percent);
3567 } else {
3568 // stderr is ignored on normal invocations, but useful when calling
3569 // /system/bin/dumpstate directly for debuggging.
3570 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3571 progress, max, percent);
3572 }
3573 // TODO(b/111441001): Remove in favor of onProgress
3574 listener_->onProgressUpdated(progress);
3575
3576 listener_->onProgress(percent);
3577 }
3578}
3579
3580void Dumpstate::TakeScreenshot(const std::string& path) {
3581 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3582 int status =
3583 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3584 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3585 if (status == 0) {
3586 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3587 } else {
3588 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3589 }
3590}
3591
3592bool is_dir(const char* pathname) {
3593 struct stat info;
3594 if (stat(pathname, &info) == -1) {
3595 return false;
3596 }
3597 return S_ISDIR(info.st_mode);
3598}
3599
3600time_t get_mtime(int fd, time_t default_mtime) {
3601 struct stat info;
3602 if (fstat(fd, &info) == -1) {
3603 return default_mtime;
3604 }
3605 return info.st_mtime;
3606}
3607
3608void dump_emmc_ecsd(const char *ext_csd_path) {
3609 // List of interesting offsets
3610 struct hex {
3611 char str[2];
3612 };
3613 static const size_t EXT_CSD_REV = 192 * sizeof(hex);
3614 static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
3615 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
3616 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
3617
3618 std::string buffer;
3619 if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
3620 return;
3621 }
3622
3623 printf("------ %s Extended CSD ------\n", ext_csd_path);
3624
3625 if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
3626 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3627 return;
3628 }
3629
3630 int ext_csd_rev = 0;
3631 std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
3632 if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
3633 printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3634 return;
3635 }
3636
3637 static const char *ver_str[] = {
3638 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
3639 };
3640 printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
3641 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
3642 : "Unknown");
3643 if (ext_csd_rev < 7) {
3644 printf("\n");
3645 return;
3646 }
3647
3648 if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
3649 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3650 return;
3651 }
3652
3653 int ext_pre_eol_info = 0;
3654 sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
3655 if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
3656 printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3657 return;
3658 }
3659
3660 static const char *eol_str[] = {
3661 "Undefined",
3662 "Normal",
3663 "Warning (consumed 80% of reserve)",
3664 "Urgent (consumed 90% of reserve)"
3665 };
3666 printf(
3667 "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
3668 eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
3669 : 0]);
3670
3671 for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
3672 lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
3673 lifetime += sizeof(hex)) {
3674 int ext_device_life_time_est;
3675 static const char *est_str[] = {
3676 "Undefined",
3677 "0-10% of device lifetime used",
3678 "10-20% of device lifetime used",
3679 "20-30% of device lifetime used",
3680 "30-40% of device lifetime used",
3681 "40-50% of device lifetime used",
3682 "50-60% of device lifetime used",
3683 "60-70% of device lifetime used",
3684 "70-80% of device lifetime used",
3685 "80-90% of device lifetime used",
3686 "90-100% of device lifetime used",
3687 "Exceeded the maximum estimated device lifetime",
3688 };
3689
3690 if (buffer.length() < (lifetime + sizeof(hex))) {
3691 printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
3692 break;
3693 }
3694
3695 ext_device_life_time_est = 0;
3696 sub = buffer.substr(lifetime, sizeof(hex));
3697 if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
3698 printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
3699 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3700 sub.c_str());
3701 continue;
3702 }
3703 printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
3704 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3705 ext_device_life_time_est,
3706 est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
3707 ? ext_device_life_time_est
3708 : 0]);
3709 }
3710
3711 printf("\n");
3712}
3713