blob: 61e22a4912bb2338fa9a69d0d1012a4f95e96c5c [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"
Yifan Hong3945e1b2019-10-29 12:59:23 -0700157#define OTA_METADATA_DIR "/metadata/ota"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700158
Narayan Kamath8f788292017-05-25 13:20:39 +0100159// TODO(narayan): Since this information has to be kept in sync
160// with tombstoned, we should just put it in a common header.
161//
162// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100163static const std::string TOMBSTONE_DIR = "/data/tombstones/";
164static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
165static const std::string ANR_DIR = "/data/anr/";
166static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700167
Felipe Lemee844a9d2016-09-21 15:01:39 -0700168// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000169
Nandana Dutt5c390032019-03-12 10:52:56 +0000170#define RETURN_IF_USER_DENIED_CONSENT() \
171 if (ds.IsUserConsentDenied()) { \
172 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
173 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
174 }
175
176// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
177// if consent is found to be denied.
178#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
179 RETURN_IF_USER_DENIED_CONSENT(); \
180 func_ptr(__VA_ARGS__); \
181 RETURN_IF_USER_DENIED_CONSENT();
182
Sahana Raof35ed432019-07-12 10:47:52 +0100183static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
184
Nandana Dutt979388e2018-11-30 16:48:55 +0000185namespace android {
186namespace os {
187namespace {
188
189static int Open(std::string path, int flags, mode_t mode = 0) {
190 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
191 if (fd == -1) {
192 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
193 }
194 return fd;
195}
196
Nandana Dutt979388e2018-11-30 16:48:55 +0000197
198static int OpenForRead(std::string path) {
199 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
200}
201
202bool CopyFile(int in_fd, int out_fd) {
203 char buf[4096];
204 ssize_t byte_count;
205 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
206 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
207 return false;
208 }
209 }
210 return (byte_count != -1);
211}
212
213static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000214 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000215
216 // Obtain a handle to the source file.
217 android::base::unique_fd in_fd(OpenForRead(input_file));
218 if (out_fd != -1 && in_fd.get() != -1) {
219 if (CopyFile(in_fd.get(), out_fd)) {
220 return true;
221 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000222 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000223 }
224 return false;
225}
226
Nandana Duttd2f5f082019-01-18 17:13:52 +0000227static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000228 if (unlink(file.c_str())) {
229 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000230 return false;
231 }
232 return true;
233}
Nandana Dutt979388e2018-11-30 16:48:55 +0000234
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000235
Nikita Ioffea325a572019-05-16 19:49:47 +0100236int64_t GetModuleMetadataVersion() {
237 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
238 if (binder == nullptr) {
239 MYLOGE("Failed to retrieve package_native service");
240 return 0L;
241 }
242 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
243 std::string package_name;
244 auto status = package_service->getModuleMetadataPackageName(&package_name);
245 if (!status.isOk()) {
246 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
247 return 0L;
248 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100249 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100250 int64_t version_code;
251 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
252 &version_code);
253 if (!status.isOk()) {
254 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
255 return 0L;
256 }
257 return version_code;
258}
259
Nandana Dutt979388e2018-11-30 16:48:55 +0000260} // namespace
261} // namespace os
262} // namespace android
263
Felipe Leme678727a2016-09-21 17:22:11 -0700264static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800265 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800266 long dumpsysTimeoutMs = 0) {
267 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700268}
269static int DumpFile(const std::string& title, const std::string& path) {
270 return ds.DumpFile(title, path);
271}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800272
Felipe Lemee844a9d2016-09-21 15:01:39 -0700273// Relative directory (inside the zip) for all files copied as-is into the bugreport.
274static const std::string ZIP_ROOT_DIR = "FS";
275
Vishnu Naire97d6122018-01-18 13:58:56 -0800276static const std::string kProtoPath = "proto/";
277static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700278static const std::string kDumpstateBoardFiles[] = {
279 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700280 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700281};
282static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
283
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700284static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700285static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700286
Felipe Lemef0292972016-11-22 13:57:05 -0800287static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
288
Narayan Kamath8f788292017-05-25 13:20:39 +0100289/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100290 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
291 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
292 * is set, the vector only contains files that were written in the last 30 minutes.
Narayan Kamath8f788292017-05-25 13:20:39 +0100293 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700294static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
295 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700296 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100297 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
298
Narayan Kamathbd863722017-06-01 18:50:12 +0100299 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100300
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700301 if (dump_dir == nullptr) {
302 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700303 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700304 }
305
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700306 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100307 struct dirent* entry = nullptr;
308 while ((entry = readdir(dump_dir.get()))) {
309 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100310 continue;
311 }
312
Narayan Kamathbd863722017-06-01 18:50:12 +0100313 const std::string base_name(entry->d_name);
314 if (base_name.find(file_prefix) != 0) {
315 continue;
316 }
317
318 const std::string abs_path = dir_path + base_name;
319 android::base::unique_fd fd(
320 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
321 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700322 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100323 break;
324 }
325
326 struct stat st = {};
327 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700328 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100329 continue;
330 }
331
Narayan Kamath3f31b632018-02-22 19:42:36 +0000332 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100333 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100334 continue;
335 }
336
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700337 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700338 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100339
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700340 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100341}
342
Narayan Kamathbd863722017-06-01 18:50:12 +0100343static bool AddDumps(const std::vector<DumpData>::const_iterator start,
344 const std::vector<DumpData>::const_iterator end,
345 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100346 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100347 for (auto it = start; it != end; ++it) {
348 const std::string& name = it->name;
349 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100350 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100351
352 // Seek to the beginning of the file before dumping any data. A given
353 // DumpData entry might be dumped multiple times in the report.
354 //
355 // For example, the most recent ANR entry is dumped to the body of the
356 // main entry and it also shows up as a separate entry in the bugreport
357 // ZIP file.
358 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
359 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
360 strerror(errno));
361 }
362
Narayan Kamath8f788292017-05-25 13:20:39 +0100363 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800364 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100365 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100366 }
367 } else {
368 dump_file_from_fd(type_name, name.c_str(), fd);
369 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100370 }
371
372 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700373}
374
Felipe Leme635ca312016-01-05 14:23:02 -0800375// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700376void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800377 char path[PATH_MAX];
378
379 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
380 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700381 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800382 char linkname[PATH_MAX];
383 ssize_t r = readlink(path, linkname, PATH_MAX);
384 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800385 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800386 return;
387 }
388 linkname[r] = '\0';
389
390 if (mount_points.find(linkname) == mount_points.end()) {
391 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700392 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700393 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800394 mount_points.insert(linkname);
395 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800396 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800397 }
398 }
399}
400
401void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700402 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700403 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800404 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800405 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700406 for_each_pid(do_mountinfo, nullptr);
407 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800408}
409
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700410static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
411{
412 DIR *d;
413 struct dirent *de;
414 char path[PATH_MAX];
415
416 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700417 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700418 return;
419 }
420
421 while ((de = readdir(d))) {
422 if (de->d_type != DT_LNK) {
423 continue;
424 }
425 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700426 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700427 }
428
429 closedir(d);
430}
431
Mark Salyzyn326842f2015-04-30 09:49:41 -0700432static bool skip_not_stat(const char *path) {
433 static const char stat[] = "/stat";
434 size_t len = strlen(path);
435 if (path[len - 1] == '/') { /* Directory? */
436 return false;
437 }
438 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
439}
440
Felipe Leme4c2d6632016-09-28 14:32:00 -0700441static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800442 return false;
443}
444
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700445unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700446
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800447//
448// stat offsets
449// Name units description
450// ---- ----- -----------
451// read I/Os requests number of read I/Os processed
452#define __STAT_READ_IOS 0
453// read merges requests number of read I/Os merged with in-queue I/O
454#define __STAT_READ_MERGES 1
455// read sectors sectors number of sectors read
456#define __STAT_READ_SECTORS 2
457// read ticks milliseconds total wait time for read requests
458#define __STAT_READ_TICKS 3
459// write I/Os requests number of write I/Os processed
460#define __STAT_WRITE_IOS 4
461// write merges requests number of write I/Os merged with in-queue I/O
462#define __STAT_WRITE_MERGES 5
463// write sectors sectors number of sectors written
464#define __STAT_WRITE_SECTORS 6
465// write ticks milliseconds total wait time for write requests
466#define __STAT_WRITE_TICKS 7
467// in_flight requests number of I/Os currently in flight
468#define __STAT_IN_FLIGHT 8
469// io_ticks milliseconds total time this block device has been active
470#define __STAT_IO_TICKS 9
471// time_in_queue milliseconds total wait time for all requests
472#define __STAT_IN_QUEUE 10
473#define __STAT_NUMBER_FIELD 11
474//
475// read I/Os, write I/Os
476// =====================
477//
478// These values increment when an I/O request completes.
479//
480// read merges, write merges
481// =========================
482//
483// These values increment when an I/O request is merged with an
484// already-queued I/O request.
485//
486// read sectors, write sectors
487// ===========================
488//
489// These values count the number of sectors read from or written to this
490// block device. The "sectors" in question are the standard UNIX 512-byte
491// sectors, not any device- or filesystem-specific block size. The
492// counters are incremented when the I/O completes.
493#define SECTOR_SIZE 512
494//
495// read ticks, write ticks
496// =======================
497//
498// These values count the number of milliseconds that I/O requests have
499// waited on this block device. If there are multiple I/O requests waiting,
500// these values will increase at a rate greater than 1000/second; for
501// example, if 60 read requests wait for an average of 30 ms, the read_ticks
502// field will increase by 60*30 = 1800.
503//
504// in_flight
505// =========
506//
507// This value counts the number of I/O requests that have been issued to
508// the device driver but have not yet completed. It does not include I/O
509// requests that are in the queue but not yet issued to the device driver.
510//
511// io_ticks
512// ========
513//
514// This value counts the number of milliseconds during which the device has
515// had I/O requests queued.
516//
517// time_in_queue
518// =============
519//
520// This value counts the number of milliseconds that I/O requests have waited
521// on this block device. If there are multiple I/O requests waiting, this
522// value will increase as the product of the number of milliseconds times the
523// number of requests waiting (see "read ticks" above for an example).
524#define S_TO_MS 1000
525//
526
Mark Salyzyn326842f2015-04-30 09:49:41 -0700527static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800528 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700529 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700530 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700531 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700532 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700533 getline(&buffer, &i, fp);
534 fclose(fp);
535 if (!buffer) {
536 return -errno;
537 }
538 i = strlen(buffer);
539 while ((i > 0) && (buffer[i - 1] == '\n')) {
540 buffer[--i] = '\0';
541 }
542 if (!*buffer) {
543 free(buffer);
544 return 0;
545 }
546 z = true;
547 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800548 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700549 if (fields[i] != 0) {
550 z = false;
551 }
552 }
553 if (z) { /* never accessed */
554 free(buffer);
555 return 0;
556 }
557
Wei Wang509bb5d2017-06-09 14:42:12 -0700558 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
559 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700560 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700561
562 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
563 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
564 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700565 free(buffer);
566
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800567 if (fields[__STAT_IO_TICKS]) {
568 unsigned long read_perf = 0;
569 unsigned long read_ios = 0;
570 if (fields[__STAT_READ_TICKS]) {
571 unsigned long long divisor = fields[__STAT_READ_TICKS]
572 * fields[__STAT_IO_TICKS];
573 read_perf = ((unsigned long long)SECTOR_SIZE
574 * fields[__STAT_READ_SECTORS]
575 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
576 / divisor;
577 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
578 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
579 / divisor;
580 }
581
582 unsigned long write_perf = 0;
583 unsigned long write_ios = 0;
584 if (fields[__STAT_WRITE_TICKS]) {
585 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
586 * fields[__STAT_IO_TICKS];
587 write_perf = ((unsigned long long)SECTOR_SIZE
588 * fields[__STAT_WRITE_SECTORS]
589 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
590 / divisor;
591 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
592 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
593 / divisor;
594 }
595
596 unsigned queue = (fields[__STAT_IN_QUEUE]
597 + (fields[__STAT_IO_TICKS] >> 1))
598 / fields[__STAT_IO_TICKS];
599
600 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700601 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 -0800602 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700603 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 -0800604 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800605 }
606
607 /* bugreport timeout factor adjustment */
608 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
609 worst_write_perf = write_perf;
610 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700611 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700612 return 0;
613}
614
Yao Chenbe3bbc12018-01-17 16:31:10 -0800615static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
616
617/* timeout in ms to read a list of buffers */
618static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
619 unsigned long timeout_ms = 0;
620 for (const auto& buffer : buffers) {
621 log_id_t id = android_name_to_log_id(buffer.c_str());
622 unsigned long property_size = __android_logger_get_buffer_size(id);
623 /* Engineering margin is ten-fold our guess */
624 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
625 }
626 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700627}
628
Nandana Duttd2f5f082019-01-18 17:13:52 +0000629Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
630}
631
632android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
633 std::lock_guard<std::mutex> lock(lock_);
634 result_ = APPROVED;
635 MYLOGD("User approved consent to share bugreport\n");
636 return android::binder::Status::ok();
637}
638
639android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
640 std::lock_guard<std::mutex> lock(lock_);
641 result_ = DENIED;
642 MYLOGW("User denied consent to share bugreport\n");
643 return android::binder::Status::ok();
644}
645
646UserConsentResult Dumpstate::ConsentCallback::getResult() {
647 std::lock_guard<std::mutex> lock(lock_);
648 return result_;
649}
650
651uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
652 return Nanotime() - start_time_;
653}
654
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700655void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700656 std::string build, fingerprint, radio, bootloader, network;
657 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700658
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700659 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
660 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700661 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
662 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
663 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700664 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700665
Felipe Lemed8b94e52016-12-08 10:21:44 -0800666 printf("========================================================\n");
667 printf("== dumpstate: %s\n", date);
668 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700669
Felipe Lemed8b94e52016-12-08 10:21:44 -0800670 printf("\n");
671 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700672 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800673 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
674 printf("Bootloader: %s\n", bootloader.c_str());
675 printf("Radio: %s\n", radio.c_str());
676 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100677 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
678 if (module_metadata_version != 0) {
679 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
680 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700681
Felipe Lemed8b94e52016-12-08 10:21:44 -0800682 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800683 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800684 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800685 printf("Uptime: ");
686 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
687 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800688 printf("Bugreport format version: %s\n", version_.c_str());
Abhijeet Kaure370d682019-10-01 16:49:30 +0100689 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
690 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800691 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800692}
693
Felipe Leme24b66ee2016-06-16 10:55:26 -0700694// List of file extensions that can cause a zip file attachment to be rejected by some email
695// service providers.
696static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
697 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
698 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
699 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
700};
701
Vishnu Naire97d6122018-01-18 13:58:56 -0800702status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
703 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700704 if (!IsZipping()) {
705 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
706 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800707 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800708 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700709 std::string valid_name = entry_name;
710
711 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700712 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700713 if (idx != std::string::npos) {
714 std::string extension = entry_name.substr(idx);
715 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
716 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
717 valid_name = entry_name + ".renamed";
718 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
719 }
720 }
721
Felipe Leme6fe9db62016-02-12 09:04:16 -0800722 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
723 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700724 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
725 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700726 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700727 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700728 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800729 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800730 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000731 bool finished_entry = false;
732 auto finish_entry = [this, &finished_entry] {
733 if (!finished_entry) {
734 // This should only be called when we're going to return an earlier error,
735 // which would've been logged. This may imply the file is already corrupt
736 // and any further logging from FinishEntry is more likely to mislead than
737 // not.
738 this->zip_writer_->FinishEntry();
739 }
740 };
741 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800742 auto start = std::chrono::steady_clock::now();
743 auto end = start + timeout;
744 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800745
Felipe Leme770410d2016-01-26 17:07:14 -0800746 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800747 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800748 if (timeout.count() > 0) {
749 // lambda to recalculate the timeout.
750 auto time_left_ms = [end]() {
751 auto now = std::chrono::steady_clock::now();
752 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
753 return std::max(diff.count(), 0LL);
754 };
755
756 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
757 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000758 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
759 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800760 return -errno;
761 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000762 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800763 entry_name.c_str(), strerror(errno), timeout.count());
764 return TIMED_OUT;
765 }
766 }
767
Zach Riggle22200402016-08-18 01:01:24 -0400768 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800769 if (bytes_read == 0) {
770 break;
771 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800772 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800773 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800774 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700775 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800776 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700777 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800778 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800779 }
780 }
781
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700782 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000783 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700784 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700785 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800786 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800787 }
788
Vishnu Naire97d6122018-01-18 13:58:56 -0800789 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800790}
791
Felipe Leme1d486fe2016-10-14 18:06:47 -0700792bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
793 android::base::unique_fd fd(
794 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700795 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800796 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800797 return false;
798 }
799
Vishnu Naire97d6122018-01-18 13:58:56 -0800800 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800801}
802
803/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700804static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800805 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800806}
807
Felipe Leme1d486fe2016-10-14 18:06:47 -0700808void Dumpstate::AddDir(const std::string& dir, bool recursive) {
809 if (!IsZipping()) {
810 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800811 return;
812 }
Felipe Leme678727a2016-09-21 17:22:11 -0700813 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800814 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700815 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800816}
817
Felipe Leme1d486fe2016-10-14 18:06:47 -0700818bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
819 if (!IsZipping()) {
820 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
821 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800822 return false;
823 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800824 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700825 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700826 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700827 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700828 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800829 return false;
830 }
831
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700832 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700833 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700834 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700835 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800836 return false;
837 }
838
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700839 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700840 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700841 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800842 return false;
843 }
844
845 return true;
846}
847
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800848static void DoKmsg() {
849 struct stat st;
850 if (!stat(PSTORE_LAST_KMSG, &st)) {
851 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
852 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
853 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
854 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
855 } else {
856 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
857 DumpFile("LAST KMSG", "/proc/last_kmsg");
858 }
859}
860
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800861static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800862 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800863 RunCommand(
864 "KERNEL LOG",
865 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
866 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
867}
868
Nandana Duttdb379fa2019-10-09 16:54:41 +0100869static void DoSystemLogcat(time_t since) {
870 char since_str[80];
871 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
872
873 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
874 RunCommand("SYSTEM LOG",
875 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
876 since_str},
877 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
878}
879
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800880static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800881 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800882 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
883 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800884 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100885 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800886 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
887 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800888 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800889 RunCommand(
890 "EVENT LOG",
891 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100892 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800893 timeout_ms = logcat_timeout({"stats"});
894 RunCommand(
895 "STATS LOG",
896 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100897 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800898 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800899 RunCommand(
900 "RADIO LOG",
901 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100902 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800903
904 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
905
906 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800907 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
908 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800909}
910
Mike Ma5c267872019-08-21 11:31:34 -0700911static void DumpIncidentReport() {
912 if (!ds.IsZipping()) {
913 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
914 return;
915 }
916 DurationReporter duration_reporter("INCIDENT REPORT");
917 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
918 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
919 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
920 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
921 if (fd < 0) {
922 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
923 return;
924 }
925 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
926 bool empty = 0 == lseek(fd, 0, SEEK_END);
927 if (!empty) {
928 // Use a different name from "incident.proto"
929 // /proto/incident.proto is reserved for incident service dump
930 // i.e. metadata for debugging.
931 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
932 }
933 unlink(path.c_str());
934}
935
Jayachandran Ca94c7172017-06-10 15:08:12 -0700936static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700937 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
938 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900939 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700940 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900941 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
942 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
943 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
944 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700945}
946
David Andersond9ba4752018-12-11 18:26:59 -0800947static void DumpDynamicPartitionInfo() {
948 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
949 return;
950 }
951
952 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700953 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800954}
955
Narayan Kamath8f788292017-05-25 13:20:39 +0100956static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
957 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
958 anr_traces_dir.c_str());
959
960 // If we're here, dump_traces_path will always be a temporary file
961 // (created with mkostemp or similar) that contains dumps taken earlier
962 // on in the process.
963 if (dump_traces_path != nullptr) {
964 if (add_to_zip) {
965 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
966 } else {
967 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
968 dump_traces_path);
969 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
970 }
971
972 const int ret = unlink(dump_traces_path);
973 if (ret == -1) {
974 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
975 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700976 }
977 }
978
Narayan Kamathbd863722017-06-01 18:50:12 +0100979 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700980 if (ds.anr_data_.size() > 0) {
981 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100982 "VM TRACES AT LAST ANR", add_to_zip);
983
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100984 // The "last" ANR will always be included as separate entry in the zip file. In addition,
985 // it will be present in the body of the main entry if |add_to_zip| == false.
986 //
987 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700988 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100989 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100990 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100991 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
992 }
993}
994
995static void AddAnrTraceFiles() {
996 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
997
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700998 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100999
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001000 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001001
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001002 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1003
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001004 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001005 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001006 int i = 0;
1007 while (true) {
1008 const std::string slow_trace_path =
1009 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1010 if (stat(slow_trace_path.c_str(), &st)) {
1011 // No traces file at this index, done with the files.
1012 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001013 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001014 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1015 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001016 }
1017}
1018
Wei Wang509bb5d2017-06-09 14:42:12 -07001019static void DumpBlockStatFiles() {
1020 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001021
Wei Wang1dc1ef52017-06-12 11:28:37 -07001022 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1023
1024 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001025 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1026 return;
1027 }
1028
1029 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001030 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001031 if ((d->d_name[0] == '.')
1032 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1033 || (d->d_name[1] == '\0'))) {
1034 continue;
1035 }
1036 const std::string new_path =
1037 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1038 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1039 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1040 printf("\n");
1041 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001042 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001043}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001044
1045static void DumpPacketStats() {
1046 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1047 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1048 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1049 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1050 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1051}
1052
1053static void DumpIpAddrAndRules() {
1054 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1055 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1056 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1057 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1058 RunCommand("IP RULES", {"ip", "rule", "show"});
1059 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1060}
1061
Nandana Dutt5c390032019-03-12 10:52:56 +00001062static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1063 std::chrono::milliseconds timeout,
1064 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001065 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001066 sp<android::IServiceManager> sm = defaultServiceManager();
1067 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001068 Vector<String16> args;
1069 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001070 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1071 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001072 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001073 std::string path(title);
1074 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001075 size_t bytes_written = 0;
Steven Moreland5a30d342019-10-08 13:53:28 -07001076 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001077 if (status == OK) {
1078 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1079 std::chrono::duration<double> elapsed_seconds;
1080 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1081 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001082 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1083 bool dump_complete = (status == OK);
1084 dumpsys.stopDumpThread(dump_complete);
1085 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001086
1087 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1088 std::chrono::steady_clock::now() - start);
1089 if (elapsed_duration > timeout) {
1090 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1091 elapsed_duration.count());
1092 break;
1093 }
1094 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001095 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001096}
1097
Vishnu Nair64afc022018-02-01 15:29:34 -08001098static void RunDumpsysText(const std::string& title, int priority,
1099 std::chrono::milliseconds timeout,
1100 std::chrono::milliseconds service_timeout) {
1101 DurationReporter duration_reporter(title);
1102 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1103 fsync(STDOUT_FILENO);
1104 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1105}
1106
1107/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001108static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1109 std::chrono::milliseconds timeout,
1110 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001111 DurationReporter duration_reporter(title);
1112 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1113 fsync(STDOUT_FILENO);
1114 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1115 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001116
1117 RETURN_IF_USER_DENIED_CONSENT();
1118
1119 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1120 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001121}
1122
Nandana Dutt5c390032019-03-12 10:52:56 +00001123static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1124 std::chrono::milliseconds timeout,
1125 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001126 if (!ds.IsZipping()) {
1127 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001128 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001129 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001130 sp<android::IServiceManager> sm = defaultServiceManager();
1131 Dumpsys dumpsys(sm.get());
1132 Vector<String16> args;
1133 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1134 DurationReporter duration_reporter(title);
1135
1136 auto start = std::chrono::steady_clock::now();
1137 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1138 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001139 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001140 std::string path(kProtoPath);
1141 path.append(String8(service).c_str());
1142 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1143 path.append("_CRITICAL");
1144 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1145 path.append("_HIGH");
1146 }
1147 path.append(kProtoExt);
Steven Moreland5a30d342019-10-08 13:53:28 -07001148 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001149 if (status == OK) {
1150 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1151 bool dumpTerminated = (status == OK);
1152 dumpsys.stopDumpThread(dumpTerminated);
1153 }
1154 ZipWriter::FileEntry file_entry;
1155 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001156
1157 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1158 std::chrono::steady_clock::now() - start);
1159 if (elapsed_duration > timeout) {
1160 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1161 elapsed_duration.count());
1162 break;
1163 }
1164 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001165 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001166}
1167
Nandana Dutta7db6342018-11-21 14:53:34 +00001168// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001169static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001170 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1171 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001172
1173 RETURN_IF_USER_DENIED_CONSENT();
1174
1175 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1176 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001177}
1178
1179// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001180static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001181 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1182 // high priority. Reduce timeout once they are able to dump in a shorter time or
1183 // moved to a parallel task.
1184 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1185 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001186
1187 RETURN_IF_USER_DENIED_CONSENT();
1188
1189 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1190 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001191}
1192
1193// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001194static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001195 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001196
1197 RETURN_IF_USER_DENIED_CONSENT();
1198
1199 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1200 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001201}
1202
Steven Moreland44cd9482018-01-04 16:24:13 -08001203static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001204 if (!ds.IsZipping()) {
1205 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1206 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1207 return;
1208 }
1209 DurationReporter duration_reporter("DUMP HALS");
1210 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001211 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001212
Steven Moreland44cd9482018-01-04 16:24:13 -08001213 using android::hidl::manager::V1_0::IServiceManager;
1214 using android::hardware::defaultServiceManager;
1215
1216 sp<IServiceManager> sm = defaultServiceManager();
1217 if (sm == nullptr) {
1218 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1219 return;
1220 }
1221
1222 auto ret = sm->list([&](const auto& interfaces) {
1223 for (const std::string& interface : interfaces) {
1224 std::string cleanName = interface;
1225 std::replace_if(cleanName.begin(),
1226 cleanName.end(),
1227 [](char c) {
1228 return !isalnum(c) &&
1229 std::string("@-_:.").find(c) == std::string::npos;
1230 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001231 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001232
1233 {
1234 auto fd = android::base::unique_fd(
1235 TEMP_FAILURE_RETRY(open(path.c_str(),
1236 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1237 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1238 if (fd < 0) {
1239 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1240 continue;
1241 }
1242 RunCommandToFd(fd,
1243 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001244 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001245 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1246
1247 bool empty = 0 == lseek(fd, 0, SEEK_END);
1248 if (!empty) {
1249 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1250 }
1251 }
1252
1253 unlink(path.c_str());
1254 }
1255 });
1256
1257 if (!ret.isOk()) {
1258 MYLOGE("Could not list hals from hwservicemanager.\n");
1259 }
1260}
1261
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001262static void DumpExternalFragmentationInfo() {
1263 struct stat st;
1264 if (stat("/proc/buddyinfo", &st) != 0) {
1265 MYLOGE("Unable to dump external fragmentation info\n");
1266 return;
1267 }
1268
1269 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1270 std::ifstream ifs("/proc/buddyinfo");
1271 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1272 for (std::string line; std::getline(ifs, line);) {
1273 std::smatch match_results;
1274 if (std::regex_match(line, match_results, unusable_index_regex)) {
1275 std::stringstream free_pages(std::string{match_results[3]});
1276 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1277 std::istream_iterator<int>());
1278
1279 int total_free_pages = 0;
1280 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1281 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1282 }
1283
1284 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1285 match_results[2].str().c_str());
1286
1287 int usable_free_pages = total_free_pages;
1288 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1289 auto unusable_index = (total_free_pages - usable_free_pages) /
1290 static_cast<double>(total_free_pages);
1291 printf(" %5.3f", unusable_index);
1292 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1293 }
1294
1295 printf("\n");
1296 }
1297 }
1298 printf("\n");
1299}
1300
Nandana Dutt5c390032019-03-12 10:52:56 +00001301// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1302// via the consent they are shown. Ignores other errors that occur while running various
1303// commands. The consent checking is currently done around long running tasks, which happen to
1304// be distributed fairly evenly throughout the function.
1305static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001306 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001307
Nandana Dutt5c390032019-03-12 10:52:56 +00001308 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1309 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1310 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001311 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001312 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001313 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001314 DumpFile("MEMORY INFO", "/proc/meminfo");
1315 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001316 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001317
1318 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1319
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001320 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1321 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1322 DumpFile("SLAB INFO", "/proc/slabinfo");
1323 DumpFile("ZONEINFO", "/proc/zoneinfo");
1324 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1325 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001326 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001327
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001328 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1329 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001330
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001331 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001332 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001333
1334 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1335 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001336
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001337 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001338
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001339 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001340 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001341 struct stat s;
1342 if (stat("/proc/modules", &s) != 0) {
1343 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1344 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001345 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001346 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001347
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001348 if (__android_logger_property_get_bool(
1349 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1350 DoKernelLogcat();
1351 } else {
1352 do_dmesg();
1353 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001354
Felipe Lemef0292972016-11-22 13:57:05 -08001355 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001356
1357 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1358
Jeff Brown1dc94e32014-09-11 14:15:27 -07001359 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001360 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001361
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001362 /* Dump Bluetooth HCI logs */
1363 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001364
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001365 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001366 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001367 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001368 }
1369
Felipe Lemee184f662016-10-27 10:04:47 -07001370 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371
Narayan Kamath8f788292017-05-25 13:20:39 +01001372 // NOTE: tombstones are always added as separate entries in the zip archive
1373 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001374 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001375 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001376 if (!tombstones_dumped) {
1377 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001378 }
1379
Jayachandran Ca94c7172017-06-10 15:08:12 -07001380 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001381
Chenbo Feng276a3b62018-08-07 11:44:49 -07001382 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1383
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001384 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001385
Jayachandran Ca94c7172017-06-10 15:08:12 -07001386 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001387
1388 dump_route_tables();
1389
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001390 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1391 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1392 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393
Nandana Dutt5c390032019-03-12 10:52:56 +00001394 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001395
Elliott Hughes23ccc622017-02-28 10:14:22 -08001396 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001397
Jin Qianf334d662017-10-10 14:41:37 -07001398 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001399
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001400 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001401
Colin Crossf45fa6b2012-03-26 12:38:26 -07001402 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001403 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1404 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1405 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1406 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1407 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001408
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001409 /* Add window and surface trace files. */
1410 if (!PropertiesHelper::IsUserBuild()) {
1411 ds.AddDir(WMTRACE_DATA_DIR, false);
1412 }
1413
Nandana Dutt5c390032019-03-12 10:52:56 +00001414 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001415
Steven Moreland7440ddb2016-12-15 16:13:39 -08001416 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001417 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1418 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001419 // su does not exist on user builds, so try running without it.
1420 // This way any implementations of vril-dump that do not require
1421 // root can run on user builds.
1422 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001423 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001424 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001425 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001426 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001427 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001428 }
1429
Felipe Lemed8b94e52016-12-08 10:21:44 -08001430 printf("========================================================\n");
1431 printf("== Android Framework Services\n");
1432 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001433
Nandana Dutt5c390032019-03-12 10:52:56 +00001434 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001435
Felipe Lemed8b94e52016-12-08 10:21:44 -08001436 printf("========================================================\n");
1437 printf("== Checkins\n");
1438 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001439
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001440 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001441
1442 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1443
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001444 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1445 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1446 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1447 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001448
Felipe Lemed8b94e52016-12-08 10:21:44 -08001449 printf("========================================================\n");
1450 printf("== Running Application Activities\n");
1451 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001452
Makoto Onuki60780982018-04-16 15:34:00 -07001453 // The following dumpsys internally collects output from running apps, so it can take a long
1454 // time. So let's extend the timeout.
1455
1456 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1457
1458 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001459
Felipe Lemed8b94e52016-12-08 10:21:44 -08001460 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001461 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001462 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001463
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001464 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001465 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001466
Felipe Lemed8b94e52016-12-08 10:21:44 -08001467 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001468 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001469 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001470
Makoto Onuki60780982018-04-16 15:34:00 -07001471 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1472 DUMPSYS_COMPONENTS_OPTIONS);
1473
1474 printf("========================================================\n");
1475 printf("== Running Application Providers (platform)\n");
1476 printf("========================================================\n");
1477
1478 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1479 DUMPSYS_COMPONENTS_OPTIONS);
1480
1481 printf("========================================================\n");
1482 printf("== Running Application Providers (non-platform)\n");
1483 printf("========================================================\n");
1484
1485 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1486 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001487
Adrian Roos8b397ab2017-04-04 16:35:44 -07001488 printf("========================================================\n");
1489 printf("== Dropbox crashes\n");
1490 printf("========================================================\n");
1491
1492 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1493 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1494
Felipe Lemed8b94e52016-12-08 10:21:44 -08001495 printf("========================================================\n");
1496 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1497 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1498 printf("========================================================\n");
1499 printf("== dumpstate: done (id %d)\n", ds.id_);
1500 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001501
1502 printf("========================================================\n");
1503 printf("== Obtaining statsd metadata\n");
1504 printf("========================================================\n");
1505 // This differs from the usual dumpsys stats, which is the stats report data.
1506 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001507
1508 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1509
Nandana Dutt5c390032019-03-12 10:52:56 +00001510 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001511}
1512
Nandana Dutt5c390032019-03-12 10:52:56 +00001513/*
1514 * Dumps state for the default case; drops root after it's no longer necessary.
1515 *
1516 * Returns RunStatus::OK if everything went fine.
1517 * Returns RunStatus::ERROR if there was an error.
1518 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1519 * with the caller.
1520 */
1521static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001522 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001523 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001524 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001525
Nandana Duttdb379fa2019-10-09 16:54:41 +01001526 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1527 // buffer.
1528 DoLogcat();
1529 // Capture timestamp after first logcat to use in next logcat
1530 time_t logcat_ts = time(nullptr);
1531
Nandana Dutt4be45d12018-09-26 15:04:23 +01001532 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001533 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001534
1535 /* Run some operations that require root. */
1536 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1537 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1538
1539 ds.AddDir(RECOVERY_DIR, true);
1540 ds.AddDir(RECOVERY_DATA_DIR, true);
1541 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1542 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1543 if (!PropertiesHelper::IsUserBuild()) {
1544 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1545 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1546 }
1547 add_mountinfo();
1548 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001549 DumpDynamicPartitionInfo();
Yifan Hong3945e1b2019-10-29 12:59:23 -07001550 ds.AddDir(OTA_METADATA_DIR, true);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001551
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001552 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001553 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1554
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001555 // Dump IPsec stats. No keys are exposed here.
1556 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1557
Nandana Dutt4be45d12018-09-26 15:04:23 +01001558 // Run ss as root so we can see socket marks.
1559 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1560
1561 // Run iotop as root to show top 100 IO threads
1562 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1563
Erick Reyese68df822019-02-11 14:46:36 -08001564 // Gather shared memory buffer info if the product implements it
1565 struct stat st;
1566 if (!stat("/product/bin/dmabuf_dump", &st)) {
1567 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1568 }
1569
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001570 DumpFile("PSI cpu", "/proc/pressure/cpu");
1571 DumpFile("PSI memory", "/proc/pressure/memory");
1572 DumpFile("PSI io", "/proc/pressure/io");
1573
Nandana Dutt4be45d12018-09-26 15:04:23 +01001574 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001575 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001576 }
1577
Nandana Dutt5c390032019-03-12 10:52:56 +00001578 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001579 Dumpstate::RunStatus status = dumpstate();
1580 // Capture logcat since the last time we did it.
1581 DoSystemLogcat(logcat_ts);
1582 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001583}
1584
mukesh agrawal253dad42018-01-23 21:59:59 -08001585// This method collects common dumpsys for telephony and wifi
1586static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001587 DumpIpTablesAsRoot();
1588
Jayachandran Cb4389d92019-07-08 09:46:05 -07001589 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1590
Jayachandran Ca94c7172017-06-10 15:08:12 -07001591 if (!DropRootUser()) {
1592 return;
1593 }
1594
1595 do_dmesg();
1596 DoLogcat();
1597 DumpPacketStats();
1598 DoKmsg();
1599 DumpIpAddrAndRules();
1600 dump_route_tables();
Jayachandran Cb4389d92019-07-08 09:46:05 -07001601 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001602
1603 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1604 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001605}
1606
1607// This method collects dumpsys for telephony debugging only
1608static void DumpstateTelephonyOnly() {
1609 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001610 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001611
1612 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001613
1614 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1615
1616 printf("========================================================\n");
1617 printf("== Android Framework Services\n");
1618 printf("========================================================\n");
1619
Vishnu Nair652cc802017-11-30 15:18:30 -08001620 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1621 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001622 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1623 SEC_TO_MSEC(10));
1624 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001625 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1626 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001627 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1628 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001629 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1630 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001631
1632 printf("========================================================\n");
1633 printf("== Running Application Services\n");
1634 printf("========================================================\n");
1635
1636 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1637
1638 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001639 printf("== Running Application Services (non-platform)\n");
1640 printf("========================================================\n");
1641
1642 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1643 DUMPSYS_COMPONENTS_OPTIONS);
1644
1645 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001646 printf("== Checkins\n");
1647 printf("========================================================\n");
1648
1649 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1650
1651 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001652 printf("== dumpstate: done (id %d)\n", ds.id_);
1653 printf("========================================================\n");
1654}
1655
mukesh agrawal253dad42018-01-23 21:59:59 -08001656// This method collects dumpsys for wifi debugging only
1657static void DumpstateWifiOnly() {
1658 DurationReporter duration_reporter("DUMPSTATE");
1659
1660 DumpstateRadioCommon();
1661
1662 printf("========================================================\n");
1663 printf("== Android Framework Services\n");
1664 printf("========================================================\n");
1665
1666 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1667 SEC_TO_MSEC(10));
1668 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1669 SEC_TO_MSEC(10));
1670
1671 printf("========================================================\n");
1672 printf("== dumpstate: done (id %d)\n", ds.id_);
1673 printf("========================================================\n");
1674}
1675
Nandana Duttcf419a72019-03-14 10:40:17 +00001676Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001677 DurationReporter duration_reporter("DUMP TRACES");
1678
1679 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1680 const size_t buf_size = temp_file_pattern.length() + 1;
1681 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1682 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1683
1684 // Create a new, empty file to receive all trace dumps.
1685 //
1686 // TODO: This can be simplified once we remove support for the old style
1687 // dumps. We can have a file descriptor passed in to dump_traces instead
1688 // of creating a file, closing it and then reopening it again.
1689 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1690 if (fd < 0) {
1691 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001692 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001693 }
1694
1695 // Nobody should have access to this temporary file except dumpstate, but we
1696 // temporarily grant 'read' to 'others' here because this file is created
1697 // when tombstoned is still running as root, but dumped after dropping. This
1698 // can go away once support for old style dumping has.
1699 const int chmod_ret = fchmod(fd, 0666);
1700 if (chmod_ret < 0) {
1701 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001702 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001703 }
1704
1705 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1706 if (proc.get() == nullptr) {
1707 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001708 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001709 }
1710
1711 // Number of times process dumping has timed out. If we encounter too many
1712 // failures, we'll give up.
1713 int timeout_failures = 0;
1714 bool dalvik_found = false;
1715
1716 const std::set<int> hal_pids = get_interesting_hal_pids();
1717
1718 struct dirent* d;
1719 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001720 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001721 int pid = atoi(d->d_name);
1722 if (pid <= 0) {
1723 continue;
1724 }
1725
1726 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1727 std::string exe;
1728 if (!android::base::Readlink(link_name, &exe)) {
1729 continue;
1730 }
1731
1732 bool is_java_process;
1733 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1734 // Don't bother dumping backtraces for the zygote.
1735 if (IsZygote(pid)) {
1736 continue;
1737 }
1738
1739 dalvik_found = true;
1740 is_java_process = true;
1741 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1742 is_java_process = false;
1743 } else {
1744 // Probably a native process we don't care about, continue.
1745 continue;
1746 }
1747
1748 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1749 if (timeout_failures == 3) {
1750 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1751 break;
1752 }
1753
1754 const uint64_t start = Nanotime();
1755 const int ret = dump_backtrace_to_file_timeout(
1756 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1757 is_java_process ? 5 : 20, fd);
1758
1759 if (ret == -1) {
1760 // For consistency, the header and footer to this message match those
1761 // dumped by debuggerd in the success case.
1762 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1763 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1764 dprintf(fd, "---- end %d ----", pid);
1765 timeout_failures++;
1766 continue;
1767 }
1768
1769 // We've successfully dumped stack traces, reset the failure count
1770 // and write a summary of the elapsed time to the file and continue with the
1771 // next process.
1772 timeout_failures = 0;
1773
1774 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1775 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1776 }
1777
1778 if (!dalvik_found) {
1779 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1780 }
1781
Nandana Duttcf419a72019-03-14 10:40:17 +00001782 *path = file_name_buf.release();
1783 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001784}
1785
Felipe Leme6f674ae2016-11-18 17:10:33 -08001786void Dumpstate::DumpstateBoard() {
1787 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001788 printf("========================================================\n");
1789 printf("== Board\n");
1790 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001791
Felipe Leme6f674ae2016-11-18 17:10:33 -08001792 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001793 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001794 return;
1795 }
1796
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001797 std::vector<std::string> paths;
1798 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001799 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001800 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1801 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001802 remover.emplace_back(android::base::make_scope_guard(
1803 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001804 }
Jie Song9fbfad02017-06-20 16:29:42 -07001805
Wei Wang587eac92018-04-05 12:17:20 -07001806 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1807 if (dumpstate_device == nullptr) {
1808 MYLOGE("No IDumpstateDevice implementation\n");
1809 return;
1810 }
1811
1812 using ScopedNativeHandle =
1813 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1814 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1815 [](native_handle_t* handle) {
1816 native_handle_close(handle);
1817 native_handle_delete(handle);
1818 });
1819 if (handle == nullptr) {
1820 MYLOGE("Could not create native_handle\n");
1821 return;
1822 }
1823
Nandana Dutt5c390032019-03-12 10:52:56 +00001824 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001825 for (size_t i = 0; i < paths.size(); i++) {
1826 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1827
1828 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1829 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1830 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1831 if (fd < 0) {
1832 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1833 return;
1834 }
1835 handle.get()->data[i] = fd.release();
1836 }
1837
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001838 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001839 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1840 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1841 // and grab whatever dumped
1842 std::packaged_task<bool()>
1843 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001844 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1845 if (!status.isOk()) {
1846 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001847 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001848 }
Wei Wang587eac92018-04-05 12:17:20 -07001849 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001850 });
Wei Wang587eac92018-04-05 12:17:20 -07001851
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001852 auto result = dumpstate_task.get_future();
1853 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001854
1855 constexpr size_t timeout_sec = 30;
1856 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1857 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1858 if (!android::base::SetProperty("ctl.interface_restart",
1859 android::base::StringPrintf("%s/default",
1860 IDumpstateDevice::descriptor))) {
1861 MYLOGE("Couldn't restart dumpstate HAL\n");
1862 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001863 }
Wei Wang587eac92018-04-05 12:17:20 -07001864 // Wait some time for init to kill dumpstate vendor HAL
1865 constexpr size_t killing_timeout_sec = 10;
1866 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1867 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1868 "there might be racing in content\n", killing_timeout_sec);
1869 }
1870
1871 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1872 for (size_t i = 0; i < paths.size(); i++) {
1873 struct stat s;
1874 if (fstat(handle.get()->data[i], &s) == -1) {
1875 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1876 strerror(errno));
1877 file_sizes[i] = -1;
1878 continue;
1879 }
1880 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001881 }
1882
1883 for (size_t i = 0; i < paths.size(); i++) {
1884 if (file_sizes[i] == -1) {
1885 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001886 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001887 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001888 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001889 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001890 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001891 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001892 }
1893
Felipe Lemed8b94e52016-12-08 10:21:44 -08001894 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001895}
1896
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001897static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001898 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001899 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Abhijeet Kaure370d682019-10-01 16:49:30 +01001900 "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001901 " -h: display this help message\n"
1902 " -b: play sound file instead of vibrate, at beginning of job\n"
1903 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001904 " -d: append date to filename\n"
1905 " -p: capture screenshot to filename.png\n"
1906 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001907 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001908 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001909 " -q: disable vibrate\n"
Abhijeet Kaure370d682019-10-01 16:49:30 +01001910 " -P: send broadcast when started and do progress updates\n"
1911 " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001912 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001913 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001914}
1915
Wei Liuf87959e2016-08-26 14:51:42 -07001916static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001917 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001918}
1919
Felipe Leme1d486fe2016-10-14 18:06:47 -07001920bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001921 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001922 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001923 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001924 // Final timestamp
1925 char date[80];
1926 time_t the_real_now_please_stand_up = time(nullptr);
1927 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001928 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001929 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001930
Felipe Leme9a523ae2016-10-20 15:10:33 -07001931 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001932 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001933 return false;
1934 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001935 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001936 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001937 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001938 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001939
Felipe Leme0f3fb202016-06-10 17:10:53 -07001940 // Add log file (which contains stderr output) to zip...
1941 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001942 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001943 MYLOGE("Failed to add dumpstate log to .zip file\n");
1944 return false;
1945 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001946 // TODO: Should truncate the existing file.
1947 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001948 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1949 return false;
1950 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001951 fprintf(stderr, "\n");
1952
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001953 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001954 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001955 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001956 return false;
1957 }
1958
Felipe Leme1d486fe2016-10-14 18:06:47 -07001959 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1960 ds.zip_file.reset(nullptr);
1961
Felipe Lemee9d2c542016-11-15 11:48:26 -08001962 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001963 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001964
Felipe Leme1e9edc62015-12-21 16:02:13 -08001965 return true;
1966}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001967
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001968static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1969 // clang-format off
1970 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1971 "--receiver-foreground", "--receiver-include-background", "-a", action};
1972 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08001973
1974 am.insert(am.end(), args.begin(), args.end());
1975
Felipe Leme8d2410e2017-02-08 09:46:08 -08001976 RunCommand("", am,
1977 CommandOptions::WithTimeout(20)
1978 .Log("Sending broadcast: '%s'\n")
1979 .Always()
1980 .DropRoot()
1981 .RedirectStderr()
1982 .Build());
1983}
1984
Felipe Leme35b8cf12017-02-10 15:47:29 -08001985static void Vibrate(int duration_ms) {
1986 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00001987 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08001988 CommandOptions::WithTimeout(10)
1989 .Log("Vibrate: '%s'\n")
1990 .Always()
1991 .Build());
1992 // clang-format on
1993}
1994
Nandana Dutt979388e2018-11-30 16:48:55 +00001995static void MaybeResolveSymlink(std::string* path) {
1996 std::string resolved_path;
1997 if (android::base::Readlink(*path, &resolved_path)) {
1998 *path = resolved_path;
1999 }
2000}
2001
Nandana Dutt4be45d12018-09-26 15:04:23 +01002002/*
2003 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2004 * if we are writing zip files and adds the version file.
2005 */
2006static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002007 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2008
Nandana Dutt4be45d12018-09-26 15:04:23 +01002009 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2010 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002011 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002012 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002013 char date[80];
2014 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2015 ds.name_ = date;
2016 } else {
2017 ds.name_ = "undated";
2018 }
2019
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002020 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002021 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002022 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002023 ds.base_name_ += "-wifi";
2024 }
2025
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002026 if (ds.options_->do_fb) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002027 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002028 }
2029 ds.tmp_path_ = ds.GetPath(".tmp");
2030 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2031
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002032 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00002033 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002034 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002035 MYLOGD(
2036 "Bugreport dir: %s\n"
2037 "Base name: %s\n"
2038 "Suffix: %s\n"
2039 "Log path: %s\n"
2040 "Temporary path: %s\n"
2041 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002042 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2043 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002044
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002045 if (ds.options_->do_zip_file) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002046 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002047 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2048 create_parent_dirs(ds.path_.c_str());
2049 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2050 if (ds.zip_file == nullptr) {
2051 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2052 } else {
2053 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2054 }
2055 ds.AddTextZipEntry("version.txt", ds.version_);
2056 }
2057}
2058
2059/*
Abhijeet Kaure370d682019-10-01 16:49:30 +01002060 * Finalizes writing to the file by zipping the tmp file to the final location,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002061 * printing zipped file status, etc.
2062 */
2063static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002064 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002065 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002066 if (!ds.FinishZipFile()) {
2067 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2068 do_text_file = true;
2069 } else {
2070 do_text_file = false;
Nandana Dutt4be45d12018-09-26 15:04:23 +01002071 }
2072 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002073 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 if (do_text_file) {
2075 dprintf(ds.control_socket_fd_,
2076 "FAIL:could not create zip file, check %s "
2077 "for more details\n",
2078 ds.log_path_.c_str());
2079 } else {
2080 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2081 }
2082 }
2083}
2084
Nandana Dutt4be45d12018-09-26 15:04:23 +01002085
Nandana Dutt58d72e22018-11-16 10:30:48 +00002086static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2087 switch (mode) {
2088 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2089 return "BUGREPORT_FULL";
2090 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2091 return "BUGREPORT_INTERACTIVE";
2092 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2093 return "BUGREPORT_REMOTE";
2094 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2095 return "BUGREPORT_WEAR";
2096 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2097 return "BUGREPORT_TELEPHONY";
2098 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2099 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002100 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2101 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002102 }
2103}
2104
2105static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002106 options->bugreport_mode = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002107 switch (mode) {
2108 case Dumpstate::BugreportMode::BUGREPORT_FULL:
Nandana Dutt58d72e22018-11-16 10:30:48 +00002109 options->do_fb = true;
2110 break;
2111 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002112 // Currently, the dumpstate binder is only used by Shell to update progress.
2113 options->do_start_service = true;
2114 options->do_progress_updates = true;
2115 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002116 break;
2117 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002118 options->do_vibrate = false;
2119 options->is_remote_mode = true;
2120 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002121 break;
2122 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002123 options->do_start_service = true;
2124 options->do_progress_updates = true;
2125 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002126 options->do_fb = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002127 break;
2128 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002129 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002130 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002131 break;
2132 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002133 options->wifi_only = true;
2134 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002135 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002136 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002137 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2138 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002139 }
2140}
2141
Nandana Dutt58d72e22018-11-16 10:30:48 +00002142static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2143 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2144 MYLOGI("do_add_date: %d\n", options.do_add_date);
2145 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2146 MYLOGI("use_socket: %d\n", options.use_socket);
2147 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2148 MYLOGI("do_fb: %d\n", options.do_fb);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002149 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2150 MYLOGI("show_header_only: %d\n", options.show_header_only);
2151 MYLOGI("do_start_service: %d\n", options.do_start_service);
2152 MYLOGI("telephony_only: %d\n", options.telephony_only);
2153 MYLOGI("wifi_only: %d\n", options.wifi_only);
2154 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002155 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Abhijeet Kaure370d682019-10-01 16:49:30 +01002156 MYLOGI("bugreport_mode: %s\n", options.bugreport_mode.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002157 MYLOGI("args: %s\n", options.args.c_str());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002158}
2159
Nandana Dutt54dbd672019-01-11 12:58:05 +00002160void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2161 const android::base::unique_fd& bugreport_fd_in,
2162 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002163 // In the new API world, date is always added; output is always a zip file.
2164 // TODO(111441001): remove these options once they are obsolete.
2165 do_add_date = true;
2166 do_zip_file = true;
2167
Nandana Dutt54dbd672019-01-11 12:58:05 +00002168 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2169 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2170 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002171
Nandana Dutt58d72e22018-11-16 10:30:48 +00002172 SetOptionsFromMode(bugreport_mode, this);
2173}
2174
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002175Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2176 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002177 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002178 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002179 switch (c) {
2180 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002181 case 'd': do_add_date = true; break;
2182 case 'z': do_zip_file = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002183 case 's': use_socket = true; break;
2184 case 'S': use_control_socket = true; break;
2185 case 'v': show_header_only = true; break;
2186 case 'q': do_vibrate = false; break;
2187 case 'p': do_fb = true; break;
2188 case 'P': do_progress_updates = true; break;
2189 case 'R': is_remote_mode = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002190 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002191 case 'w':
2192 // This was already processed
2193 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002194 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002195 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002196 break;
2197 default:
2198 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002199 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002200 break;
2201 // clang-format on
2202 }
2203 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002204
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002205 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002206 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002207 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002208 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002209 }
2210 }
2211
2212 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2213 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002214
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002215 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002216}
2217
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002218bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002219 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002220 return false;
2221 }
2222
Abhijeet Kaure370d682019-10-01 16:49:30 +01002223 if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002224 return false;
2225 }
2226
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002227 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002228 return false;
2229 }
2230
Abhijeet Kaure370d682019-10-01 16:49:30 +01002231 if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002232 return false;
2233 }
2234 return true;
2235}
2236
Nandana Dutt197661d2018-11-16 16:40:21 +00002237void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2238 options_ = std::move(options);
2239}
2240
Nandana Duttd2f5f082019-01-18 17:13:52 +00002241Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2242 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002243 if (listener_ != nullptr) {
2244 switch (status) {
2245 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002246 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002247 break;
2248 case Dumpstate::RunStatus::HELP:
2249 break;
2250 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002251 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002252 break;
2253 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002254 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2255 break;
2256 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2257 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2258 break;
2259 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2260 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002261 break;
2262 }
2263 }
2264 return status;
2265}
2266
Nandana Dutt979388e2018-11-30 16:48:55 +00002267/*
2268 * Dumps relevant information to a bugreport based on the given options.
2269 *
2270 * The bugreport can be dumped to a file or streamed to a socket.
2271 *
2272 * How dumping to file works:
2273 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2274 * stderr is redirected a log file.
2275 *
2276 * The temporary bugreport is then populated via printfs, dumping contents of files and
2277 * output of commands to stdout.
2278 *
2279 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2280 * text file.
2281 *
2282 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2283 * gets added to the archive.
2284 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002285 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2286 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002287 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002288Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2289 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002290 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002291 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002292 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002293 return RunStatus::INVALID_INPUT;
2294 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002295 /* set as high priority, and protect from OOM killer */
2296 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002297
Felipe Lemed071c682016-10-20 16:48:00 -07002298 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002299 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002300 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002301 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002302 } else {
2303 /* fallback to kernels <= 2.6.35 */
2304 oom_adj = fopen("/proc/self/oom_adj", "we");
2305 if (oom_adj) {
2306 fputs("-17", oom_adj);
2307 fclose(oom_adj);
2308 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002309 }
2310
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002311 if (version_ == VERSION_DEFAULT) {
2312 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002313 }
2314
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002315 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002316 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002317 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002318 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002319 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002320 }
2321
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002322 if (options_->show_header_only) {
2323 PrintHeader();
2324 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002325 }
2326
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002327 MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
2328 calling_uid, calling_package.c_str());
Abhijeet Kaure370d682019-10-01 16:49:30 +01002329 if (CalledByApi()) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002330 // If the output needs to be copied over to the caller's fd, get user consent.
2331 android::String16 package(calling_package.c_str());
2332 CheckUserConsent(calling_uid, package);
2333 }
2334
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002335 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002336 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002337
2338 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002339 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002340 is_redirecting
2341 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2342 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002343 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002344
Felipe Lemed071c682016-10-20 16:48:00 -07002345 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002346 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002347 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002348 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2349
2350 MYLOGI("begin\n");
2351
Sahana Raof35ed432019-07-12 10:47:52 +01002352 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2353 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2354 } else {
2355 // Wake lock will be released automatically on process death
2356 MYLOGD("Wake lock acquired.\n");
2357 }
2358
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002359 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002360
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002361 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002362 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002363 MYLOGI("Starting 'dumpstate' service\n");
2364 android::status_t ret;
2365 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2366 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2367 }
2368 }
2369
Felipe Lemef0292972016-11-22 13:57:05 -08002370 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002371 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2372 }
2373
Abhijeet Kaure370d682019-10-01 16:49:30 +01002374 MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s)\n", id_, options_->args.c_str(),
2375 options_->bugreport_mode.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002376
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002377 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002378
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002379 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002380
Christopher Ferrised9354f2014-10-01 17:35:01 -07002381 // If we are going to use a socket, do it as early as possible
2382 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002383 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002384 if (!redirect_to_socket(stdout, "dumpstate")) {
2385 return ERROR;
2386 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002387 }
2388
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002389 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002390 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002391 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002392 if (control_socket_fd_ == -1) {
2393 return ERROR;
2394 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002395 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002396 }
2397
Felipe Leme71bbfc52015-11-23 14:14:51 -08002398 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002399 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002400
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002401 if (options_->do_progress_updates) {
Abhijeet Kaure370d682019-10-01 16:49:30 +01002402 // clang-format off
2403 std::vector<std::string> am_args = {
2404 "--receiver-permission", "android.permission.DUMP",
2405 };
2406 // clang-format on
2407 // Send STARTED broadcast for apps that listen to bugreport generation events
2408 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002409 if (options_->use_control_socket) {
2410 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002411 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002412 }
2413 }
2414
Nick Kralevichf3599b32016-01-25 15:05:16 -08002415 /* read /proc/cmdline before dropping root */
2416 FILE *cmdline = fopen("/proc/cmdline", "re");
2417 if (cmdline) {
2418 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2419 fclose(cmdline);
2420 }
2421
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002422 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002423 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002424 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002425
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002426 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002427 MYLOGI("taking early screenshot\n");
2428 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002429 }
2430
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002431 if (options_->do_zip_file && zip_file != nullptr) {
2432 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2433 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002434 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002435 }
2436 }
2437
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002438 int dup_stdout_fd;
2439 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002440 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002441 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002442 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002443 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2444 return ERROR;
2445 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002446 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2447 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2448 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002449 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002450
2451 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2452 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002453 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002454 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002455 /* TODO: rather than generating a text file now and zipping it later,
2456 it would be more efficient to redirect stdout to the zip entry
2457 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002458 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2459 return ERROR;
2460 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002461 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002462 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002463 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002464 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002465 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002466
2467 // Don't buffer stdout
2468 setvbuf(stdout, nullptr, _IONBF, 0);
2469
Felipe Leme608385d2016-02-01 10:35:38 -08002470 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2471 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002472 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002473 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002474
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002475 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002476 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002477 DumpstateBoard();
2478 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002479 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002480 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002481 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002482 RunStatus s = DumpstateDefault();
2483 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002484 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002485 HandleUserConsentDenied();
2486 }
2487 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002488 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002489 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002490
Felipe Leme55b42a62015-11-10 17:39:08 -08002491 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002492 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002493 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002494 }
2495
Abhijeet Kaure370d682019-10-01 16:49:30 +01002496 // Zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002497 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002498 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002499 }
2500
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002501 // Share the final file with the caller if the user has consented or Shell is the caller.
Nandana Duttd2f5f082019-01-18 17:13:52 +00002502 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
Abhijeet Kaure370d682019-10-01 16:49:30 +01002503 if (CalledByApi()) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002504 status = CopyBugreportIfUserConsented(calling_uid);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002505 if (status != Dumpstate::RunStatus::OK &&
2506 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2507 // Do an early return if there were errors. We make an exception for consent
2508 // timing out because it's possible the user got distracted. In this case the
2509 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002510 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002511 return status;
2512 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002513 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002514 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2515 options_->screenshot_fd.get());
2516 if (copy_succeeded) {
2517 android::os::UnlinkAndLogOnError(screenshot_path_);
2518 }
2519 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002520 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2521 MYLOGI(
2522 "Did not receive user consent yet."
2523 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002524 const String16 incidentcompanion("incidentcompanion");
2525 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2526 if (ics != nullptr) {
2527 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2528 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2529 consent_callback_.get());
2530 } else {
2531 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2532 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002533 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002534 }
2535
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002536 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002537 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002538 for (int i = 0; i < 3; i++) {
2539 Vibrate(75);
2540 usleep((75 + 50) * 1000);
2541 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002542 }
2543
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002544 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2545 progress_->GetInitialMax());
2546 progress_->Save();
2547 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002548
Felipe Leme107a05f2016-03-08 15:11:15 -08002549 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002550 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002551 }
2552
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002553 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002554 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002555 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002556 }
2557
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002558 tombstone_data_.clear();
2559 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002560
Nandana Duttd2f5f082019-01-18 17:13:52 +00002561 return (consent_callback_ != nullptr &&
2562 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2563 ? USER_CONSENT_TIMED_OUT
2564 : RunStatus::OK;
2565}
2566
2567void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002568 if (calling_uid == AID_SHELL) {
2569 return;
2570 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002571 consent_callback_ = new ConsentCallback();
2572 const String16 incidentcompanion("incidentcompanion");
2573 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2574 if (ics != nullptr) {
2575 MYLOGD("Checking user consent via incidentcompanion service\n");
2576 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002577 calling_uid, calling_package, String16(), String16(),
2578 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002579 } else {
2580 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2581 }
2582}
2583
Nandana Dutt5c390032019-03-12 10:52:56 +00002584bool Dumpstate::IsUserConsentDenied() const {
2585 return ds.consent_callback_ != nullptr &&
2586 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2587}
2588
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002589bool Dumpstate::CalledByApi() const {
2590 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2591}
2592
Nandana Duttd2f5f082019-01-18 17:13:52 +00002593void Dumpstate::CleanupFiles() {
2594 android::os::UnlinkAndLogOnError(tmp_path_);
2595 android::os::UnlinkAndLogOnError(screenshot_path_);
2596 android::os::UnlinkAndLogOnError(path_);
2597}
2598
2599Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2600 MYLOGD("User denied consent; deleting files and returning\n");
2601 CleanupFiles();
2602 return USER_CONSENT_DENIED;
2603}
2604
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002605Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002606 // If the caller has asked to copy the bugreport over to their directory, we need explicit
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002607 // user consent (unless the caller is Shell).
2608 UserConsentResult consent_result;
2609 if (calling_uid == AID_SHELL) {
2610 consent_result = UserConsentResult::APPROVED;
2611 } else {
2612 consent_result = consent_callback_->getResult();
2613 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002614 if (consent_result == UserConsentResult::UNAVAILABLE) {
2615 // User has not responded yet.
2616 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2617 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2618 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2619 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2620 sleep(delay_seconds);
2621 }
2622 consent_result = consent_callback_->getResult();
2623 }
2624 if (consent_result == UserConsentResult::DENIED) {
2625 // User has explicitly denied sharing with the app. To be safe delete the
2626 // internal bugreport & tmp files.
2627 return HandleUserConsentDenied();
2628 }
2629 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002630 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2631 if (copy_succeeded) {
2632 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002633 }
2634 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2635 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2636 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2637 // Since we do not have user consent to share the bugreport it does not get
2638 // copied over to the calling app but remains in the internal directory from
2639 // where the user can manually pull it.
2640 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2641 }
2642 // Unknown result; must be a programming error.
2643 MYLOGE("Unknown user consent result:%d\n", consent_result);
2644 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002645}
2646
Nandana Duttf02564e2019-02-15 15:24:24 +00002647Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002648 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2649 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2650 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002651 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002652 // When directly running dumpstate binary, the output is not expected to be written
2653 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002654 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002655
2656 // calling_uid and calling_package are for user consent to share the bugreport with
2657 // an app; they are irrelvant here because bugreport is only written to a local
2658 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002659 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002660 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002661 return status;
2662}
2663
2664/* Main entry point for dumpstate binary. */
2665int run_main(int argc, char* argv[]) {
2666 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002667
2668 switch (status) {
2669 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002670 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002671 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002672 ShowUsage();
2673 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002674 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002675 fprintf(stderr, "Invalid combination of args\n");
2676 ShowUsage();
2677 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002678 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002679 FALLTHROUGH_INTENDED;
2680 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2681 FALLTHROUGH_INTENDED;
2682 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002683 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002684 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002685}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002686
2687// TODO(111441001): Default DumpOptions to sensible values.
2688Dumpstate::Dumpstate(const std::string& version)
2689 : pid_(getpid()),
2690 options_(new Dumpstate::DumpOptions()),
Nandana Dutt402a8392019-06-14 14:25:13 +01002691 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002692 version_(version),
2693 now_(time(nullptr)) {
2694}
2695
2696Dumpstate& Dumpstate::GetInstance() {
2697 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2698 return singleton_;
2699}
2700
Nandana Dutt8d945c02019-08-14 13:30:07 +01002701DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2702 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002703 if (!title_.empty()) {
2704 started_ = Nanotime();
2705 }
2706}
2707
2708DurationReporter::~DurationReporter() {
2709 if (!title_.empty()) {
2710 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002711 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002712 return;
2713 }
2714 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2715 if (logcat_only_) {
2716 return;
2717 }
2718 // Use "Yoda grammar" to make it easier to grep|sort sections.
2719 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2720 }
2721}
2722
2723const int32_t Progress::kDefaultMax = 5000;
2724
2725Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2726}
2727
2728Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2729 : Progress(initial_max, growth_factor, "") {
2730 progress_ = progress;
2731}
2732
2733Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2734 : initial_max_(initial_max),
2735 progress_(0),
2736 max_(initial_max),
2737 growth_factor_(growth_factor),
2738 n_runs_(0),
2739 average_max_(0),
2740 path_(path) {
2741 if (!path_.empty()) {
2742 Load();
2743 }
2744}
2745
2746void Progress::Load() {
2747 MYLOGD("Loading stats from %s\n", path_.c_str());
2748 std::string content;
2749 if (!android::base::ReadFileToString(path_, &content)) {
2750 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2751 return;
2752 }
2753 if (content.empty()) {
2754 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2755 return;
2756 }
2757 std::vector<std::string> lines = android::base::Split(content, "\n");
2758
2759 if (lines.size() < 1) {
2760 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2761 (int)lines.size(), max_);
2762 return;
2763 }
2764 char* ptr;
2765 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2766 average_max_ = strtol(ptr, nullptr, 10);
2767 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2768 average_max_ > STATS_MAX_AVERAGE) {
2769 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2770 initial_max_ = Progress::kDefaultMax;
2771 } else {
2772 initial_max_ = average_max_;
2773 }
2774 max_ = initial_max_;
2775
2776 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2777}
2778
2779void Progress::Save() {
2780 int32_t total = n_runs_ * average_max_ + progress_;
2781 int32_t runs = n_runs_ + 1;
2782 int32_t average = floor(((float)total) / runs);
2783 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2784 path_.c_str());
2785 if (path_.empty()) {
2786 return;
2787 }
2788
2789 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2790 if (!android::base::WriteStringToFile(content, path_)) {
2791 MYLOGE("Could not save stats on %s\n", path_.c_str());
2792 }
2793}
2794
2795int32_t Progress::Get() const {
2796 return progress_;
2797}
2798
2799bool Progress::Inc(int32_t delta_sec) {
2800 bool changed = false;
2801 if (delta_sec >= 0) {
2802 progress_ += delta_sec;
2803 if (progress_ > max_) {
2804 int32_t old_max = max_;
2805 max_ = floor((float)progress_ * growth_factor_);
2806 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2807 changed = true;
2808 }
2809 }
2810 return changed;
2811}
2812
2813int32_t Progress::GetMax() const {
2814 return max_;
2815}
2816
2817int32_t Progress::GetInitialMax() const {
2818 return initial_max_;
2819}
2820
2821void Progress::Dump(int fd, const std::string& prefix) const {
2822 const char* pr = prefix.c_str();
2823 dprintf(fd, "%sprogress: %d\n", pr, progress_);
2824 dprintf(fd, "%smax: %d\n", pr, max_);
2825 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
2826 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
2827 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
2828 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
2829 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
2830}
2831
2832bool Dumpstate::IsZipping() const {
2833 return zip_writer_ != nullptr;
2834}
2835
2836std::string Dumpstate::GetPath(const std::string& suffix) const {
2837 return GetPath(bugreport_internal_dir_, suffix);
2838}
2839
2840std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
2841 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
2842 name_.c_str(), suffix.c_str());
2843}
2844
2845void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
2846 progress_ = std::move(progress);
2847}
2848
2849void for_each_userid(void (*func)(int), const char *header) {
2850 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
2851 "for_each_userid(%s)", header);
2852 DurationReporter duration_reporter(title);
2853 if (PropertiesHelper::IsDryRun()) return;
2854
2855 DIR *d;
2856 struct dirent *de;
2857
2858 if (header) printf("\n------ %s ------\n", header);
2859 func(0);
2860
2861 if (!(d = opendir("/data/system/users"))) {
2862 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
2863 return;
2864 }
2865
2866 while ((de = readdir(d))) {
2867 int userid;
2868 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
2869 continue;
2870 }
2871 func(userid);
2872 }
2873
2874 closedir(d);
2875}
2876
2877static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
2878 DIR *d;
2879 struct dirent *de;
2880
2881 if (!(d = opendir("/proc"))) {
2882 printf("Failed to open /proc (%s)\n", strerror(errno));
2883 return;
2884 }
2885
2886 if (header) printf("\n------ %s ------\n", header);
2887 while ((de = readdir(d))) {
2888 if (ds.IsUserConsentDenied()) {
2889 MYLOGE(
2890 "Returning early because user denied consent to share bugreport with calling app.");
2891 closedir(d);
2892 return;
2893 }
2894 int pid;
2895 int fd;
2896 char cmdpath[255];
2897 char cmdline[255];
2898
2899 if (!(pid = atoi(de->d_name))) {
2900 continue;
2901 }
2902
2903 memset(cmdline, 0, sizeof(cmdline));
2904
2905 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
2906 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2907 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
2908 close(fd);
2909 if (cmdline[0]) {
2910 helper(pid, cmdline, arg);
2911 continue;
2912 }
2913 }
2914
2915 // if no cmdline, a kernel thread has comm
2916 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
2917 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
2918 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
2919 close(fd);
2920 if (cmdline[1]) {
2921 cmdline[0] = '[';
2922 size_t len = strcspn(cmdline, "\f\b\r\n");
2923 cmdline[len] = ']';
2924 cmdline[len+1] = '\0';
2925 }
2926 }
2927 if (!cmdline[0]) {
2928 strcpy(cmdline, "N/A");
2929 }
2930 helper(pid, cmdline, arg);
2931 }
2932
2933 closedir(d);
2934}
2935
2936static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
2937 for_each_pid_func *func = (for_each_pid_func*) arg;
2938 func(pid, cmdline);
2939}
2940
2941void for_each_pid(for_each_pid_func func, const char *header) {
2942 std::string title = header == nullptr ? "for_each_pid"
2943 : android::base::StringPrintf("for_each_pid(%s)", header);
2944 DurationReporter duration_reporter(title);
2945 if (PropertiesHelper::IsDryRun()) return;
2946
2947 __for_each_pid(for_each_pid_helper, header, (void *) func);
2948}
2949
2950static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
2951 DIR *d;
2952 struct dirent *de;
2953 char taskpath[255];
2954 for_each_tid_func *func = (for_each_tid_func *) arg;
2955
2956 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
2957
2958 if (!(d = opendir(taskpath))) {
2959 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
2960 return;
2961 }
2962
2963 func(pid, pid, cmdline);
2964
2965 while ((de = readdir(d))) {
2966 if (ds.IsUserConsentDenied()) {
2967 MYLOGE(
2968 "Returning early because user denied consent to share bugreport with calling app.");
2969 closedir(d);
2970 return;
2971 }
2972 int tid;
2973 int fd;
2974 char commpath[255];
2975 char comm[255];
2976
2977 if (!(tid = atoi(de->d_name))) {
2978 continue;
2979 }
2980
2981 if (tid == pid)
2982 continue;
2983
2984 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
2985 memset(comm, 0, sizeof(comm));
2986 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
2987 strcpy(comm, "N/A");
2988 } else {
2989 char *c;
2990 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
2991 close(fd);
2992
2993 c = strrchr(comm, '\n');
2994 if (c) {
2995 *c = '\0';
2996 }
2997 }
2998 func(pid, tid, comm);
2999 }
3000
3001 closedir(d);
3002}
3003
3004void for_each_tid(for_each_tid_func func, const char *header) {
3005 std::string title = header == nullptr ? "for_each_tid"
3006 : android::base::StringPrintf("for_each_tid(%s)", header);
3007 DurationReporter duration_reporter(title);
3008
3009 if (PropertiesHelper::IsDryRun()) return;
3010
3011 __for_each_pid(for_each_tid_helper, header, (void *) func);
3012}
3013
3014void show_wchan(int pid, int tid, const char *name) {
3015 if (PropertiesHelper::IsDryRun()) return;
3016
3017 char path[255];
3018 char buffer[255];
3019 int fd, ret, save_errno;
3020 char name_buffer[255];
3021
3022 memset(buffer, 0, sizeof(buffer));
3023
3024 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3025 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3026 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3027 return;
3028 }
3029
3030 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3031 save_errno = errno;
3032 close(fd);
3033
3034 if (ret < 0) {
3035 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3036 return;
3037 }
3038
3039 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3040 pid == tid ? 0 : 3, "", name);
3041
3042 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3043
3044 return;
3045}
3046
3047// print time in centiseconds
3048static void snprcent(char *buffer, size_t len, size_t spc,
3049 unsigned long long time) {
3050 static long hz; // cache discovered hz
3051
3052 if (hz <= 0) {
3053 hz = sysconf(_SC_CLK_TCK);
3054 if (hz <= 0) {
3055 hz = 1000;
3056 }
3057 }
3058
3059 // convert to centiseconds
3060 time = (time * 100 + (hz / 2)) / hz;
3061
3062 char str[16];
3063
3064 snprintf(str, sizeof(str), " %llu.%02u",
3065 time / 100, (unsigned)(time % 100));
3066 size_t offset = strlen(buffer);
3067 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3068 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3069}
3070
3071// print permille as a percent
3072static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3073 char str[16];
3074
3075 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3076 size_t offset = strlen(buffer);
3077 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3078 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3079}
3080
3081void show_showtime(int pid, const char *name) {
3082 if (PropertiesHelper::IsDryRun()) return;
3083
3084 char path[255];
3085 char buffer[1023];
3086 int fd, ret, save_errno;
3087
3088 memset(buffer, 0, sizeof(buffer));
3089
3090 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3091 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3092 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3093 return;
3094 }
3095
3096 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3097 save_errno = errno;
3098 close(fd);
3099
3100 if (ret < 0) {
3101 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3102 return;
3103 }
3104
3105 // field 14 is utime
3106 // field 15 is stime
3107 // field 42 is iotime
3108 unsigned long long utime = 0, stime = 0, iotime = 0;
3109 if (sscanf(buffer,
3110 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3111 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3112 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3113 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3114 &utime, &stime, &iotime) != 3) {
3115 return;
3116 }
3117
3118 unsigned long long total = utime + stime;
3119 if (!total) {
3120 return;
3121 }
3122
3123 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3124 if (permille > 1000) {
3125 permille = 1000;
3126 }
3127
3128 // try to beautify and stabilize columns at <80 characters
3129 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3130 if ((name[0] != '[') || utime) {
3131 snprcent(buffer, sizeof(buffer), 57, utime);
3132 }
3133 snprcent(buffer, sizeof(buffer), 65, stime);
3134 if ((name[0] != '[') || iotime) {
3135 snprcent(buffer, sizeof(buffer), 73, iotime);
3136 }
3137 if (iotime) {
3138 snprdec(buffer, sizeof(buffer), 79, permille);
3139 }
3140 puts(buffer); // adds a trailing newline
3141
3142 return;
3143}
3144
3145void do_dmesg() {
3146 const char *title = "KERNEL LOG (dmesg)";
3147 DurationReporter duration_reporter(title);
3148 printf("------ %s ------\n", title);
3149
3150 if (PropertiesHelper::IsDryRun()) return;
3151
3152 /* Get size of kernel buffer */
3153 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3154 if (size <= 0) {
3155 printf("Unexpected klogctl return value: %d\n\n", size);
3156 return;
3157 }
3158 char *buf = (char *) malloc(size + 1);
3159 if (buf == nullptr) {
3160 printf("memory allocation failed\n\n");
3161 return;
3162 }
3163 int retval = klogctl(KLOG_READ_ALL, buf, size);
3164 if (retval < 0) {
3165 printf("klogctl failure\n\n");
3166 free(buf);
3167 return;
3168 }
3169 buf[retval] = '\0';
3170 printf("%s\n\n", buf);
3171 free(buf);
3172 return;
3173}
3174
3175void do_showmap(int pid, const char *name) {
3176 char title[255];
3177 char arg[255];
3178
3179 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3180 snprintf(arg, sizeof(arg), "%d", pid);
3181 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3182}
3183
3184int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3185 DurationReporter duration_reporter(title);
3186
3187 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3188
3189 UpdateProgress(WEIGHT_FILE);
3190
3191 return status;
3192}
3193
3194int read_file_as_long(const char *path, long int *output) {
3195 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3196 if (fd < 0) {
3197 int err = errno;
3198 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3199 return -1;
3200 }
3201 char buffer[50];
3202 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3203 if (bytes_read == -1) {
3204 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3205 return -2;
3206 }
3207 if (bytes_read == 0) {
3208 MYLOGE("File %s is empty\n", path);
3209 return -3;
3210 }
3211 *output = atoi(buffer);
3212 return 0;
3213}
3214
3215/* calls skip to gate calling dump_from_fd recursively
3216 * in the specified directory. dump_from_fd defaults to
3217 * dump_file_from_fd above when set to NULL. skip defaults
3218 * to false when set to NULL. dump_from_fd will always be
3219 * called with title NULL.
3220 */
3221int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3222 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3223 DurationReporter duration_reporter(title);
3224 DIR *dirp;
3225 struct dirent *d;
3226 char *newpath = nullptr;
3227 const char *slash = "/";
3228 int retval = 0;
3229
3230 if (!title.empty()) {
3231 printf("------ %s (%s) ------\n", title.c_str(), dir);
3232 }
3233 if (PropertiesHelper::IsDryRun()) return 0;
3234
3235 if (dir[strlen(dir) - 1] == '/') {
3236 ++slash;
3237 }
3238 dirp = opendir(dir);
3239 if (dirp == nullptr) {
3240 retval = -errno;
3241 MYLOGE("%s: %s\n", dir, strerror(errno));
3242 return retval;
3243 }
3244
3245 if (!dump_from_fd) {
3246 dump_from_fd = dump_file_from_fd;
3247 }
3248 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3249 if ((d->d_name[0] == '.')
3250 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3251 || (d->d_name[1] == '\0'))) {
3252 continue;
3253 }
3254 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3255 (d->d_type == DT_DIR) ? "/" : "");
3256 if (!newpath) {
3257 retval = -errno;
3258 continue;
3259 }
3260 if (skip && (*skip)(newpath)) {
3261 continue;
3262 }
3263 if (d->d_type == DT_DIR) {
3264 int ret = dump_files("", newpath, skip, dump_from_fd);
3265 if (ret < 0) {
3266 retval = ret;
3267 }
3268 continue;
3269 }
3270 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3271 if (fd.get() < 0) {
3272 retval = -1;
3273 printf("*** %s: %s\n", newpath, strerror(errno));
3274 continue;
3275 }
3276 (*dump_from_fd)(nullptr, newpath, fd.get());
3277 }
3278 closedir(dirp);
3279 if (!title.empty()) {
3280 printf("\n");
3281 }
3282 return retval;
3283}
3284
3285/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3286 * it's possible to avoid issues where opening the file itself can get
3287 * stuck.
3288 */
3289int dump_file_from_fd(const char *title, const char *path, int fd) {
3290 if (PropertiesHelper::IsDryRun()) return 0;
3291
3292 int flags = fcntl(fd, F_GETFL);
3293 if (flags == -1) {
3294 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3295 return -1;
3296 } else if (!(flags & O_NONBLOCK)) {
3297 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3298 return -1;
3299 }
3300 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3301}
3302
3303int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003304 const CommandOptions& options, bool verbose_duration) {
3305 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003306
3307 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3308
3309 /* TODO: for now we're simplifying the progress calculation by using the
3310 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3311 * where its weight should be much higher proportionally to its timeout.
3312 * Ideally, it should use a options.EstimatedDuration() instead...*/
3313 UpdateProgress(options.Timeout());
3314
3315 return status;
3316}
3317
3318void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3319 const CommandOptions& options, long dumpsysTimeoutMs) {
3320 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3321 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3322 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3323 RunCommand(title, dumpsys, options);
3324}
3325
3326int open_socket(const char *service) {
3327 int s = android_get_control_socket(service);
3328 if (s < 0) {
3329 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3330 return -1;
3331 }
3332 fcntl(s, F_SETFD, FD_CLOEXEC);
3333
3334 // Set backlog to 0 to make sure that queue size will be minimum.
3335 // In Linux, because the minimum queue will be 1, connect() will be blocked
3336 // if the other clients already called connect() and the connection request was not accepted.
3337 if (listen(s, 0) < 0) {
3338 MYLOGE("listen(control socket): %s\n", strerror(errno));
3339 return -1;
3340 }
3341
3342 struct sockaddr addr;
3343 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003344 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003345
3346 // Close socket just after accept(), to make sure that connect() by client will get error
3347 // when the socket is used by the other services.
3348 // There is still a race condition possibility between accept and close, but there is no way
3349 // to close-on-accept atomically.
3350 // See detail; b/123306389#comment25
3351 close(s);
3352
3353 if (fd < 0) {
3354 MYLOGE("accept(control socket): %s\n", strerror(errno));
3355 return -1;
3356 }
3357
3358 return fd;
3359}
3360
3361/* redirect output to a service control socket */
3362bool redirect_to_socket(FILE* redirect, const char* service) {
3363 int fd = open_socket(service);
3364 if (fd == -1) {
3365 return false;
3366 }
3367 fflush(redirect);
3368 // TODO: handle dup2 failure
3369 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3370 close(fd);
3371 return true;
3372}
3373
3374// TODO: should call is_valid_output_file and/or be merged into it.
3375void create_parent_dirs(const char *path) {
3376 char *chp = const_cast<char *> (path);
3377
3378 /* skip initial slash */
3379 if (chp[0] == '/')
3380 chp++;
3381
3382 /* create leading directories, if necessary */
3383 struct stat dir_stat;
3384 while (chp && chp[0]) {
3385 chp = strchr(chp, '/');
3386 if (chp) {
3387 *chp = 0;
3388 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3389 MYLOGI("Creating directory %s\n", path);
3390 if (mkdir(path, 0770)) { /* drwxrwx--- */
3391 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3392 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3393 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3394 }
3395 }
3396 *chp++ = '/';
3397 }
3398 }
3399}
3400
3401bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3402 create_parent_dirs(path);
3403
3404 int fd = TEMP_FAILURE_RETRY(open(path,
3405 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3406 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3407 if (fd < 0) {
3408 MYLOGE("%s: %s\n", path, strerror(errno));
3409 return false;
3410 }
3411
3412 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3413 close(fd);
3414 return true;
3415}
3416
3417bool redirect_to_file(FILE* redirect, char* path) {
3418 return _redirect_to_file(redirect, path, O_TRUNC);
3419}
3420
3421bool redirect_to_existing_file(FILE* redirect, char* path) {
3422 return _redirect_to_file(redirect, path, O_APPEND);
3423}
3424
3425void dump_route_tables() {
3426 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3427 if (PropertiesHelper::IsDryRun()) return;
3428 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3429 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3430 FILE* fp = fopen(RT_TABLES_PATH, "re");
3431 if (!fp) {
3432 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3433 return;
3434 }
3435 char table[16];
3436 // Each line has an integer (the table number), a space, and a string (the table name). We only
3437 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3438 // Add a fixed max limit so this doesn't go awry.
3439 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3440 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3441 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3442 }
3443 fclose(fp);
3444}
3445
3446// TODO: make this function thread safe if sections are generated in parallel.
3447void Dumpstate::UpdateProgress(int32_t delta_sec) {
3448 if (progress_ == nullptr) {
3449 MYLOGE("UpdateProgress: progress_ not set\n");
3450 return;
3451 }
3452
3453 // Always update progess so stats can be tuned...
Nandana Dutt402a8392019-06-14 14:25:13 +01003454 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003455
3456 // ...but only notifiy listeners when necessary.
3457 if (!options_->do_progress_updates) return;
3458
3459 int progress = progress_->Get();
3460 int max = progress_->GetMax();
Nandana Dutt402a8392019-06-14 14:25:13 +01003461 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003462
Nandana Dutt402a8392019-06-14 14:25:13 +01003463 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003464 return;
3465 }
Nandana Dutt402a8392019-06-14 14:25:13 +01003466 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003467
3468 if (control_socket_fd_ >= 0) {
3469 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3470 fsync(control_socket_fd_);
3471 }
3472
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003473 if (listener_ != nullptr) {
3474 if (percent % 5 == 0) {
3475 // We don't want to spam logcat, so only log multiples of 5.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003476 MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003477 } else {
3478 // stderr is ignored on normal invocations, but useful when calling
3479 // /system/bin/dumpstate directly for debuggging.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003480 fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003481 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003482
3483 listener_->onProgress(percent);
3484 }
3485}
3486
3487void Dumpstate::TakeScreenshot(const std::string& path) {
3488 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3489 int status =
3490 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3491 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3492 if (status == 0) {
3493 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3494 } else {
3495 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3496 }
3497}
3498
3499bool is_dir(const char* pathname) {
3500 struct stat info;
3501 if (stat(pathname, &info) == -1) {
3502 return false;
3503 }
3504 return S_ISDIR(info.st_mode);
3505}
3506
3507time_t get_mtime(int fd, time_t default_mtime) {
3508 struct stat info;
3509 if (fstat(fd, &info) == -1) {
3510 return default_mtime;
3511 }
3512 return info.st_mtime;
3513}