blob: 9cccd5b14b555a6d497033e9dc73083af5fbeb8d [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010022#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010025#include <math.h>
26#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080031#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010037#include <signal.h>
38#include <stdarg.h>
39#include <string.h>
40#include <sys/capability.h>
41#include <sys/inotify.h>
42#include <sys/klog.h>
43#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070045
46#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070047#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000048#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070049#include <functional>
50#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010051#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070052#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <regex>
54#include <set>
55#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070056#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010057#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070058
Felipe Leme96c2bbb2016-09-26 09:21:21 -070059#include <android-base/file.h>
60#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070061#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080062#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070063#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070064#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010065#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080066#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080067#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000068#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010069#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080070#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070071#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010072#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080074#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000075#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010076#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080077#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010078#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070079#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070080#include <private/android_filesystem_config.h>
81#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070083#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080084#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070085#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070086#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080087
Steven Morelandcb7ef822016-11-29 13:20:37 -080088using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080089using ::std::literals::chrono_literals::operator""ms;
90using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080091
Felipe Leme47e9be22016-12-21 15:37:07 -080092// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080093using android::defaultServiceManager;
94using android::Dumpsys;
95using android::INVALID_OPERATION;
96using android::IServiceManager;
97using android::OK;
98using android::sp;
99using android::status_t;
100using android::String16;
101using android::String8;
102using android::TIMED_OUT;
103using android::UNKNOWN_ERROR;
104using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000105using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000106using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107using android::os::dumpstate::CommandOptions;
108using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100124}
125
126// Reasonable value for max stats.
127static const int STATS_MAX_N_RUNS = 1000;
128static const long STATS_MAX_AVERAGE = 100000;
129
130CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
Nandana Duttd2f5f082019-01-18 17:13:52 +0000132typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134/* read before root is shed */
135static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700136static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000137static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700138
Felipe Leme1d486fe2016-10-14 18:06:47 -0700139// TODO: variables and functions below should be part of dumpstate object
140
Felipe Leme635ca312016-01-05 14:23:02 -0800141static std::set<std::string> mount_points;
142void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800143
Todd Poynor2a83daa2013-11-22 15:44:22 -0800144#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700145#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700146#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800147
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700149#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700150#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700151#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100152#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
153#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800154#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900155#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800156#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700157
Narayan Kamath8f788292017-05-25 13:20:39 +0100158// TODO(narayan): Since this information has to be kept in sync
159// with tombstoned, we should just put it in a common header.
160//
161// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100162static const std::string TOMBSTONE_DIR = "/data/tombstones/";
163static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
164static const std::string ANR_DIR = "/data/anr/";
165static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700166
Felipe Lemee844a9d2016-09-21 15:01:39 -0700167// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000168
Nandana Dutt5c390032019-03-12 10:52:56 +0000169#define RETURN_IF_USER_DENIED_CONSENT() \
170 if (ds.IsUserConsentDenied()) { \
171 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
172 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
173 }
174
175// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
176// if consent is found to be denied.
177#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
178 RETURN_IF_USER_DENIED_CONSENT(); \
179 func_ptr(__VA_ARGS__); \
180 RETURN_IF_USER_DENIED_CONSENT();
181
Sahana Raof35ed432019-07-12 10:47:52 +0100182static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
183
Nandana Dutt979388e2018-11-30 16:48:55 +0000184namespace android {
185namespace os {
186namespace {
187
188static int Open(std::string path, int flags, mode_t mode = 0) {
189 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
190 if (fd == -1) {
191 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
192 }
193 return fd;
194}
195
Nandana Dutt979388e2018-11-30 16:48:55 +0000196
197static int OpenForRead(std::string path) {
198 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
199}
200
201bool CopyFile(int in_fd, int out_fd) {
202 char buf[4096];
203 ssize_t byte_count;
204 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
205 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
206 return false;
207 }
208 }
209 return (byte_count != -1);
210}
211
212static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000213 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000214
215 // Obtain a handle to the source file.
216 android::base::unique_fd in_fd(OpenForRead(input_file));
217 if (out_fd != -1 && in_fd.get() != -1) {
218 if (CopyFile(in_fd.get(), out_fd)) {
219 return true;
220 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000221 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000222 }
223 return false;
224}
225
Nandana Duttd2f5f082019-01-18 17:13:52 +0000226static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000227 if (unlink(file.c_str())) {
228 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000229 return false;
230 }
231 return true;
232}
Nandana Dutt979388e2018-11-30 16:48:55 +0000233
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000234static bool IsFileEmpty(const std::string& file_path) {
235 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
236 if(file.bad()) {
237 MYLOGE("Cannot open file: %s\n", file_path.c_str());
238 return true;
239 }
240 return file.tellg() <= 0;
241}
242
Nikita Ioffea325a572019-05-16 19:49:47 +0100243int64_t GetModuleMetadataVersion() {
244 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
245 if (binder == nullptr) {
246 MYLOGE("Failed to retrieve package_native service");
247 return 0L;
248 }
249 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
250 std::string package_name;
251 auto status = package_service->getModuleMetadataPackageName(&package_name);
252 if (!status.isOk()) {
253 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
254 return 0L;
255 }
256 MYLOGD("Module metadata package name: %s", package_name.c_str());
257 int64_t version_code;
258 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
259 &version_code);
260 if (!status.isOk()) {
261 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
262 return 0L;
263 }
264 return version_code;
265}
266
Nandana Dutt979388e2018-11-30 16:48:55 +0000267} // namespace
268} // namespace os
269} // namespace android
270
Felipe Leme678727a2016-09-21 17:22:11 -0700271static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800272 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800273 long dumpsysTimeoutMs = 0) {
274 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700275}
276static int DumpFile(const std::string& title, const std::string& path) {
277 return ds.DumpFile(title, path);
278}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800279
Felipe Lemee844a9d2016-09-21 15:01:39 -0700280// Relative directory (inside the zip) for all files copied as-is into the bugreport.
281static const std::string ZIP_ROOT_DIR = "FS";
282
Vishnu Naire97d6122018-01-18 13:58:56 -0800283static const std::string kProtoPath = "proto/";
284static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700285static const std::string kDumpstateBoardFiles[] = {
286 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700287 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700288};
289static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
290
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700291static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700292static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700293static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700294static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
295static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700296
Felipe Lemef0292972016-11-22 13:57:05 -0800297static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
298
Narayan Kamath8f788292017-05-25 13:20:39 +0100299/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100300 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
301 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
302 * is set, the vector only contains files that were written in the last 30 minutes.
Andreas Gamped0d76952017-08-22 13:08:37 -0700303 * If |limit_by_count| is set, the vector only contains the ten latest files.
Narayan Kamath8f788292017-05-25 13:20:39 +0100304 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700305static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
306 const std::string& file_prefix,
307 bool limit_by_mtime,
308 bool limit_by_count = true) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100309 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
310
Narayan Kamathbd863722017-06-01 18:50:12 +0100311 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100312
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700313 if (dump_dir == nullptr) {
314 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700315 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700316 }
317
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700318 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100319 struct dirent* entry = nullptr;
320 while ((entry = readdir(dump_dir.get()))) {
321 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100322 continue;
323 }
324
Narayan Kamathbd863722017-06-01 18:50:12 +0100325 const std::string base_name(entry->d_name);
326 if (base_name.find(file_prefix) != 0) {
327 continue;
328 }
329
330 const std::string abs_path = dir_path + base_name;
331 android::base::unique_fd fd(
332 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
333 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700334 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100335 break;
336 }
337
338 struct stat st = {};
339 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700340 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100341 continue;
342 }
343
Narayan Kamath3f31b632018-02-22 19:42:36 +0000344 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100345 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100346 continue;
347 }
348
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700349 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700350 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100351
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700352 // Sort in descending modification time so that we only keep the newest
353 // reports if |limit_by_count| is true.
354 std::sort(dump_data.begin(), dump_data.end(),
355 [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
Narayan Kamath8f788292017-05-25 13:20:39 +0100356
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700357 if (limit_by_count && dump_data.size() > 10) {
358 dump_data.erase(dump_data.begin() + 10, dump_data.end());
Andreas Gamped0d76952017-08-22 13:08:37 -0700359 }
360
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700361 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100362}
363
Narayan Kamathbd863722017-06-01 18:50:12 +0100364static bool AddDumps(const std::vector<DumpData>::const_iterator start,
365 const std::vector<DumpData>::const_iterator end,
366 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100367 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100368 for (auto it = start; it != end; ++it) {
369 const std::string& name = it->name;
370 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100371 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100372
373 // Seek to the beginning of the file before dumping any data. A given
374 // DumpData entry might be dumped multiple times in the report.
375 //
376 // For example, the most recent ANR entry is dumped to the body of the
377 // main entry and it also shows up as a separate entry in the bugreport
378 // ZIP file.
379 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
380 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
381 strerror(errno));
382 }
383
Narayan Kamath8f788292017-05-25 13:20:39 +0100384 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800385 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100386 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100387 }
388 } else {
389 dump_file_from_fd(type_name, name.c_str(), fd);
390 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100391 }
392
393 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700394}
395
Felipe Leme635ca312016-01-05 14:23:02 -0800396// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700397void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800398 char path[PATH_MAX];
399
400 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
401 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700402 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800403 char linkname[PATH_MAX];
404 ssize_t r = readlink(path, linkname, PATH_MAX);
405 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800406 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800407 return;
408 }
409 linkname[r] = '\0';
410
411 if (mount_points.find(linkname) == mount_points.end()) {
412 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700413 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700414 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800415 mount_points.insert(linkname);
416 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800417 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800418 }
419 }
420}
421
422void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700423 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700424 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800425 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800426 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700427 for_each_pid(do_mountinfo, nullptr);
428 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800429}
430
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700431static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
432{
433 DIR *d;
434 struct dirent *de;
435 char path[PATH_MAX];
436
437 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700438 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700439 return;
440 }
441
442 while ((de = readdir(d))) {
443 if (de->d_type != DT_LNK) {
444 continue;
445 }
446 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700447 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700448 }
449
450 closedir(d);
451}
452
Mark Salyzyn326842f2015-04-30 09:49:41 -0700453static bool skip_not_stat(const char *path) {
454 static const char stat[] = "/stat";
455 size_t len = strlen(path);
456 if (path[len - 1] == '/') { /* Directory? */
457 return false;
458 }
459 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
460}
461
Felipe Leme4c2d6632016-09-28 14:32:00 -0700462static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800463 return false;
464}
465
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700466unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700467
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800468//
469// stat offsets
470// Name units description
471// ---- ----- -----------
472// read I/Os requests number of read I/Os processed
473#define __STAT_READ_IOS 0
474// read merges requests number of read I/Os merged with in-queue I/O
475#define __STAT_READ_MERGES 1
476// read sectors sectors number of sectors read
477#define __STAT_READ_SECTORS 2
478// read ticks milliseconds total wait time for read requests
479#define __STAT_READ_TICKS 3
480// write I/Os requests number of write I/Os processed
481#define __STAT_WRITE_IOS 4
482// write merges requests number of write I/Os merged with in-queue I/O
483#define __STAT_WRITE_MERGES 5
484// write sectors sectors number of sectors written
485#define __STAT_WRITE_SECTORS 6
486// write ticks milliseconds total wait time for write requests
487#define __STAT_WRITE_TICKS 7
488// in_flight requests number of I/Os currently in flight
489#define __STAT_IN_FLIGHT 8
490// io_ticks milliseconds total time this block device has been active
491#define __STAT_IO_TICKS 9
492// time_in_queue milliseconds total wait time for all requests
493#define __STAT_IN_QUEUE 10
494#define __STAT_NUMBER_FIELD 11
495//
496// read I/Os, write I/Os
497// =====================
498//
499// These values increment when an I/O request completes.
500//
501// read merges, write merges
502// =========================
503//
504// These values increment when an I/O request is merged with an
505// already-queued I/O request.
506//
507// read sectors, write sectors
508// ===========================
509//
510// These values count the number of sectors read from or written to this
511// block device. The "sectors" in question are the standard UNIX 512-byte
512// sectors, not any device- or filesystem-specific block size. The
513// counters are incremented when the I/O completes.
514#define SECTOR_SIZE 512
515//
516// read ticks, write ticks
517// =======================
518//
519// These values count the number of milliseconds that I/O requests have
520// waited on this block device. If there are multiple I/O requests waiting,
521// these values will increase at a rate greater than 1000/second; for
522// example, if 60 read requests wait for an average of 30 ms, the read_ticks
523// field will increase by 60*30 = 1800.
524//
525// in_flight
526// =========
527//
528// This value counts the number of I/O requests that have been issued to
529// the device driver but have not yet completed. It does not include I/O
530// requests that are in the queue but not yet issued to the device driver.
531//
532// io_ticks
533// ========
534//
535// This value counts the number of milliseconds during which the device has
536// had I/O requests queued.
537//
538// time_in_queue
539// =============
540//
541// This value counts the number of milliseconds that I/O requests have waited
542// on this block device. If there are multiple I/O requests waiting, this
543// value will increase as the product of the number of milliseconds times the
544// number of requests waiting (see "read ticks" above for an example).
545#define S_TO_MS 1000
546//
547
Mark Salyzyn326842f2015-04-30 09:49:41 -0700548static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800549 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700550 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700551 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700552 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700553 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700554 getline(&buffer, &i, fp);
555 fclose(fp);
556 if (!buffer) {
557 return -errno;
558 }
559 i = strlen(buffer);
560 while ((i > 0) && (buffer[i - 1] == '\n')) {
561 buffer[--i] = '\0';
562 }
563 if (!*buffer) {
564 free(buffer);
565 return 0;
566 }
567 z = true;
568 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800569 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700570 if (fields[i] != 0) {
571 z = false;
572 }
573 }
574 if (z) { /* never accessed */
575 free(buffer);
576 return 0;
577 }
578
Wei Wang509bb5d2017-06-09 14:42:12 -0700579 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
580 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700581 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700582
583 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
584 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
585 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700586 free(buffer);
587
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800588 if (fields[__STAT_IO_TICKS]) {
589 unsigned long read_perf = 0;
590 unsigned long read_ios = 0;
591 if (fields[__STAT_READ_TICKS]) {
592 unsigned long long divisor = fields[__STAT_READ_TICKS]
593 * fields[__STAT_IO_TICKS];
594 read_perf = ((unsigned long long)SECTOR_SIZE
595 * fields[__STAT_READ_SECTORS]
596 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
597 / divisor;
598 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
599 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
600 / divisor;
601 }
602
603 unsigned long write_perf = 0;
604 unsigned long write_ios = 0;
605 if (fields[__STAT_WRITE_TICKS]) {
606 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
607 * fields[__STAT_IO_TICKS];
608 write_perf = ((unsigned long long)SECTOR_SIZE
609 * fields[__STAT_WRITE_SECTORS]
610 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
611 / divisor;
612 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
613 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
614 / divisor;
615 }
616
617 unsigned queue = (fields[__STAT_IN_QUEUE]
618 + (fields[__STAT_IO_TICKS] >> 1))
619 / fields[__STAT_IO_TICKS];
620
621 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700622 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 -0800623 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700624 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 -0800625 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800626 }
627
628 /* bugreport timeout factor adjustment */
629 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
630 worst_write_perf = write_perf;
631 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700632 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700633 return 0;
634}
635
Yao Chenbe3bbc12018-01-17 16:31:10 -0800636static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
637
638/* timeout in ms to read a list of buffers */
639static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
640 unsigned long timeout_ms = 0;
641 for (const auto& buffer : buffers) {
642 log_id_t id = android_name_to_log_id(buffer.c_str());
643 unsigned long property_size = __android_logger_get_buffer_size(id);
644 /* Engineering margin is ten-fold our guess */
645 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
646 }
647 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700648}
649
Nandana Duttd2f5f082019-01-18 17:13:52 +0000650Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
651}
652
653android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
654 std::lock_guard<std::mutex> lock(lock_);
655 result_ = APPROVED;
656 MYLOGD("User approved consent to share bugreport\n");
657 return android::binder::Status::ok();
658}
659
660android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
661 std::lock_guard<std::mutex> lock(lock_);
662 result_ = DENIED;
663 MYLOGW("User denied consent to share bugreport\n");
664 return android::binder::Status::ok();
665}
666
667UserConsentResult Dumpstate::ConsentCallback::getResult() {
668 std::lock_guard<std::mutex> lock(lock_);
669 return result_;
670}
671
672uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
673 return Nanotime() - start_time_;
674}
675
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700676void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700677 std::string build, fingerprint, radio, bootloader, network;
678 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700679
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700680 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
681 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700682 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
683 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
684 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700685 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700686
Felipe Lemed8b94e52016-12-08 10:21:44 -0800687 printf("========================================================\n");
688 printf("== dumpstate: %s\n", date);
689 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700690
Felipe Lemed8b94e52016-12-08 10:21:44 -0800691 printf("\n");
692 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700693 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800694 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
695 printf("Bootloader: %s\n", bootloader.c_str());
696 printf("Radio: %s\n", radio.c_str());
697 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100698 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
699 if (module_metadata_version != 0) {
700 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
701 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700702
Felipe Lemed8b94e52016-12-08 10:21:44 -0800703 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800704 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800705 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800706 printf("Uptime: ");
707 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
708 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800709 printf("Bugreport format version: %s\n", version_.c_str());
710 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
Nandana Dutt5fb117b2018-09-27 09:23:36 +0100711 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800712 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800713}
714
Felipe Leme24b66ee2016-06-16 10:55:26 -0700715// List of file extensions that can cause a zip file attachment to be rejected by some email
716// service providers.
717static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
718 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
719 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
720 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
721};
722
Vishnu Naire97d6122018-01-18 13:58:56 -0800723status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
724 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700725 if (!IsZipping()) {
726 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
727 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800728 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800729 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700730 std::string valid_name = entry_name;
731
732 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700733 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700734 if (idx != std::string::npos) {
735 std::string extension = entry_name.substr(idx);
736 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
737 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
738 valid_name = entry_name + ".renamed";
739 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
740 }
741 }
742
Felipe Leme6fe9db62016-02-12 09:04:16 -0800743 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
744 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700745 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
746 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700747 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700748 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700749 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800750 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800751 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000752 bool finished_entry = false;
753 auto finish_entry = [this, &finished_entry] {
754 if (!finished_entry) {
755 // This should only be called when we're going to return an earlier error,
756 // which would've been logged. This may imply the file is already corrupt
757 // and any further logging from FinishEntry is more likely to mislead than
758 // not.
759 this->zip_writer_->FinishEntry();
760 }
761 };
762 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800763 auto start = std::chrono::steady_clock::now();
764 auto end = start + timeout;
765 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800766
Felipe Leme770410d2016-01-26 17:07:14 -0800767 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800768 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800769 if (timeout.count() > 0) {
770 // lambda to recalculate the timeout.
771 auto time_left_ms = [end]() {
772 auto now = std::chrono::steady_clock::now();
773 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
774 return std::max(diff.count(), 0LL);
775 };
776
777 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
778 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000779 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
780 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800781 return -errno;
782 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000783 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800784 entry_name.c_str(), strerror(errno), timeout.count());
785 return TIMED_OUT;
786 }
787 }
788
Zach Riggle22200402016-08-18 01:01:24 -0400789 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800790 if (bytes_read == 0) {
791 break;
792 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800793 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800794 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800795 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700796 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800797 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700798 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800799 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800800 }
801 }
802
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700803 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000804 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700805 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700806 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800807 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800808 }
809
Vishnu Naire97d6122018-01-18 13:58:56 -0800810 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800811}
812
Felipe Leme1d486fe2016-10-14 18:06:47 -0700813bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
814 android::base::unique_fd fd(
815 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700816 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800817 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800818 return false;
819 }
820
Vishnu Naire97d6122018-01-18 13:58:56 -0800821 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800822}
823
824/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700825static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800826 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800827}
828
Felipe Leme1d486fe2016-10-14 18:06:47 -0700829void Dumpstate::AddDir(const std::string& dir, bool recursive) {
830 if (!IsZipping()) {
831 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800832 return;
833 }
Felipe Leme678727a2016-09-21 17:22:11 -0700834 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800835 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700836 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800837}
838
Felipe Leme1d486fe2016-10-14 18:06:47 -0700839bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
840 if (!IsZipping()) {
841 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
842 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800843 return false;
844 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800845 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700846 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700847 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700848 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700849 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800850 return false;
851 }
852
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700853 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700854 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700855 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700856 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800857 return false;
858 }
859
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700860 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700861 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700862 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800863 return false;
864 }
865
866 return true;
867}
868
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800869static void DoKmsg() {
870 struct stat st;
871 if (!stat(PSTORE_LAST_KMSG, &st)) {
872 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
873 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
874 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
875 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
876 } else {
877 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
878 DumpFile("LAST KMSG", "/proc/last_kmsg");
879 }
880}
881
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800882static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800883 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800884 RunCommand(
885 "KERNEL LOG",
886 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
887 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
888}
889
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800890static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800891 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800892 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
893 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800894 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100895 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800896 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
897 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800898 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800899 RunCommand(
900 "EVENT LOG",
901 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100902 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800903 timeout_ms = logcat_timeout({"stats"});
904 RunCommand(
905 "STATS LOG",
906 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100907 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800908 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800909 RunCommand(
910 "RADIO LOG",
911 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100912 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800913
914 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
915
916 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800917 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
918 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800919}
920
Mike Ma5c267872019-08-21 11:31:34 -0700921static void DumpIncidentReport() {
922 if (!ds.IsZipping()) {
923 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
924 return;
925 }
926 DurationReporter duration_reporter("INCIDENT REPORT");
927 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
928 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
929 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
930 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
931 if (fd < 0) {
932 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
933 return;
934 }
935 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
936 bool empty = 0 == lseek(fd, 0, SEEK_END);
937 if (!empty) {
938 // Use a different name from "incident.proto"
939 // /proto/incident.proto is reserved for incident service dump
940 // i.e. metadata for debugging.
941 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
942 }
943 unlink(path.c_str());
944}
945
Jayachandran Ca94c7172017-06-10 15:08:12 -0700946static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700947 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
948 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900949 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700950 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900951 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
952 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
953 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
954 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700955}
956
David Andersond9ba4752018-12-11 18:26:59 -0800957static void DumpDynamicPartitionInfo() {
958 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
959 return;
960 }
961
962 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700963 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800964}
965
Narayan Kamath8f788292017-05-25 13:20:39 +0100966static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
967 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
968 anr_traces_dir.c_str());
969
970 // If we're here, dump_traces_path will always be a temporary file
971 // (created with mkostemp or similar) that contains dumps taken earlier
972 // on in the process.
973 if (dump_traces_path != nullptr) {
974 if (add_to_zip) {
975 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
976 } else {
977 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
978 dump_traces_path);
979 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
980 }
981
982 const int ret = unlink(dump_traces_path);
983 if (ret == -1) {
984 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
985 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700986 }
987 }
988
Narayan Kamathbd863722017-06-01 18:50:12 +0100989 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700990 if (ds.anr_data_.size() > 0) {
991 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100992 "VM TRACES AT LAST ANR", add_to_zip);
993
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100994 // The "last" ANR will always be included as separate entry in the zip file. In addition,
995 // it will be present in the body of the main entry if |add_to_zip| == false.
996 //
997 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700998 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100999 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001000 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001001 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1002 }
1003}
1004
1005static void AddAnrTraceFiles() {
1006 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1007
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001008 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001009
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001010 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001011
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001012 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1013
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001014 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001015 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001016 int i = 0;
1017 while (true) {
1018 const std::string slow_trace_path =
1019 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1020 if (stat(slow_trace_path.c_str(), &st)) {
1021 // No traces file at this index, done with the files.
1022 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001023 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001024 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1025 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001026 }
1027}
1028
Wei Wang509bb5d2017-06-09 14:42:12 -07001029static void DumpBlockStatFiles() {
1030 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001031
Wei Wang1dc1ef52017-06-12 11:28:37 -07001032 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1033
1034 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001035 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1036 return;
1037 }
1038
1039 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001040 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001041 if ((d->d_name[0] == '.')
1042 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1043 || (d->d_name[1] == '\0'))) {
1044 continue;
1045 }
1046 const std::string new_path =
1047 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1048 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1049 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1050 printf("\n");
1051 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001052 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001053}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001054
1055static void DumpPacketStats() {
1056 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1057 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1058 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1059 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1060 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1061}
1062
1063static void DumpIpAddrAndRules() {
1064 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1065 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1066 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1067 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1068 RunCommand("IP RULES", {"ip", "rule", "show"});
1069 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1070}
1071
Nandana Dutt5c390032019-03-12 10:52:56 +00001072static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1073 std::chrono::milliseconds timeout,
1074 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001075 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001076 sp<android::IServiceManager> sm = defaultServiceManager();
1077 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001078 Vector<String16> args;
1079 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001080 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1081 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001082 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001083 std::string path(title);
1084 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001085 size_t bytes_written = 0;
Steven Morelanda6ddb9a2019-09-27 16:41:02 +00001086 status_t status = dumpsys.startDumpThread(service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001087 if (status == OK) {
1088 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1089 std::chrono::duration<double> elapsed_seconds;
1090 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1091 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001092 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1093 bool dump_complete = (status == OK);
1094 dumpsys.stopDumpThread(dump_complete);
1095 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001096
1097 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1098 std::chrono::steady_clock::now() - start);
1099 if (elapsed_duration > timeout) {
1100 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1101 elapsed_duration.count());
1102 break;
1103 }
1104 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001105 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001106}
1107
Vishnu Nair64afc022018-02-01 15:29:34 -08001108static void RunDumpsysText(const std::string& title, int priority,
1109 std::chrono::milliseconds timeout,
1110 std::chrono::milliseconds service_timeout) {
1111 DurationReporter duration_reporter(title);
1112 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1113 fsync(STDOUT_FILENO);
1114 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1115}
1116
1117/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001118static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1119 std::chrono::milliseconds timeout,
1120 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001121 DurationReporter duration_reporter(title);
1122 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1123 fsync(STDOUT_FILENO);
1124 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1125 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001126
1127 RETURN_IF_USER_DENIED_CONSENT();
1128
1129 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1130 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001131}
1132
Nandana Dutt5c390032019-03-12 10:52:56 +00001133static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1134 std::chrono::milliseconds timeout,
1135 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001136 if (!ds.IsZipping()) {
1137 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001138 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001139 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001140 sp<android::IServiceManager> sm = defaultServiceManager();
1141 Dumpsys dumpsys(sm.get());
1142 Vector<String16> args;
1143 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1144 DurationReporter duration_reporter(title);
1145
1146 auto start = std::chrono::steady_clock::now();
1147 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1148 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001149 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001150 std::string path(kProtoPath);
1151 path.append(String8(service).c_str());
1152 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1153 path.append("_CRITICAL");
1154 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1155 path.append("_HIGH");
1156 }
1157 path.append(kProtoExt);
Steven Morelanda6ddb9a2019-09-27 16:41:02 +00001158 status_t status = dumpsys.startDumpThread(service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001159 if (status == OK) {
1160 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1161 bool dumpTerminated = (status == OK);
1162 dumpsys.stopDumpThread(dumpTerminated);
1163 }
1164 ZipWriter::FileEntry file_entry;
1165 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001166
1167 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1168 std::chrono::steady_clock::now() - start);
1169 if (elapsed_duration > timeout) {
1170 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1171 elapsed_duration.count());
1172 break;
1173 }
1174 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001175 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001176}
1177
Nandana Dutta7db6342018-11-21 14:53:34 +00001178// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001179static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001180 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1181 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001182
1183 RETURN_IF_USER_DENIED_CONSENT();
1184
1185 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1186 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001187}
1188
1189// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001190static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001191 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1192 // high priority. Reduce timeout once they are able to dump in a shorter time or
1193 // moved to a parallel task.
1194 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1195 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001196
1197 RETURN_IF_USER_DENIED_CONSENT();
1198
1199 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1200 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001201}
1202
1203// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001204static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001205 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001206
1207 RETURN_IF_USER_DENIED_CONSENT();
1208
1209 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1210 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001211}
1212
Steven Moreland44cd9482018-01-04 16:24:13 -08001213static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001214 if (!ds.IsZipping()) {
1215 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1216 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1217 return;
1218 }
1219 DurationReporter duration_reporter("DUMP HALS");
1220 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001221 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001222
Steven Moreland44cd9482018-01-04 16:24:13 -08001223 using android::hidl::manager::V1_0::IServiceManager;
1224 using android::hardware::defaultServiceManager;
1225
1226 sp<IServiceManager> sm = defaultServiceManager();
1227 if (sm == nullptr) {
1228 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1229 return;
1230 }
1231
1232 auto ret = sm->list([&](const auto& interfaces) {
1233 for (const std::string& interface : interfaces) {
1234 std::string cleanName = interface;
1235 std::replace_if(cleanName.begin(),
1236 cleanName.end(),
1237 [](char c) {
1238 return !isalnum(c) &&
1239 std::string("@-_:.").find(c) == std::string::npos;
1240 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001241 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001242
1243 {
1244 auto fd = android::base::unique_fd(
1245 TEMP_FAILURE_RETRY(open(path.c_str(),
1246 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1247 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1248 if (fd < 0) {
1249 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1250 continue;
1251 }
1252 RunCommandToFd(fd,
1253 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001254 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001255 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1256
1257 bool empty = 0 == lseek(fd, 0, SEEK_END);
1258 if (!empty) {
1259 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1260 }
1261 }
1262
1263 unlink(path.c_str());
1264 }
1265 });
1266
1267 if (!ret.isOk()) {
1268 MYLOGE("Could not list hals from hwservicemanager.\n");
1269 }
1270}
1271
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001272static void DumpExternalFragmentationInfo() {
1273 struct stat st;
1274 if (stat("/proc/buddyinfo", &st) != 0) {
1275 MYLOGE("Unable to dump external fragmentation info\n");
1276 return;
1277 }
1278
1279 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1280 std::ifstream ifs("/proc/buddyinfo");
1281 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1282 for (std::string line; std::getline(ifs, line);) {
1283 std::smatch match_results;
1284 if (std::regex_match(line, match_results, unusable_index_regex)) {
1285 std::stringstream free_pages(std::string{match_results[3]});
1286 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1287 std::istream_iterator<int>());
1288
1289 int total_free_pages = 0;
1290 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1291 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1292 }
1293
1294 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1295 match_results[2].str().c_str());
1296
1297 int usable_free_pages = total_free_pages;
1298 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1299 auto unusable_index = (total_free_pages - usable_free_pages) /
1300 static_cast<double>(total_free_pages);
1301 printf(" %5.3f", unusable_index);
1302 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1303 }
1304
1305 printf("\n");
1306 }
1307 }
1308 printf("\n");
1309}
1310
Nandana Dutt5c390032019-03-12 10:52:56 +00001311// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1312// via the consent they are shown. Ignores other errors that occur while running various
1313// commands. The consent checking is currently done around long running tasks, which happen to
1314// be distributed fairly evenly throughout the function.
1315static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001316 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001317
Nandana Dutt5c390032019-03-12 10:52:56 +00001318 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1319 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1320 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001321 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001322 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001323 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001324 DumpFile("MEMORY INFO", "/proc/meminfo");
1325 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001326 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001327
1328 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1329
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001330 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1331 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1332 DumpFile("SLAB INFO", "/proc/slabinfo");
1333 DumpFile("ZONEINFO", "/proc/zoneinfo");
1334 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1335 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001336 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001337
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001338 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1339 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001340
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001341 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001342 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001343
1344 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1345 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001346
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001347 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001348
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001349 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001350 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001351 struct stat s;
1352 if (stat("/proc/modules", &s) != 0) {
1353 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1354 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001355 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001356 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001357
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001358 if (__android_logger_property_get_bool(
1359 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1360 DoKernelLogcat();
1361 } else {
1362 do_dmesg();
1363 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001364
Felipe Lemef0292972016-11-22 13:57:05 -08001365 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001366
1367 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1368
Jeff Brown1dc94e32014-09-11 14:15:27 -07001369 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001370 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001372 /* Dump Bluetooth HCI logs */
1373 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001374
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001375 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001376 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001377 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001378 }
1379
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001380 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001381
Felipe Lemee184f662016-10-27 10:04:47 -07001382 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001383
Narayan Kamath8f788292017-05-25 13:20:39 +01001384 // NOTE: tombstones are always added as separate entries in the zip archive
1385 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001386 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001387 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001388 if (!tombstones_dumped) {
1389 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001390 }
1391
Jayachandran Ca94c7172017-06-10 15:08:12 -07001392 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393
Chenbo Feng276a3b62018-08-07 11:44:49 -07001394 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1395
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001396 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001397
Jayachandran Ca94c7172017-06-10 15:08:12 -07001398 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001399
1400 dump_route_tables();
1401
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001402 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1403 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1404 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001405
Nandana Dutt5c390032019-03-12 10:52:56 +00001406 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001407
Elliott Hughes23ccc622017-02-28 10:14:22 -08001408 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001409
Jin Qianf334d662017-10-10 14:41:37 -07001410 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001411
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001412 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001413
Colin Crossf45fa6b2012-03-26 12:38:26 -07001414 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001415 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1416 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1417 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1418 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1419 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001420
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001421 /* Add window and surface trace files. */
1422 if (!PropertiesHelper::IsUserBuild()) {
1423 ds.AddDir(WMTRACE_DATA_DIR, false);
1424 }
1425
Nandana Dutt5c390032019-03-12 10:52:56 +00001426 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001427
Steven Moreland7440ddb2016-12-15 16:13:39 -08001428 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001429 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1430 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001431 // su does not exist on user builds, so try running without it.
1432 // This way any implementations of vril-dump that do not require
1433 // root can run on user builds.
1434 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001435 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001436 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001437 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001438 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001439 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001440 }
1441
Felipe Lemed8b94e52016-12-08 10:21:44 -08001442 printf("========================================================\n");
1443 printf("== Android Framework Services\n");
1444 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001445
Nandana Dutt5c390032019-03-12 10:52:56 +00001446 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001447
Felipe Lemed8b94e52016-12-08 10:21:44 -08001448 printf("========================================================\n");
1449 printf("== Checkins\n");
1450 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001451
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001452 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001453
1454 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1455
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001456 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1457 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1458 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1459 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001460
Felipe Lemed8b94e52016-12-08 10:21:44 -08001461 printf("========================================================\n");
1462 printf("== Running Application Activities\n");
1463 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001464
Makoto Onuki60780982018-04-16 15:34:00 -07001465 // The following dumpsys internally collects output from running apps, so it can take a long
1466 // time. So let's extend the timeout.
1467
1468 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1469
1470 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001471
Felipe Lemed8b94e52016-12-08 10:21:44 -08001472 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001473 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001474 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001475
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001476 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001477 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001478
Felipe Lemed8b94e52016-12-08 10:21:44 -08001479 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001480 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001481 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001482
Makoto Onuki60780982018-04-16 15:34:00 -07001483 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1484 DUMPSYS_COMPONENTS_OPTIONS);
1485
1486 printf("========================================================\n");
1487 printf("== Running Application Providers (platform)\n");
1488 printf("========================================================\n");
1489
1490 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1491 DUMPSYS_COMPONENTS_OPTIONS);
1492
1493 printf("========================================================\n");
1494 printf("== Running Application Providers (non-platform)\n");
1495 printf("========================================================\n");
1496
1497 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1498 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001499
Adrian Roos8b397ab2017-04-04 16:35:44 -07001500 printf("========================================================\n");
1501 printf("== Dropbox crashes\n");
1502 printf("========================================================\n");
1503
1504 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1505 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1506
Felipe Lemed8b94e52016-12-08 10:21:44 -08001507 printf("========================================================\n");
1508 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1509 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1510 printf("========================================================\n");
1511 printf("== dumpstate: done (id %d)\n", ds.id_);
1512 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001513
1514 printf("========================================================\n");
1515 printf("== Obtaining statsd metadata\n");
1516 printf("========================================================\n");
1517 // This differs from the usual dumpsys stats, which is the stats report data.
1518 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001519
1520 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1521
Nandana Dutt5c390032019-03-12 10:52:56 +00001522 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001523}
1524
Nandana Dutt5c390032019-03-12 10:52:56 +00001525/*
1526 * Dumps state for the default case; drops root after it's no longer necessary.
1527 *
1528 * Returns RunStatus::OK if everything went fine.
1529 * Returns RunStatus::ERROR if there was an error.
1530 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1531 * with the caller.
1532 */
1533static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001534 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001535 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001536 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001537
1538 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001539 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001540
1541 /* Run some operations that require root. */
1542 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1543 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1544
1545 ds.AddDir(RECOVERY_DIR, true);
1546 ds.AddDir(RECOVERY_DATA_DIR, true);
1547 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1548 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1549 if (!PropertiesHelper::IsUserBuild()) {
1550 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1551 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1552 }
1553 add_mountinfo();
1554 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001555 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001556
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001557 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001558 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1559
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001560 // Dump IPsec stats. No keys are exposed here.
1561 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1562
Nandana Dutt4be45d12018-09-26 15:04:23 +01001563 // Run ss as root so we can see socket marks.
1564 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1565
1566 // Run iotop as root to show top 100 IO threads
1567 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1568
Erick Reyese68df822019-02-11 14:46:36 -08001569 // Gather shared memory buffer info if the product implements it
1570 struct stat st;
1571 if (!stat("/product/bin/dmabuf_dump", &st)) {
1572 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1573 }
1574
Nandana Dutt4be45d12018-09-26 15:04:23 +01001575 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001576 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001577 }
1578
Nandana Dutt5c390032019-03-12 10:52:56 +00001579 RETURN_IF_USER_DENIED_CONSENT();
1580 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001581}
1582
mukesh agrawal253dad42018-01-23 21:59:59 -08001583// This method collects common dumpsys for telephony and wifi
1584static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001585 DumpIpTablesAsRoot();
1586
Jayachandran C69968272019-07-08 09:46:05 -07001587 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1588
Jayachandran Ca94c7172017-06-10 15:08:12 -07001589 if (!DropRootUser()) {
1590 return;
1591 }
1592
1593 do_dmesg();
1594 DoLogcat();
1595 DumpPacketStats();
1596 DoKmsg();
1597 DumpIpAddrAndRules();
1598 dump_route_tables();
Jayachandran C69968272019-07-08 09:46:05 -07001599 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001600
1601 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1602 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001603}
1604
1605// This method collects dumpsys for telephony debugging only
1606static void DumpstateTelephonyOnly() {
1607 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001608 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001609
1610 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001611
1612 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1613
1614 printf("========================================================\n");
1615 printf("== Android Framework Services\n");
1616 printf("========================================================\n");
1617
Vishnu Nair652cc802017-11-30 15:18:30 -08001618 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1619 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001620 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1621 SEC_TO_MSEC(10));
1622 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001623 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1624 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001625 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1626 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001627 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1628 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001629
1630 printf("========================================================\n");
1631 printf("== Running Application Services\n");
1632 printf("========================================================\n");
1633
1634 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1635
1636 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001637 printf("== Running Application Services (non-platform)\n");
1638 printf("========================================================\n");
1639
1640 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1641 DUMPSYS_COMPONENTS_OPTIONS);
1642
1643 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001644 printf("== Checkins\n");
1645 printf("========================================================\n");
1646
1647 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1648
1649 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001650 printf("== dumpstate: done (id %d)\n", ds.id_);
1651 printf("========================================================\n");
1652}
1653
mukesh agrawal253dad42018-01-23 21:59:59 -08001654// This method collects dumpsys for wifi debugging only
1655static void DumpstateWifiOnly() {
1656 DurationReporter duration_reporter("DUMPSTATE");
1657
1658 DumpstateRadioCommon();
1659
1660 printf("========================================================\n");
1661 printf("== Android Framework Services\n");
1662 printf("========================================================\n");
1663
1664 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1665 SEC_TO_MSEC(10));
1666 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1667 SEC_TO_MSEC(10));
1668
1669 printf("========================================================\n");
1670 printf("== dumpstate: done (id %d)\n", ds.id_);
1671 printf("========================================================\n");
1672}
1673
Nandana Duttcf419a72019-03-14 10:40:17 +00001674Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001675 DurationReporter duration_reporter("DUMP TRACES");
1676
1677 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1678 const size_t buf_size = temp_file_pattern.length() + 1;
1679 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1680 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1681
1682 // Create a new, empty file to receive all trace dumps.
1683 //
1684 // TODO: This can be simplified once we remove support for the old style
1685 // dumps. We can have a file descriptor passed in to dump_traces instead
1686 // of creating a file, closing it and then reopening it again.
1687 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1688 if (fd < 0) {
1689 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001690 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001691 }
1692
1693 // Nobody should have access to this temporary file except dumpstate, but we
1694 // temporarily grant 'read' to 'others' here because this file is created
1695 // when tombstoned is still running as root, but dumped after dropping. This
1696 // can go away once support for old style dumping has.
1697 const int chmod_ret = fchmod(fd, 0666);
1698 if (chmod_ret < 0) {
1699 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001700 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001701 }
1702
1703 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1704 if (proc.get() == nullptr) {
1705 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001706 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001707 }
1708
1709 // Number of times process dumping has timed out. If we encounter too many
1710 // failures, we'll give up.
1711 int timeout_failures = 0;
1712 bool dalvik_found = false;
1713
1714 const std::set<int> hal_pids = get_interesting_hal_pids();
1715
1716 struct dirent* d;
1717 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001718 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001719 int pid = atoi(d->d_name);
1720 if (pid <= 0) {
1721 continue;
1722 }
1723
1724 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1725 std::string exe;
1726 if (!android::base::Readlink(link_name, &exe)) {
1727 continue;
1728 }
1729
1730 bool is_java_process;
1731 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1732 // Don't bother dumping backtraces for the zygote.
1733 if (IsZygote(pid)) {
1734 continue;
1735 }
1736
1737 dalvik_found = true;
1738 is_java_process = true;
1739 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1740 is_java_process = false;
1741 } else {
1742 // Probably a native process we don't care about, continue.
1743 continue;
1744 }
1745
1746 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1747 if (timeout_failures == 3) {
1748 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1749 break;
1750 }
1751
1752 const uint64_t start = Nanotime();
1753 const int ret = dump_backtrace_to_file_timeout(
1754 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1755 is_java_process ? 5 : 20, fd);
1756
1757 if (ret == -1) {
1758 // For consistency, the header and footer to this message match those
1759 // dumped by debuggerd in the success case.
1760 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1761 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1762 dprintf(fd, "---- end %d ----", pid);
1763 timeout_failures++;
1764 continue;
1765 }
1766
1767 // We've successfully dumped stack traces, reset the failure count
1768 // and write a summary of the elapsed time to the file and continue with the
1769 // next process.
1770 timeout_failures = 0;
1771
1772 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1773 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1774 }
1775
1776 if (!dalvik_found) {
1777 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1778 }
1779
Nandana Duttcf419a72019-03-14 10:40:17 +00001780 *path = file_name_buf.release();
1781 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001782}
1783
Felipe Leme6f674ae2016-11-18 17:10:33 -08001784void Dumpstate::DumpstateBoard() {
1785 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001786 printf("========================================================\n");
1787 printf("== Board\n");
1788 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001789
Felipe Leme6f674ae2016-11-18 17:10:33 -08001790 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001791 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001792 return;
1793 }
1794
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001795 std::vector<std::string> paths;
1796 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001797 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001798 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1799 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001800 remover.emplace_back(android::base::make_scope_guard(
1801 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001802 }
Jie Song9fbfad02017-06-20 16:29:42 -07001803
Wei Wang587eac92018-04-05 12:17:20 -07001804 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1805 if (dumpstate_device == nullptr) {
1806 MYLOGE("No IDumpstateDevice implementation\n");
1807 return;
1808 }
1809
1810 using ScopedNativeHandle =
1811 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1812 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1813 [](native_handle_t* handle) {
1814 native_handle_close(handle);
1815 native_handle_delete(handle);
1816 });
1817 if (handle == nullptr) {
1818 MYLOGE("Could not create native_handle\n");
1819 return;
1820 }
1821
Nandana Dutt5c390032019-03-12 10:52:56 +00001822 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001823 for (size_t i = 0; i < paths.size(); i++) {
1824 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1825
1826 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1827 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1828 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1829 if (fd < 0) {
1830 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1831 return;
1832 }
1833 handle.get()->data[i] = fd.release();
1834 }
1835
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001836 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001837 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1838 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1839 // and grab whatever dumped
1840 std::packaged_task<bool()>
1841 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001842 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1843 if (!status.isOk()) {
1844 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001845 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001846 }
Wei Wang587eac92018-04-05 12:17:20 -07001847 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001848 });
Wei Wang587eac92018-04-05 12:17:20 -07001849
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001850 auto result = dumpstate_task.get_future();
1851 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001852
1853 constexpr size_t timeout_sec = 30;
1854 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1855 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1856 if (!android::base::SetProperty("ctl.interface_restart",
1857 android::base::StringPrintf("%s/default",
1858 IDumpstateDevice::descriptor))) {
1859 MYLOGE("Couldn't restart dumpstate HAL\n");
1860 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001861 }
Wei Wang587eac92018-04-05 12:17:20 -07001862 // Wait some time for init to kill dumpstate vendor HAL
1863 constexpr size_t killing_timeout_sec = 10;
1864 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1865 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1866 "there might be racing in content\n", killing_timeout_sec);
1867 }
1868
1869 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1870 for (size_t i = 0; i < paths.size(); i++) {
1871 struct stat s;
1872 if (fstat(handle.get()->data[i], &s) == -1) {
1873 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1874 strerror(errno));
1875 file_sizes[i] = -1;
1876 continue;
1877 }
1878 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001879 }
1880
1881 for (size_t i = 0; i < paths.size(); i++) {
1882 if (file_sizes[i] == -1) {
1883 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001884 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001885 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001886 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001887 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001888 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001889 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001890 }
1891
Felipe Lemed8b94e52016-12-08 10:21:44 -08001892 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001893}
1894
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001895static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001896 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001897 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001898 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1899 " -h: display this help message\n"
1900 " -b: play sound file instead of vibrate, at beginning of job\n"
1901 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001902 " -d: append date to filename\n"
1903 " -p: capture screenshot to filename.png\n"
1904 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001905 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001906 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001907 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001908 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001909 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001910 "progress (requires -B)\n"
1911 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001912 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001913 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001914 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001915}
1916
Wei Liuf87959e2016-08-26 14:51:42 -07001917static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001918 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001919}
1920
Felipe Leme1d486fe2016-10-14 18:06:47 -07001921bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001922 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001923 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001924 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001925 // Final timestamp
1926 char date[80];
1927 time_t the_real_now_please_stand_up = time(nullptr);
1928 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001929 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001930 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001931
Felipe Leme9a523ae2016-10-20 15:10:33 -07001932 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001933 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001934 return false;
1935 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001936 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001937 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001938 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001939 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001940
Felipe Leme0f3fb202016-06-10 17:10:53 -07001941 // Add log file (which contains stderr output) to zip...
1942 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001943 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001944 MYLOGE("Failed to add dumpstate log to .zip file\n");
1945 return false;
1946 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001947 // TODO: Should truncate the existing file.
1948 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001949 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1950 return false;
1951 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001952 fprintf(stderr, "\n");
1953
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001954 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001955 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001956 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001957 return false;
1958 }
1959
Felipe Leme1d486fe2016-10-14 18:06:47 -07001960 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1961 ds.zip_file.reset(nullptr);
1962
Felipe Lemee9d2c542016-11-15 11:48:26 -08001963 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001964 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001965
Felipe Leme1e9edc62015-12-21 16:02:13 -08001966 return true;
1967}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001968
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001969static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001970 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1971 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001972 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001973 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001974 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001975 }
1976
1977 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001978 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001979
1980 std::vector<uint8_t> buffer(65536);
1981 while (1) {
1982 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1983 if (bytes_read == 0) {
1984 break;
1985 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001986 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001987 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001988 }
1989
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001990 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001991 }
1992
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001993 uint8_t hash[SHA256_DIGEST_LENGTH];
1994 SHA256_Final(hash, &ctx);
1995
1996 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1997 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001998 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001999 }
2000 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2001 return std::string(hash_buffer);
2002}
2003
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002004static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2005 // clang-format off
2006 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2007 "--receiver-foreground", "--receiver-include-background", "-a", action};
2008 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002009
2010 am.insert(am.end(), args.begin(), args.end());
2011
Felipe Leme8d2410e2017-02-08 09:46:08 -08002012 RunCommand("", am,
2013 CommandOptions::WithTimeout(20)
2014 .Log("Sending broadcast: '%s'\n")
2015 .Always()
2016 .DropRoot()
2017 .RedirectStderr()
2018 .Build());
2019}
2020
Felipe Leme35b8cf12017-02-10 15:47:29 -08002021static void Vibrate(int duration_ms) {
2022 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002023 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002024 CommandOptions::WithTimeout(10)
2025 .Log("Vibrate: '%s'\n")
2026 .Always()
2027 .Build());
2028 // clang-format on
2029}
2030
Nandana Dutt979388e2018-11-30 16:48:55 +00002031static void MaybeResolveSymlink(std::string* path) {
2032 std::string resolved_path;
2033 if (android::base::Readlink(*path, &resolved_path)) {
2034 *path = resolved_path;
2035 }
2036}
2037
Nandana Dutt4be45d12018-09-26 15:04:23 +01002038/*
2039 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2040 * if we are writing zip files and adds the version file.
2041 */
2042static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002043 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2044
Nandana Dutt4be45d12018-09-26 15:04:23 +01002045 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2046 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002047 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002048 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002049 char date[80];
2050 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2051 ds.name_ = date;
2052 } else {
2053 ds.name_ = "undated";
2054 }
2055
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002056 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002057 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002058 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002059 ds.base_name_ += "-wifi";
2060 }
2061
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002062 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002063 ds.screenshot_path_ = ds.GetPath(".png");
2064 }
2065 ds.tmp_path_ = ds.GetPath(".tmp");
2066 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2067
Nandana Dutt54dbd672019-01-11 12:58:05 +00002068 std::string destination = ds.options_->bugreport_fd.get() != -1
2069 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002070 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002071 MYLOGD(
2072 "Bugreport dir: %s\n"
2073 "Base name: %s\n"
2074 "Suffix: %s\n"
2075 "Log path: %s\n"
2076 "Temporary path: %s\n"
2077 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002078 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2079 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002080
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002081 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002082 ds.path_ = ds.GetPath(".zip");
2083 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2084 create_parent_dirs(ds.path_.c_str());
2085 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2086 if (ds.zip_file == nullptr) {
2087 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2088 } else {
2089 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2090 }
2091 ds.AddTextZipEntry("version.txt", ds.version_);
2092 }
2093}
2094
2095/*
2096 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2097 * printing zipped file status, etc.
2098 */
2099static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002100 /* check if user changed the suffix using system properties */
2101 std::string name =
2102 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2103 bool change_suffix = false;
2104 if (!name.empty()) {
2105 /* must whitelist which characters are allowed, otherwise it could cross directories */
2106 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2107 if (std::regex_match(name.c_str(), valid_regex)) {
2108 change_suffix = true;
2109 } else {
2110 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2111 }
2112 }
2113 if (change_suffix) {
2114 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2115 ds.name_ = name;
2116 if (!ds.screenshot_path_.empty()) {
2117 std::string new_screenshot_path = ds.GetPath(".png");
2118 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2119 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2120 new_screenshot_path.c_str(), strerror(errno));
2121 } else {
2122 ds.screenshot_path_ = new_screenshot_path;
2123 }
2124 }
2125 }
2126
2127 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002128 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002129 if (!ds.FinishZipFile()) {
2130 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2131 do_text_file = true;
2132 } else {
2133 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002134 // If the user has changed the suffix, we need to change the zip file name.
2135 std::string new_path = ds.GetPath(".zip");
2136 if (ds.path_ != new_path) {
2137 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2138 if (rename(ds.path_.c_str(), new_path.c_str())) {
2139 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2140 strerror(errno));
2141 } else {
2142 ds.path_ = new_path;
2143 }
2144 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002145 }
2146 }
2147 if (do_text_file) {
2148 ds.path_ = ds.GetPath(".txt");
2149 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2150 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2151 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2152 ds.path_.clear();
2153 }
2154 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002155 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002156 if (do_text_file) {
2157 dprintf(ds.control_socket_fd_,
2158 "FAIL:could not create zip file, check %s "
2159 "for more details\n",
2160 ds.log_path_.c_str());
2161 } else {
2162 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2163 }
2164 }
2165}
2166
2167/* Broadcasts that we are done with the bugreport */
2168static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002169 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002170 if (!ds.path_.empty()) {
2171 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002172 // clang-format off
2173
2174 std::vector<std::string> am_args = {
2175 "--receiver-permission", "android.permission.DUMP",
2176 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2177 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2178 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002179 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002180 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2181 };
2182 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002183 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002184 am_args.push_back("--es");
2185 am_args.push_back("android.intent.extra.SCREENSHOT");
2186 am_args.push_back(ds.screenshot_path_);
2187 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002188 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002189 am_args.push_back("--es");
2190 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002191 am_args.push_back(ds.options_->notification_title);
2192 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002193 am_args.push_back("--es");
2194 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002195 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002196 }
2197 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002198 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002199 am_args.push_back("--es");
2200 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002201 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002202 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2203 } else {
2204 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2205 }
2206 } else {
2207 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2208 }
2209}
2210
Nandana Dutt58d72e22018-11-16 10:30:48 +00002211static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2212 switch (mode) {
2213 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2214 return "BUGREPORT_FULL";
2215 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2216 return "BUGREPORT_INTERACTIVE";
2217 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2218 return "BUGREPORT_REMOTE";
2219 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2220 return "BUGREPORT_WEAR";
2221 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2222 return "BUGREPORT_TELEPHONY";
2223 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2224 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002225 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2226 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002227 }
2228}
2229
2230static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002231 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002232 switch (mode) {
2233 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2234 options->do_broadcast = true;
2235 options->do_fb = true;
2236 break;
2237 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002238 // Currently, the dumpstate binder is only used by Shell to update progress.
2239 options->do_start_service = true;
2240 options->do_progress_updates = true;
2241 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002242 options->do_broadcast = true;
2243 break;
2244 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002245 options->do_vibrate = false;
2246 options->is_remote_mode = true;
2247 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002248 options->do_broadcast = true;
2249 break;
2250 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002251 options->do_start_service = true;
2252 options->do_progress_updates = true;
2253 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002254 options->do_fb = true;
2255 options->do_broadcast = true;
2256 break;
2257 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002258 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002259 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002260 options->do_broadcast = true;
2261 break;
2262 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002263 options->wifi_only = true;
2264 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002265 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002266 options->do_broadcast = true;
2267 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002268 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2269 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002270 }
2271}
2272
2273static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002274 // If the system property is not set, it's assumed to be a default bugreport.
2275 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002276
2277 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2278 if (!extra_options.empty()) {
2279 // Framework uses a system property to override some command-line args.
2280 // Currently, it contains the type of the requested bugreport.
2281 if (extra_options == "bugreportplus") {
2282 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002283 } else if (extra_options == "bugreportfull") {
2284 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002285 } else if (extra_options == "bugreportremote") {
2286 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2287 } else if (extra_options == "bugreportwear") {
2288 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2289 } else if (extra_options == "bugreporttelephony") {
2290 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2291 } else if (extra_options == "bugreportwifi") {
2292 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002293 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002294 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002295 }
2296 // Reset the property
2297 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2298 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002299 return mode;
2300}
2301
2302// TODO: Move away from system properties when we have options passed via binder calls.
2303/* Sets runtime options from the system properties and then clears those properties. */
2304static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2305 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2306 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002307
2308 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2309 if (!options->notification_title.empty()) {
2310 // Reset the property
2311 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2312
Nandana Duttdd8cca32018-11-14 10:10:29 +00002313 options->notification_description =
2314 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002315 if (!options->notification_description.empty()) {
2316 // Reset the property
2317 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2318 }
2319 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2320 options->notification_description.c_str());
2321 }
2322}
2323
Nandana Dutt58d72e22018-11-16 10:30:48 +00002324static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2325 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2326 MYLOGI("do_add_date: %d\n", options.do_add_date);
2327 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2328 MYLOGI("use_socket: %d\n", options.use_socket);
2329 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2330 MYLOGI("do_fb: %d\n", options.do_fb);
2331 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2332 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2333 MYLOGI("show_header_only: %d\n", options.show_header_only);
2334 MYLOGI("do_start_service: %d\n", options.do_start_service);
2335 MYLOGI("telephony_only: %d\n", options.telephony_only);
2336 MYLOGI("wifi_only: %d\n", options.wifi_only);
2337 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002338 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002339 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2340 MYLOGI("args: %s\n", options.args.c_str());
2341 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2342 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2343}
2344
Nandana Dutt54dbd672019-01-11 12:58:05 +00002345void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2346 const android::base::unique_fd& bugreport_fd_in,
2347 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002348 // In the new API world, date is always added; output is always a zip file.
2349 // TODO(111441001): remove these options once they are obsolete.
2350 do_add_date = true;
2351 do_zip_file = true;
2352
Nandana Dutt54dbd672019-01-11 12:58:05 +00002353 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2354 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2355 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002356
2357 extra_options = ModeToString(bugreport_mode);
2358 SetOptionsFromMode(bugreport_mode, this);
2359}
2360
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002361Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2362 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002363 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002364 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002365 switch (c) {
2366 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002367 case 'd': do_add_date = true; break;
2368 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002369 // o=use_outfile not supported anymore.
2370 // TODO(b/111441001): Remove when all callers have migrated.
2371 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002372 case 's': use_socket = true; break;
2373 case 'S': use_control_socket = true; break;
2374 case 'v': show_header_only = true; break;
2375 case 'q': do_vibrate = false; break;
2376 case 'p': do_fb = true; break;
2377 case 'P': do_progress_updates = true; break;
2378 case 'R': is_remote_mode = true; break;
2379 case 'B': do_broadcast = true; break;
2380 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002381 case 'w':
2382 // This was already processed
2383 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002384 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002385 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002386 break;
2387 default:
2388 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002389 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002390 break;
2391 // clang-format on
2392 }
2393 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002394
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002395 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002396 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002397 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002398 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002399 }
2400 }
2401
2402 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2403 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002404
2405 SetOptionsFromProperties(this);
2406 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002407}
2408
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002409bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002410 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002411 return false;
2412 }
2413
Nandana Dutt9a76d202019-01-21 15:56:48 +00002414 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002415 return false;
2416 }
2417
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002418 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002419 return false;
2420 }
2421
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002422 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002423 return false;
2424 }
2425
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002426 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002427 return false;
2428 }
2429 return true;
2430}
2431
Nandana Dutt197661d2018-11-16 16:40:21 +00002432void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2433 options_ = std::move(options);
2434}
2435
Nandana Duttd2f5f082019-01-18 17:13:52 +00002436Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2437 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002438 if (listener_ != nullptr) {
2439 switch (status) {
2440 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002441 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002442 break;
2443 case Dumpstate::RunStatus::HELP:
2444 break;
2445 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002446 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002447 break;
2448 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002449 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2450 break;
2451 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2452 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2453 break;
2454 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2455 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002456 break;
2457 }
2458 }
2459 return status;
2460}
2461
Nandana Dutt979388e2018-11-30 16:48:55 +00002462/*
2463 * Dumps relevant information to a bugreport based on the given options.
2464 *
2465 * The bugreport can be dumped to a file or streamed to a socket.
2466 *
2467 * How dumping to file works:
2468 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2469 * stderr is redirected a log file.
2470 *
2471 * The temporary bugreport is then populated via printfs, dumping contents of files and
2472 * output of commands to stdout.
2473 *
2474 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2475 * text file.
2476 *
2477 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2478 * gets added to the archive.
2479 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002480 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2481 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002482 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002483Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2484 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002485 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002486 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002487 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002488 return RunStatus::INVALID_INPUT;
2489 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002490 /* set as high priority, and protect from OOM killer */
2491 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002492
Felipe Lemed071c682016-10-20 16:48:00 -07002493 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002494 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002495 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002496 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002497 } else {
2498 /* fallback to kernels <= 2.6.35 */
2499 oom_adj = fopen("/proc/self/oom_adj", "we");
2500 if (oom_adj) {
2501 fputs("-17", oom_adj);
2502 fclose(oom_adj);
2503 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002504 }
2505
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002506 if (version_ == VERSION_DEFAULT) {
2507 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002508 }
2509
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002510 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002511 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002512 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002513 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002514 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002515 }
2516
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002517 if (options_->show_header_only) {
2518 PrintHeader();
2519 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002520 }
2521
Nandana Duttd2f5f082019-01-18 17:13:52 +00002522 if (options_->bugreport_fd.get() != -1) {
2523 // If the output needs to be copied over to the caller's fd, get user consent.
2524 android::String16 package(calling_package.c_str());
2525 CheckUserConsent(calling_uid, package);
2526 }
2527
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002528 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002529 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002530
2531 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002532 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002533 is_redirecting
2534 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2535 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002536 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002537
Felipe Lemed071c682016-10-20 16:48:00 -07002538 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002539 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002540 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002541 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2542
2543 MYLOGI("begin\n");
2544
Sahana Raof35ed432019-07-12 10:47:52 +01002545 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2546 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2547 } else {
2548 // Wake lock will be released automatically on process death
2549 MYLOGD("Wake lock acquired.\n");
2550 }
2551
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002552 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002553
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002554 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002555 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002556 MYLOGI("Starting 'dumpstate' service\n");
2557 android::status_t ret;
2558 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2559 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2560 }
2561 }
2562
Felipe Lemef0292972016-11-22 13:57:05 -08002563 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002564 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2565 }
2566
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002567 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2568 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002569
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002570 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002571
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002572 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002573
Christopher Ferrised9354f2014-10-01 17:35:01 -07002574 // If we are going to use a socket, do it as early as possible
2575 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002576 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002577 if (!redirect_to_socket(stdout, "dumpstate")) {
2578 return ERROR;
2579 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002580 }
2581
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002582 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002583 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002584 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002585 if (control_socket_fd_ == -1) {
2586 return ERROR;
2587 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002588 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002589 }
2590
Felipe Leme71bbfc52015-11-23 14:14:51 -08002591 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002592 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002593
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002594 if (options_->do_progress_updates) {
2595 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002596 // clang-format off
2597 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002598 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002599 "--es", "android.intent.extra.NAME", name_,
2600 "--ei", "android.intent.extra.ID", std::to_string(id_),
2601 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2602 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002603 };
2604 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002605 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002606 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002607 if (options_->use_control_socket) {
2608 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002609 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002610 }
2611 }
2612
Nick Kralevichf3599b32016-01-25 15:05:16 -08002613 /* read /proc/cmdline before dropping root */
2614 FILE *cmdline = fopen("/proc/cmdline", "re");
2615 if (cmdline) {
2616 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2617 fclose(cmdline);
2618 }
2619
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002620 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002621 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002622 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002623
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002624 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002625 MYLOGI("taking early screenshot\n");
2626 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002627 }
2628
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002629 if (options_->do_zip_file && zip_file != nullptr) {
2630 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2631 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002632 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002633 }
2634 }
2635
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002636 int dup_stdout_fd;
2637 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002638 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002639 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002640 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002641 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2642 return ERROR;
2643 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002644 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2645 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2646 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002647 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002648
2649 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2650 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002651 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002652 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002653 /* TODO: rather than generating a text file now and zipping it later,
2654 it would be more efficient to redirect stdout to the zip entry
2655 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002656 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2657 return ERROR;
2658 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002659 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002660 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002661 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002662 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002663 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002664
2665 // Don't buffer stdout
2666 setvbuf(stdout, nullptr, _IONBF, 0);
2667
Felipe Leme608385d2016-02-01 10:35:38 -08002668 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2669 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002670 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002671 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002672
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002673 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002674 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002675 DumpstateBoard();
2676 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002677 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002678 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002679 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002680 RunStatus s = DumpstateDefault();
2681 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002682 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002683 HandleUserConsentDenied();
2684 }
2685 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002686 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002687 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002688
Felipe Leme55b42a62015-11-10 17:39:08 -08002689 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002690 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002691 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002692 }
2693
Nandana Duttd2f5f082019-01-18 17:13:52 +00002694 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002695 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002696 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002697 }
2698
Nandana Duttd2f5f082019-01-18 17:13:52 +00002699 // Share the final file with the caller if the user has consented.
2700 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2701 if (options_->bugreport_fd.get() != -1) {
2702 status = CopyBugreportIfUserConsented();
2703 if (status != Dumpstate::RunStatus::OK &&
2704 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2705 // Do an early return if there were errors. We make an exception for consent
2706 // timing out because it's possible the user got distracted. In this case the
2707 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002708 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002709 return status;
2710 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002711 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002712 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2713 options_->screenshot_fd.get());
2714 if (copy_succeeded) {
2715 android::os::UnlinkAndLogOnError(screenshot_path_);
2716 }
2717 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002718 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2719 MYLOGI(
2720 "Did not receive user consent yet."
2721 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002722 const String16 incidentcompanion("incidentcompanion");
2723 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2724 if (ics != nullptr) {
2725 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2726 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2727 consent_callback_.get());
2728 } else {
2729 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2730 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002731 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002732 }
2733
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002734 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002735 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002736 for (int i = 0; i < 3; i++) {
2737 Vibrate(75);
2738 usleep((75 + 50) * 1000);
2739 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002740 }
2741
Jeff Brown1dc94e32014-09-11 14:15:27 -07002742 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002743 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002744 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002745 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002746 }
2747
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002748 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2749 progress_->GetInitialMax());
2750 progress_->Save();
2751 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002752
Felipe Leme107a05f2016-03-08 15:11:15 -08002753 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002754 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002755 }
2756
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002757 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002758 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002759 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002760 }
2761
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002762 tombstone_data_.clear();
2763 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002764
Nandana Duttd2f5f082019-01-18 17:13:52 +00002765 return (consent_callback_ != nullptr &&
2766 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2767 ? USER_CONSENT_TIMED_OUT
2768 : RunStatus::OK;
2769}
2770
2771void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2772 consent_callback_ = new ConsentCallback();
2773 const String16 incidentcompanion("incidentcompanion");
2774 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2775 if (ics != nullptr) {
2776 MYLOGD("Checking user consent via incidentcompanion service\n");
2777 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002778 calling_uid, calling_package, String16(), String16(),
2779 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002780 } else {
2781 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2782 }
2783}
2784
Nandana Dutt5c390032019-03-12 10:52:56 +00002785bool Dumpstate::IsUserConsentDenied() const {
2786 return ds.consent_callback_ != nullptr &&
2787 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2788}
2789
Nandana Duttd2f5f082019-01-18 17:13:52 +00002790void Dumpstate::CleanupFiles() {
2791 android::os::UnlinkAndLogOnError(tmp_path_);
2792 android::os::UnlinkAndLogOnError(screenshot_path_);
2793 android::os::UnlinkAndLogOnError(path_);
2794}
2795
2796Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2797 MYLOGD("User denied consent; deleting files and returning\n");
2798 CleanupFiles();
2799 return USER_CONSENT_DENIED;
2800}
2801
2802Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2803 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2804 // user consent.
2805 UserConsentResult consent_result = consent_callback_->getResult();
2806 if (consent_result == UserConsentResult::UNAVAILABLE) {
2807 // User has not responded yet.
2808 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2809 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2810 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2811 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2812 sleep(delay_seconds);
2813 }
2814 consent_result = consent_callback_->getResult();
2815 }
2816 if (consent_result == UserConsentResult::DENIED) {
2817 // User has explicitly denied sharing with the app. To be safe delete the
2818 // internal bugreport & tmp files.
2819 return HandleUserConsentDenied();
2820 }
2821 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002822 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2823 if (copy_succeeded) {
2824 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002825 }
2826 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2827 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2828 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2829 // Since we do not have user consent to share the bugreport it does not get
2830 // copied over to the calling app but remains in the internal directory from
2831 // where the user can manually pull it.
2832 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2833 }
2834 // Unknown result; must be a programming error.
2835 MYLOGE("Unknown user consent result:%d\n", consent_result);
2836 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002837}
2838
Nandana Duttf02564e2019-02-15 15:24:24 +00002839Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002840 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2841 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2842 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002843 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002844 // When directly running dumpstate binary, the output is not expected to be written
2845 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002846 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002847
2848 // calling_uid and calling_package are for user consent to share the bugreport with
2849 // an app; they are irrelvant here because bugreport is only written to a local
2850 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002851 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002852 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002853 return status;
2854}
2855
2856/* Main entry point for dumpstate binary. */
2857int run_main(int argc, char* argv[]) {
2858 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002859
2860 switch (status) {
2861 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002862 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002863 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002864 ShowUsage();
2865 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002866 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002867 fprintf(stderr, "Invalid combination of args\n");
2868 ShowUsage();
2869 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002870 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002871 FALLTHROUGH_INTENDED;
2872 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2873 FALLTHROUGH_INTENDED;
2874 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002875 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002876 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002877}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002878
2879// TODO(111441001): Default DumpOptions to sensible values.
2880Dumpstate::Dumpstate(const std::string& version)
2881 : pid_(getpid()),
2882 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002883 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002884 version_(version),
2885 now_(time(nullptr)) {
2886}
2887
2888Dumpstate& Dumpstate::GetInstance() {
2889 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2890 return singleton_;
2891}
2892
Nandana Dutt8d945c02019-08-14 13:30:07 +01002893DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2894 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002895 if (!title_.empty()) {
2896 started_ = Nanotime();
2897 }
2898}
2899
2900DurationReporter::~DurationReporter() {
2901 if (!title_.empty()) {
2902 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002903 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002904 return;
2905 }
2906 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2907 if (logcat_only_) {
2908 return;
2909 }
2910 // Use "Yoda grammar" to make it easier to grep|sort sections.
2911 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2912 }
2913}
2914
2915const int32_t Progress::kDefaultMax = 5000;
2916
2917Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2918}
2919
2920Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2921 : Progress(initial_max, growth_factor, "") {
2922 progress_ = progress;
2923}
2924
2925Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2926 : initial_max_(initial_max),
2927 progress_(0),
2928 max_(initial_max),
2929 growth_factor_(growth_factor),
2930 n_runs_(0),
2931 average_max_(0),
2932 path_(path) {
2933 if (!path_.empty()) {
2934 Load();
2935 }
2936}
2937
2938void Progress::Load() {
2939 MYLOGD("Loading stats from %s\n", path_.c_str());
2940 std::string content;
2941 if (!android::base::ReadFileToString(path_, &content)) {
2942 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2943 return;
2944 }
2945 if (content.empty()) {
2946 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2947 return;
2948 }
2949 std::vector<std::string> lines = android::base::Split(content, "\n");
2950
2951 if (lines.size() < 1) {
2952 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2953 (int)lines.size(), max_);
2954 return;
2955 }
2956 char* ptr;
2957 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2958 average_max_ = strtol(ptr, nullptr, 10);
2959 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2960 average_max_ > STATS_MAX_AVERAGE) {
2961 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2962 initial_max_ = Progress::kDefaultMax;
2963 } else {
2964 initial_max_ = average_max_;
2965 }
2966 max_ = initial_max_;
2967
2968 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2969}
2970
2971void Progress::Save() {
2972 int32_t total = n_runs_ * average_max_ + progress_;
2973 int32_t runs = n_runs_ + 1;
2974 int32_t average = floor(((float)total) / runs);
2975 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2976 path_.c_str());
2977 if (path_.empty()) {
2978 return;
2979 }
2980
2981 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2982 if (!android::base::WriteStringToFile(content, path_)) {
2983 MYLOGE("Could not save stats on %s\n", path_.c_str());
2984 }
2985}
2986
2987int32_t Progress::Get() const {
2988 return progress_;
2989}
2990
2991bool Progress::Inc(int32_t delta_sec) {
2992 bool changed = false;
2993 if (delta_sec >= 0) {
2994 progress_ += delta_sec;
2995 if (progress_ > max_) {
2996 int32_t old_max = max_;
2997 max_ = floor((float)progress_ * growth_factor_);
2998 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2999 changed = true;
3000 }
3001 }
3002 return changed;
3003}
3004
3005int32_t Progress::GetMax() const {
3006 return max_;
3007}
3008
3009int32_t Progress::GetInitialMax() const {
3010 return initial_max_;
3011}
3012
3013void Progress::Dump(int fd, const std::string& prefix) const {
3014 const char* pr = prefix.c_str();
3015 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3016 dprintf(fd, "%smax: %d\n", pr, max_);
3017 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3018 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3019 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3020 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3021 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3022}
3023
3024bool Dumpstate::IsZipping() const {
3025 return zip_writer_ != nullptr;
3026}
3027
3028std::string Dumpstate::GetPath(const std::string& suffix) const {
3029 return GetPath(bugreport_internal_dir_, suffix);
3030}
3031
3032std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3033 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3034 name_.c_str(), suffix.c_str());
3035}
3036
3037void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3038 progress_ = std::move(progress);
3039}
3040
3041void for_each_userid(void (*func)(int), const char *header) {
3042 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3043 "for_each_userid(%s)", header);
3044 DurationReporter duration_reporter(title);
3045 if (PropertiesHelper::IsDryRun()) return;
3046
3047 DIR *d;
3048 struct dirent *de;
3049
3050 if (header) printf("\n------ %s ------\n", header);
3051 func(0);
3052
3053 if (!(d = opendir("/data/system/users"))) {
3054 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3055 return;
3056 }
3057
3058 while ((de = readdir(d))) {
3059 int userid;
3060 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3061 continue;
3062 }
3063 func(userid);
3064 }
3065
3066 closedir(d);
3067}
3068
3069static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3070 DIR *d;
3071 struct dirent *de;
3072
3073 if (!(d = opendir("/proc"))) {
3074 printf("Failed to open /proc (%s)\n", strerror(errno));
3075 return;
3076 }
3077
3078 if (header) printf("\n------ %s ------\n", header);
3079 while ((de = readdir(d))) {
3080 if (ds.IsUserConsentDenied()) {
3081 MYLOGE(
3082 "Returning early because user denied consent to share bugreport with calling app.");
3083 closedir(d);
3084 return;
3085 }
3086 int pid;
3087 int fd;
3088 char cmdpath[255];
3089 char cmdline[255];
3090
3091 if (!(pid = atoi(de->d_name))) {
3092 continue;
3093 }
3094
3095 memset(cmdline, 0, sizeof(cmdline));
3096
3097 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3098 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3099 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3100 close(fd);
3101 if (cmdline[0]) {
3102 helper(pid, cmdline, arg);
3103 continue;
3104 }
3105 }
3106
3107 // if no cmdline, a kernel thread has comm
3108 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3109 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3110 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3111 close(fd);
3112 if (cmdline[1]) {
3113 cmdline[0] = '[';
3114 size_t len = strcspn(cmdline, "\f\b\r\n");
3115 cmdline[len] = ']';
3116 cmdline[len+1] = '\0';
3117 }
3118 }
3119 if (!cmdline[0]) {
3120 strcpy(cmdline, "N/A");
3121 }
3122 helper(pid, cmdline, arg);
3123 }
3124
3125 closedir(d);
3126}
3127
3128static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3129 for_each_pid_func *func = (for_each_pid_func*) arg;
3130 func(pid, cmdline);
3131}
3132
3133void for_each_pid(for_each_pid_func func, const char *header) {
3134 std::string title = header == nullptr ? "for_each_pid"
3135 : android::base::StringPrintf("for_each_pid(%s)", header);
3136 DurationReporter duration_reporter(title);
3137 if (PropertiesHelper::IsDryRun()) return;
3138
3139 __for_each_pid(for_each_pid_helper, header, (void *) func);
3140}
3141
3142static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3143 DIR *d;
3144 struct dirent *de;
3145 char taskpath[255];
3146 for_each_tid_func *func = (for_each_tid_func *) arg;
3147
3148 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3149
3150 if (!(d = opendir(taskpath))) {
3151 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3152 return;
3153 }
3154
3155 func(pid, pid, cmdline);
3156
3157 while ((de = readdir(d))) {
3158 if (ds.IsUserConsentDenied()) {
3159 MYLOGE(
3160 "Returning early because user denied consent to share bugreport with calling app.");
3161 closedir(d);
3162 return;
3163 }
3164 int tid;
3165 int fd;
3166 char commpath[255];
3167 char comm[255];
3168
3169 if (!(tid = atoi(de->d_name))) {
3170 continue;
3171 }
3172
3173 if (tid == pid)
3174 continue;
3175
3176 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3177 memset(comm, 0, sizeof(comm));
3178 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3179 strcpy(comm, "N/A");
3180 } else {
3181 char *c;
3182 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3183 close(fd);
3184
3185 c = strrchr(comm, '\n');
3186 if (c) {
3187 *c = '\0';
3188 }
3189 }
3190 func(pid, tid, comm);
3191 }
3192
3193 closedir(d);
3194}
3195
3196void for_each_tid(for_each_tid_func func, const char *header) {
3197 std::string title = header == nullptr ? "for_each_tid"
3198 : android::base::StringPrintf("for_each_tid(%s)", header);
3199 DurationReporter duration_reporter(title);
3200
3201 if (PropertiesHelper::IsDryRun()) return;
3202
3203 __for_each_pid(for_each_tid_helper, header, (void *) func);
3204}
3205
3206void show_wchan(int pid, int tid, const char *name) {
3207 if (PropertiesHelper::IsDryRun()) return;
3208
3209 char path[255];
3210 char buffer[255];
3211 int fd, ret, save_errno;
3212 char name_buffer[255];
3213
3214 memset(buffer, 0, sizeof(buffer));
3215
3216 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3217 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3218 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3219 return;
3220 }
3221
3222 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3223 save_errno = errno;
3224 close(fd);
3225
3226 if (ret < 0) {
3227 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3228 return;
3229 }
3230
3231 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3232 pid == tid ? 0 : 3, "", name);
3233
3234 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3235
3236 return;
3237}
3238
3239// print time in centiseconds
3240static void snprcent(char *buffer, size_t len, size_t spc,
3241 unsigned long long time) {
3242 static long hz; // cache discovered hz
3243
3244 if (hz <= 0) {
3245 hz = sysconf(_SC_CLK_TCK);
3246 if (hz <= 0) {
3247 hz = 1000;
3248 }
3249 }
3250
3251 // convert to centiseconds
3252 time = (time * 100 + (hz / 2)) / hz;
3253
3254 char str[16];
3255
3256 snprintf(str, sizeof(str), " %llu.%02u",
3257 time / 100, (unsigned)(time % 100));
3258 size_t offset = strlen(buffer);
3259 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3260 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3261}
3262
3263// print permille as a percent
3264static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3265 char str[16];
3266
3267 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3268 size_t offset = strlen(buffer);
3269 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3270 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3271}
3272
3273void show_showtime(int pid, const char *name) {
3274 if (PropertiesHelper::IsDryRun()) return;
3275
3276 char path[255];
3277 char buffer[1023];
3278 int fd, ret, save_errno;
3279
3280 memset(buffer, 0, sizeof(buffer));
3281
3282 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3283 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3284 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3285 return;
3286 }
3287
3288 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3289 save_errno = errno;
3290 close(fd);
3291
3292 if (ret < 0) {
3293 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3294 return;
3295 }
3296
3297 // field 14 is utime
3298 // field 15 is stime
3299 // field 42 is iotime
3300 unsigned long long utime = 0, stime = 0, iotime = 0;
3301 if (sscanf(buffer,
3302 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3303 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3304 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3305 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3306 &utime, &stime, &iotime) != 3) {
3307 return;
3308 }
3309
3310 unsigned long long total = utime + stime;
3311 if (!total) {
3312 return;
3313 }
3314
3315 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3316 if (permille > 1000) {
3317 permille = 1000;
3318 }
3319
3320 // try to beautify and stabilize columns at <80 characters
3321 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3322 if ((name[0] != '[') || utime) {
3323 snprcent(buffer, sizeof(buffer), 57, utime);
3324 }
3325 snprcent(buffer, sizeof(buffer), 65, stime);
3326 if ((name[0] != '[') || iotime) {
3327 snprcent(buffer, sizeof(buffer), 73, iotime);
3328 }
3329 if (iotime) {
3330 snprdec(buffer, sizeof(buffer), 79, permille);
3331 }
3332 puts(buffer); // adds a trailing newline
3333
3334 return;
3335}
3336
3337void do_dmesg() {
3338 const char *title = "KERNEL LOG (dmesg)";
3339 DurationReporter duration_reporter(title);
3340 printf("------ %s ------\n", title);
3341
3342 if (PropertiesHelper::IsDryRun()) return;
3343
3344 /* Get size of kernel buffer */
3345 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3346 if (size <= 0) {
3347 printf("Unexpected klogctl return value: %d\n\n", size);
3348 return;
3349 }
3350 char *buf = (char *) malloc(size + 1);
3351 if (buf == nullptr) {
3352 printf("memory allocation failed\n\n");
3353 return;
3354 }
3355 int retval = klogctl(KLOG_READ_ALL, buf, size);
3356 if (retval < 0) {
3357 printf("klogctl failure\n\n");
3358 free(buf);
3359 return;
3360 }
3361 buf[retval] = '\0';
3362 printf("%s\n\n", buf);
3363 free(buf);
3364 return;
3365}
3366
3367void do_showmap(int pid, const char *name) {
3368 char title[255];
3369 char arg[255];
3370
3371 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3372 snprintf(arg, sizeof(arg), "%d", pid);
3373 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3374}
3375
3376int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3377 DurationReporter duration_reporter(title);
3378
3379 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3380
3381 UpdateProgress(WEIGHT_FILE);
3382
3383 return status;
3384}
3385
3386int read_file_as_long(const char *path, long int *output) {
3387 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3388 if (fd < 0) {
3389 int err = errno;
3390 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3391 return -1;
3392 }
3393 char buffer[50];
3394 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3395 if (bytes_read == -1) {
3396 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3397 return -2;
3398 }
3399 if (bytes_read == 0) {
3400 MYLOGE("File %s is empty\n", path);
3401 return -3;
3402 }
3403 *output = atoi(buffer);
3404 return 0;
3405}
3406
3407/* calls skip to gate calling dump_from_fd recursively
3408 * in the specified directory. dump_from_fd defaults to
3409 * dump_file_from_fd above when set to NULL. skip defaults
3410 * to false when set to NULL. dump_from_fd will always be
3411 * called with title NULL.
3412 */
3413int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3414 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3415 DurationReporter duration_reporter(title);
3416 DIR *dirp;
3417 struct dirent *d;
3418 char *newpath = nullptr;
3419 const char *slash = "/";
3420 int retval = 0;
3421
3422 if (!title.empty()) {
3423 printf("------ %s (%s) ------\n", title.c_str(), dir);
3424 }
3425 if (PropertiesHelper::IsDryRun()) return 0;
3426
3427 if (dir[strlen(dir) - 1] == '/') {
3428 ++slash;
3429 }
3430 dirp = opendir(dir);
3431 if (dirp == nullptr) {
3432 retval = -errno;
3433 MYLOGE("%s: %s\n", dir, strerror(errno));
3434 return retval;
3435 }
3436
3437 if (!dump_from_fd) {
3438 dump_from_fd = dump_file_from_fd;
3439 }
3440 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3441 if ((d->d_name[0] == '.')
3442 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3443 || (d->d_name[1] == '\0'))) {
3444 continue;
3445 }
3446 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3447 (d->d_type == DT_DIR) ? "/" : "");
3448 if (!newpath) {
3449 retval = -errno;
3450 continue;
3451 }
3452 if (skip && (*skip)(newpath)) {
3453 continue;
3454 }
3455 if (d->d_type == DT_DIR) {
3456 int ret = dump_files("", newpath, skip, dump_from_fd);
3457 if (ret < 0) {
3458 retval = ret;
3459 }
3460 continue;
3461 }
3462 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3463 if (fd.get() < 0) {
3464 retval = -1;
3465 printf("*** %s: %s\n", newpath, strerror(errno));
3466 continue;
3467 }
3468 (*dump_from_fd)(nullptr, newpath, fd.get());
3469 }
3470 closedir(dirp);
3471 if (!title.empty()) {
3472 printf("\n");
3473 }
3474 return retval;
3475}
3476
3477/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3478 * it's possible to avoid issues where opening the file itself can get
3479 * stuck.
3480 */
3481int dump_file_from_fd(const char *title, const char *path, int fd) {
3482 if (PropertiesHelper::IsDryRun()) return 0;
3483
3484 int flags = fcntl(fd, F_GETFL);
3485 if (flags == -1) {
3486 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3487 return -1;
3488 } else if (!(flags & O_NONBLOCK)) {
3489 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3490 return -1;
3491 }
3492 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3493}
3494
3495int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003496 const CommandOptions& options, bool verbose_duration) {
3497 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003498
3499 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3500
3501 /* TODO: for now we're simplifying the progress calculation by using the
3502 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3503 * where its weight should be much higher proportionally to its timeout.
3504 * Ideally, it should use a options.EstimatedDuration() instead...*/
3505 UpdateProgress(options.Timeout());
3506
3507 return status;
3508}
3509
3510void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3511 const CommandOptions& options, long dumpsysTimeoutMs) {
3512 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3513 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3514 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3515 RunCommand(title, dumpsys, options);
3516}
3517
3518int open_socket(const char *service) {
3519 int s = android_get_control_socket(service);
3520 if (s < 0) {
3521 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3522 return -1;
3523 }
3524 fcntl(s, F_SETFD, FD_CLOEXEC);
3525
3526 // Set backlog to 0 to make sure that queue size will be minimum.
3527 // In Linux, because the minimum queue will be 1, connect() will be blocked
3528 // if the other clients already called connect() and the connection request was not accepted.
3529 if (listen(s, 0) < 0) {
3530 MYLOGE("listen(control socket): %s\n", strerror(errno));
3531 return -1;
3532 }
3533
3534 struct sockaddr addr;
3535 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003536 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003537
3538 // Close socket just after accept(), to make sure that connect() by client will get error
3539 // when the socket is used by the other services.
3540 // There is still a race condition possibility between accept and close, but there is no way
3541 // to close-on-accept atomically.
3542 // See detail; b/123306389#comment25
3543 close(s);
3544
3545 if (fd < 0) {
3546 MYLOGE("accept(control socket): %s\n", strerror(errno));
3547 return -1;
3548 }
3549
3550 return fd;
3551}
3552
3553/* redirect output to a service control socket */
3554bool redirect_to_socket(FILE* redirect, const char* service) {
3555 int fd = open_socket(service);
3556 if (fd == -1) {
3557 return false;
3558 }
3559 fflush(redirect);
3560 // TODO: handle dup2 failure
3561 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3562 close(fd);
3563 return true;
3564}
3565
3566// TODO: should call is_valid_output_file and/or be merged into it.
3567void create_parent_dirs(const char *path) {
3568 char *chp = const_cast<char *> (path);
3569
3570 /* skip initial slash */
3571 if (chp[0] == '/')
3572 chp++;
3573
3574 /* create leading directories, if necessary */
3575 struct stat dir_stat;
3576 while (chp && chp[0]) {
3577 chp = strchr(chp, '/');
3578 if (chp) {
3579 *chp = 0;
3580 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3581 MYLOGI("Creating directory %s\n", path);
3582 if (mkdir(path, 0770)) { /* drwxrwx--- */
3583 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3584 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3585 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3586 }
3587 }
3588 *chp++ = '/';
3589 }
3590 }
3591}
3592
3593bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3594 create_parent_dirs(path);
3595
3596 int fd = TEMP_FAILURE_RETRY(open(path,
3597 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3598 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3599 if (fd < 0) {
3600 MYLOGE("%s: %s\n", path, strerror(errno));
3601 return false;
3602 }
3603
3604 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3605 close(fd);
3606 return true;
3607}
3608
3609bool redirect_to_file(FILE* redirect, char* path) {
3610 return _redirect_to_file(redirect, path, O_TRUNC);
3611}
3612
3613bool redirect_to_existing_file(FILE* redirect, char* path) {
3614 return _redirect_to_file(redirect, path, O_APPEND);
3615}
3616
3617void dump_route_tables() {
3618 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3619 if (PropertiesHelper::IsDryRun()) return;
3620 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3621 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3622 FILE* fp = fopen(RT_TABLES_PATH, "re");
3623 if (!fp) {
3624 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3625 return;
3626 }
3627 char table[16];
3628 // Each line has an integer (the table number), a space, and a string (the table name). We only
3629 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3630 // Add a fixed max limit so this doesn't go awry.
3631 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3632 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3633 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3634 }
3635 fclose(fp);
3636}
3637
3638// TODO: make this function thread safe if sections are generated in parallel.
3639void Dumpstate::UpdateProgress(int32_t delta_sec) {
3640 if (progress_ == nullptr) {
3641 MYLOGE("UpdateProgress: progress_ not set\n");
3642 return;
3643 }
3644
3645 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003646 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003647
3648 // ...but only notifiy listeners when necessary.
3649 if (!options_->do_progress_updates) return;
3650
3651 int progress = progress_->Get();
3652 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003653 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003654
Nandana Duttf02cd782019-06-14 14:25:13 +01003655 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003656 return;
3657 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003658 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003659
3660 if (control_socket_fd_ >= 0) {
3661 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3662 fsync(control_socket_fd_);
3663 }
3664
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003665 if (listener_ != nullptr) {
3666 if (percent % 5 == 0) {
3667 // We don't want to spam logcat, so only log multiples of 5.
3668 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3669 percent);
3670 } else {
3671 // stderr is ignored on normal invocations, but useful when calling
3672 // /system/bin/dumpstate directly for debuggging.
3673 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3674 progress, max, percent);
3675 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003676
3677 listener_->onProgress(percent);
3678 }
3679}
3680
3681void Dumpstate::TakeScreenshot(const std::string& path) {
3682 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3683 int status =
3684 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3685 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3686 if (status == 0) {
3687 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3688 } else {
3689 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3690 }
3691}
3692
3693bool is_dir(const char* pathname) {
3694 struct stat info;
3695 if (stat(pathname, &info) == -1) {
3696 return false;
3697 }
3698 return S_ISDIR(info.st_mode);
3699}
3700
3701time_t get_mtime(int fd, time_t default_mtime) {
3702 struct stat info;
3703 if (fstat(fd, &info) == -1) {
3704 return default_mtime;
3705 }
3706 return info.st_mtime;
3707}