blob: 5469d0cfea201d5367e321a0c3e706cfcaa688ef [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010022#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010025#include <math.h>
26#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080031#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010037#include <signal.h>
38#include <stdarg.h>
39#include <string.h>
40#include <sys/capability.h>
41#include <sys/inotify.h>
42#include <sys/klog.h>
43#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070045
46#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070047#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000048#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070049#include <functional>
50#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010051#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070052#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <regex>
54#include <set>
55#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070056#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010057#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070058
Felipe Leme96c2bbb2016-09-26 09:21:21 -070059#include <android-base/file.h>
60#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070061#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080062#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070063#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070064#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010065#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080066#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080067#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000068#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010069#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080070#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070071#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010072#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080074#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000075#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010076#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080077#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010078#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070079#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070080#include <private/android_filesystem_config.h>
81#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070083#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080084#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070085#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070086#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080087
Steven Morelandcb7ef822016-11-29 13:20:37 -080088using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080089using ::std::literals::chrono_literals::operator""ms;
90using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080091
Felipe Leme47e9be22016-12-21 15:37:07 -080092// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080093using android::defaultServiceManager;
94using android::Dumpsys;
95using android::INVALID_OPERATION;
96using android::IServiceManager;
97using android::OK;
98using android::sp;
99using android::status_t;
100using android::String16;
101using android::String8;
102using android::TIMED_OUT;
103using android::UNKNOWN_ERROR;
104using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000105using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000106using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107using android::os::dumpstate::CommandOptions;
108using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100124}
125
126// Reasonable value for max stats.
127static const int STATS_MAX_N_RUNS = 1000;
128static const long STATS_MAX_AVERAGE = 100000;
129
130CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
Nandana Duttd2f5f082019-01-18 17:13:52 +0000132typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134/* read before root is shed */
135static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700136static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000137static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700138
Felipe Leme1d486fe2016-10-14 18:06:47 -0700139// TODO: variables and functions below should be part of dumpstate object
140
Felipe Leme635ca312016-01-05 14:23:02 -0800141static std::set<std::string> mount_points;
142void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800143
Todd Poynor2a83daa2013-11-22 15:44:22 -0800144#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700145#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700146#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800147
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700149#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700150#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700151#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100152#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
153#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800154#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900155#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800156#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700157
Narayan Kamath8f788292017-05-25 13:20:39 +0100158// TODO(narayan): Since this information has to be kept in sync
159// with tombstoned, we should just put it in a common header.
160//
161// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100162static const std::string TOMBSTONE_DIR = "/data/tombstones/";
163static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
164static const std::string ANR_DIR = "/data/anr/";
165static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700166
Felipe Lemee844a9d2016-09-21 15:01:39 -0700167// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000168
Nandana Dutt5c390032019-03-12 10:52:56 +0000169#define RETURN_IF_USER_DENIED_CONSENT() \
170 if (ds.IsUserConsentDenied()) { \
171 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
172 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
173 }
174
175// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
176// if consent is found to be denied.
177#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
178 RETURN_IF_USER_DENIED_CONSENT(); \
179 func_ptr(__VA_ARGS__); \
180 RETURN_IF_USER_DENIED_CONSENT();
181
Sahana Raof35ed432019-07-12 10:47:52 +0100182static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
183
Nandana Dutt979388e2018-11-30 16:48:55 +0000184namespace android {
185namespace os {
186namespace {
187
188static int Open(std::string path, int flags, mode_t mode = 0) {
189 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
190 if (fd == -1) {
191 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
192 }
193 return fd;
194}
195
Nandana Dutt979388e2018-11-30 16:48:55 +0000196
197static int OpenForRead(std::string path) {
198 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
199}
200
201bool CopyFile(int in_fd, int out_fd) {
202 char buf[4096];
203 ssize_t byte_count;
204 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
205 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
206 return false;
207 }
208 }
209 return (byte_count != -1);
210}
211
212static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000213 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000214
215 // Obtain a handle to the source file.
216 android::base::unique_fd in_fd(OpenForRead(input_file));
217 if (out_fd != -1 && in_fd.get() != -1) {
218 if (CopyFile(in_fd.get(), out_fd)) {
219 return true;
220 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000221 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000222 }
223 return false;
224}
225
Nandana Duttd2f5f082019-01-18 17:13:52 +0000226static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000227 if (unlink(file.c_str())) {
228 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000229 return false;
230 }
231 return true;
232}
Nandana Dutt979388e2018-11-30 16:48:55 +0000233
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000234
Nikita Ioffea325a572019-05-16 19:49:47 +0100235int64_t GetModuleMetadataVersion() {
236 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
237 if (binder == nullptr) {
238 MYLOGE("Failed to retrieve package_native service");
239 return 0L;
240 }
241 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
242 std::string package_name;
243 auto status = package_service->getModuleMetadataPackageName(&package_name);
244 if (!status.isOk()) {
245 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
246 return 0L;
247 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100248 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100249 int64_t version_code;
250 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
251 &version_code);
252 if (!status.isOk()) {
253 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
254 return 0L;
255 }
256 return version_code;
257}
258
Nandana Dutt979388e2018-11-30 16:48:55 +0000259} // namespace
260} // namespace os
261} // namespace android
262
Felipe Leme678727a2016-09-21 17:22:11 -0700263static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800264 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800265 long dumpsysTimeoutMs = 0) {
266 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700267}
268static int DumpFile(const std::string& title, const std::string& path) {
269 return ds.DumpFile(title, path);
270}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800271
Felipe Lemee844a9d2016-09-21 15:01:39 -0700272// Relative directory (inside the zip) for all files copied as-is into the bugreport.
273static const std::string ZIP_ROOT_DIR = "FS";
274
Vishnu Naire97d6122018-01-18 13:58:56 -0800275static const std::string kProtoPath = "proto/";
276static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700277static const std::string kDumpstateBoardFiles[] = {
278 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700279 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700280};
281static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
282
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700283static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700284static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700285
Felipe Lemef0292972016-11-22 13:57:05 -0800286static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
287
Narayan Kamath8f788292017-05-25 13:20:39 +0100288/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100289 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
290 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
291 * is set, the vector only contains files that were written in the last 30 minutes.
Narayan Kamath8f788292017-05-25 13:20:39 +0100292 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700293static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
294 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700295 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100296 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
297
Narayan Kamathbd863722017-06-01 18:50:12 +0100298 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100299
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700300 if (dump_dir == nullptr) {
301 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700302 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700303 }
304
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700305 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100306 struct dirent* entry = nullptr;
307 while ((entry = readdir(dump_dir.get()))) {
308 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100309 continue;
310 }
311
Narayan Kamathbd863722017-06-01 18:50:12 +0100312 const std::string base_name(entry->d_name);
313 if (base_name.find(file_prefix) != 0) {
314 continue;
315 }
316
317 const std::string abs_path = dir_path + base_name;
318 android::base::unique_fd fd(
319 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
320 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700321 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100322 break;
323 }
324
325 struct stat st = {};
326 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700327 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100328 continue;
329 }
330
Narayan Kamath3f31b632018-02-22 19:42:36 +0000331 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100332 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100333 continue;
334 }
335
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700336 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700337 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100338
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700339 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100340}
341
Narayan Kamathbd863722017-06-01 18:50:12 +0100342static bool AddDumps(const std::vector<DumpData>::const_iterator start,
343 const std::vector<DumpData>::const_iterator end,
344 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100345 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100346 for (auto it = start; it != end; ++it) {
347 const std::string& name = it->name;
348 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100349 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100350
351 // Seek to the beginning of the file before dumping any data. A given
352 // DumpData entry might be dumped multiple times in the report.
353 //
354 // For example, the most recent ANR entry is dumped to the body of the
355 // main entry and it also shows up as a separate entry in the bugreport
356 // ZIP file.
357 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
358 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
359 strerror(errno));
360 }
361
Narayan Kamath8f788292017-05-25 13:20:39 +0100362 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800363 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100364 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100365 }
366 } else {
367 dump_file_from_fd(type_name, name.c_str(), fd);
368 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100369 }
370
371 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700372}
373
Felipe Leme635ca312016-01-05 14:23:02 -0800374// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700375void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800376 char path[PATH_MAX];
377
378 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
379 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700380 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800381 char linkname[PATH_MAX];
382 ssize_t r = readlink(path, linkname, PATH_MAX);
383 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800384 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800385 return;
386 }
387 linkname[r] = '\0';
388
389 if (mount_points.find(linkname) == mount_points.end()) {
390 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700391 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700392 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800393 mount_points.insert(linkname);
394 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800395 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800396 }
397 }
398}
399
400void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700401 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700402 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800403 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800404 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700405 for_each_pid(do_mountinfo, nullptr);
406 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800407}
408
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700409static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
410{
411 DIR *d;
412 struct dirent *de;
413 char path[PATH_MAX];
414
415 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700416 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700417 return;
418 }
419
420 while ((de = readdir(d))) {
421 if (de->d_type != DT_LNK) {
422 continue;
423 }
424 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700425 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700426 }
427
428 closedir(d);
429}
430
Mark Salyzyn326842f2015-04-30 09:49:41 -0700431static bool skip_not_stat(const char *path) {
432 static const char stat[] = "/stat";
433 size_t len = strlen(path);
434 if (path[len - 1] == '/') { /* Directory? */
435 return false;
436 }
437 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
438}
439
Felipe Leme4c2d6632016-09-28 14:32:00 -0700440static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800441 return false;
442}
443
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700444unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700445
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800446//
447// stat offsets
448// Name units description
449// ---- ----- -----------
450// read I/Os requests number of read I/Os processed
451#define __STAT_READ_IOS 0
452// read merges requests number of read I/Os merged with in-queue I/O
453#define __STAT_READ_MERGES 1
454// read sectors sectors number of sectors read
455#define __STAT_READ_SECTORS 2
456// read ticks milliseconds total wait time for read requests
457#define __STAT_READ_TICKS 3
458// write I/Os requests number of write I/Os processed
459#define __STAT_WRITE_IOS 4
460// write merges requests number of write I/Os merged with in-queue I/O
461#define __STAT_WRITE_MERGES 5
462// write sectors sectors number of sectors written
463#define __STAT_WRITE_SECTORS 6
464// write ticks milliseconds total wait time for write requests
465#define __STAT_WRITE_TICKS 7
466// in_flight requests number of I/Os currently in flight
467#define __STAT_IN_FLIGHT 8
468// io_ticks milliseconds total time this block device has been active
469#define __STAT_IO_TICKS 9
470// time_in_queue milliseconds total wait time for all requests
471#define __STAT_IN_QUEUE 10
472#define __STAT_NUMBER_FIELD 11
473//
474// read I/Os, write I/Os
475// =====================
476//
477// These values increment when an I/O request completes.
478//
479// read merges, write merges
480// =========================
481//
482// These values increment when an I/O request is merged with an
483// already-queued I/O request.
484//
485// read sectors, write sectors
486// ===========================
487//
488// These values count the number of sectors read from or written to this
489// block device. The "sectors" in question are the standard UNIX 512-byte
490// sectors, not any device- or filesystem-specific block size. The
491// counters are incremented when the I/O completes.
492#define SECTOR_SIZE 512
493//
494// read ticks, write ticks
495// =======================
496//
497// These values count the number of milliseconds that I/O requests have
498// waited on this block device. If there are multiple I/O requests waiting,
499// these values will increase at a rate greater than 1000/second; for
500// example, if 60 read requests wait for an average of 30 ms, the read_ticks
501// field will increase by 60*30 = 1800.
502//
503// in_flight
504// =========
505//
506// This value counts the number of I/O requests that have been issued to
507// the device driver but have not yet completed. It does not include I/O
508// requests that are in the queue but not yet issued to the device driver.
509//
510// io_ticks
511// ========
512//
513// This value counts the number of milliseconds during which the device has
514// had I/O requests queued.
515//
516// time_in_queue
517// =============
518//
519// This value counts the number of milliseconds that I/O requests have waited
520// on this block device. If there are multiple I/O requests waiting, this
521// value will increase as the product of the number of milliseconds times the
522// number of requests waiting (see "read ticks" above for an example).
523#define S_TO_MS 1000
524//
525
Mark Salyzyn326842f2015-04-30 09:49:41 -0700526static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800527 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700528 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700529 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700530 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700531 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700532 getline(&buffer, &i, fp);
533 fclose(fp);
534 if (!buffer) {
535 return -errno;
536 }
537 i = strlen(buffer);
538 while ((i > 0) && (buffer[i - 1] == '\n')) {
539 buffer[--i] = '\0';
540 }
541 if (!*buffer) {
542 free(buffer);
543 return 0;
544 }
545 z = true;
546 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800547 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700548 if (fields[i] != 0) {
549 z = false;
550 }
551 }
552 if (z) { /* never accessed */
553 free(buffer);
554 return 0;
555 }
556
Wei Wang509bb5d2017-06-09 14:42:12 -0700557 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
558 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700559 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700560
561 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
562 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
563 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700564 free(buffer);
565
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800566 if (fields[__STAT_IO_TICKS]) {
567 unsigned long read_perf = 0;
568 unsigned long read_ios = 0;
569 if (fields[__STAT_READ_TICKS]) {
570 unsigned long long divisor = fields[__STAT_READ_TICKS]
571 * fields[__STAT_IO_TICKS];
572 read_perf = ((unsigned long long)SECTOR_SIZE
573 * fields[__STAT_READ_SECTORS]
574 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
575 / divisor;
576 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
577 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
578 / divisor;
579 }
580
581 unsigned long write_perf = 0;
582 unsigned long write_ios = 0;
583 if (fields[__STAT_WRITE_TICKS]) {
584 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
585 * fields[__STAT_IO_TICKS];
586 write_perf = ((unsigned long long)SECTOR_SIZE
587 * fields[__STAT_WRITE_SECTORS]
588 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
589 / divisor;
590 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
591 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
592 / divisor;
593 }
594
595 unsigned queue = (fields[__STAT_IN_QUEUE]
596 + (fields[__STAT_IO_TICKS] >> 1))
597 / fields[__STAT_IO_TICKS];
598
599 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700600 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 -0800601 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700602 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 -0800603 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800604 }
605
606 /* bugreport timeout factor adjustment */
607 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
608 worst_write_perf = write_perf;
609 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700610 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700611 return 0;
612}
613
Yao Chenbe3bbc12018-01-17 16:31:10 -0800614static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
615
616/* timeout in ms to read a list of buffers */
617static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
618 unsigned long timeout_ms = 0;
619 for (const auto& buffer : buffers) {
620 log_id_t id = android_name_to_log_id(buffer.c_str());
621 unsigned long property_size = __android_logger_get_buffer_size(id);
622 /* Engineering margin is ten-fold our guess */
623 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
624 }
625 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700626}
627
Nandana Duttd2f5f082019-01-18 17:13:52 +0000628Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
629}
630
631android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
632 std::lock_guard<std::mutex> lock(lock_);
633 result_ = APPROVED;
634 MYLOGD("User approved consent to share bugreport\n");
635 return android::binder::Status::ok();
636}
637
638android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
639 std::lock_guard<std::mutex> lock(lock_);
640 result_ = DENIED;
641 MYLOGW("User denied consent to share bugreport\n");
642 return android::binder::Status::ok();
643}
644
645UserConsentResult Dumpstate::ConsentCallback::getResult() {
646 std::lock_guard<std::mutex> lock(lock_);
647 return result_;
648}
649
650uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
651 return Nanotime() - start_time_;
652}
653
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700654void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700655 std::string build, fingerprint, radio, bootloader, network;
656 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700657
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700658 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
659 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700660 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
661 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
662 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700663 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700664
Felipe Lemed8b94e52016-12-08 10:21:44 -0800665 printf("========================================================\n");
666 printf("== dumpstate: %s\n", date);
667 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700668
Felipe Lemed8b94e52016-12-08 10:21:44 -0800669 printf("\n");
670 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700671 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800672 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
673 printf("Bootloader: %s\n", bootloader.c_str());
674 printf("Radio: %s\n", radio.c_str());
675 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100676 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
677 if (module_metadata_version != 0) {
678 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
679 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700680
Felipe Lemed8b94e52016-12-08 10:21:44 -0800681 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800682 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800683 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800684 printf("Uptime: ");
685 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
686 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800687 printf("Bugreport format version: %s\n", version_.c_str());
Abhijeet Kaure370d682019-10-01 16:49:30 +0100688 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
689 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800690 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800691}
692
Felipe Leme24b66ee2016-06-16 10:55:26 -0700693// List of file extensions that can cause a zip file attachment to be rejected by some email
694// service providers.
695static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
696 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
697 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
698 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
699};
700
Vishnu Naire97d6122018-01-18 13:58:56 -0800701status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
702 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700703 if (!IsZipping()) {
704 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
705 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800706 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800707 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700708 std::string valid_name = entry_name;
709
710 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700711 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700712 if (idx != std::string::npos) {
713 std::string extension = entry_name.substr(idx);
714 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
715 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
716 valid_name = entry_name + ".renamed";
717 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
718 }
719 }
720
Felipe Leme6fe9db62016-02-12 09:04:16 -0800721 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
722 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700723 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
724 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700725 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700726 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700727 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800728 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800729 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000730 bool finished_entry = false;
731 auto finish_entry = [this, &finished_entry] {
732 if (!finished_entry) {
733 // This should only be called when we're going to return an earlier error,
734 // which would've been logged. This may imply the file is already corrupt
735 // and any further logging from FinishEntry is more likely to mislead than
736 // not.
737 this->zip_writer_->FinishEntry();
738 }
739 };
740 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800741 auto start = std::chrono::steady_clock::now();
742 auto end = start + timeout;
743 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800744
Felipe Leme770410d2016-01-26 17:07:14 -0800745 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800746 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800747 if (timeout.count() > 0) {
748 // lambda to recalculate the timeout.
749 auto time_left_ms = [end]() {
750 auto now = std::chrono::steady_clock::now();
751 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
752 return std::max(diff.count(), 0LL);
753 };
754
755 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
756 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000757 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
758 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800759 return -errno;
760 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000761 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800762 entry_name.c_str(), strerror(errno), timeout.count());
763 return TIMED_OUT;
764 }
765 }
766
Zach Riggle22200402016-08-18 01:01:24 -0400767 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800768 if (bytes_read == 0) {
769 break;
770 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800771 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800772 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800773 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700774 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800775 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700776 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800777 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800778 }
779 }
780
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700781 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000782 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700783 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700784 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800785 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 }
787
Vishnu Naire97d6122018-01-18 13:58:56 -0800788 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800789}
790
Felipe Leme1d486fe2016-10-14 18:06:47 -0700791bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
792 android::base::unique_fd fd(
793 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700794 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800795 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800796 return false;
797 }
798
Vishnu Naire97d6122018-01-18 13:58:56 -0800799 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800800}
801
802/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700803static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800804 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800805}
806
Felipe Leme1d486fe2016-10-14 18:06:47 -0700807void Dumpstate::AddDir(const std::string& dir, bool recursive) {
808 if (!IsZipping()) {
809 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800810 return;
811 }
Felipe Leme678727a2016-09-21 17:22:11 -0700812 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800813 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700814 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800815}
816
Felipe Leme1d486fe2016-10-14 18:06:47 -0700817bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
818 if (!IsZipping()) {
819 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
820 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800821 return false;
822 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800823 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700824 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700825 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700826 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700827 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800828 return false;
829 }
830
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700831 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700832 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700833 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700834 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800835 return false;
836 }
837
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700838 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700839 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700840 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800841 return false;
842 }
843
844 return true;
845}
846
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800847static void DoKmsg() {
848 struct stat st;
849 if (!stat(PSTORE_LAST_KMSG, &st)) {
850 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
851 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
852 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
853 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
854 } else {
855 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
856 DumpFile("LAST KMSG", "/proc/last_kmsg");
857 }
858}
859
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800860static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800861 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800862 RunCommand(
863 "KERNEL LOG",
864 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
865 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
866}
867
Nandana Duttdb379fa2019-10-09 16:54:41 +0100868static void DoSystemLogcat(time_t since) {
869 char since_str[80];
870 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
871
872 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
873 RunCommand("SYSTEM LOG",
874 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
875 since_str},
876 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
877}
878
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800879static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800880 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800881 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
882 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800883 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100884 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800885 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
886 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800887 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800888 RunCommand(
889 "EVENT LOG",
890 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100891 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800892 timeout_ms = logcat_timeout({"stats"});
893 RunCommand(
894 "STATS LOG",
895 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100896 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800897 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800898 RunCommand(
899 "RADIO LOG",
900 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100901 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800902
903 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
904
905 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800906 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
907 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800908}
909
Mike Ma5c267872019-08-21 11:31:34 -0700910static void DumpIncidentReport() {
911 if (!ds.IsZipping()) {
912 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
913 return;
914 }
915 DurationReporter duration_reporter("INCIDENT REPORT");
916 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
917 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
918 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
919 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
920 if (fd < 0) {
921 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
922 return;
923 }
924 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
925 bool empty = 0 == lseek(fd, 0, SEEK_END);
926 if (!empty) {
927 // Use a different name from "incident.proto"
928 // /proto/incident.proto is reserved for incident service dump
929 // i.e. metadata for debugging.
930 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
931 }
932 unlink(path.c_str());
933}
934
Jayachandran Ca94c7172017-06-10 15:08:12 -0700935static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700936 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
937 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900938 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700939 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900940 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
941 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
942 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
943 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700944}
945
David Andersond9ba4752018-12-11 18:26:59 -0800946static void DumpDynamicPartitionInfo() {
947 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
948 return;
949 }
950
951 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700952 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800953}
954
Narayan Kamath8f788292017-05-25 13:20:39 +0100955static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
956 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
957 anr_traces_dir.c_str());
958
959 // If we're here, dump_traces_path will always be a temporary file
960 // (created with mkostemp or similar) that contains dumps taken earlier
961 // on in the process.
962 if (dump_traces_path != nullptr) {
963 if (add_to_zip) {
964 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
965 } else {
966 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
967 dump_traces_path);
968 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
969 }
970
971 const int ret = unlink(dump_traces_path);
972 if (ret == -1) {
973 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
974 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700975 }
976 }
977
Narayan Kamathbd863722017-06-01 18:50:12 +0100978 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700979 if (ds.anr_data_.size() > 0) {
980 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100981 "VM TRACES AT LAST ANR", add_to_zip);
982
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100983 // The "last" ANR will always be included as separate entry in the zip file. In addition,
984 // it will be present in the body of the main entry if |add_to_zip| == false.
985 //
986 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700987 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100988 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100989 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100990 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
991 }
992}
993
994static void AddAnrTraceFiles() {
995 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
996
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700997 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100998
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700999 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001000
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001001 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1002
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001003 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001004 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001005 int i = 0;
1006 while (true) {
1007 const std::string slow_trace_path =
1008 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1009 if (stat(slow_trace_path.c_str(), &st)) {
1010 // No traces file at this index, done with the files.
1011 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001012 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001013 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1014 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001015 }
1016}
1017
Wei Wang509bb5d2017-06-09 14:42:12 -07001018static void DumpBlockStatFiles() {
1019 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001020
Wei Wang1dc1ef52017-06-12 11:28:37 -07001021 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1022
1023 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001024 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1025 return;
1026 }
1027
1028 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001029 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001030 if ((d->d_name[0] == '.')
1031 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1032 || (d->d_name[1] == '\0'))) {
1033 continue;
1034 }
1035 const std::string new_path =
1036 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1037 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1038 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1039 printf("\n");
1040 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001041 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001042}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001043
1044static void DumpPacketStats() {
1045 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1046 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1047 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1048 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1049 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1050}
1051
1052static void DumpIpAddrAndRules() {
1053 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1054 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1055 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1056 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1057 RunCommand("IP RULES", {"ip", "rule", "show"});
1058 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1059}
1060
Nandana Dutt5c390032019-03-12 10:52:56 +00001061static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1062 std::chrono::milliseconds timeout,
1063 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001064 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001065 sp<android::IServiceManager> sm = defaultServiceManager();
1066 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001067 Vector<String16> args;
1068 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001069 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1070 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001071 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001072 std::string path(title);
1073 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001074 size_t bytes_written = 0;
Steven Moreland5a30d342019-10-08 13:53:28 -07001075 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001076 if (status == OK) {
1077 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1078 std::chrono::duration<double> elapsed_seconds;
1079 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1080 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001081 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1082 bool dump_complete = (status == OK);
1083 dumpsys.stopDumpThread(dump_complete);
1084 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001085
1086 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1087 std::chrono::steady_clock::now() - start);
1088 if (elapsed_duration > timeout) {
1089 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1090 elapsed_duration.count());
1091 break;
1092 }
1093 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001094 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001095}
1096
Vishnu Nair64afc022018-02-01 15:29:34 -08001097static void RunDumpsysText(const std::string& title, int priority,
1098 std::chrono::milliseconds timeout,
1099 std::chrono::milliseconds service_timeout) {
1100 DurationReporter duration_reporter(title);
1101 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1102 fsync(STDOUT_FILENO);
1103 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1104}
1105
1106/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001107static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1108 std::chrono::milliseconds timeout,
1109 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001110 DurationReporter duration_reporter(title);
1111 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1112 fsync(STDOUT_FILENO);
1113 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1114 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001115
1116 RETURN_IF_USER_DENIED_CONSENT();
1117
1118 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1119 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001120}
1121
Nandana Dutt5c390032019-03-12 10:52:56 +00001122static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1123 std::chrono::milliseconds timeout,
1124 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001125 if (!ds.IsZipping()) {
1126 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001127 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001128 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001129 sp<android::IServiceManager> sm = defaultServiceManager();
1130 Dumpsys dumpsys(sm.get());
1131 Vector<String16> args;
1132 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1133 DurationReporter duration_reporter(title);
1134
1135 auto start = std::chrono::steady_clock::now();
1136 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1137 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001138 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001139 std::string path(kProtoPath);
1140 path.append(String8(service).c_str());
1141 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1142 path.append("_CRITICAL");
1143 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1144 path.append("_HIGH");
1145 }
1146 path.append(kProtoExt);
Steven Moreland5a30d342019-10-08 13:53:28 -07001147 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001148 if (status == OK) {
1149 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1150 bool dumpTerminated = (status == OK);
1151 dumpsys.stopDumpThread(dumpTerminated);
1152 }
1153 ZipWriter::FileEntry file_entry;
1154 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001155
1156 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1157 std::chrono::steady_clock::now() - start);
1158 if (elapsed_duration > timeout) {
1159 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1160 elapsed_duration.count());
1161 break;
1162 }
1163 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001164 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001165}
1166
Nandana Dutta7db6342018-11-21 14:53:34 +00001167// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001168static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001169 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1170 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001171
1172 RETURN_IF_USER_DENIED_CONSENT();
1173
1174 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1175 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001176}
1177
1178// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001179static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001180 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1181 // high priority. Reduce timeout once they are able to dump in a shorter time or
1182 // moved to a parallel task.
1183 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1184 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001185
1186 RETURN_IF_USER_DENIED_CONSENT();
1187
1188 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1189 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001190}
1191
1192// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001193static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001194 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001195
1196 RETURN_IF_USER_DENIED_CONSENT();
1197
1198 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1199 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001200}
1201
Steven Moreland44cd9482018-01-04 16:24:13 -08001202static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001203 if (!ds.IsZipping()) {
1204 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1205 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1206 return;
1207 }
1208 DurationReporter duration_reporter("DUMP HALS");
1209 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001210 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001211
Steven Moreland44cd9482018-01-04 16:24:13 -08001212 using android::hidl::manager::V1_0::IServiceManager;
1213 using android::hardware::defaultServiceManager;
1214
1215 sp<IServiceManager> sm = defaultServiceManager();
1216 if (sm == nullptr) {
1217 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1218 return;
1219 }
1220
1221 auto ret = sm->list([&](const auto& interfaces) {
1222 for (const std::string& interface : interfaces) {
1223 std::string cleanName = interface;
1224 std::replace_if(cleanName.begin(),
1225 cleanName.end(),
1226 [](char c) {
1227 return !isalnum(c) &&
1228 std::string("@-_:.").find(c) == std::string::npos;
1229 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001230 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001231
1232 {
1233 auto fd = android::base::unique_fd(
1234 TEMP_FAILURE_RETRY(open(path.c_str(),
1235 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1236 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1237 if (fd < 0) {
1238 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1239 continue;
1240 }
1241 RunCommandToFd(fd,
1242 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001243 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001244 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1245
1246 bool empty = 0 == lseek(fd, 0, SEEK_END);
1247 if (!empty) {
1248 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1249 }
1250 }
1251
1252 unlink(path.c_str());
1253 }
1254 });
1255
1256 if (!ret.isOk()) {
1257 MYLOGE("Could not list hals from hwservicemanager.\n");
1258 }
1259}
1260
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001261static void DumpExternalFragmentationInfo() {
1262 struct stat st;
1263 if (stat("/proc/buddyinfo", &st) != 0) {
1264 MYLOGE("Unable to dump external fragmentation info\n");
1265 return;
1266 }
1267
1268 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1269 std::ifstream ifs("/proc/buddyinfo");
1270 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1271 for (std::string line; std::getline(ifs, line);) {
1272 std::smatch match_results;
1273 if (std::regex_match(line, match_results, unusable_index_regex)) {
1274 std::stringstream free_pages(std::string{match_results[3]});
1275 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1276 std::istream_iterator<int>());
1277
1278 int total_free_pages = 0;
1279 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1280 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1281 }
1282
1283 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1284 match_results[2].str().c_str());
1285
1286 int usable_free_pages = total_free_pages;
1287 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1288 auto unusable_index = (total_free_pages - usable_free_pages) /
1289 static_cast<double>(total_free_pages);
1290 printf(" %5.3f", unusable_index);
1291 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1292 }
1293
1294 printf("\n");
1295 }
1296 }
1297 printf("\n");
1298}
1299
Nandana Dutt5c390032019-03-12 10:52:56 +00001300// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1301// via the consent they are shown. Ignores other errors that occur while running various
1302// commands. The consent checking is currently done around long running tasks, which happen to
1303// be distributed fairly evenly throughout the function.
1304static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001305 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001306
Nandana Dutt5c390032019-03-12 10:52:56 +00001307 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1308 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1309 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001310 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001311 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001312 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001313 DumpFile("MEMORY INFO", "/proc/meminfo");
1314 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001315 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001316
1317 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1318
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001319 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1320 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1321 DumpFile("SLAB INFO", "/proc/slabinfo");
1322 DumpFile("ZONEINFO", "/proc/zoneinfo");
1323 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1324 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001325 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001326
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001327 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1328 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001329
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001330 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001331 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001332
1333 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1334 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001335
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001336 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001337
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001338 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001339 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001340 struct stat s;
1341 if (stat("/proc/modules", &s) != 0) {
1342 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1343 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001344 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001345 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001346
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001347 if (__android_logger_property_get_bool(
1348 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1349 DoKernelLogcat();
1350 } else {
1351 do_dmesg();
1352 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001353
Felipe Lemef0292972016-11-22 13:57:05 -08001354 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001355
1356 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1357
Jeff Brown1dc94e32014-09-11 14:15:27 -07001358 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001359 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001360
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001361 /* Dump Bluetooth HCI logs */
1362 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001363
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001364 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001365 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001366 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001367 }
1368
Felipe Lemee184f662016-10-27 10:04:47 -07001369 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001370
Narayan Kamath8f788292017-05-25 13:20:39 +01001371 // NOTE: tombstones are always added as separate entries in the zip archive
1372 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001373 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001374 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001375 if (!tombstones_dumped) {
1376 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001377 }
1378
Jayachandran Ca94c7172017-06-10 15:08:12 -07001379 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001380
Chenbo Feng276a3b62018-08-07 11:44:49 -07001381 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1382
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001383 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001384
Jayachandran Ca94c7172017-06-10 15:08:12 -07001385 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001386
1387 dump_route_tables();
1388
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001389 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1390 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1391 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001392
Nandana Dutt5c390032019-03-12 10:52:56 +00001393 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001394
Elliott Hughes23ccc622017-02-28 10:14:22 -08001395 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001396
Jin Qianf334d662017-10-10 14:41:37 -07001397 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001398
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001399 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001400
Colin Crossf45fa6b2012-03-26 12:38:26 -07001401 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001402 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1403 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1404 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1405 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1406 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001407
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001408 /* Add window and surface trace files. */
1409 if (!PropertiesHelper::IsUserBuild()) {
1410 ds.AddDir(WMTRACE_DATA_DIR, false);
1411 }
1412
Nandana Dutt5c390032019-03-12 10:52:56 +00001413 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001414
Steven Moreland7440ddb2016-12-15 16:13:39 -08001415 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001416 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1417 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001418 // su does not exist on user builds, so try running without it.
1419 // This way any implementations of vril-dump that do not require
1420 // root can run on user builds.
1421 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001422 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001423 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001424 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001425 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001426 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001427 }
1428
Felipe Lemed8b94e52016-12-08 10:21:44 -08001429 printf("========================================================\n");
1430 printf("== Android Framework Services\n");
1431 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001432
Nandana Dutt5c390032019-03-12 10:52:56 +00001433 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001434
Felipe Lemed8b94e52016-12-08 10:21:44 -08001435 printf("========================================================\n");
1436 printf("== Checkins\n");
1437 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001438
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001439 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001440
1441 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1442
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001443 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1444 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1445 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1446 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001447
Felipe Lemed8b94e52016-12-08 10:21:44 -08001448 printf("========================================================\n");
1449 printf("== Running Application Activities\n");
1450 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001451
Makoto Onuki60780982018-04-16 15:34:00 -07001452 // The following dumpsys internally collects output from running apps, so it can take a long
1453 // time. So let's extend the timeout.
1454
1455 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1456
1457 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001458
Felipe Lemed8b94e52016-12-08 10:21:44 -08001459 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001460 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001461 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001462
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001463 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001464 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001465
Felipe Lemed8b94e52016-12-08 10:21:44 -08001466 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001467 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001468 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001469
Makoto Onuki60780982018-04-16 15:34:00 -07001470 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1471 DUMPSYS_COMPONENTS_OPTIONS);
1472
1473 printf("========================================================\n");
1474 printf("== Running Application Providers (platform)\n");
1475 printf("========================================================\n");
1476
1477 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1478 DUMPSYS_COMPONENTS_OPTIONS);
1479
1480 printf("========================================================\n");
1481 printf("== Running Application Providers (non-platform)\n");
1482 printf("========================================================\n");
1483
1484 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1485 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001486
Adrian Roos8b397ab2017-04-04 16:35:44 -07001487 printf("========================================================\n");
1488 printf("== Dropbox crashes\n");
1489 printf("========================================================\n");
1490
1491 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1492 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1493
Felipe Lemed8b94e52016-12-08 10:21:44 -08001494 printf("========================================================\n");
1495 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1496 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1497 printf("========================================================\n");
1498 printf("== dumpstate: done (id %d)\n", ds.id_);
1499 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001500
1501 printf("========================================================\n");
1502 printf("== Obtaining statsd metadata\n");
1503 printf("========================================================\n");
1504 // This differs from the usual dumpsys stats, which is the stats report data.
1505 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001506
1507 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1508
Nandana Dutt5c390032019-03-12 10:52:56 +00001509 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001510}
1511
Nandana Dutt5c390032019-03-12 10:52:56 +00001512/*
1513 * Dumps state for the default case; drops root after it's no longer necessary.
1514 *
1515 * Returns RunStatus::OK if everything went fine.
1516 * Returns RunStatus::ERROR if there was an error.
1517 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1518 * with the caller.
1519 */
1520static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001521 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001522 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001523 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001524
Nandana Duttdb379fa2019-10-09 16:54:41 +01001525 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1526 // buffer.
1527 DoLogcat();
1528 // Capture timestamp after first logcat to use in next logcat
1529 time_t logcat_ts = time(nullptr);
1530
Nandana Dutt4be45d12018-09-26 15:04:23 +01001531 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001532 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001533
1534 /* Run some operations that require root. */
1535 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1536 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1537
1538 ds.AddDir(RECOVERY_DIR, true);
1539 ds.AddDir(RECOVERY_DATA_DIR, true);
1540 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1541 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1542 if (!PropertiesHelper::IsUserBuild()) {
1543 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1544 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1545 }
1546 add_mountinfo();
1547 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001548 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001549
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001550 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001551 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1552
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001553 // Dump IPsec stats. No keys are exposed here.
1554 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1555
Nandana Dutt4be45d12018-09-26 15:04:23 +01001556 // Run ss as root so we can see socket marks.
1557 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1558
1559 // Run iotop as root to show top 100 IO threads
1560 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1561
Erick Reyese68df822019-02-11 14:46:36 -08001562 // Gather shared memory buffer info if the product implements it
1563 struct stat st;
1564 if (!stat("/product/bin/dmabuf_dump", &st)) {
1565 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1566 }
1567
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001568 DumpFile("PSI cpu", "/proc/pressure/cpu");
1569 DumpFile("PSI memory", "/proc/pressure/memory");
1570 DumpFile("PSI io", "/proc/pressure/io");
1571
Nandana Dutt4be45d12018-09-26 15:04:23 +01001572 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001573 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001574 }
1575
Nandana Dutt5c390032019-03-12 10:52:56 +00001576 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001577 Dumpstate::RunStatus status = dumpstate();
1578 // Capture logcat since the last time we did it.
1579 DoSystemLogcat(logcat_ts);
1580 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001581}
1582
mukesh agrawal253dad42018-01-23 21:59:59 -08001583// This method collects common dumpsys for telephony and wifi
1584static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001585 DumpIpTablesAsRoot();
1586
Jayachandran Cb4389d92019-07-08 09:46:05 -07001587 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1588
Jayachandran Ca94c7172017-06-10 15:08:12 -07001589 if (!DropRootUser()) {
1590 return;
1591 }
1592
1593 do_dmesg();
1594 DoLogcat();
1595 DumpPacketStats();
1596 DoKmsg();
1597 DumpIpAddrAndRules();
1598 dump_route_tables();
Jayachandran Cb4389d92019-07-08 09:46:05 -07001599 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001600
1601 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1602 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001603}
1604
1605// This method collects dumpsys for telephony debugging only
1606static void DumpstateTelephonyOnly() {
1607 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001608 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001609
1610 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001611
1612 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1613
1614 printf("========================================================\n");
1615 printf("== Android Framework Services\n");
1616 printf("========================================================\n");
1617
Vishnu Nair652cc802017-11-30 15:18:30 -08001618 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1619 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001620 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1621 SEC_TO_MSEC(10));
1622 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001623 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1624 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001625 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1626 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001627 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1628 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001629
1630 printf("========================================================\n");
1631 printf("== Running Application Services\n");
1632 printf("========================================================\n");
1633
1634 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1635
1636 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001637 printf("== Running Application Services (non-platform)\n");
1638 printf("========================================================\n");
1639
1640 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1641 DUMPSYS_COMPONENTS_OPTIONS);
1642
1643 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001644 printf("== Checkins\n");
1645 printf("========================================================\n");
1646
1647 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1648
1649 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001650 printf("== dumpstate: done (id %d)\n", ds.id_);
1651 printf("========================================================\n");
1652}
1653
mukesh agrawal253dad42018-01-23 21:59:59 -08001654// This method collects dumpsys for wifi debugging only
1655static void DumpstateWifiOnly() {
1656 DurationReporter duration_reporter("DUMPSTATE");
1657
1658 DumpstateRadioCommon();
1659
1660 printf("========================================================\n");
1661 printf("== Android Framework Services\n");
1662 printf("========================================================\n");
1663
1664 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1665 SEC_TO_MSEC(10));
1666 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1667 SEC_TO_MSEC(10));
1668
1669 printf("========================================================\n");
1670 printf("== dumpstate: done (id %d)\n", ds.id_);
1671 printf("========================================================\n");
1672}
1673
Nandana Duttcf419a72019-03-14 10:40:17 +00001674Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001675 DurationReporter duration_reporter("DUMP TRACES");
1676
1677 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1678 const size_t buf_size = temp_file_pattern.length() + 1;
1679 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1680 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1681
1682 // Create a new, empty file to receive all trace dumps.
1683 //
1684 // TODO: This can be simplified once we remove support for the old style
1685 // dumps. We can have a file descriptor passed in to dump_traces instead
1686 // of creating a file, closing it and then reopening it again.
1687 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1688 if (fd < 0) {
1689 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001690 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001691 }
1692
1693 // Nobody should have access to this temporary file except dumpstate, but we
1694 // temporarily grant 'read' to 'others' here because this file is created
1695 // when tombstoned is still running as root, but dumped after dropping. This
1696 // can go away once support for old style dumping has.
1697 const int chmod_ret = fchmod(fd, 0666);
1698 if (chmod_ret < 0) {
1699 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001700 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001701 }
1702
1703 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1704 if (proc.get() == nullptr) {
1705 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001706 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001707 }
1708
1709 // Number of times process dumping has timed out. If we encounter too many
1710 // failures, we'll give up.
1711 int timeout_failures = 0;
1712 bool dalvik_found = false;
1713
1714 const std::set<int> hal_pids = get_interesting_hal_pids();
1715
1716 struct dirent* d;
1717 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001718 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001719 int pid = atoi(d->d_name);
1720 if (pid <= 0) {
1721 continue;
1722 }
1723
1724 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1725 std::string exe;
1726 if (!android::base::Readlink(link_name, &exe)) {
1727 continue;
1728 }
1729
1730 bool is_java_process;
1731 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1732 // Don't bother dumping backtraces for the zygote.
1733 if (IsZygote(pid)) {
1734 continue;
1735 }
1736
1737 dalvik_found = true;
1738 is_java_process = true;
1739 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1740 is_java_process = false;
1741 } else {
1742 // Probably a native process we don't care about, continue.
1743 continue;
1744 }
1745
1746 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1747 if (timeout_failures == 3) {
1748 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1749 break;
1750 }
1751
1752 const uint64_t start = Nanotime();
1753 const int ret = dump_backtrace_to_file_timeout(
1754 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1755 is_java_process ? 5 : 20, fd);
1756
1757 if (ret == -1) {
1758 // For consistency, the header and footer to this message match those
1759 // dumped by debuggerd in the success case.
1760 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1761 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1762 dprintf(fd, "---- end %d ----", pid);
1763 timeout_failures++;
1764 continue;
1765 }
1766
1767 // We've successfully dumped stack traces, reset the failure count
1768 // and write a summary of the elapsed time to the file and continue with the
1769 // next process.
1770 timeout_failures = 0;
1771
1772 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1773 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1774 }
1775
1776 if (!dalvik_found) {
1777 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1778 }
1779
Nandana Duttcf419a72019-03-14 10:40:17 +00001780 *path = file_name_buf.release();
1781 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001782}
1783
Felipe Leme6f674ae2016-11-18 17:10:33 -08001784void Dumpstate::DumpstateBoard() {
1785 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001786 printf("========================================================\n");
1787 printf("== Board\n");
1788 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001789
Felipe Leme6f674ae2016-11-18 17:10:33 -08001790 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001791 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001792 return;
1793 }
1794
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001795 std::vector<std::string> paths;
1796 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001797 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001798 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1799 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001800 remover.emplace_back(android::base::make_scope_guard(
1801 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001802 }
Jie Song9fbfad02017-06-20 16:29:42 -07001803
Wei Wang587eac92018-04-05 12:17:20 -07001804 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1805 if (dumpstate_device == nullptr) {
1806 MYLOGE("No IDumpstateDevice implementation\n");
1807 return;
1808 }
1809
1810 using ScopedNativeHandle =
1811 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1812 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1813 [](native_handle_t* handle) {
1814 native_handle_close(handle);
1815 native_handle_delete(handle);
1816 });
1817 if (handle == nullptr) {
1818 MYLOGE("Could not create native_handle\n");
1819 return;
1820 }
1821
Nandana Dutt5c390032019-03-12 10:52:56 +00001822 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001823 for (size_t i = 0; i < paths.size(); i++) {
1824 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1825
1826 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1827 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1828 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1829 if (fd < 0) {
1830 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1831 return;
1832 }
1833 handle.get()->data[i] = fd.release();
1834 }
1835
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001836 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001837 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1838 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1839 // and grab whatever dumped
1840 std::packaged_task<bool()>
1841 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001842 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1843 if (!status.isOk()) {
1844 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001845 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001846 }
Wei Wang587eac92018-04-05 12:17:20 -07001847 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001848 });
Wei Wang587eac92018-04-05 12:17:20 -07001849
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001850 auto result = dumpstate_task.get_future();
1851 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001852
1853 constexpr size_t timeout_sec = 30;
1854 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1855 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1856 if (!android::base::SetProperty("ctl.interface_restart",
1857 android::base::StringPrintf("%s/default",
1858 IDumpstateDevice::descriptor))) {
1859 MYLOGE("Couldn't restart dumpstate HAL\n");
1860 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001861 }
Wei Wang587eac92018-04-05 12:17:20 -07001862 // Wait some time for init to kill dumpstate vendor HAL
1863 constexpr size_t killing_timeout_sec = 10;
1864 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1865 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1866 "there might be racing in content\n", killing_timeout_sec);
1867 }
1868
1869 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1870 for (size_t i = 0; i < paths.size(); i++) {
1871 struct stat s;
1872 if (fstat(handle.get()->data[i], &s) == -1) {
1873 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1874 strerror(errno));
1875 file_sizes[i] = -1;
1876 continue;
1877 }
1878 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001879 }
1880
1881 for (size_t i = 0; i < paths.size(); i++) {
1882 if (file_sizes[i] == -1) {
1883 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001884 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001885 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001886 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001887 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001888 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001889 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001890 }
1891
Felipe Lemed8b94e52016-12-08 10:21:44 -08001892 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001893}
1894
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001895static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001896 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001897 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Abhijeet Kaure370d682019-10-01 16:49:30 +01001898 "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001899 " -h: display this help message\n"
1900 " -b: play sound file instead of vibrate, at beginning of job\n"
1901 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001902 " -d: append date to filename\n"
1903 " -p: capture screenshot to filename.png\n"
1904 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001905 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001906 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001907 " -q: disable vibrate\n"
Abhijeet Kaure370d682019-10-01 16:49:30 +01001908 " -P: send broadcast when started and do progress updates\n"
1909 " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001910 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001911 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001912}
1913
Wei Liuf87959e2016-08-26 14:51:42 -07001914static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001915 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001916}
1917
Felipe Leme1d486fe2016-10-14 18:06:47 -07001918bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001919 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001920 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001921 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001922 // Final timestamp
1923 char date[80];
1924 time_t the_real_now_please_stand_up = time(nullptr);
1925 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001926 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001927 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001928
Felipe Leme9a523ae2016-10-20 15:10:33 -07001929 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001930 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001931 return false;
1932 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001933 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001934 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001935 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001936 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001937
Felipe Leme0f3fb202016-06-10 17:10:53 -07001938 // Add log file (which contains stderr output) to zip...
1939 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001940 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001941 MYLOGE("Failed to add dumpstate log to .zip file\n");
1942 return false;
1943 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001944 // TODO: Should truncate the existing file.
1945 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001946 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1947 return false;
1948 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001949 fprintf(stderr, "\n");
1950
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001951 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001952 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001953 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001954 return false;
1955 }
1956
Felipe Leme1d486fe2016-10-14 18:06:47 -07001957 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1958 ds.zip_file.reset(nullptr);
1959
Felipe Lemee9d2c542016-11-15 11:48:26 -08001960 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001961 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001962
Felipe Leme1e9edc62015-12-21 16:02:13 -08001963 return true;
1964}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001965
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001966static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1967 // clang-format off
1968 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1969 "--receiver-foreground", "--receiver-include-background", "-a", action};
1970 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001971
1972 am.insert(am.end(), args.begin(), args.end());
1973
Felipe Leme8d2410e2017-02-08 09:46:08 -08001974 RunCommand("", am,
1975 CommandOptions::WithTimeout(20)
1976 .Log("Sending broadcast: '%s'\n")
1977 .Always()
1978 .DropRoot()
1979 .RedirectStderr()
1980 .Build());
1981}
1982
Felipe Leme35b8cf12017-02-10 15:47:29 -08001983static void Vibrate(int duration_ms) {
1984 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00001985 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001986 CommandOptions::WithTimeout(10)
1987 .Log("Vibrate: '%s'\n")
1988 .Always()
1989 .Build());
1990 // clang-format on
1991}
1992
Nandana Dutt979388e2018-11-30 16:48:55 +00001993static void MaybeResolveSymlink(std::string* path) {
1994 std::string resolved_path;
1995 if (android::base::Readlink(*path, &resolved_path)) {
1996 *path = resolved_path;
1997 }
1998}
1999
Nandana Dutt4be45d12018-09-26 15:04:23 +01002000/*
2001 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2002 * if we are writing zip files and adds the version file.
2003 */
2004static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002005 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2006
Nandana Dutt4be45d12018-09-26 15:04:23 +01002007 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2008 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002009 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002010 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002011 char date[80];
2012 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2013 ds.name_ = date;
2014 } else {
2015 ds.name_ = "undated";
2016 }
2017
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002018 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002019 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002020 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002021 ds.base_name_ += "-wifi";
2022 }
2023
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002024 if (ds.options_->do_fb) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002025 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002026 }
2027 ds.tmp_path_ = ds.GetPath(".tmp");
2028 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2029
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002030 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00002031 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002032 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002033 MYLOGD(
2034 "Bugreport dir: %s\n"
2035 "Base name: %s\n"
2036 "Suffix: %s\n"
2037 "Log path: %s\n"
2038 "Temporary path: %s\n"
2039 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002040 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2041 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002042
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002043 if (ds.options_->do_zip_file) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002044 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002045 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2046 create_parent_dirs(ds.path_.c_str());
2047 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2048 if (ds.zip_file == nullptr) {
2049 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2050 } else {
2051 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2052 }
2053 ds.AddTextZipEntry("version.txt", ds.version_);
2054 }
2055}
2056
2057/*
Abhijeet Kaure370d682019-10-01 16:49:30 +01002058 * Finalizes writing to the file by zipping the tmp file to the final location,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002059 * printing zipped file status, etc.
2060 */
2061static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002062 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002063 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002064 if (!ds.FinishZipFile()) {
2065 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2066 do_text_file = true;
2067 } else {
2068 do_text_file = false;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002069 }
2070 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002071 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002072 if (do_text_file) {
2073 dprintf(ds.control_socket_fd_,
2074 "FAIL:could not create zip file, check %s "
2075 "for more details\n",
2076 ds.log_path_.c_str());
2077 } else {
2078 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2079 }
2080 }
2081}
2082
Nandana Dutt4be45d12018-09-26 15:04:23 +01002083
Nandana Dutt58d72e22018-11-16 10:30:48 +00002084static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2085 switch (mode) {
2086 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2087 return "BUGREPORT_FULL";
2088 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2089 return "BUGREPORT_INTERACTIVE";
2090 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2091 return "BUGREPORT_REMOTE";
2092 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2093 return "BUGREPORT_WEAR";
2094 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2095 return "BUGREPORT_TELEPHONY";
2096 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2097 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002098 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2099 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002100 }
2101}
2102
2103static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002104 options->bugreport_mode = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002105 switch (mode) {
2106 case Dumpstate::BugreportMode::BUGREPORT_FULL:
Nandana Dutt58d72e22018-11-16 10:30:48 +00002107 options->do_fb = true;
2108 break;
2109 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002110 // Currently, the dumpstate binder is only used by Shell to update progress.
2111 options->do_start_service = true;
2112 options->do_progress_updates = true;
2113 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002114 break;
2115 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002116 options->do_vibrate = false;
2117 options->is_remote_mode = true;
2118 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002119 break;
2120 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002121 options->do_start_service = true;
2122 options->do_progress_updates = true;
2123 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002124 options->do_fb = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002125 break;
2126 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002127 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002128 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002129 break;
2130 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002131 options->wifi_only = true;
2132 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002133 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002134 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002135 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2136 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002137 }
2138}
2139
Nandana Dutt58d72e22018-11-16 10:30:48 +00002140static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2141 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2142 MYLOGI("do_add_date: %d\n", options.do_add_date);
2143 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2144 MYLOGI("use_socket: %d\n", options.use_socket);
2145 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2146 MYLOGI("do_fb: %d\n", options.do_fb);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002147 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2148 MYLOGI("show_header_only: %d\n", options.show_header_only);
2149 MYLOGI("do_start_service: %d\n", options.do_start_service);
2150 MYLOGI("telephony_only: %d\n", options.telephony_only);
2151 MYLOGI("wifi_only: %d\n", options.wifi_only);
2152 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002153 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Abhijeet Kaure370d682019-10-01 16:49:30 +01002154 MYLOGI("bugreport_mode: %s\n", options.bugreport_mode.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002155 MYLOGI("args: %s\n", options.args.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002156}
2157
Nandana Dutt54dbd672019-01-11 12:58:05 +00002158void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2159 const android::base::unique_fd& bugreport_fd_in,
2160 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002161 // In the new API world, date is always added; output is always a zip file.
2162 // TODO(111441001): remove these options once they are obsolete.
2163 do_add_date = true;
2164 do_zip_file = true;
2165
Nandana Dutt54dbd672019-01-11 12:58:05 +00002166 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2167 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2168 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002169
Nandana Dutt58d72e22018-11-16 10:30:48 +00002170 SetOptionsFromMode(bugreport_mode, this);
2171}
2172
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002173Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2174 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002175 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002176 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002177 switch (c) {
2178 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002179 case 'd': do_add_date = true; break;
2180 case 'z': do_zip_file = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002181 case 's': use_socket = true; break;
2182 case 'S': use_control_socket = true; break;
2183 case 'v': show_header_only = true; break;
2184 case 'q': do_vibrate = false; break;
2185 case 'p': do_fb = true; break;
2186 case 'P': do_progress_updates = true; break;
2187 case 'R': is_remote_mode = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002188 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002189 case 'w':
2190 // This was already processed
2191 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002192 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002193 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002194 break;
2195 default:
2196 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002197 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002198 break;
2199 // clang-format on
2200 }
2201 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002202
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002203 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002204 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002205 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002206 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002207 }
2208 }
2209
2210 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2211 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002212
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002213 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002214}
2215
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002216bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002217 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002218 return false;
2219 }
2220
Abhijeet Kaure370d682019-10-01 16:49:30 +01002221 if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002222 return false;
2223 }
2224
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002225 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002226 return false;
2227 }
2228
Abhijeet Kaure370d682019-10-01 16:49:30 +01002229 if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002230 return false;
2231 }
2232 return true;
2233}
2234
Nandana Dutt197661d2018-11-16 16:40:21 +00002235void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2236 options_ = std::move(options);
2237}
2238
Nandana Duttd2f5f082019-01-18 17:13:52 +00002239Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2240 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002241 if (listener_ != nullptr) {
2242 switch (status) {
2243 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002244 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002245 break;
2246 case Dumpstate::RunStatus::HELP:
2247 break;
2248 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002249 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002250 break;
2251 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002252 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2253 break;
2254 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2255 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2256 break;
2257 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2258 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002259 break;
2260 }
2261 }
2262 return status;
2263}
2264
Nandana Dutt979388e2018-11-30 16:48:55 +00002265/*
2266 * Dumps relevant information to a bugreport based on the given options.
2267 *
2268 * The bugreport can be dumped to a file or streamed to a socket.
2269 *
2270 * How dumping to file works:
2271 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2272 * stderr is redirected a log file.
2273 *
2274 * The temporary bugreport is then populated via printfs, dumping contents of files and
2275 * output of commands to stdout.
2276 *
2277 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2278 * text file.
2279 *
2280 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2281 * gets added to the archive.
2282 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002283 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2284 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002285 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002286Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2287 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002288 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002289 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002290 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002291 return RunStatus::INVALID_INPUT;
2292 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002293 /* set as high priority, and protect from OOM killer */
2294 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002295
Felipe Lemed071c682016-10-20 16:48:00 -07002296 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002297 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002298 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002299 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002300 } else {
2301 /* fallback to kernels <= 2.6.35 */
2302 oom_adj = fopen("/proc/self/oom_adj", "we");
2303 if (oom_adj) {
2304 fputs("-17", oom_adj);
2305 fclose(oom_adj);
2306 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002307 }
2308
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002309 if (version_ == VERSION_DEFAULT) {
2310 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002311 }
2312
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002313 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002314 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002315 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002316 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002317 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002318 }
2319
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002320 if (options_->show_header_only) {
2321 PrintHeader();
2322 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002323 }
2324
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002325 MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
2326 calling_uid, calling_package.c_str());
Abhijeet Kaure370d682019-10-01 16:49:30 +01002327 if (CalledByApi()) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002328 // If the output needs to be copied over to the caller's fd, get user consent.
2329 android::String16 package(calling_package.c_str());
2330 CheckUserConsent(calling_uid, package);
2331 }
2332
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002333 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002334 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002335
2336 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002337 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002338 is_redirecting
2339 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2340 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002341 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002342
Felipe Lemed071c682016-10-20 16:48:00 -07002343 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002344 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002345 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002346 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2347
2348 MYLOGI("begin\n");
2349
Sahana Raof35ed432019-07-12 10:47:52 +01002350 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2351 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2352 } else {
2353 // Wake lock will be released automatically on process death
2354 MYLOGD("Wake lock acquired.\n");
2355 }
2356
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002357 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002358
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002359 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002360 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002361 MYLOGI("Starting 'dumpstate' service\n");
2362 android::status_t ret;
2363 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2364 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2365 }
2366 }
2367
Felipe Lemef0292972016-11-22 13:57:05 -08002368 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002369 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2370 }
2371
Abhijeet Kaure370d682019-10-01 16:49:30 +01002372 MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s)\n", id_, options_->args.c_str(),
2373 options_->bugreport_mode.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002374
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002375 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002376
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002377 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002378
Christopher Ferrised9354f2014-10-01 17:35:01 -07002379 // If we are going to use a socket, do it as early as possible
2380 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002381 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002382 if (!redirect_to_socket(stdout, "dumpstate")) {
2383 return ERROR;
2384 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002385 }
2386
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002387 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002388 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002389 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002390 if (control_socket_fd_ == -1) {
2391 return ERROR;
2392 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002393 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002394 }
2395
Felipe Leme71bbfc52015-11-23 14:14:51 -08002396 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002397 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002398
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002399 if (options_->do_progress_updates) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002400 // clang-format off
2401 std::vector<std::string> am_args = {
2402 "--receiver-permission", "android.permission.DUMP",
2403 };
2404 // clang-format on
2405 // Send STARTED broadcast for apps that listen to bugreport generation events
2406 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002407 if (options_->use_control_socket) {
2408 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002409 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002410 }
2411 }
2412
Nick Kralevichf3599b32016-01-25 15:05:16 -08002413 /* read /proc/cmdline before dropping root */
2414 FILE *cmdline = fopen("/proc/cmdline", "re");
2415 if (cmdline) {
2416 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2417 fclose(cmdline);
2418 }
2419
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002420 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002421 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002422 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002423
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002424 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002425 MYLOGI("taking early screenshot\n");
2426 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002427 }
2428
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002429 if (options_->do_zip_file && zip_file != nullptr) {
2430 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2431 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002432 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002433 }
2434 }
2435
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002436 int dup_stdout_fd;
2437 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002438 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002439 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002440 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002441 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2442 return ERROR;
2443 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002444 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2445 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2446 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002447 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002448
2449 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2450 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002451 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002452 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002453 /* TODO: rather than generating a text file now and zipping it later,
2454 it would be more efficient to redirect stdout to the zip entry
2455 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002456 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2457 return ERROR;
2458 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002459 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002460 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002461 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002462 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002463 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002464
2465 // Don't buffer stdout
2466 setvbuf(stdout, nullptr, _IONBF, 0);
2467
Felipe Leme608385d2016-02-01 10:35:38 -08002468 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2469 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002470 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002471 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002472
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002473 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002474 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002475 DumpstateBoard();
2476 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002477 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002478 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002479 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002480 RunStatus s = DumpstateDefault();
2481 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002482 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002483 HandleUserConsentDenied();
2484 }
2485 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002486 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002487 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002488
Felipe Leme55b42a62015-11-10 17:39:08 -08002489 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002490 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002491 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002492 }
2493
Abhijeet Kaure370d682019-10-01 16:49:30 +01002494 // Zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002495 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002496 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002497 }
2498
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002499 // Share the final file with the caller if the user has consented or Shell is the caller.
Nandana Duttd2f5f082019-01-18 17:13:52 +00002500 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
Abhijeet Kaure370d682019-10-01 16:49:30 +01002501 if (CalledByApi()) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002502 status = CopyBugreportIfUserConsented(calling_uid);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002503 if (status != Dumpstate::RunStatus::OK &&
2504 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2505 // Do an early return if there were errors. We make an exception for consent
2506 // timing out because it's possible the user got distracted. In this case the
2507 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002508 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002509 return status;
2510 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002511 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002512 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2513 options_->screenshot_fd.get());
2514 if (copy_succeeded) {
2515 android::os::UnlinkAndLogOnError(screenshot_path_);
2516 }
2517 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002518 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2519 MYLOGI(
2520 "Did not receive user consent yet."
2521 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002522 const String16 incidentcompanion("incidentcompanion");
2523 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2524 if (ics != nullptr) {
2525 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2526 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2527 consent_callback_.get());
2528 } else {
2529 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2530 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002531 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002532 }
2533
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002534 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002535 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002536 for (int i = 0; i < 3; i++) {
2537 Vibrate(75);
2538 usleep((75 + 50) * 1000);
2539 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002540 }
2541
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002542 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2543 progress_->GetInitialMax());
2544 progress_->Save();
2545 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002546
Felipe Leme107a05f2016-03-08 15:11:15 -08002547 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002548 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002549 }
2550
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002551 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002552 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002553 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002554 }
2555
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002556 tombstone_data_.clear();
2557 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002558
Nandana Duttd2f5f082019-01-18 17:13:52 +00002559 return (consent_callback_ != nullptr &&
2560 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2561 ? USER_CONSENT_TIMED_OUT
2562 : RunStatus::OK;
2563}
2564
2565void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002566 if (calling_uid == AID_SHELL) {
2567 return;
2568 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002569 consent_callback_ = new ConsentCallback();
2570 const String16 incidentcompanion("incidentcompanion");
2571 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2572 if (ics != nullptr) {
2573 MYLOGD("Checking user consent via incidentcompanion service\n");
2574 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002575 calling_uid, calling_package, String16(), String16(),
2576 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002577 } else {
2578 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2579 }
2580}
2581
Nandana Dutt5c390032019-03-12 10:52:56 +00002582bool Dumpstate::IsUserConsentDenied() const {
2583 return ds.consent_callback_ != nullptr &&
2584 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2585}
2586
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002587bool Dumpstate::CalledByApi() const {
2588 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2589}
2590
Nandana Duttd2f5f082019-01-18 17:13:52 +00002591void Dumpstate::CleanupFiles() {
2592 android::os::UnlinkAndLogOnError(tmp_path_);
2593 android::os::UnlinkAndLogOnError(screenshot_path_);
2594 android::os::UnlinkAndLogOnError(path_);
2595}
2596
2597Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2598 MYLOGD("User denied consent; deleting files and returning\n");
2599 CleanupFiles();
2600 return USER_CONSENT_DENIED;
2601}
2602
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002603Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002604 // If the caller has asked to copy the bugreport over to their directory, we need explicit
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002605 // user consent (unless the caller is Shell).
2606 UserConsentResult consent_result;
2607 if (calling_uid == AID_SHELL) {
2608 consent_result = UserConsentResult::APPROVED;
2609 } else {
2610 consent_result = consent_callback_->getResult();
2611 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002612 if (consent_result == UserConsentResult::UNAVAILABLE) {
2613 // User has not responded yet.
2614 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2615 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2616 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2617 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2618 sleep(delay_seconds);
2619 }
2620 consent_result = consent_callback_->getResult();
2621 }
2622 if (consent_result == UserConsentResult::DENIED) {
2623 // User has explicitly denied sharing with the app. To be safe delete the
2624 // internal bugreport & tmp files.
2625 return HandleUserConsentDenied();
2626 }
2627 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002628 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2629 if (copy_succeeded) {
2630 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002631 }
2632 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2633 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2634 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2635 // Since we do not have user consent to share the bugreport it does not get
2636 // copied over to the calling app but remains in the internal directory from
2637 // where the user can manually pull it.
2638 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2639 }
2640 // Unknown result; must be a programming error.
2641 MYLOGE("Unknown user consent result:%d\n", consent_result);
2642 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002643}
2644
Nandana Duttf02564e2019-02-15 15:24:24 +00002645Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002646 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2647 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2648 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002649 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002650 // When directly running dumpstate binary, the output is not expected to be written
2651 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002652 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002653
2654 // calling_uid and calling_package are for user consent to share the bugreport with
2655 // an app; they are irrelvant here because bugreport is only written to a local
2656 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002657 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002658 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002659 return status;
2660}
2661
2662/* Main entry point for dumpstate binary. */
2663int run_main(int argc, char* argv[]) {
2664 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002665
2666 switch (status) {
2667 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002668 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002669 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002670 ShowUsage();
2671 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002672 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002673 fprintf(stderr, "Invalid combination of args\n");
2674 ShowUsage();
2675 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002676 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002677 FALLTHROUGH_INTENDED;
2678 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2679 FALLTHROUGH_INTENDED;
2680 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002681 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002682 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002683}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002684
2685// TODO(111441001): Default DumpOptions to sensible values.
2686Dumpstate::Dumpstate(const std::string& version)
2687 : pid_(getpid()),
2688 options_(new Dumpstate::DumpOptions()),
Nandana Dutt402a8392019-06-14 14:25:13 +01002689 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002690 version_(version),
2691 now_(time(nullptr)) {
2692}
2693
2694Dumpstate& Dumpstate::GetInstance() {
2695 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2696 return singleton_;
2697}
2698
Nandana Dutt8d945c02019-08-14 13:30:07 +01002699DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2700 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002701 if (!title_.empty()) {
2702 started_ = Nanotime();
2703 }
2704}
2705
2706DurationReporter::~DurationReporter() {
2707 if (!title_.empty()) {
2708 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002709 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002710 return;
2711 }
2712 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2713 if (logcat_only_) {
2714 return;
2715 }
2716 // Use "Yoda grammar" to make it easier to grep|sort sections.
2717 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2718 }
2719}
2720
2721const int32_t Progress::kDefaultMax = 5000;
2722
2723Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2724}
2725
2726Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2727 : Progress(initial_max, growth_factor, "") {
2728 progress_ = progress;
2729}
2730
2731Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2732 : initial_max_(initial_max),
2733 progress_(0),
2734 max_(initial_max),
2735 growth_factor_(growth_factor),
2736 n_runs_(0),
2737 average_max_(0),
2738 path_(path) {
2739 if (!path_.empty()) {
2740 Load();
2741 }
2742}
2743
2744void Progress::Load() {
2745 MYLOGD("Loading stats from %s\n", path_.c_str());
2746 std::string content;
2747 if (!android::base::ReadFileToString(path_, &content)) {
2748 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2749 return;
2750 }
2751 if (content.empty()) {
2752 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2753 return;
2754 }
2755 std::vector<std::string> lines = android::base::Split(content, "\n");
2756
2757 if (lines.size() < 1) {
2758 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2759 (int)lines.size(), max_);
2760 return;
2761 }
2762 char* ptr;
2763 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2764 average_max_ = strtol(ptr, nullptr, 10);
2765 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2766 average_max_ > STATS_MAX_AVERAGE) {
2767 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2768 initial_max_ = Progress::kDefaultMax;
2769 } else {
2770 initial_max_ = average_max_;
2771 }
2772 max_ = initial_max_;
2773
2774 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2775}
2776
2777void Progress::Save() {
2778 int32_t total = n_runs_ * average_max_ + progress_;
2779 int32_t runs = n_runs_ + 1;
2780 int32_t average = floor(((float)total) / runs);
2781 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2782 path_.c_str());
2783 if (path_.empty()) {
2784 return;
2785 }
2786
2787 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2788 if (!android::base::WriteStringToFile(content, path_)) {
2789 MYLOGE("Could not save stats on %s\n", path_.c_str());
2790 }
2791}
2792
2793int32_t Progress::Get() const {
2794 return progress_;
2795}
2796
2797bool Progress::Inc(int32_t delta_sec) {
2798 bool changed = false;
2799 if (delta_sec >= 0) {
2800 progress_ += delta_sec;
2801 if (progress_ > max_) {
2802 int32_t old_max = max_;
2803 max_ = floor((float)progress_ * growth_factor_);
2804 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2805 changed = true;
2806 }
2807 }
2808 return changed;
2809}
2810
2811int32_t Progress::GetMax() const {
2812 return max_;
2813}
2814
2815int32_t Progress::GetInitialMax() const {
2816 return initial_max_;
2817}
2818
2819void Progress::Dump(int fd, const std::string& prefix) const {
2820 const char* pr = prefix.c_str();
2821 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2822 dprintf(fd, "%smax: %d\n", pr, max_);
2823 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2824 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2825 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2826 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2827 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2828}
2829
2830bool Dumpstate::IsZipping() const {
2831 return zip_writer_ != nullptr;
2832}
2833
2834std::string Dumpstate::GetPath(const std::string& suffix) const {
2835 return GetPath(bugreport_internal_dir_, suffix);
2836}
2837
2838std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2839 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2840 name_.c_str(), suffix.c_str());
2841}
2842
2843void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2844 progress_ = std::move(progress);
2845}
2846
2847void for_each_userid(void (*func)(int), const char *header) {
2848 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2849 "for_each_userid(%s)", header);
2850 DurationReporter duration_reporter(title);
2851 if (PropertiesHelper::IsDryRun()) return;
2852
2853 DIR *d;
2854 struct dirent *de;
2855
2856 if (header) printf("\n------ %s ------\n", header);
2857 func(0);
2858
2859 if (!(d = opendir("/data/system/users"))) {
2860 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2861 return;
2862 }
2863
2864 while ((de = readdir(d))) {
2865 int userid;
2866 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2867 continue;
2868 }
2869 func(userid);
2870 }
2871
2872 closedir(d);
2873}
2874
2875static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2876 DIR *d;
2877 struct dirent *de;
2878
2879 if (!(d = opendir("/proc"))) {
2880 printf("Failed to open /proc (%s)\n", strerror(errno));
2881 return;
2882 }
2883
2884 if (header) printf("\n------ %s ------\n", header);
2885 while ((de = readdir(d))) {
2886 if (ds.IsUserConsentDenied()) {
2887 MYLOGE(
2888 "Returning early because user denied consent to share bugreport with calling app.");
2889 closedir(d);
2890 return;
2891 }
2892 int pid;
2893 int fd;
2894 char cmdpath[255];
2895 char cmdline[255];
2896
2897 if (!(pid = atoi(de->d_name))) {
2898 continue;
2899 }
2900
2901 memset(cmdline, 0, sizeof(cmdline));
2902
2903 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
2904 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2905 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
2906 close(fd);
2907 if (cmdline[0]) {
2908 helper(pid, cmdline, arg);
2909 continue;
2910 }
2911 }
2912
2913 // if no cmdline, a kernel thread has comm
2914 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
2915 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2916 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
2917 close(fd);
2918 if (cmdline[1]) {
2919 cmdline[0] = '[';
2920 size_t len = strcspn(cmdline, "\f\b\r\n");
2921 cmdline[len] = ']';
2922 cmdline[len+1] = '\0';
2923 }
2924 }
2925 if (!cmdline[0]) {
2926 strcpy(cmdline, "N/A");
2927 }
2928 helper(pid, cmdline, arg);
2929 }
2930
2931 closedir(d);
2932}
2933
2934static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
2935 for_each_pid_func *func = (for_each_pid_func*) arg;
2936 func(pid, cmdline);
2937}
2938
2939void for_each_pid(for_each_pid_func func, const char *header) {
2940 std::string title = header == nullptr ? "for_each_pid"
2941 : android::base::StringPrintf("for_each_pid(%s)", header);
2942 DurationReporter duration_reporter(title);
2943 if (PropertiesHelper::IsDryRun()) return;
2944
2945 __for_each_pid(for_each_pid_helper, header, (void *) func);
2946}
2947
2948static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
2949 DIR *d;
2950 struct dirent *de;
2951 char taskpath[255];
2952 for_each_tid_func *func = (for_each_tid_func *) arg;
2953
2954 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
2955
2956 if (!(d = opendir(taskpath))) {
2957 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
2958 return;
2959 }
2960
2961 func(pid, pid, cmdline);
2962
2963 while ((de = readdir(d))) {
2964 if (ds.IsUserConsentDenied()) {
2965 MYLOGE(
2966 "Returning early because user denied consent to share bugreport with calling app.");
2967 closedir(d);
2968 return;
2969 }
2970 int tid;
2971 int fd;
2972 char commpath[255];
2973 char comm[255];
2974
2975 if (!(tid = atoi(de->d_name))) {
2976 continue;
2977 }
2978
2979 if (tid == pid)
2980 continue;
2981
2982 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
2983 memset(comm, 0, sizeof(comm));
2984 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
2985 strcpy(comm, "N/A");
2986 } else {
2987 char *c;
2988 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
2989 close(fd);
2990
2991 c = strrchr(comm, '\n');
2992 if (c) {
2993 *c = '\0';
2994 }
2995 }
2996 func(pid, tid, comm);
2997 }
2998
2999 closedir(d);
3000}
3001
3002void for_each_tid(for_each_tid_func func, const char *header) {
3003 std::string title = header == nullptr ? "for_each_tid"
3004 : android::base::StringPrintf("for_each_tid(%s)", header);
3005 DurationReporter duration_reporter(title);
3006
3007 if (PropertiesHelper::IsDryRun()) return;
3008
3009 __for_each_pid(for_each_tid_helper, header, (void *) func);
3010}
3011
3012void show_wchan(int pid, int tid, const char *name) {
3013 if (PropertiesHelper::IsDryRun()) return;
3014
3015 char path[255];
3016 char buffer[255];
3017 int fd, ret, save_errno;
3018 char name_buffer[255];
3019
3020 memset(buffer, 0, sizeof(buffer));
3021
3022 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3023 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3024 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3025 return;
3026 }
3027
3028 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3029 save_errno = errno;
3030 close(fd);
3031
3032 if (ret < 0) {
3033 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3034 return;
3035 }
3036
3037 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3038 pid == tid ? 0 : 3, "", name);
3039
3040 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3041
3042 return;
3043}
3044
3045// print time in centiseconds
3046static void snprcent(char *buffer, size_t len, size_t spc,
3047 unsigned long long time) {
3048 static long hz; // cache discovered hz
3049
3050 if (hz <= 0) {
3051 hz = sysconf(_SC_CLK_TCK);
3052 if (hz <= 0) {
3053 hz = 1000;
3054 }
3055 }
3056
3057 // convert to centiseconds
3058 time = (time * 100 + (hz / 2)) / hz;
3059
3060 char str[16];
3061
3062 snprintf(str, sizeof(str), " %llu.%02u",
3063 time / 100, (unsigned)(time % 100));
3064 size_t offset = strlen(buffer);
3065 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3066 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3067}
3068
3069// print permille as a percent
3070static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3071 char str[16];
3072
3073 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3074 size_t offset = strlen(buffer);
3075 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3076 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3077}
3078
3079void show_showtime(int pid, const char *name) {
3080 if (PropertiesHelper::IsDryRun()) return;
3081
3082 char path[255];
3083 char buffer[1023];
3084 int fd, ret, save_errno;
3085
3086 memset(buffer, 0, sizeof(buffer));
3087
3088 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3089 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3090 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3091 return;
3092 }
3093
3094 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3095 save_errno = errno;
3096 close(fd);
3097
3098 if (ret < 0) {
3099 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3100 return;
3101 }
3102
3103 // field 14 is utime
3104 // field 15 is stime
3105 // field 42 is iotime
3106 unsigned long long utime = 0, stime = 0, iotime = 0;
3107 if (sscanf(buffer,
3108 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3109 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3110 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3111 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3112 &utime, &stime, &iotime) != 3) {
3113 return;
3114 }
3115
3116 unsigned long long total = utime + stime;
3117 if (!total) {
3118 return;
3119 }
3120
3121 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3122 if (permille > 1000) {
3123 permille = 1000;
3124 }
3125
3126 // try to beautify and stabilize columns at <80 characters
3127 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3128 if ((name[0] != '[') || utime) {
3129 snprcent(buffer, sizeof(buffer), 57, utime);
3130 }
3131 snprcent(buffer, sizeof(buffer), 65, stime);
3132 if ((name[0] != '[') || iotime) {
3133 snprcent(buffer, sizeof(buffer), 73, iotime);
3134 }
3135 if (iotime) {
3136 snprdec(buffer, sizeof(buffer), 79, permille);
3137 }
3138 puts(buffer); // adds a trailing newline
3139
3140 return;
3141}
3142
3143void do_dmesg() {
3144 const char *title = "KERNEL LOG (dmesg)";
3145 DurationReporter duration_reporter(title);
3146 printf("------ %s ------\n", title);
3147
3148 if (PropertiesHelper::IsDryRun()) return;
3149
3150 /* Get size of kernel buffer */
3151 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3152 if (size <= 0) {
3153 printf("Unexpected klogctl return value: %d\n\n", size);
3154 return;
3155 }
3156 char *buf = (char *) malloc(size + 1);
3157 if (buf == nullptr) {
3158 printf("memory allocation failed\n\n");
3159 return;
3160 }
3161 int retval = klogctl(KLOG_READ_ALL, buf, size);
3162 if (retval < 0) {
3163 printf("klogctl failure\n\n");
3164 free(buf);
3165 return;
3166 }
3167 buf[retval] = '\0';
3168 printf("%s\n\n", buf);
3169 free(buf);
3170 return;
3171}
3172
3173void do_showmap(int pid, const char *name) {
3174 char title[255];
3175 char arg[255];
3176
3177 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3178 snprintf(arg, sizeof(arg), "%d", pid);
3179 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3180}
3181
3182int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3183 DurationReporter duration_reporter(title);
3184
3185 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3186
3187 UpdateProgress(WEIGHT_FILE);
3188
3189 return status;
3190}
3191
3192int read_file_as_long(const char *path, long int *output) {
3193 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3194 if (fd < 0) {
3195 int err = errno;
3196 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3197 return -1;
3198 }
3199 char buffer[50];
3200 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3201 if (bytes_read == -1) {
3202 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3203 return -2;
3204 }
3205 if (bytes_read == 0) {
3206 MYLOGE("File %s is empty\n", path);
3207 return -3;
3208 }
3209 *output = atoi(buffer);
3210 return 0;
3211}
3212
3213/* calls skip to gate calling dump_from_fd recursively
3214 * in the specified directory. dump_from_fd defaults to
3215 * dump_file_from_fd above when set to NULL. skip defaults
3216 * to false when set to NULL. dump_from_fd will always be
3217 * called with title NULL.
3218 */
3219int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3220 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3221 DurationReporter duration_reporter(title);
3222 DIR *dirp;
3223 struct dirent *d;
3224 char *newpath = nullptr;
3225 const char *slash = "/";
3226 int retval = 0;
3227
3228 if (!title.empty()) {
3229 printf("------ %s (%s) ------\n", title.c_str(), dir);
3230 }
3231 if (PropertiesHelper::IsDryRun()) return 0;
3232
3233 if (dir[strlen(dir) - 1] == '/') {
3234 ++slash;
3235 }
3236 dirp = opendir(dir);
3237 if (dirp == nullptr) {
3238 retval = -errno;
3239 MYLOGE("%s: %s\n", dir, strerror(errno));
3240 return retval;
3241 }
3242
3243 if (!dump_from_fd) {
3244 dump_from_fd = dump_file_from_fd;
3245 }
3246 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3247 if ((d->d_name[0] == '.')
3248 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3249 || (d->d_name[1] == '\0'))) {
3250 continue;
3251 }
3252 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3253 (d->d_type == DT_DIR) ? "/" : "");
3254 if (!newpath) {
3255 retval = -errno;
3256 continue;
3257 }
3258 if (skip && (*skip)(newpath)) {
3259 continue;
3260 }
3261 if (d->d_type == DT_DIR) {
3262 int ret = dump_files("", newpath, skip, dump_from_fd);
3263 if (ret < 0) {
3264 retval = ret;
3265 }
3266 continue;
3267 }
3268 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3269 if (fd.get() < 0) {
3270 retval = -1;
3271 printf("*** %s: %s\n", newpath, strerror(errno));
3272 continue;
3273 }
3274 (*dump_from_fd)(nullptr, newpath, fd.get());
3275 }
3276 closedir(dirp);
3277 if (!title.empty()) {
3278 printf("\n");
3279 }
3280 return retval;
3281}
3282
3283/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3284 * it's possible to avoid issues where opening the file itself can get
3285 * stuck.
3286 */
3287int dump_file_from_fd(const char *title, const char *path, int fd) {
3288 if (PropertiesHelper::IsDryRun()) return 0;
3289
3290 int flags = fcntl(fd, F_GETFL);
3291 if (flags == -1) {
3292 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3293 return -1;
3294 } else if (!(flags & O_NONBLOCK)) {
3295 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3296 return -1;
3297 }
3298 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3299}
3300
3301int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003302 const CommandOptions& options, bool verbose_duration) {
3303 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003304
3305 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3306
3307 /* TODO: for now we're simplifying the progress calculation by using the
3308 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3309 * where its weight should be much higher proportionally to its timeout.
3310 * Ideally, it should use a options.EstimatedDuration() instead...*/
3311 UpdateProgress(options.Timeout());
3312
3313 return status;
3314}
3315
3316void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3317 const CommandOptions& options, long dumpsysTimeoutMs) {
3318 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3319 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3320 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3321 RunCommand(title, dumpsys, options);
3322}
3323
3324int open_socket(const char *service) {
3325 int s = android_get_control_socket(service);
3326 if (s < 0) {
3327 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3328 return -1;
3329 }
3330 fcntl(s, F_SETFD, FD_CLOEXEC);
3331
3332 // Set backlog to 0 to make sure that queue size will be minimum.
3333 // In Linux, because the minimum queue will be 1, connect() will be blocked
3334 // if the other clients already called connect() and the connection request was not accepted.
3335 if (listen(s, 0) < 0) {
3336 MYLOGE("listen(control socket): %s\n", strerror(errno));
3337 return -1;
3338 }
3339
3340 struct sockaddr addr;
3341 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003342 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003343
3344 // Close socket just after accept(), to make sure that connect() by client will get error
3345 // when the socket is used by the other services.
3346 // There is still a race condition possibility between accept and close, but there is no way
3347 // to close-on-accept atomically.
3348 // See detail; b/123306389#comment25
3349 close(s);
3350
3351 if (fd < 0) {
3352 MYLOGE("accept(control socket): %s\n", strerror(errno));
3353 return -1;
3354 }
3355
3356 return fd;
3357}
3358
3359/* redirect output to a service control socket */
3360bool redirect_to_socket(FILE* redirect, const char* service) {
3361 int fd = open_socket(service);
3362 if (fd == -1) {
3363 return false;
3364 }
3365 fflush(redirect);
3366 // TODO: handle dup2 failure
3367 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3368 close(fd);
3369 return true;
3370}
3371
3372// TODO: should call is_valid_output_file and/or be merged into it.
3373void create_parent_dirs(const char *path) {
3374 char *chp = const_cast<char *> (path);
3375
3376 /* skip initial slash */
3377 if (chp[0] == '/')
3378 chp++;
3379
3380 /* create leading directories, if necessary */
3381 struct stat dir_stat;
3382 while (chp && chp[0]) {
3383 chp = strchr(chp, '/');
3384 if (chp) {
3385 *chp = 0;
3386 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3387 MYLOGI("Creating directory %s\n", path);
3388 if (mkdir(path, 0770)) { /* drwxrwx--- */
3389 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3390 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3391 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3392 }
3393 }
3394 *chp++ = '/';
3395 }
3396 }
3397}
3398
3399bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3400 create_parent_dirs(path);
3401
3402 int fd = TEMP_FAILURE_RETRY(open(path,
3403 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3404 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3405 if (fd < 0) {
3406 MYLOGE("%s: %s\n", path, strerror(errno));
3407 return false;
3408 }
3409
3410 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3411 close(fd);
3412 return true;
3413}
3414
3415bool redirect_to_file(FILE* redirect, char* path) {
3416 return _redirect_to_file(redirect, path, O_TRUNC);
3417}
3418
3419bool redirect_to_existing_file(FILE* redirect, char* path) {
3420 return _redirect_to_file(redirect, path, O_APPEND);
3421}
3422
3423void dump_route_tables() {
3424 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3425 if (PropertiesHelper::IsDryRun()) return;
3426 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3427 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3428 FILE* fp = fopen(RT_TABLES_PATH, "re");
3429 if (!fp) {
3430 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3431 return;
3432 }
3433 char table[16];
3434 // Each line has an integer (the table number), a space, and a string (the table name). We only
3435 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3436 // Add a fixed max limit so this doesn't go awry.
3437 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3438 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3439 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3440 }
3441 fclose(fp);
3442}
3443
3444// TODO: make this function thread safe if sections are generated in parallel.
3445void Dumpstate::UpdateProgress(int32_t delta_sec) {
3446 if (progress_ == nullptr) {
3447 MYLOGE("UpdateProgress: progress_ not set\n");
3448 return;
3449 }
3450
3451 // Always update progess so stats can be tuned...
Nandana Dutt402a8392019-06-14 14:25:13 +01003452 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003453
3454 // ...but only notifiy listeners when necessary.
3455 if (!options_->do_progress_updates) return;
3456
3457 int progress = progress_->Get();
3458 int max = progress_->GetMax();
Nandana Dutt402a8392019-06-14 14:25:13 +01003459 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003460
Nandana Dutt402a8392019-06-14 14:25:13 +01003461 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003462 return;
3463 }
Nandana Dutt402a8392019-06-14 14:25:13 +01003464 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003465
3466 if (control_socket_fd_ >= 0) {
3467 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3468 fsync(control_socket_fd_);
3469 }
3470
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003471 if (listener_ != nullptr) {
3472 if (percent % 5 == 0) {
3473 // We don't want to spam logcat, so only log multiples of 5.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003474 MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003475 } else {
3476 // stderr is ignored on normal invocations, but useful when calling
3477 // /system/bin/dumpstate directly for debuggging.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003478 fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003479 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003480
3481 listener_->onProgress(percent);
3482 }
3483}
3484
3485void Dumpstate::TakeScreenshot(const std::string& path) {
3486 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3487 int status =
3488 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3489 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3490 if (status == 0) {
3491 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3492 } else {
3493 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3494 }
3495}
3496
3497bool is_dir(const char* pathname) {
3498 struct stat info;
3499 if (stat(pathname, &info) == -1) {
3500 return false;
3501 }
3502 return S_ISDIR(info.st_mode);
3503}
3504
3505time_t get_mtime(int fd, time_t default_mtime) {
3506 struct stat info;
3507 if (fstat(fd, &info) == -1) {
3508 return default_mtime;
3509 }
3510 return info.st_mtime;
3511}