blob: 957dfa1c415b6a20262e2d683342ca7e22bd3f17 [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>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070046#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000047#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070048#include <functional>
49#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010050#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070051#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010052#include <regex>
53#include <set>
54#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070055#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010056#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070057
Felipe Leme96c2bbb2016-09-26 09:21:21 -070058#include <android-base/file.h>
59#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070060#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080061#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070062#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070063#include <android-base/unique_fd.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080064#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080065#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000066#include <android/os/IIncidentCompanion.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080067#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070068#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010069#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000070#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080071#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000072#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010073#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080074#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010075#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070076#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070077#include <private/android_filesystem_config.h>
78#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080079#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070080#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080081#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070082#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070083#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080084
Steven Morelandcb7ef822016-11-29 13:20:37 -080085using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080086using ::std::literals::chrono_literals::operator""ms;
87using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080088
Felipe Leme47e9be22016-12-21 15:37:07 -080089// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080090using android::defaultServiceManager;
91using android::Dumpsys;
92using android::INVALID_OPERATION;
93using android::IServiceManager;
94using android::OK;
95using android::sp;
96using android::status_t;
97using android::String16;
98using android::String8;
99using android::TIMED_OUT;
100using android::UNKNOWN_ERROR;
101using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000102using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000103using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800104using android::os::dumpstate::CommandOptions;
105using android::os::dumpstate::DumpFileToFd;
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());
Vishnu Naire97d6122018-01-18 13:58:56 -08001019 size_t bytes_written = 0;
1020 status_t status = dumpsys.startDumpThread(service, args);
1021 if (status == OK) {
1022 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1023 std::chrono::duration<double> elapsed_seconds;
1024 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1025 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001026 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1027 bool dump_complete = (status == OK);
1028 dumpsys.stopDumpThread(dump_complete);
1029 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001030
1031 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1032 std::chrono::steady_clock::now() - start);
1033 if (elapsed_duration > timeout) {
1034 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1035 elapsed_duration.count());
1036 break;
1037 }
1038 }
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001039 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001040}
1041
Vishnu Nair64afc022018-02-01 15:29:34 -08001042static void RunDumpsysText(const std::string& title, int priority,
1043 std::chrono::milliseconds timeout,
1044 std::chrono::milliseconds service_timeout) {
1045 DurationReporter duration_reporter(title);
1046 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1047 fsync(STDOUT_FILENO);
1048 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1049}
1050
1051/* Dump all services registered with Normal or Default priority. */
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001052static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1053 std::chrono::milliseconds timeout,
1054 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001055 DurationReporter duration_reporter(title);
1056 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1057 fsync(STDOUT_FILENO);
1058 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1059 service_timeout);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001060
1061 RETURN_IF_USER_DENIED_CONSENT();
1062
1063 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1064 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001065}
1066
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001067static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1068 std::chrono::milliseconds timeout,
1069 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001070 if (!ds.IsZipping()) {
1071 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001072 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001073 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001074 sp<android::IServiceManager> sm = defaultServiceManager();
1075 Dumpsys dumpsys(sm.get());
1076 Vector<String16> args;
1077 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1078 DurationReporter duration_reporter(title);
1079
1080 auto start = std::chrono::steady_clock::now();
1081 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1082 for (const String16& service : services) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001083 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001084 std::string path(kProtoPath);
1085 path.append(String8(service).c_str());
1086 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1087 path.append("_CRITICAL");
1088 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1089 path.append("_HIGH");
1090 }
1091 path.append(kProtoExt);
Vishnu Naire97d6122018-01-18 13:58:56 -08001092 status_t status = dumpsys.startDumpThread(service, args);
1093 if (status == OK) {
1094 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1095 bool dumpTerminated = (status == OK);
1096 dumpsys.stopDumpThread(dumpTerminated);
1097 }
1098 ZipWriter::FileEntry file_entry;
1099 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001100
1101 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1102 std::chrono::steady_clock::now() - start);
1103 if (elapsed_duration > timeout) {
1104 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1105 elapsed_duration.count());
1106 break;
1107 }
1108 }
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001109 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001110}
1111
Nandana Dutta7db6342018-11-21 14:53:34 +00001112// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001113static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001114 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1115 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001116
1117 RETURN_IF_USER_DENIED_CONSENT();
1118
1119 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1120 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001121}
1122
1123// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001124static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001125 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1126 // high priority. Reduce timeout once they are able to dump in a shorter time or
1127 // moved to a parallel task.
1128 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1129 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001130
1131 RETURN_IF_USER_DENIED_CONSENT();
1132
1133 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1134 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001135}
1136
1137// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001138static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001139 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001140
1141 RETURN_IF_USER_DENIED_CONSENT();
1142
1143 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1144 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001145}
1146
Steven Moreland44cd9482018-01-04 16:24:13 -08001147static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001148 if (!ds.IsZipping()) {
1149 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1150 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1151 return;
1152 }
1153 DurationReporter duration_reporter("DUMP HALS");
1154 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001155 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001156
Steven Moreland44cd9482018-01-04 16:24:13 -08001157 using android::hidl::manager::V1_0::IServiceManager;
1158 using android::hardware::defaultServiceManager;
1159
1160 sp<IServiceManager> sm = defaultServiceManager();
1161 if (sm == nullptr) {
1162 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1163 return;
1164 }
1165
1166 auto ret = sm->list([&](const auto& interfaces) {
1167 for (const std::string& interface : interfaces) {
1168 std::string cleanName = interface;
1169 std::replace_if(cleanName.begin(),
1170 cleanName.end(),
1171 [](char c) {
1172 return !isalnum(c) &&
1173 std::string("@-_:.").find(c) == std::string::npos;
1174 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001175 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001176
1177 {
1178 auto fd = android::base::unique_fd(
1179 TEMP_FAILURE_RETRY(open(path.c_str(),
1180 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1181 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1182 if (fd < 0) {
1183 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1184 continue;
1185 }
1186 RunCommandToFd(fd,
1187 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001188 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001189 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1190
1191 bool empty = 0 == lseek(fd, 0, SEEK_END);
1192 if (!empty) {
1193 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1194 }
1195 }
1196
1197 unlink(path.c_str());
1198 }
1199 });
1200
1201 if (!ret.isOk()) {
1202 MYLOGE("Could not list hals from hwservicemanager.\n");
1203 }
1204}
1205
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001206static void DumpExternalFragmentationInfo() {
1207 struct stat st;
1208 if (stat("/proc/buddyinfo", &st) != 0) {
1209 MYLOGE("Unable to dump external fragmentation info\n");
1210 return;
1211 }
1212
1213 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1214 std::ifstream ifs("/proc/buddyinfo");
1215 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1216 for (std::string line; std::getline(ifs, line);) {
1217 std::smatch match_results;
1218 if (std::regex_match(line, match_results, unusable_index_regex)) {
1219 std::stringstream free_pages(std::string{match_results[3]});
1220 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1221 std::istream_iterator<int>());
1222
1223 int total_free_pages = 0;
1224 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1225 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1226 }
1227
1228 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1229 match_results[2].str().c_str());
1230
1231 int usable_free_pages = total_free_pages;
1232 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1233 auto unusable_index = (total_free_pages - usable_free_pages) /
1234 static_cast<double>(total_free_pages);
1235 printf(" %5.3f", unusable_index);
1236 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1237 }
1238
1239 printf("\n");
1240 }
1241 }
1242 printf("\n");
1243}
1244
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001245// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1246// via the consent they are shown. Ignores other errors that occur while running various
1247// commands. The consent checking is currently done around long running tasks, which happen to
1248// be distributed fairly evenly throughout the function.
1249static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001250 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001251
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001252 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1253 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1254 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001255 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001256 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001257 DumpBlockStatFiles();
Mark Salyzyn8c8130e2015-12-09 11:21:28 -08001258 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001259 DumpFile("MEMORY INFO", "/proc/meminfo");
1260 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001261 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001262
1263 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1264
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001265 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1266 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1267 DumpFile("SLAB INFO", "/proc/slabinfo");
1268 DumpFile("ZONEINFO", "/proc/zoneinfo");
1269 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1270 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001271 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001272
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001273 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1274 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001275
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001276 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001277 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001278
1279 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1280 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001281
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001282 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001283
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001284 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001285 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001286 struct stat s;
1287 if (stat("/proc/modules", &s) != 0) {
1288 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1289 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001290 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001291 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001292
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001293 if (__android_logger_property_get_bool(
1294 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1295 DoKernelLogcat();
1296 } else {
1297 do_dmesg();
1298 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001299
Felipe Lemef0292972016-11-22 13:57:05 -08001300 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001301
1302 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1303
Jeff Brown1dc94e32014-09-11 14:15:27 -07001304 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001305 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001306
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001307 /* Dump Bluetooth HCI logs */
1308 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001309
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001310 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001311 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001312 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001313 }
1314
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001315 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001316
Felipe Lemee184f662016-10-27 10:04:47 -07001317 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001318
Narayan Kamath8f788292017-05-25 13:20:39 +01001319 // NOTE: tombstones are always added as separate entries in the zip archive
1320 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001321 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001322 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001323 if (!tombstones_dumped) {
1324 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001325 }
1326
Jayachandran Ca94c7172017-06-10 15:08:12 -07001327 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001328
Chenbo Feng276a3b62018-08-07 11:44:49 -07001329 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1330
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001331 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001332
Jayachandran Ca94c7172017-06-10 15:08:12 -07001333 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001334
1335 dump_route_tables();
1336
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001337 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1338 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1339 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001340
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001341 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001342
Elliott Hughes23ccc622017-02-28 10:14:22 -08001343 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001344
Jin Qianf334d662017-10-10 14:41:37 -07001345 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001346
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001347 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001348
Colin Crossf45fa6b2012-03-26 12:38:26 -07001349 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001350 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1351 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1352 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1353 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1354 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001355
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001356 /* Add window and surface trace files. */
1357 if (!PropertiesHelper::IsUserBuild()) {
1358 ds.AddDir(WMTRACE_DATA_DIR, false);
1359 }
1360
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001361 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001362
Steven Moreland7440ddb2016-12-15 16:13:39 -08001363 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001364 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1365 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001366 // su does not exist on user builds, so try running without it.
1367 // This way any implementations of vril-dump that do not require
1368 // root can run on user builds.
1369 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001370 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001371 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001372 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001373 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001374 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001375 }
1376
Felipe Lemed8b94e52016-12-08 10:21:44 -08001377 printf("========================================================\n");
1378 printf("== Android Framework Services\n");
1379 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001380
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001381 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001382
Felipe Lemed8b94e52016-12-08 10:21:44 -08001383 printf("========================================================\n");
1384 printf("== Checkins\n");
1385 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001386
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001387 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001388
1389 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1390
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001391 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1392 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1393 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1394 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001395
Felipe Lemed8b94e52016-12-08 10:21:44 -08001396 printf("========================================================\n");
1397 printf("== Running Application Activities\n");
1398 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001399
Makoto Onuki60780982018-04-16 15:34:00 -07001400 // The following dumpsys internally collects output from running apps, so it can take a long
1401 // time. So let's extend the timeout.
1402
1403 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1404
1405 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001406
Felipe Lemed8b94e52016-12-08 10:21:44 -08001407 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001408 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001409 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001410
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001411 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001412 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001413
Felipe Lemed8b94e52016-12-08 10:21:44 -08001414 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001415 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001416 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001417
Makoto Onuki60780982018-04-16 15:34:00 -07001418 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1419 DUMPSYS_COMPONENTS_OPTIONS);
1420
1421 printf("========================================================\n");
1422 printf("== Running Application Providers (platform)\n");
1423 printf("========================================================\n");
1424
1425 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1426 DUMPSYS_COMPONENTS_OPTIONS);
1427
1428 printf("========================================================\n");
1429 printf("== Running Application Providers (non-platform)\n");
1430 printf("========================================================\n");
1431
1432 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1433 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001434
Adrian Roos8b397ab2017-04-04 16:35:44 -07001435 printf("========================================================\n");
1436 printf("== Dropbox crashes\n");
1437 printf("========================================================\n");
1438
1439 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1440 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1441
Felipe Lemed8b94e52016-12-08 10:21:44 -08001442 printf("========================================================\n");
1443 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1444 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1445 printf("========================================================\n");
1446 printf("== dumpstate: done (id %d)\n", ds.id_);
1447 printf("========================================================\n");
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001448 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001449}
1450
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001451/*
1452 * Dumps state for the default case; drops root after it's no longer necessary.
1453 *
1454 * Returns RunStatus::OK if everything went fine.
1455 * Returns RunStatus::ERROR if there was an error.
1456 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1457 * with the caller.
1458 */
1459static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001460 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001461 // keep the system stats as close to its initial state as possible.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001462 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001463
1464 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001465 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001466
1467 /* Run some operations that require root. */
1468 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1469 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1470
1471 ds.AddDir(RECOVERY_DIR, true);
1472 ds.AddDir(RECOVERY_DATA_DIR, true);
1473 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1474 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1475 if (!PropertiesHelper::IsUserBuild()) {
1476 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1477 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1478 }
1479 add_mountinfo();
1480 DumpIpTablesAsRoot();
1481
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001482 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001483 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1484
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001485 // Dump IPsec stats. No keys are exposed here.
1486 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1487
Nandana Dutt4be45d12018-09-26 15:04:23 +01001488 // Run ss as root so we can see socket marks.
1489 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1490
1491 // Run iotop as root to show top 100 IO threads
1492 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1493
Erick Reyese68df822019-02-11 14:46:36 -08001494 // Gather shared memory buffer info if the product implements it
1495 struct stat st;
1496 if (!stat("/product/bin/dmabuf_dump", &st)) {
1497 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1498 }
1499
Nandana Dutt4be45d12018-09-26 15:04:23 +01001500 if (!DropRootUser()) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001501 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001502 }
1503
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001504 RETURN_IF_USER_DENIED_CONSENT();
1505 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001506}
1507
mukesh agrawal253dad42018-01-23 21:59:59 -08001508// This method collects common dumpsys for telephony and wifi
1509static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001510 DumpIpTablesAsRoot();
1511
1512 if (!DropRootUser()) {
1513 return;
1514 }
1515
1516 do_dmesg();
1517 DoLogcat();
1518 DumpPacketStats();
1519 DoKmsg();
1520 DumpIpAddrAndRules();
1521 dump_route_tables();
1522
1523 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1524 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001525}
1526
1527// This method collects dumpsys for telephony debugging only
1528static void DumpstateTelephonyOnly() {
1529 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001530 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001531
1532 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001533
1534 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1535
1536 printf("========================================================\n");
1537 printf("== Android Framework Services\n");
1538 printf("========================================================\n");
1539
Vishnu Nair652cc802017-11-30 15:18:30 -08001540 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1541 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001542 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1543 SEC_TO_MSEC(10));
1544 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001545 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1546 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001547 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1548 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001549 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1550 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001551
1552 printf("========================================================\n");
1553 printf("== Running Application Services\n");
1554 printf("========================================================\n");
1555
1556 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1557
1558 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001559 printf("== Running Application Services (non-platform)\n");
1560 printf("========================================================\n");
1561
1562 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1563 DUMPSYS_COMPONENTS_OPTIONS);
1564
1565 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001566 printf("== Checkins\n");
1567 printf("========================================================\n");
1568
1569 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1570
1571 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001572 printf("== dumpstate: done (id %d)\n", ds.id_);
1573 printf("========================================================\n");
1574}
1575
mukesh agrawal253dad42018-01-23 21:59:59 -08001576// This method collects dumpsys for wifi debugging only
1577static void DumpstateWifiOnly() {
1578 DurationReporter duration_reporter("DUMPSTATE");
1579
1580 DumpstateRadioCommon();
1581
1582 printf("========================================================\n");
1583 printf("== Android Framework Services\n");
1584 printf("========================================================\n");
1585
1586 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1587 SEC_TO_MSEC(10));
1588 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1589 SEC_TO_MSEC(10));
1590
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001591 DumpHals();
Roger Wang70399032019-01-08 16:10:37 +08001592
mukesh agrawal253dad42018-01-23 21:59:59 -08001593 printf("========================================================\n");
1594 printf("== dumpstate: done (id %d)\n", ds.id_);
1595 printf("========================================================\n");
1596}
1597
Nandana Duttcf419a72019-03-14 10:40:17 +00001598Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001599 DurationReporter duration_reporter("DUMP TRACES");
1600
1601 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1602 const size_t buf_size = temp_file_pattern.length() + 1;
1603 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1604 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1605
1606 // Create a new, empty file to receive all trace dumps.
1607 //
1608 // TODO: This can be simplified once we remove support for the old style
1609 // dumps. We can have a file descriptor passed in to dump_traces instead
1610 // of creating a file, closing it and then reopening it again.
1611 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1612 if (fd < 0) {
1613 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001614 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001615 }
1616
1617 // Nobody should have access to this temporary file except dumpstate, but we
1618 // temporarily grant 'read' to 'others' here because this file is created
1619 // when tombstoned is still running as root, but dumped after dropping. This
1620 // can go away once support for old style dumping has.
1621 const int chmod_ret = fchmod(fd, 0666);
1622 if (chmod_ret < 0) {
1623 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001624 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001625 }
1626
1627 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1628 if (proc.get() == nullptr) {
1629 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001630 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001631 }
1632
1633 // Number of times process dumping has timed out. If we encounter too many
1634 // failures, we'll give up.
1635 int timeout_failures = 0;
1636 bool dalvik_found = false;
1637
1638 const std::set<int> hal_pids = get_interesting_hal_pids();
1639
1640 struct dirent* d;
1641 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001642 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001643 int pid = atoi(d->d_name);
1644 if (pid <= 0) {
1645 continue;
1646 }
1647
1648 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1649 std::string exe;
1650 if (!android::base::Readlink(link_name, &exe)) {
1651 continue;
1652 }
1653
1654 bool is_java_process;
1655 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1656 // Don't bother dumping backtraces for the zygote.
1657 if (IsZygote(pid)) {
1658 continue;
1659 }
1660
1661 dalvik_found = true;
1662 is_java_process = true;
1663 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1664 is_java_process = false;
1665 } else {
1666 // Probably a native process we don't care about, continue.
1667 continue;
1668 }
1669
1670 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1671 if (timeout_failures == 3) {
1672 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1673 break;
1674 }
1675
1676 const uint64_t start = Nanotime();
1677 const int ret = dump_backtrace_to_file_timeout(
1678 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1679 is_java_process ? 5 : 20, fd);
1680
1681 if (ret == -1) {
1682 // For consistency, the header and footer to this message match those
1683 // dumped by debuggerd in the success case.
1684 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1685 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1686 dprintf(fd, "---- end %d ----", pid);
1687 timeout_failures++;
1688 continue;
1689 }
1690
1691 // We've successfully dumped stack traces, reset the failure count
1692 // and write a summary of the elapsed time to the file and continue with the
1693 // next process.
1694 timeout_failures = 0;
1695
1696 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1697 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1698 }
1699
1700 if (!dalvik_found) {
1701 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1702 }
1703
Nandana Duttcf419a72019-03-14 10:40:17 +00001704 *path = file_name_buf.release();
1705 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001706}
1707
Felipe Leme6f674ae2016-11-18 17:10:33 -08001708void Dumpstate::DumpstateBoard() {
1709 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001710 printf("========================================================\n");
1711 printf("== Board\n");
1712 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001713
Felipe Leme6f674ae2016-11-18 17:10:33 -08001714 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001715 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001716 return;
1717 }
1718
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001719 std::vector<std::string> paths;
1720 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001721 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001722 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1723 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001724 remover.emplace_back(android::base::make_scope_guard(
1725 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001726 }
Jie Song9fbfad02017-06-20 16:29:42 -07001727
Wei Wang587eac92018-04-05 12:17:20 -07001728 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1729 if (dumpstate_device == nullptr) {
1730 MYLOGE("No IDumpstateDevice implementation\n");
1731 return;
1732 }
1733
1734 using ScopedNativeHandle =
1735 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1736 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1737 [](native_handle_t* handle) {
1738 native_handle_close(handle);
1739 native_handle_delete(handle);
1740 });
1741 if (handle == nullptr) {
1742 MYLOGE("Could not create native_handle\n");
1743 return;
1744 }
1745
Nandana Duttbbdb5b42019-03-12 10:52:56 +00001746 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001747 for (size_t i = 0; i < paths.size(); i++) {
1748 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1749
1750 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1751 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1752 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1753 if (fd < 0) {
1754 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1755 return;
1756 }
1757 handle.get()->data[i] = fd.release();
1758 }
1759
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001760 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001761 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1762 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1763 // and grab whatever dumped
1764 std::packaged_task<bool()>
1765 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001766 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1767 if (!status.isOk()) {
1768 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001769 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001770 }
Wei Wang587eac92018-04-05 12:17:20 -07001771 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001772 });
Wei Wang587eac92018-04-05 12:17:20 -07001773
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001774 auto result = dumpstate_task.get_future();
1775 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001776
1777 constexpr size_t timeout_sec = 30;
1778 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1779 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1780 if (!android::base::SetProperty("ctl.interface_restart",
1781 android::base::StringPrintf("%s/default",
1782 IDumpstateDevice::descriptor))) {
1783 MYLOGE("Couldn't restart dumpstate HAL\n");
1784 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001785 }
Wei Wang587eac92018-04-05 12:17:20 -07001786 // Wait some time for init to kill dumpstate vendor HAL
1787 constexpr size_t killing_timeout_sec = 10;
1788 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1789 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1790 "there might be racing in content\n", killing_timeout_sec);
1791 }
1792
1793 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1794 for (size_t i = 0; i < paths.size(); i++) {
1795 struct stat s;
1796 if (fstat(handle.get()->data[i], &s) == -1) {
1797 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1798 strerror(errno));
1799 file_sizes[i] = -1;
1800 continue;
1801 }
1802 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001803 }
1804
1805 for (size_t i = 0; i < paths.size(); i++) {
1806 if (file_sizes[i] == -1) {
1807 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001808 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001809 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001810 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001811 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001812 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001813 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001814 }
1815
Felipe Lemed8b94e52016-12-08 10:21:44 -08001816 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001817}
1818
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001819static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001820 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001821 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001822 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1823 " -h: display this help message\n"
1824 " -b: play sound file instead of vibrate, at beginning of job\n"
1825 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001826 " -d: append date to filename\n"
1827 " -p: capture screenshot to filename.png\n"
1828 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001829 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001830 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001831 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001832 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001833 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001834 "progress (requires -B)\n"
1835 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001836 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001837 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001838 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001839}
1840
Wei Liuf87959e2016-08-26 14:51:42 -07001841static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001842 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001843}
1844
Felipe Leme1d486fe2016-10-14 18:06:47 -07001845bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001846 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001847 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001848 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001849 // Final timestamp
1850 char date[80];
1851 time_t the_real_now_please_stand_up = time(nullptr);
1852 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001853 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001854 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001855
Felipe Leme9a523ae2016-10-20 15:10:33 -07001856 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001857 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001858 return false;
1859 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001860 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001861 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001862 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001863 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001864
Felipe Leme0f3fb202016-06-10 17:10:53 -07001865 // Add log file (which contains stderr output) to zip...
1866 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001867 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001868 MYLOGE("Failed to add dumpstate log to .zip file\n");
1869 return false;
1870 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001871 // TODO: Should truncate the existing file.
1872 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001873 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1874 return false;
1875 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001876 fprintf(stderr, "\n");
1877
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001878 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001879 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001880 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001881 return false;
1882 }
1883
Felipe Leme1d486fe2016-10-14 18:06:47 -07001884 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1885 ds.zip_file.reset(nullptr);
1886
Felipe Lemee9d2c542016-11-15 11:48:26 -08001887 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001888 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001889
Felipe Leme1e9edc62015-12-21 16:02:13 -08001890 return true;
1891}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001892
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001893static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001894 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1895 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001896 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001897 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001898 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001899 }
1900
1901 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001902 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001903
1904 std::vector<uint8_t> buffer(65536);
1905 while (1) {
1906 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1907 if (bytes_read == 0) {
1908 break;
1909 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001910 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001911 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001912 }
1913
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001914 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001915 }
1916
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001917 uint8_t hash[SHA256_DIGEST_LENGTH];
1918 SHA256_Final(hash, &ctx);
1919
1920 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1921 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001922 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001923 }
1924 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1925 return std::string(hash_buffer);
1926}
1927
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001928static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1929 // clang-format off
1930 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1931 "--receiver-foreground", "--receiver-include-background", "-a", action};
1932 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001933
1934 am.insert(am.end(), args.begin(), args.end());
1935
Felipe Leme8d2410e2017-02-08 09:46:08 -08001936 RunCommand("", am,
1937 CommandOptions::WithTimeout(20)
1938 .Log("Sending broadcast: '%s'\n")
1939 .Always()
1940 .DropRoot()
1941 .RedirectStderr()
1942 .Build());
1943}
1944
Felipe Leme35b8cf12017-02-10 15:47:29 -08001945static void Vibrate(int duration_ms) {
1946 // clang-format off
Chris Friese7e95fb2019-06-14 14:47:59 +00001947 RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001948 CommandOptions::WithTimeout(10)
1949 .Log("Vibrate: '%s'\n")
1950 .Always()
1951 .Build());
1952 // clang-format on
1953}
1954
Nandana Dutt979388e2018-11-30 16:48:55 +00001955static void MaybeResolveSymlink(std::string* path) {
1956 std::string resolved_path;
1957 if (android::base::Readlink(*path, &resolved_path)) {
1958 *path = resolved_path;
1959 }
1960}
1961
Nandana Dutt4be45d12018-09-26 15:04:23 +01001962/*
1963 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
1964 * if we are writing zip files and adds the version file.
1965 */
1966static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00001967 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
1968
Nandana Dutt4be45d12018-09-26 15:04:23 +01001969 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1970 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00001971 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001972 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001973 char date[80];
1974 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
1975 ds.name_ = date;
1976 } else {
1977 ds.name_ = "undated";
1978 }
1979
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001980 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001981 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001982 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001983 ds.base_name_ += "-wifi";
1984 }
1985
Nandana Dutt5fb117b2018-09-27 09:23:36 +01001986 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01001987 ds.screenshot_path_ = ds.GetPath(".png");
1988 }
1989 ds.tmp_path_ = ds.GetPath(".tmp");
1990 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
1991
Nandana Dutt54dbd672019-01-11 12:58:05 +00001992 std::string destination = ds.options_->bugreport_fd.get() != -1
1993 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00001994 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001995 MYLOGD(
1996 "Bugreport dir: %s\n"
1997 "Base name: %s\n"
1998 "Suffix: %s\n"
1999 "Log path: %s\n"
2000 "Temporary path: %s\n"
2001 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002002 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2003 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002004
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002005 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002006 ds.path_ = ds.GetPath(".zip");
2007 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2008 create_parent_dirs(ds.path_.c_str());
2009 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2010 if (ds.zip_file == nullptr) {
2011 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2012 } else {
2013 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2014 }
2015 ds.AddTextZipEntry("version.txt", ds.version_);
2016 }
2017}
2018
2019/*
2020 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2021 * printing zipped file status, etc.
2022 */
2023static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002024 /* check if user changed the suffix using system properties */
2025 std::string name =
2026 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2027 bool change_suffix = false;
2028 if (!name.empty()) {
2029 /* must whitelist which characters are allowed, otherwise it could cross directories */
2030 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2031 if (std::regex_match(name.c_str(), valid_regex)) {
2032 change_suffix = true;
2033 } else {
2034 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2035 }
2036 }
2037 if (change_suffix) {
2038 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2039 ds.name_ = name;
2040 if (!ds.screenshot_path_.empty()) {
2041 std::string new_screenshot_path = ds.GetPath(".png");
2042 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2043 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2044 new_screenshot_path.c_str(), strerror(errno));
2045 } else {
2046 ds.screenshot_path_ = new_screenshot_path;
2047 }
2048 }
2049 }
2050
2051 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002052 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002053 if (!ds.FinishZipFile()) {
2054 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2055 do_text_file = true;
2056 } else {
2057 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002058 // If the user has changed the suffix, we need to change the zip file name.
2059 std::string new_path = ds.GetPath(".zip");
2060 if (ds.path_ != new_path) {
2061 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2062 if (rename(ds.path_.c_str(), new_path.c_str())) {
2063 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2064 strerror(errno));
2065 } else {
2066 ds.path_ = new_path;
2067 }
2068 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002069 }
2070 }
2071 if (do_text_file) {
2072 ds.path_ = ds.GetPath(".txt");
2073 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2074 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2075 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2076 ds.path_.clear();
2077 }
2078 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002079 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002080 if (do_text_file) {
2081 dprintf(ds.control_socket_fd_,
2082 "FAIL:could not create zip file, check %s "
2083 "for more details\n",
2084 ds.log_path_.c_str());
2085 } else {
2086 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2087 }
2088 }
2089}
2090
2091/* Broadcasts that we are done with the bugreport */
2092static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002093 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002094 if (!ds.path_.empty()) {
2095 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002096 // clang-format off
2097
2098 std::vector<std::string> am_args = {
2099 "--receiver-permission", "android.permission.DUMP",
2100 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2101 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2102 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002103 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002104 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2105 };
2106 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002107 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002108 am_args.push_back("--es");
2109 am_args.push_back("android.intent.extra.SCREENSHOT");
2110 am_args.push_back(ds.screenshot_path_);
2111 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002112 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002113 am_args.push_back("--es");
2114 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002115 am_args.push_back(ds.options_->notification_title);
2116 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002117 am_args.push_back("--es");
2118 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002119 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002120 }
2121 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002122 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002123 am_args.push_back("--es");
2124 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002125 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002126 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2127 } else {
2128 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2129 }
2130 } else {
2131 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2132 }
2133}
2134
Nandana Dutt58d72e22018-11-16 10:30:48 +00002135static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2136 switch (mode) {
2137 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2138 return "BUGREPORT_FULL";
2139 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2140 return "BUGREPORT_INTERACTIVE";
2141 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2142 return "BUGREPORT_REMOTE";
2143 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2144 return "BUGREPORT_WEAR";
2145 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2146 return "BUGREPORT_TELEPHONY";
2147 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2148 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002149 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2150 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002151 }
2152}
2153
2154static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002155 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002156 switch (mode) {
2157 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2158 options->do_broadcast = true;
2159 options->do_fb = true;
2160 break;
2161 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002162 // Currently, the dumpstate binder is only used by Shell to update progress.
2163 options->do_start_service = true;
2164 options->do_progress_updates = true;
2165 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002166 options->do_broadcast = true;
2167 break;
2168 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002169 options->do_vibrate = false;
2170 options->is_remote_mode = true;
2171 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002172 options->do_broadcast = true;
2173 break;
2174 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002175 options->do_start_service = true;
2176 options->do_progress_updates = true;
2177 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002178 options->do_fb = true;
2179 options->do_broadcast = true;
2180 break;
2181 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002182 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002183 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002184 options->do_broadcast = true;
2185 break;
2186 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002187 options->wifi_only = true;
2188 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002189 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002190 options->do_broadcast = true;
2191 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002192 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2193 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002194 }
2195}
2196
2197static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002198 // If the system property is not set, it's assumed to be a default bugreport.
2199 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002200
2201 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2202 if (!extra_options.empty()) {
2203 // Framework uses a system property to override some command-line args.
2204 // Currently, it contains the type of the requested bugreport.
2205 if (extra_options == "bugreportplus") {
2206 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002207 } else if (extra_options == "bugreportfull") {
2208 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002209 } else if (extra_options == "bugreportremote") {
2210 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2211 } else if (extra_options == "bugreportwear") {
2212 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2213 } else if (extra_options == "bugreporttelephony") {
2214 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2215 } else if (extra_options == "bugreportwifi") {
2216 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002217 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002218 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002219 }
2220 // Reset the property
2221 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2222 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002223 return mode;
2224}
2225
2226// TODO: Move away from system properties when we have options passed via binder calls.
2227/* Sets runtime options from the system properties and then clears those properties. */
2228static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2229 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2230 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002231
2232 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2233 if (!options->notification_title.empty()) {
2234 // Reset the property
2235 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2236
Nandana Duttdd8cca32018-11-14 10:10:29 +00002237 options->notification_description =
2238 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002239 if (!options->notification_description.empty()) {
2240 // Reset the property
2241 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2242 }
2243 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2244 options->notification_description.c_str());
2245 }
2246}
2247
Nandana Dutt58d72e22018-11-16 10:30:48 +00002248static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2249 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2250 MYLOGI("do_add_date: %d\n", options.do_add_date);
2251 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2252 MYLOGI("use_socket: %d\n", options.use_socket);
2253 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2254 MYLOGI("do_fb: %d\n", options.do_fb);
2255 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2256 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2257 MYLOGI("show_header_only: %d\n", options.show_header_only);
2258 MYLOGI("do_start_service: %d\n", options.do_start_service);
2259 MYLOGI("telephony_only: %d\n", options.telephony_only);
2260 MYLOGI("wifi_only: %d\n", options.wifi_only);
2261 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002262 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002263 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2264 MYLOGI("args: %s\n", options.args.c_str());
2265 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2266 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2267}
2268
Nandana Dutt54dbd672019-01-11 12:58:05 +00002269void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2270 const android::base::unique_fd& bugreport_fd_in,
2271 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002272 // In the new API world, date is always added; output is always a zip file.
2273 // TODO(111441001): remove these options once they are obsolete.
2274 do_add_date = true;
2275 do_zip_file = true;
2276
Nandana Dutt54dbd672019-01-11 12:58:05 +00002277 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2278 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2279 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002280
2281 extra_options = ModeToString(bugreport_mode);
2282 SetOptionsFromMode(bugreport_mode, this);
2283}
2284
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002285Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2286 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002287 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002288 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002289 switch (c) {
2290 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002291 case 'd': do_add_date = true; break;
2292 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002293 // o=use_outfile not supported anymore.
2294 // TODO(b/111441001): Remove when all callers have migrated.
2295 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002296 case 's': use_socket = true; break;
2297 case 'S': use_control_socket = true; break;
2298 case 'v': show_header_only = true; break;
2299 case 'q': do_vibrate = false; break;
2300 case 'p': do_fb = true; break;
2301 case 'P': do_progress_updates = true; break;
2302 case 'R': is_remote_mode = true; break;
2303 case 'B': do_broadcast = true; break;
2304 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002305 case 'w':
2306 // This was already processed
2307 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002308 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002309 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002310 break;
2311 default:
2312 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002313 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002314 break;
2315 // clang-format on
2316 }
2317 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002318
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002319 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002320 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002321 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002322 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002323 }
2324 }
2325
2326 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2327 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002328
2329 SetOptionsFromProperties(this);
2330 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002331}
2332
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002333bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002334 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002335 return false;
2336 }
2337
Nandana Dutt9a76d202019-01-21 15:56:48 +00002338 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002339 return false;
2340 }
2341
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002342 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002343 return false;
2344 }
2345
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002346 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002347 return false;
2348 }
2349
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002350 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002351 return false;
2352 }
2353 return true;
2354}
2355
Nandana Dutt197661d2018-11-16 16:40:21 +00002356void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2357 options_ = std::move(options);
2358}
2359
Nandana Duttd2f5f082019-01-18 17:13:52 +00002360Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2361 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002362 if (listener_ != nullptr) {
2363 switch (status) {
2364 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002365 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002366 break;
2367 case Dumpstate::RunStatus::HELP:
2368 break;
2369 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002370 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002371 break;
2372 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002373 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2374 break;
2375 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2376 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2377 break;
2378 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2379 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002380 break;
2381 }
2382 }
2383 return status;
2384}
2385
Nandana Dutt979388e2018-11-30 16:48:55 +00002386/*
2387 * Dumps relevant information to a bugreport based on the given options.
2388 *
2389 * The bugreport can be dumped to a file or streamed to a socket.
2390 *
2391 * How dumping to file works:
2392 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2393 * stderr is redirected a log file.
2394 *
2395 * The temporary bugreport is then populated via printfs, dumping contents of files and
2396 * output of commands to stdout.
2397 *
2398 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2399 * text file.
2400 *
2401 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2402 * gets added to the archive.
2403 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002404 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2405 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002406 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002407Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2408 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002409 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002410 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002411 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002412 return RunStatus::INVALID_INPUT;
2413 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002414 /* set as high priority, and protect from OOM killer */
2415 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002416
Felipe Lemed071c682016-10-20 16:48:00 -07002417 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002418 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002419 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002420 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002421 } else {
2422 /* fallback to kernels <= 2.6.35 */
2423 oom_adj = fopen("/proc/self/oom_adj", "we");
2424 if (oom_adj) {
2425 fputs("-17", oom_adj);
2426 fclose(oom_adj);
2427 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002428 }
2429
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002430 if (version_ == VERSION_DEFAULT) {
2431 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002432 }
2433
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002434 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002435 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002436 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002437 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002438 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002439 }
2440
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002441 if (options_->show_header_only) {
2442 PrintHeader();
2443 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002444 }
2445
Nandana Duttd2f5f082019-01-18 17:13:52 +00002446 if (options_->bugreport_fd.get() != -1) {
2447 // If the output needs to be copied over to the caller's fd, get user consent.
2448 android::String16 package(calling_package.c_str());
2449 CheckUserConsent(calling_uid, package);
2450 }
2451
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002452 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002453 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002454
2455 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002456 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002457 is_redirecting
2458 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2459 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002460 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002461
Felipe Lemed071c682016-10-20 16:48:00 -07002462 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002463 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002464 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002465 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2466
2467 MYLOGI("begin\n");
2468
Sahana Raof35ed432019-07-12 10:47:52 +01002469 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2470 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2471 } else {
2472 // Wake lock will be released automatically on process death
2473 MYLOGD("Wake lock acquired.\n");
2474 }
2475
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002476 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002477
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002478 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002479 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002480 MYLOGI("Starting 'dumpstate' service\n");
2481 android::status_t ret;
2482 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2483 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2484 }
2485 }
2486
Felipe Lemef0292972016-11-22 13:57:05 -08002487 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002488 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2489 }
2490
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002491 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2492 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002493
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002494 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002495
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002496 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002497
Christopher Ferrised9354f2014-10-01 17:35:01 -07002498 // If we are going to use a socket, do it as early as possible
2499 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002500 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002501 if (!redirect_to_socket(stdout, "dumpstate")) {
2502 return ERROR;
2503 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002504 }
2505
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002506 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002507 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002508 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002509 if (control_socket_fd_ == -1) {
2510 return ERROR;
2511 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002512 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002513 }
2514
Felipe Leme71bbfc52015-11-23 14:14:51 -08002515 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002516 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002517
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002518 if (options_->do_progress_updates) {
2519 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002520 // clang-format off
2521 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002522 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002523 "--es", "android.intent.extra.NAME", name_,
2524 "--ei", "android.intent.extra.ID", std::to_string(id_),
2525 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2526 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002527 };
2528 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002529 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002530 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002531 if (options_->use_control_socket) {
2532 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002533 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002534 }
2535 }
2536
Nick Kralevichf3599b32016-01-25 15:05:16 -08002537 /* read /proc/cmdline before dropping root */
2538 FILE *cmdline = fopen("/proc/cmdline", "re");
2539 if (cmdline) {
2540 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2541 fclose(cmdline);
2542 }
2543
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002544 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002545 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002546 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002547
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002548 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002549 MYLOGI("taking early screenshot\n");
2550 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002551 }
2552
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002553 if (options_->do_zip_file && zip_file != nullptr) {
2554 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2555 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002556 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002557 }
2558 }
2559
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002560 int dup_stdout_fd;
2561 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002562 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002563 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002564 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002565 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2566 return ERROR;
2567 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002568 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2569 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2570 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002571 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002572
2573 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2574 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002575 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002576 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002577 /* TODO: rather than generating a text file now and zipping it later,
2578 it would be more efficient to redirect stdout to the zip entry
2579 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002580 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2581 return ERROR;
2582 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002583 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002584 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002585 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002586 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002587 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002588
2589 // Don't buffer stdout
2590 setvbuf(stdout, nullptr, _IONBF, 0);
2591
Felipe Leme608385d2016-02-01 10:35:38 -08002592 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2593 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002594 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002595 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002596
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002597 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002598 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002599 DumpstateBoard();
2600 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002601 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002602 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002603 // Dump state for the default case. This also drops root.
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002604 RunStatus s = DumpstateDefault();
2605 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002606 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002607 HandleUserConsentDenied();
2608 }
2609 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002610 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002611 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002612
Felipe Leme55b42a62015-11-10 17:39:08 -08002613 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002614 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002615 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002616 }
2617
Nandana Duttd2f5f082019-01-18 17:13:52 +00002618 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002619 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002620 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002621 }
2622
Nandana Duttd2f5f082019-01-18 17:13:52 +00002623 // Share the final file with the caller if the user has consented.
2624 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2625 if (options_->bugreport_fd.get() != -1) {
2626 status = CopyBugreportIfUserConsented();
2627 if (status != Dumpstate::RunStatus::OK &&
2628 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2629 // Do an early return if there were errors. We make an exception for consent
2630 // timing out because it's possible the user got distracted. In this case the
2631 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002632 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002633 return status;
2634 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002635 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002636 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2637 options_->screenshot_fd.get());
2638 if (copy_succeeded) {
2639 android::os::UnlinkAndLogOnError(screenshot_path_);
2640 }
2641 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002642 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2643 MYLOGI(
2644 "Did not receive user consent yet."
2645 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002646 const String16 incidentcompanion("incidentcompanion");
2647 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2648 if (ics != nullptr) {
2649 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2650 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2651 consent_callback_.get());
2652 } else {
2653 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2654 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002655 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002656 }
2657
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002658 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002659 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002660 for (int i = 0; i < 3; i++) {
2661 Vibrate(75);
2662 usleep((75 + 50) * 1000);
2663 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002664 }
2665
Jeff Brown1dc94e32014-09-11 14:15:27 -07002666 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002667 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002668 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002669 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002670 }
2671
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002672 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2673 progress_->GetInitialMax());
2674 progress_->Save();
2675 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002676
Felipe Leme107a05f2016-03-08 15:11:15 -08002677 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002678 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002679 }
2680
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002681 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002682 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002683 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002684 }
2685
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002686 tombstone_data_.clear();
2687 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002688
Nandana Duttd2f5f082019-01-18 17:13:52 +00002689 return (consent_callback_ != nullptr &&
2690 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2691 ? USER_CONSENT_TIMED_OUT
2692 : RunStatus::OK;
2693}
2694
2695void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2696 consent_callback_ = new ConsentCallback();
2697 const String16 incidentcompanion("incidentcompanion");
2698 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2699 if (ics != nullptr) {
2700 MYLOGD("Checking user consent via incidentcompanion service\n");
2701 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
2702 calling_uid, calling_package, 0x1 /* FLAG_CONFIRMATION_DIALOG */,
2703 consent_callback_.get());
2704 } else {
2705 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2706 }
2707}
2708
Nandana Duttbbdb5b42019-03-12 10:52:56 +00002709bool Dumpstate::IsUserConsentDenied() const {
2710 return ds.consent_callback_ != nullptr &&
2711 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2712}
2713
Nandana Duttd2f5f082019-01-18 17:13:52 +00002714void Dumpstate::CleanupFiles() {
2715 android::os::UnlinkAndLogOnError(tmp_path_);
2716 android::os::UnlinkAndLogOnError(screenshot_path_);
2717 android::os::UnlinkAndLogOnError(path_);
2718}
2719
2720Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2721 MYLOGD("User denied consent; deleting files and returning\n");
2722 CleanupFiles();
2723 return USER_CONSENT_DENIED;
2724}
2725
2726Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2727 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2728 // user consent.
2729 UserConsentResult consent_result = consent_callback_->getResult();
2730 if (consent_result == UserConsentResult::UNAVAILABLE) {
2731 // User has not responded yet.
2732 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2733 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2734 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2735 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2736 sleep(delay_seconds);
2737 }
2738 consent_result = consent_callback_->getResult();
2739 }
2740 if (consent_result == UserConsentResult::DENIED) {
2741 // User has explicitly denied sharing with the app. To be safe delete the
2742 // internal bugreport & tmp files.
2743 return HandleUserConsentDenied();
2744 }
2745 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002746 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2747 if (copy_succeeded) {
2748 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002749 }
2750 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2751 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2752 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2753 // Since we do not have user consent to share the bugreport it does not get
2754 // copied over to the calling app but remains in the internal directory from
2755 // where the user can manually pull it.
2756 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2757 }
2758 // Unknown result; must be a programming error.
2759 MYLOGE("Unknown user consent result:%d\n", consent_result);
2760 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002761}
2762
Nandana Duttf02564e2019-02-15 15:24:24 +00002763Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002764 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2765 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2766 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002767 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002768 // When directly running dumpstate binary, the output is not expected to be written
2769 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002770 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002771
2772 // calling_uid and calling_package are for user consent to share the bugreport with
2773 // an app; they are irrelvant here because bugreport is only written to a local
2774 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002775 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002776 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002777 return status;
2778}
2779
2780/* Main entry point for dumpstate binary. */
2781int run_main(int argc, char* argv[]) {
2782 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002783
2784 switch (status) {
2785 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002786 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002787 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002788 ShowUsage();
2789 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002790 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002791 fprintf(stderr, "Invalid combination of args\n");
2792 ShowUsage();
2793 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002794 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002795 FALLTHROUGH_INTENDED;
2796 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2797 FALLTHROUGH_INTENDED;
2798 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002799 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002800 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002801}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002802
2803// TODO(111441001): Default DumpOptions to sensible values.
2804Dumpstate::Dumpstate(const std::string& version)
2805 : pid_(getpid()),
2806 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002807 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002808 version_(version),
2809 now_(time(nullptr)) {
2810}
2811
2812Dumpstate& Dumpstate::GetInstance() {
2813 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2814 return singleton_;
2815}
2816
2817DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
2818 : title_(title), logcat_only_(logcat_only) {
2819 if (!title_.empty()) {
2820 started_ = Nanotime();
2821 }
2822}
2823
2824DurationReporter::~DurationReporter() {
2825 if (!title_.empty()) {
2826 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
2827 if (elapsed < .5f) {
2828 return;
2829 }
2830 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2831 if (logcat_only_) {
2832 return;
2833 }
2834 // Use "Yoda grammar" to make it easier to grep|sort sections.
2835 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2836 }
2837}
2838
2839const int32_t Progress::kDefaultMax = 5000;
2840
2841Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2842}
2843
2844Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2845 : Progress(initial_max, growth_factor, "") {
2846 progress_ = progress;
2847}
2848
2849Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2850 : initial_max_(initial_max),
2851 progress_(0),
2852 max_(initial_max),
2853 growth_factor_(growth_factor),
2854 n_runs_(0),
2855 average_max_(0),
2856 path_(path) {
2857 if (!path_.empty()) {
2858 Load();
2859 }
2860}
2861
2862void Progress::Load() {
2863 MYLOGD("Loading stats from %s\n", path_.c_str());
2864 std::string content;
2865 if (!android::base::ReadFileToString(path_, &content)) {
2866 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2867 return;
2868 }
2869 if (content.empty()) {
2870 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2871 return;
2872 }
2873 std::vector<std::string> lines = android::base::Split(content, "\n");
2874
2875 if (lines.size() < 1) {
2876 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2877 (int)lines.size(), max_);
2878 return;
2879 }
2880 char* ptr;
2881 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2882 average_max_ = strtol(ptr, nullptr, 10);
2883 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2884 average_max_ > STATS_MAX_AVERAGE) {
2885 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2886 initial_max_ = Progress::kDefaultMax;
2887 } else {
2888 initial_max_ = average_max_;
2889 }
2890 max_ = initial_max_;
2891
2892 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2893}
2894
2895void Progress::Save() {
2896 int32_t total = n_runs_ * average_max_ + progress_;
2897 int32_t runs = n_runs_ + 1;
2898 int32_t average = floor(((float)total) / runs);
2899 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2900 path_.c_str());
2901 if (path_.empty()) {
2902 return;
2903 }
2904
2905 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2906 if (!android::base::WriteStringToFile(content, path_)) {
2907 MYLOGE("Could not save stats on %s\n", path_.c_str());
2908 }
2909}
2910
2911int32_t Progress::Get() const {
2912 return progress_;
2913}
2914
2915bool Progress::Inc(int32_t delta_sec) {
2916 bool changed = false;
2917 if (delta_sec >= 0) {
2918 progress_ += delta_sec;
2919 if (progress_ > max_) {
2920 int32_t old_max = max_;
2921 max_ = floor((float)progress_ * growth_factor_);
2922 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2923 changed = true;
2924 }
2925 }
2926 return changed;
2927}
2928
2929int32_t Progress::GetMax() const {
2930 return max_;
2931}
2932
2933int32_t Progress::GetInitialMax() const {
2934 return initial_max_;
2935}
2936
2937void Progress::Dump(int fd, const std::string& prefix) const {
2938 const char* pr = prefix.c_str();
2939 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2940 dprintf(fd, "%smax: %d\n", pr, max_);
2941 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2942 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2943 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2944 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2945 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2946}
2947
2948bool Dumpstate::IsZipping() const {
2949 return zip_writer_ != nullptr;
2950}
2951
2952std::string Dumpstate::GetPath(const std::string& suffix) const {
2953 return GetPath(bugreport_internal_dir_, suffix);
2954}
2955
2956std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2957 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2958 name_.c_str(), suffix.c_str());
2959}
2960
2961void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2962 progress_ = std::move(progress);
2963}
2964
2965void for_each_userid(void (*func)(int), const char *header) {
2966 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2967 "for_each_userid(%s)", header);
2968 DurationReporter duration_reporter(title);
2969 if (PropertiesHelper::IsDryRun()) return;
2970
2971 DIR *d;
2972 struct dirent *de;
2973
2974 if (header) printf("\n------ %s ------\n", header);
2975 func(0);
2976
2977 if (!(d = opendir("/data/system/users"))) {
2978 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2979 return;
2980 }
2981
2982 while ((de = readdir(d))) {
2983 int userid;
2984 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2985 continue;
2986 }
2987 func(userid);
2988 }
2989
2990 closedir(d);
2991}
2992
2993static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2994 DIR *d;
2995 struct dirent *de;
2996
2997 if (!(d = opendir("/proc"))) {
2998 printf("Failed to open /proc (%s)\n", strerror(errno));
2999 return;
3000 }
3001
3002 if (header) printf("\n------ %s ------\n", header);
3003 while ((de = readdir(d))) {
3004 if (ds.IsUserConsentDenied()) {
3005 MYLOGE(
3006 "Returning early because user denied consent to share bugreport with calling app.");
3007 closedir(d);
3008 return;
3009 }
3010 int pid;
3011 int fd;
3012 char cmdpath[255];
3013 char cmdline[255];
3014
3015 if (!(pid = atoi(de->d_name))) {
3016 continue;
3017 }
3018
3019 memset(cmdline, 0, sizeof(cmdline));
3020
3021 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3022 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3023 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3024 close(fd);
3025 if (cmdline[0]) {
3026 helper(pid, cmdline, arg);
3027 continue;
3028 }
3029 }
3030
3031 // if no cmdline, a kernel thread has comm
3032 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3033 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3034 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3035 close(fd);
3036 if (cmdline[1]) {
3037 cmdline[0] = '[';
3038 size_t len = strcspn(cmdline, "\f\b\r\n");
3039 cmdline[len] = ']';
3040 cmdline[len+1] = '\0';
3041 }
3042 }
3043 if (!cmdline[0]) {
3044 strcpy(cmdline, "N/A");
3045 }
3046 helper(pid, cmdline, arg);
3047 }
3048
3049 closedir(d);
3050}
3051
3052static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3053 for_each_pid_func *func = (for_each_pid_func*) arg;
3054 func(pid, cmdline);
3055}
3056
3057void for_each_pid(for_each_pid_func func, const char *header) {
3058 std::string title = header == nullptr ? "for_each_pid"
3059 : android::base::StringPrintf("for_each_pid(%s)", header);
3060 DurationReporter duration_reporter(title);
3061 if (PropertiesHelper::IsDryRun()) return;
3062
3063 __for_each_pid(for_each_pid_helper, header, (void *) func);
3064}
3065
3066static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3067 DIR *d;
3068 struct dirent *de;
3069 char taskpath[255];
3070 for_each_tid_func *func = (for_each_tid_func *) arg;
3071
3072 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3073
3074 if (!(d = opendir(taskpath))) {
3075 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3076 return;
3077 }
3078
3079 func(pid, pid, cmdline);
3080
3081 while ((de = readdir(d))) {
3082 if (ds.IsUserConsentDenied()) {
3083 MYLOGE(
3084 "Returning early because user denied consent to share bugreport with calling app.");
3085 closedir(d);
3086 return;
3087 }
3088 int tid;
3089 int fd;
3090 char commpath[255];
3091 char comm[255];
3092
3093 if (!(tid = atoi(de->d_name))) {
3094 continue;
3095 }
3096
3097 if (tid == pid)
3098 continue;
3099
3100 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3101 memset(comm, 0, sizeof(comm));
3102 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3103 strcpy(comm, "N/A");
3104 } else {
3105 char *c;
3106 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3107 close(fd);
3108
3109 c = strrchr(comm, '\n');
3110 if (c) {
3111 *c = '\0';
3112 }
3113 }
3114 func(pid, tid, comm);
3115 }
3116
3117 closedir(d);
3118}
3119
3120void for_each_tid(for_each_tid_func func, const char *header) {
3121 std::string title = header == nullptr ? "for_each_tid"
3122 : android::base::StringPrintf("for_each_tid(%s)", header);
3123 DurationReporter duration_reporter(title);
3124
3125 if (PropertiesHelper::IsDryRun()) return;
3126
3127 __for_each_pid(for_each_tid_helper, header, (void *) func);
3128}
3129
3130void show_wchan(int pid, int tid, const char *name) {
3131 if (PropertiesHelper::IsDryRun()) return;
3132
3133 char path[255];
3134 char buffer[255];
3135 int fd, ret, save_errno;
3136 char name_buffer[255];
3137
3138 memset(buffer, 0, sizeof(buffer));
3139
3140 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3141 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3142 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3143 return;
3144 }
3145
3146 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3147 save_errno = errno;
3148 close(fd);
3149
3150 if (ret < 0) {
3151 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3152 return;
3153 }
3154
3155 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3156 pid == tid ? 0 : 3, "", name);
3157
3158 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3159
3160 return;
3161}
3162
3163// print time in centiseconds
3164static void snprcent(char *buffer, size_t len, size_t spc,
3165 unsigned long long time) {
3166 static long hz; // cache discovered hz
3167
3168 if (hz <= 0) {
3169 hz = sysconf(_SC_CLK_TCK);
3170 if (hz <= 0) {
3171 hz = 1000;
3172 }
3173 }
3174
3175 // convert to centiseconds
3176 time = (time * 100 + (hz / 2)) / hz;
3177
3178 char str[16];
3179
3180 snprintf(str, sizeof(str), " %llu.%02u",
3181 time / 100, (unsigned)(time % 100));
3182 size_t offset = strlen(buffer);
3183 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3184 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3185}
3186
3187// print permille as a percent
3188static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3189 char str[16];
3190
3191 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3192 size_t offset = strlen(buffer);
3193 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3194 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3195}
3196
3197void show_showtime(int pid, const char *name) {
3198 if (PropertiesHelper::IsDryRun()) return;
3199
3200 char path[255];
3201 char buffer[1023];
3202 int fd, ret, save_errno;
3203
3204 memset(buffer, 0, sizeof(buffer));
3205
3206 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3207 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3208 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3209 return;
3210 }
3211
3212 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3213 save_errno = errno;
3214 close(fd);
3215
3216 if (ret < 0) {
3217 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3218 return;
3219 }
3220
3221 // field 14 is utime
3222 // field 15 is stime
3223 // field 42 is iotime
3224 unsigned long long utime = 0, stime = 0, iotime = 0;
3225 if (sscanf(buffer,
3226 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3227 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3228 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3229 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3230 &utime, &stime, &iotime) != 3) {
3231 return;
3232 }
3233
3234 unsigned long long total = utime + stime;
3235 if (!total) {
3236 return;
3237 }
3238
3239 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3240 if (permille > 1000) {
3241 permille = 1000;
3242 }
3243
3244 // try to beautify and stabilize columns at <80 characters
3245 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3246 if ((name[0] != '[') || utime) {
3247 snprcent(buffer, sizeof(buffer), 57, utime);
3248 }
3249 snprcent(buffer, sizeof(buffer), 65, stime);
3250 if ((name[0] != '[') || iotime) {
3251 snprcent(buffer, sizeof(buffer), 73, iotime);
3252 }
3253 if (iotime) {
3254 snprdec(buffer, sizeof(buffer), 79, permille);
3255 }
3256 puts(buffer); // adds a trailing newline
3257
3258 return;
3259}
3260
3261void do_dmesg() {
3262 const char *title = "KERNEL LOG (dmesg)";
3263 DurationReporter duration_reporter(title);
3264 printf("------ %s ------\n", title);
3265
3266 if (PropertiesHelper::IsDryRun()) return;
3267
3268 /* Get size of kernel buffer */
3269 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3270 if (size <= 0) {
3271 printf("Unexpected klogctl return value: %d\n\n", size);
3272 return;
3273 }
3274 char *buf = (char *) malloc(size + 1);
3275 if (buf == nullptr) {
3276 printf("memory allocation failed\n\n");
3277 return;
3278 }
3279 int retval = klogctl(KLOG_READ_ALL, buf, size);
3280 if (retval < 0) {
3281 printf("klogctl failure\n\n");
3282 free(buf);
3283 return;
3284 }
3285 buf[retval] = '\0';
3286 printf("%s\n\n", buf);
3287 free(buf);
3288 return;
3289}
3290
3291void do_showmap(int pid, const char *name) {
3292 char title[255];
3293 char arg[255];
3294
3295 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3296 snprintf(arg, sizeof(arg), "%d", pid);
3297 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3298}
3299
3300int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3301 DurationReporter duration_reporter(title);
3302
3303 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3304
3305 UpdateProgress(WEIGHT_FILE);
3306
3307 return status;
3308}
3309
3310int read_file_as_long(const char *path, long int *output) {
3311 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3312 if (fd < 0) {
3313 int err = errno;
3314 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3315 return -1;
3316 }
3317 char buffer[50];
3318 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3319 if (bytes_read == -1) {
3320 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3321 return -2;
3322 }
3323 if (bytes_read == 0) {
3324 MYLOGE("File %s is empty\n", path);
3325 return -3;
3326 }
3327 *output = atoi(buffer);
3328 return 0;
3329}
3330
3331/* calls skip to gate calling dump_from_fd recursively
3332 * in the specified directory. dump_from_fd defaults to
3333 * dump_file_from_fd above when set to NULL. skip defaults
3334 * to false when set to NULL. dump_from_fd will always be
3335 * called with title NULL.
3336 */
3337int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3338 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3339 DurationReporter duration_reporter(title);
3340 DIR *dirp;
3341 struct dirent *d;
3342 char *newpath = nullptr;
3343 const char *slash = "/";
3344 int retval = 0;
3345
3346 if (!title.empty()) {
3347 printf("------ %s (%s) ------\n", title.c_str(), dir);
3348 }
3349 if (PropertiesHelper::IsDryRun()) return 0;
3350
3351 if (dir[strlen(dir) - 1] == '/') {
3352 ++slash;
3353 }
3354 dirp = opendir(dir);
3355 if (dirp == nullptr) {
3356 retval = -errno;
3357 MYLOGE("%s: %s\n", dir, strerror(errno));
3358 return retval;
3359 }
3360
3361 if (!dump_from_fd) {
3362 dump_from_fd = dump_file_from_fd;
3363 }
3364 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3365 if ((d->d_name[0] == '.')
3366 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3367 || (d->d_name[1] == '\0'))) {
3368 continue;
3369 }
3370 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3371 (d->d_type == DT_DIR) ? "/" : "");
3372 if (!newpath) {
3373 retval = -errno;
3374 continue;
3375 }
3376 if (skip && (*skip)(newpath)) {
3377 continue;
3378 }
3379 if (d->d_type == DT_DIR) {
3380 int ret = dump_files("", newpath, skip, dump_from_fd);
3381 if (ret < 0) {
3382 retval = ret;
3383 }
3384 continue;
3385 }
3386 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3387 if (fd.get() < 0) {
3388 retval = -1;
3389 printf("*** %s: %s\n", newpath, strerror(errno));
3390 continue;
3391 }
3392 (*dump_from_fd)(nullptr, newpath, fd.get());
3393 }
3394 closedir(dirp);
3395 if (!title.empty()) {
3396 printf("\n");
3397 }
3398 return retval;
3399}
3400
3401/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3402 * it's possible to avoid issues where opening the file itself can get
3403 * stuck.
3404 */
3405int dump_file_from_fd(const char *title, const char *path, int fd) {
3406 if (PropertiesHelper::IsDryRun()) return 0;
3407
3408 int flags = fcntl(fd, F_GETFL);
3409 if (flags == -1) {
3410 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3411 return -1;
3412 } else if (!(flags & O_NONBLOCK)) {
3413 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3414 return -1;
3415 }
3416 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3417}
3418
3419int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
3420 const CommandOptions& options) {
3421 DurationReporter duration_reporter(title);
3422
3423 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3424
3425 /* TODO: for now we're simplifying the progress calculation by using the
3426 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3427 * where its weight should be much higher proportionally to its timeout.
3428 * Ideally, it should use a options.EstimatedDuration() instead...*/
3429 UpdateProgress(options.Timeout());
3430
3431 return status;
3432}
3433
3434void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3435 const CommandOptions& options, long dumpsysTimeoutMs) {
3436 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3437 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3438 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3439 RunCommand(title, dumpsys, options);
3440}
3441
3442int open_socket(const char *service) {
3443 int s = android_get_control_socket(service);
3444 if (s < 0) {
3445 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3446 return -1;
3447 }
3448 fcntl(s, F_SETFD, FD_CLOEXEC);
3449
3450 // Set backlog to 0 to make sure that queue size will be minimum.
3451 // In Linux, because the minimum queue will be 1, connect() will be blocked
3452 // if the other clients already called connect() and the connection request was not accepted.
3453 if (listen(s, 0) < 0) {
3454 MYLOGE("listen(control socket): %s\n", strerror(errno));
3455 return -1;
3456 }
3457
3458 struct sockaddr addr;
3459 socklen_t alen = sizeof(addr);
3460 int fd = accept(s, &addr, &alen);
3461
3462 // Close socket just after accept(), to make sure that connect() by client will get error
3463 // when the socket is used by the other services.
3464 // There is still a race condition possibility between accept and close, but there is no way
3465 // to close-on-accept atomically.
3466 // See detail; b/123306389#comment25
3467 close(s);
3468
3469 if (fd < 0) {
3470 MYLOGE("accept(control socket): %s\n", strerror(errno));
3471 return -1;
3472 }
3473
3474 return fd;
3475}
3476
3477/* redirect output to a service control socket */
3478bool redirect_to_socket(FILE* redirect, const char* service) {
3479 int fd = open_socket(service);
3480 if (fd == -1) {
3481 return false;
3482 }
3483 fflush(redirect);
3484 // TODO: handle dup2 failure
3485 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3486 close(fd);
3487 return true;
3488}
3489
3490// TODO: should call is_valid_output_file and/or be merged into it.
3491void create_parent_dirs(const char *path) {
3492 char *chp = const_cast<char *> (path);
3493
3494 /* skip initial slash */
3495 if (chp[0] == '/')
3496 chp++;
3497
3498 /* create leading directories, if necessary */
3499 struct stat dir_stat;
3500 while (chp && chp[0]) {
3501 chp = strchr(chp, '/');
3502 if (chp) {
3503 *chp = 0;
3504 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3505 MYLOGI("Creating directory %s\n", path);
3506 if (mkdir(path, 0770)) { /* drwxrwx--- */
3507 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3508 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3509 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3510 }
3511 }
3512 *chp++ = '/';
3513 }
3514 }
3515}
3516
3517bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3518 create_parent_dirs(path);
3519
3520 int fd = TEMP_FAILURE_RETRY(open(path,
3521 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3522 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3523 if (fd < 0) {
3524 MYLOGE("%s: %s\n", path, strerror(errno));
3525 return false;
3526 }
3527
3528 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3529 close(fd);
3530 return true;
3531}
3532
3533bool redirect_to_file(FILE* redirect, char* path) {
3534 return _redirect_to_file(redirect, path, O_TRUNC);
3535}
3536
3537bool redirect_to_existing_file(FILE* redirect, char* path) {
3538 return _redirect_to_file(redirect, path, O_APPEND);
3539}
3540
3541void dump_route_tables() {
3542 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3543 if (PropertiesHelper::IsDryRun()) return;
3544 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3545 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3546 FILE* fp = fopen(RT_TABLES_PATH, "re");
3547 if (!fp) {
3548 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3549 return;
3550 }
3551 char table[16];
3552 // Each line has an integer (the table number), a space, and a string (the table name). We only
3553 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3554 // Add a fixed max limit so this doesn't go awry.
3555 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3556 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3557 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3558 }
3559 fclose(fp);
3560}
3561
3562// TODO: make this function thread safe if sections are generated in parallel.
3563void Dumpstate::UpdateProgress(int32_t delta_sec) {
3564 if (progress_ == nullptr) {
3565 MYLOGE("UpdateProgress: progress_ not set\n");
3566 return;
3567 }
3568
3569 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003570 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003571
3572 // ...but only notifiy listeners when necessary.
3573 if (!options_->do_progress_updates) return;
3574
3575 int progress = progress_->Get();
3576 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003577 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003578
Nandana Duttf02cd782019-06-14 14:25:13 +01003579 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003580 return;
3581 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003582 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003583
3584 if (control_socket_fd_ >= 0) {
3585 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3586 fsync(control_socket_fd_);
3587 }
3588
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003589 if (listener_ != nullptr) {
3590 if (percent % 5 == 0) {
3591 // We don't want to spam logcat, so only log multiples of 5.
3592 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3593 percent);
3594 } else {
3595 // stderr is ignored on normal invocations, but useful when calling
3596 // /system/bin/dumpstate directly for debuggging.
3597 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3598 progress, max, percent);
3599 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003600
3601 listener_->onProgress(percent);
3602 }
3603}
3604
3605void Dumpstate::TakeScreenshot(const std::string& path) {
3606 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3607 int status =
3608 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3609 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3610 if (status == 0) {
3611 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3612 } else {
3613 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3614 }
3615}
3616
3617bool is_dir(const char* pathname) {
3618 struct stat info;
3619 if (stat(pathname, &info) == -1) {
3620 return false;
3621 }
3622 return S_ISDIR(info.st_mode);
3623}
3624
3625time_t get_mtime(int fd, time_t default_mtime) {
3626 struct stat info;
3627 if (fstat(fd, &info) == -1) {
3628 return default_mtime;
3629 }
3630 return info.st_mtime;
3631}
3632
3633void dump_emmc_ecsd(const char *ext_csd_path) {
3634 // List of interesting offsets
3635 struct hex {
3636 char str[2];
3637 };
3638 static const size_t EXT_CSD_REV = 192 * sizeof(hex);
3639 static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
3640 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
3641 static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
3642
3643 std::string buffer;
3644 if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
3645 return;
3646 }
3647
3648 printf("------ %s Extended CSD ------\n", ext_csd_path);
3649
3650 if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
3651 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3652 return;
3653 }
3654
3655 int ext_csd_rev = 0;
3656 std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
3657 if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
3658 printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3659 return;
3660 }
3661
3662 static const char *ver_str[] = {
3663 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
3664 };
3665 printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
3666 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
3667 : "Unknown");
3668 if (ext_csd_rev < 7) {
3669 printf("\n");
3670 return;
3671 }
3672
3673 if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
3674 printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
3675 return;
3676 }
3677
3678 int ext_pre_eol_info = 0;
3679 sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
3680 if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
3681 printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
3682 return;
3683 }
3684
3685 static const char *eol_str[] = {
3686 "Undefined",
3687 "Normal",
3688 "Warning (consumed 80% of reserve)",
3689 "Urgent (consumed 90% of reserve)"
3690 };
3691 printf(
3692 "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
3693 eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
3694 : 0]);
3695
3696 for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
3697 lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
3698 lifetime += sizeof(hex)) {
3699 int ext_device_life_time_est;
3700 static const char *est_str[] = {
3701 "Undefined",
3702 "0-10% of device lifetime used",
3703 "10-20% of device lifetime used",
3704 "20-30% of device lifetime used",
3705 "30-40% of device lifetime used",
3706 "40-50% of device lifetime used",
3707 "50-60% of device lifetime used",
3708 "60-70% of device lifetime used",
3709 "70-80% of device lifetime used",
3710 "80-90% of device lifetime used",
3711 "90-100% of device lifetime used",
3712 "Exceeded the maximum estimated device lifetime",
3713 };
3714
3715 if (buffer.length() < (lifetime + sizeof(hex))) {
3716 printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
3717 break;
3718 }
3719
3720 ext_device_life_time_est = 0;
3721 sub = buffer.substr(lifetime, sizeof(hex));
3722 if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
3723 printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
3724 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3725 sub.c_str());
3726 continue;
3727 }
3728 printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
3729 (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
3730 ext_device_life_time_est,
3731 est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
3732 ? ext_device_life_time_est
3733 : 0]);
3734 }
3735
3736 printf("\n");
3737}
3738