blob: 92b126658a092b3a78d0d9a9dec513d0a8daad92 [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"});
963}
964
Narayan Kamath8f788292017-05-25 13:20:39 +0100965static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
966 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
967 anr_traces_dir.c_str());
968
969 // If we're here, dump_traces_path will always be a temporary file
970 // (created with mkostemp or similar) that contains dumps taken earlier
971 // on in the process.
972 if (dump_traces_path != nullptr) {
973 if (add_to_zip) {
974 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
975 } else {
976 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
977 dump_traces_path);
978 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
979 }
980
981 const int ret = unlink(dump_traces_path);
982 if (ret == -1) {
983 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
984 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700985 }
986 }
987
Narayan Kamathbd863722017-06-01 18:50:12 +0100988 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700989 if (ds.anr_data_.size() > 0) {
990 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100991 "VM TRACES AT LAST ANR", add_to_zip);
992
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100993 // The "last" ANR will always be included as separate entry in the zip file. In addition,
994 // it will be present in the body of the main entry if |add_to_zip| == false.
995 //
996 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700997 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100998 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100999 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001000 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1001 }
1002}
1003
1004static void AddAnrTraceFiles() {
1005 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1006
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001007 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001008
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001009 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001010
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001011 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1012
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001013 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001014 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001015 int i = 0;
1016 while (true) {
1017 const std::string slow_trace_path =
1018 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1019 if (stat(slow_trace_path.c_str(), &st)) {
1020 // No traces file at this index, done with the files.
1021 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001022 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001023 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1024 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001025 }
1026}
1027
Wei Wang509bb5d2017-06-09 14:42:12 -07001028static void DumpBlockStatFiles() {
1029 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001030
Wei Wang1dc1ef52017-06-12 11:28:37 -07001031 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1032
1033 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001034 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1035 return;
1036 }
1037
1038 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001039 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001040 if ((d->d_name[0] == '.')
1041 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1042 || (d->d_name[1] == '\0'))) {
1043 continue;
1044 }
1045 const std::string new_path =
1046 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1047 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1048 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1049 printf("\n");
1050 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001051 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001052}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001053
1054static void DumpPacketStats() {
1055 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1056 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1057 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1058 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1059 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1060}
1061
1062static void DumpIpAddrAndRules() {
1063 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1064 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1065 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1066 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1067 RunCommand("IP RULES", {"ip", "rule", "show"});
1068 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1069}
1070
Nandana Dutt5c390032019-03-12 10:52:56 +00001071static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1072 std::chrono::milliseconds timeout,
1073 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001074 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001075 sp<android::IServiceManager> sm = defaultServiceManager();
1076 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001077 Vector<String16> args;
1078 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001079 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1080 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001081 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001082 std::string path(title);
1083 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001084 size_t bytes_written = 0;
1085 status_t status = dumpsys.startDumpThread(service, args);
1086 if (status == OK) {
1087 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1088 std::chrono::duration<double> elapsed_seconds;
1089 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1090 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001091 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1092 bool dump_complete = (status == OK);
1093 dumpsys.stopDumpThread(dump_complete);
1094 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001095
1096 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1097 std::chrono::steady_clock::now() - start);
1098 if (elapsed_duration > timeout) {
1099 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1100 elapsed_duration.count());
1101 break;
1102 }
1103 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001104 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001105}
1106
Vishnu Nair64afc022018-02-01 15:29:34 -08001107static void RunDumpsysText(const std::string& title, int priority,
1108 std::chrono::milliseconds timeout,
1109 std::chrono::milliseconds service_timeout) {
1110 DurationReporter duration_reporter(title);
1111 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1112 fsync(STDOUT_FILENO);
1113 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1114}
1115
1116/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001117static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1118 std::chrono::milliseconds timeout,
1119 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001120 DurationReporter duration_reporter(title);
1121 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1122 fsync(STDOUT_FILENO);
1123 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1124 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001125
1126 RETURN_IF_USER_DENIED_CONSENT();
1127
1128 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1129 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001130}
1131
Nandana Dutt5c390032019-03-12 10:52:56 +00001132static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1133 std::chrono::milliseconds timeout,
1134 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001135 if (!ds.IsZipping()) {
1136 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001137 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001138 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001139 sp<android::IServiceManager> sm = defaultServiceManager();
1140 Dumpsys dumpsys(sm.get());
1141 Vector<String16> args;
1142 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1143 DurationReporter duration_reporter(title);
1144
1145 auto start = std::chrono::steady_clock::now();
1146 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1147 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001148 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001149 std::string path(kProtoPath);
1150 path.append(String8(service).c_str());
1151 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1152 path.append("_CRITICAL");
1153 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1154 path.append("_HIGH");
1155 }
1156 path.append(kProtoExt);
Vishnu Naire97d6122018-01-18 13:58:56 -08001157 status_t status = dumpsys.startDumpThread(service, args);
1158 if (status == OK) {
1159 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1160 bool dumpTerminated = (status == OK);
1161 dumpsys.stopDumpThread(dumpTerminated);
1162 }
1163 ZipWriter::FileEntry file_entry;
1164 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001165
1166 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1167 std::chrono::steady_clock::now() - start);
1168 if (elapsed_duration > timeout) {
1169 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1170 elapsed_duration.count());
1171 break;
1172 }
1173 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001174 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001175}
1176
Nandana Dutta7db6342018-11-21 14:53:34 +00001177// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001178static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001179 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1180 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001181
1182 RETURN_IF_USER_DENIED_CONSENT();
1183
1184 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1185 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001186}
1187
1188// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001189static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001190 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1191 // high priority. Reduce timeout once they are able to dump in a shorter time or
1192 // moved to a parallel task.
1193 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1194 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001195
1196 RETURN_IF_USER_DENIED_CONSENT();
1197
1198 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1199 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001200}
1201
1202// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001203static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001204 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001205
1206 RETURN_IF_USER_DENIED_CONSENT();
1207
1208 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1209 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001210}
1211
Steven Moreland44cd9482018-01-04 16:24:13 -08001212static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001213 if (!ds.IsZipping()) {
1214 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1215 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1216 return;
1217 }
1218 DurationReporter duration_reporter("DUMP HALS");
1219 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001220 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001221
Steven Moreland44cd9482018-01-04 16:24:13 -08001222 using android::hidl::manager::V1_0::IServiceManager;
1223 using android::hardware::defaultServiceManager;
1224
1225 sp<IServiceManager> sm = defaultServiceManager();
1226 if (sm == nullptr) {
1227 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1228 return;
1229 }
1230
1231 auto ret = sm->list([&](const auto& interfaces) {
1232 for (const std::string& interface : interfaces) {
1233 std::string cleanName = interface;
1234 std::replace_if(cleanName.begin(),
1235 cleanName.end(),
1236 [](char c) {
1237 return !isalnum(c) &&
1238 std::string("@-_:.").find(c) == std::string::npos;
1239 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001240 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001241
1242 {
1243 auto fd = android::base::unique_fd(
1244 TEMP_FAILURE_RETRY(open(path.c_str(),
1245 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1246 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1247 if (fd < 0) {
1248 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1249 continue;
1250 }
1251 RunCommandToFd(fd,
1252 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001253 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001254 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1255
1256 bool empty = 0 == lseek(fd, 0, SEEK_END);
1257 if (!empty) {
1258 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1259 }
1260 }
1261
1262 unlink(path.c_str());
1263 }
1264 });
1265
1266 if (!ret.isOk()) {
1267 MYLOGE("Could not list hals from hwservicemanager.\n");
1268 }
1269}
1270
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001271static void DumpExternalFragmentationInfo() {
1272 struct stat st;
1273 if (stat("/proc/buddyinfo", &st) != 0) {
1274 MYLOGE("Unable to dump external fragmentation info\n");
1275 return;
1276 }
1277
1278 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1279 std::ifstream ifs("/proc/buddyinfo");
1280 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1281 for (std::string line; std::getline(ifs, line);) {
1282 std::smatch match_results;
1283 if (std::regex_match(line, match_results, unusable_index_regex)) {
1284 std::stringstream free_pages(std::string{match_results[3]});
1285 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1286 std::istream_iterator<int>());
1287
1288 int total_free_pages = 0;
1289 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1290 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1291 }
1292
1293 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1294 match_results[2].str().c_str());
1295
1296 int usable_free_pages = total_free_pages;
1297 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1298 auto unusable_index = (total_free_pages - usable_free_pages) /
1299 static_cast<double>(total_free_pages);
1300 printf(" %5.3f", unusable_index);
1301 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1302 }
1303
1304 printf("\n");
1305 }
1306 }
1307 printf("\n");
1308}
1309
Nandana Dutt5c390032019-03-12 10:52:56 +00001310// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1311// via the consent they are shown. Ignores other errors that occur while running various
1312// commands. The consent checking is currently done around long running tasks, which happen to
1313// be distributed fairly evenly throughout the function.
1314static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001315 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001316
Nandana Dutt5c390032019-03-12 10:52:56 +00001317 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1318 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1319 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001320 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001321 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001322 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001323 DumpFile("MEMORY INFO", "/proc/meminfo");
1324 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001325 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001326
1327 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1328
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001329 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1330 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1331 DumpFile("SLAB INFO", "/proc/slabinfo");
1332 DumpFile("ZONEINFO", "/proc/zoneinfo");
1333 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1334 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001335 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001336
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001337 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1338 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001339
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001340 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001341 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001342
1343 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1344 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001345
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001346 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001347
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001348 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001349 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001350 struct stat s;
1351 if (stat("/proc/modules", &s) != 0) {
1352 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1353 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001354 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001355 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001356
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001357 if (__android_logger_property_get_bool(
1358 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1359 DoKernelLogcat();
1360 } else {
1361 do_dmesg();
1362 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001363
Felipe Lemef0292972016-11-22 13:57:05 -08001364 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001365
1366 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1367
Jeff Brown1dc94e32014-09-11 14:15:27 -07001368 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001369 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001370
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001371 /* Dump Bluetooth HCI logs */
1372 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001373
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001374 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001375 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001376 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001377 }
1378
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001379 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001380
Felipe Lemee184f662016-10-27 10:04:47 -07001381 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001382
Narayan Kamath8f788292017-05-25 13:20:39 +01001383 // NOTE: tombstones are always added as separate entries in the zip archive
1384 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001385 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001386 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001387 if (!tombstones_dumped) {
1388 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001389 }
1390
Jayachandran Ca94c7172017-06-10 15:08:12 -07001391 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001392
Chenbo Feng276a3b62018-08-07 11:44:49 -07001393 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1394
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001395 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001396
Jayachandran Ca94c7172017-06-10 15:08:12 -07001397 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001398
1399 dump_route_tables();
1400
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001401 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1402 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1403 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001404
Nandana Dutt5c390032019-03-12 10:52:56 +00001405 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001406
Elliott Hughes23ccc622017-02-28 10:14:22 -08001407 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001408
Jin Qianf334d662017-10-10 14:41:37 -07001409 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001410
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001411 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001412
Colin Crossf45fa6b2012-03-26 12:38:26 -07001413 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001414 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1415 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1416 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1417 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1418 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001419
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001420 /* Add window and surface trace files. */
1421 if (!PropertiesHelper::IsUserBuild()) {
1422 ds.AddDir(WMTRACE_DATA_DIR, false);
1423 }
1424
Nandana Dutt5c390032019-03-12 10:52:56 +00001425 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001426
Steven Moreland7440ddb2016-12-15 16:13:39 -08001427 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001428 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1429 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001430 // su does not exist on user builds, so try running without it.
1431 // This way any implementations of vril-dump that do not require
1432 // root can run on user builds.
1433 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001434 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001435 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001436 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001437 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001438 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001439 }
1440
Felipe Lemed8b94e52016-12-08 10:21:44 -08001441 printf("========================================================\n");
1442 printf("== Android Framework Services\n");
1443 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001444
Nandana Dutt5c390032019-03-12 10:52:56 +00001445 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001446
Felipe Lemed8b94e52016-12-08 10:21:44 -08001447 printf("========================================================\n");
1448 printf("== Checkins\n");
1449 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001450
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001451 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001452
1453 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1454
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001455 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1456 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1457 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1458 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001459
Felipe Lemed8b94e52016-12-08 10:21:44 -08001460 printf("========================================================\n");
1461 printf("== Running Application Activities\n");
1462 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001463
Makoto Onuki60780982018-04-16 15:34:00 -07001464 // The following dumpsys internally collects output from running apps, so it can take a long
1465 // time. So let's extend the timeout.
1466
1467 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1468
1469 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001470
Felipe Lemed8b94e52016-12-08 10:21:44 -08001471 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001472 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001473 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001474
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001475 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001476 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001477
Felipe Lemed8b94e52016-12-08 10:21:44 -08001478 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001479 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001480 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001481
Makoto Onuki60780982018-04-16 15:34:00 -07001482 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1483 DUMPSYS_COMPONENTS_OPTIONS);
1484
1485 printf("========================================================\n");
1486 printf("== Running Application Providers (platform)\n");
1487 printf("========================================================\n");
1488
1489 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1490 DUMPSYS_COMPONENTS_OPTIONS);
1491
1492 printf("========================================================\n");
1493 printf("== Running Application Providers (non-platform)\n");
1494 printf("========================================================\n");
1495
1496 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1497 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001498
Adrian Roos8b397ab2017-04-04 16:35:44 -07001499 printf("========================================================\n");
1500 printf("== Dropbox crashes\n");
1501 printf("========================================================\n");
1502
1503 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1504 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1505
Felipe Lemed8b94e52016-12-08 10:21:44 -08001506 printf("========================================================\n");
1507 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1508 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1509 printf("========================================================\n");
1510 printf("== dumpstate: done (id %d)\n", ds.id_);
1511 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001512
1513 printf("========================================================\n");
1514 printf("== Obtaining statsd metadata\n");
1515 printf("========================================================\n");
1516 // This differs from the usual dumpsys stats, which is the stats report data.
1517 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001518
1519 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1520
Nandana Dutt5c390032019-03-12 10:52:56 +00001521 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001522}
1523
Nandana Dutt5c390032019-03-12 10:52:56 +00001524/*
1525 * Dumps state for the default case; drops root after it's no longer necessary.
1526 *
1527 * Returns RunStatus::OK if everything went fine.
1528 * Returns RunStatus::ERROR if there was an error.
1529 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1530 * with the caller.
1531 */
1532static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001533 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001534 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001535 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001536
1537 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001538 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001539
1540 /* Run some operations that require root. */
1541 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1542 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1543
1544 ds.AddDir(RECOVERY_DIR, true);
1545 ds.AddDir(RECOVERY_DATA_DIR, true);
1546 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1547 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1548 if (!PropertiesHelper::IsUserBuild()) {
1549 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1550 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1551 }
1552 add_mountinfo();
1553 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001554 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001555
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001556 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001557 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1558
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001559 // Dump IPsec stats. No keys are exposed here.
1560 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1561
Nandana Dutt4be45d12018-09-26 15:04:23 +01001562 // Run ss as root so we can see socket marks.
1563 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1564
1565 // Run iotop as root to show top 100 IO threads
1566 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1567
Erick Reyese68df822019-02-11 14:46:36 -08001568 // Gather shared memory buffer info if the product implements it
1569 struct stat st;
1570 if (!stat("/product/bin/dmabuf_dump", &st)) {
1571 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1572 }
1573
Nandana Dutt4be45d12018-09-26 15:04:23 +01001574 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001575 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001576 }
1577
Nandana Dutt5c390032019-03-12 10:52:56 +00001578 RETURN_IF_USER_DENIED_CONSENT();
1579 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001580}
1581
mukesh agrawal253dad42018-01-23 21:59:59 -08001582// This method collects common dumpsys for telephony and wifi
1583static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001584 DumpIpTablesAsRoot();
1585
Jayachandran C69968272019-07-08 09:46:05 -07001586 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1587
Jayachandran Ca94c7172017-06-10 15:08:12 -07001588 if (!DropRootUser()) {
1589 return;
1590 }
1591
1592 do_dmesg();
1593 DoLogcat();
1594 DumpPacketStats();
1595 DoKmsg();
1596 DumpIpAddrAndRules();
1597 dump_route_tables();
Jayachandran C69968272019-07-08 09:46:05 -07001598 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001599
1600 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1601 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001602}
1603
1604// This method collects dumpsys for telephony debugging only
1605static void DumpstateTelephonyOnly() {
1606 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001607 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001608
1609 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001610
1611 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1612
1613 printf("========================================================\n");
1614 printf("== Android Framework Services\n");
1615 printf("========================================================\n");
1616
Vishnu Nair652cc802017-11-30 15:18:30 -08001617 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1618 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001619 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1620 SEC_TO_MSEC(10));
1621 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001622 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1623 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001624 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1625 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001626 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1627 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001628
1629 printf("========================================================\n");
1630 printf("== Running Application Services\n");
1631 printf("========================================================\n");
1632
1633 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1634
1635 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001636 printf("== Running Application Services (non-platform)\n");
1637 printf("========================================================\n");
1638
1639 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1640 DUMPSYS_COMPONENTS_OPTIONS);
1641
1642 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001643 printf("== Checkins\n");
1644 printf("========================================================\n");
1645
1646 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1647
1648 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001649 printf("== dumpstate: done (id %d)\n", ds.id_);
1650 printf("========================================================\n");
1651}
1652
mukesh agrawal253dad42018-01-23 21:59:59 -08001653// This method collects dumpsys for wifi debugging only
1654static void DumpstateWifiOnly() {
1655 DurationReporter duration_reporter("DUMPSTATE");
1656
1657 DumpstateRadioCommon();
1658
1659 printf("========================================================\n");
1660 printf("== Android Framework Services\n");
1661 printf("========================================================\n");
1662
1663 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1664 SEC_TO_MSEC(10));
1665 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1666 SEC_TO_MSEC(10));
1667
1668 printf("========================================================\n");
1669 printf("== dumpstate: done (id %d)\n", ds.id_);
1670 printf("========================================================\n");
1671}
1672
Nandana Duttcf419a72019-03-14 10:40:17 +00001673Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001674 DurationReporter duration_reporter("DUMP TRACES");
1675
1676 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1677 const size_t buf_size = temp_file_pattern.length() + 1;
1678 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1679 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1680
1681 // Create a new, empty file to receive all trace dumps.
1682 //
1683 // TODO: This can be simplified once we remove support for the old style
1684 // dumps. We can have a file descriptor passed in to dump_traces instead
1685 // of creating a file, closing it and then reopening it again.
1686 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1687 if (fd < 0) {
1688 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001689 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001690 }
1691
1692 // Nobody should have access to this temporary file except dumpstate, but we
1693 // temporarily grant 'read' to 'others' here because this file is created
1694 // when tombstoned is still running as root, but dumped after dropping. This
1695 // can go away once support for old style dumping has.
1696 const int chmod_ret = fchmod(fd, 0666);
1697 if (chmod_ret < 0) {
1698 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001699 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001700 }
1701
1702 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1703 if (proc.get() == nullptr) {
1704 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001705 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001706 }
1707
1708 // Number of times process dumping has timed out. If we encounter too many
1709 // failures, we'll give up.
1710 int timeout_failures = 0;
1711 bool dalvik_found = false;
1712
1713 const std::set<int> hal_pids = get_interesting_hal_pids();
1714
1715 struct dirent* d;
1716 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001717 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001718 int pid = atoi(d->d_name);
1719 if (pid <= 0) {
1720 continue;
1721 }
1722
1723 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1724 std::string exe;
1725 if (!android::base::Readlink(link_name, &exe)) {
1726 continue;
1727 }
1728
1729 bool is_java_process;
1730 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1731 // Don't bother dumping backtraces for the zygote.
1732 if (IsZygote(pid)) {
1733 continue;
1734 }
1735
1736 dalvik_found = true;
1737 is_java_process = true;
1738 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1739 is_java_process = false;
1740 } else {
1741 // Probably a native process we don't care about, continue.
1742 continue;
1743 }
1744
1745 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1746 if (timeout_failures == 3) {
1747 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1748 break;
1749 }
1750
1751 const uint64_t start = Nanotime();
1752 const int ret = dump_backtrace_to_file_timeout(
1753 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1754 is_java_process ? 5 : 20, fd);
1755
1756 if (ret == -1) {
1757 // For consistency, the header and footer to this message match those
1758 // dumped by debuggerd in the success case.
1759 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1760 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1761 dprintf(fd, "---- end %d ----", pid);
1762 timeout_failures++;
1763 continue;
1764 }
1765
1766 // We've successfully dumped stack traces, reset the failure count
1767 // and write a summary of the elapsed time to the file and continue with the
1768 // next process.
1769 timeout_failures = 0;
1770
1771 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1772 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1773 }
1774
1775 if (!dalvik_found) {
1776 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1777 }
1778
Nandana Duttcf419a72019-03-14 10:40:17 +00001779 *path = file_name_buf.release();
1780 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001781}
1782
Felipe Leme6f674ae2016-11-18 17:10:33 -08001783void Dumpstate::DumpstateBoard() {
1784 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001785 printf("========================================================\n");
1786 printf("== Board\n");
1787 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001788
Felipe Leme6f674ae2016-11-18 17:10:33 -08001789 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001790 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001791 return;
1792 }
1793
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001794 std::vector<std::string> paths;
1795 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001796 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001797 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1798 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001799 remover.emplace_back(android::base::make_scope_guard(
1800 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001801 }
Jie Song9fbfad02017-06-20 16:29:42 -07001802
Wei Wang587eac92018-04-05 12:17:20 -07001803 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1804 if (dumpstate_device == nullptr) {
1805 MYLOGE("No IDumpstateDevice implementation\n");
1806 return;
1807 }
1808
1809 using ScopedNativeHandle =
1810 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1811 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1812 [](native_handle_t* handle) {
1813 native_handle_close(handle);
1814 native_handle_delete(handle);
1815 });
1816 if (handle == nullptr) {
1817 MYLOGE("Could not create native_handle\n");
1818 return;
1819 }
1820
Nandana Dutt5c390032019-03-12 10:52:56 +00001821 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001822 for (size_t i = 0; i < paths.size(); i++) {
1823 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1824
1825 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1826 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1827 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1828 if (fd < 0) {
1829 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1830 return;
1831 }
1832 handle.get()->data[i] = fd.release();
1833 }
1834
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001835 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001836 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1837 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1838 // and grab whatever dumped
1839 std::packaged_task<bool()>
1840 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001841 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1842 if (!status.isOk()) {
1843 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001844 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001845 }
Wei Wang587eac92018-04-05 12:17:20 -07001846 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001847 });
Wei Wang587eac92018-04-05 12:17:20 -07001848
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001849 auto result = dumpstate_task.get_future();
1850 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001851
1852 constexpr size_t timeout_sec = 30;
1853 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1854 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1855 if (!android::base::SetProperty("ctl.interface_restart",
1856 android::base::StringPrintf("%s/default",
1857 IDumpstateDevice::descriptor))) {
1858 MYLOGE("Couldn't restart dumpstate HAL\n");
1859 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001860 }
Wei Wang587eac92018-04-05 12:17:20 -07001861 // Wait some time for init to kill dumpstate vendor HAL
1862 constexpr size_t killing_timeout_sec = 10;
1863 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1864 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1865 "there might be racing in content\n", killing_timeout_sec);
1866 }
1867
1868 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1869 for (size_t i = 0; i < paths.size(); i++) {
1870 struct stat s;
1871 if (fstat(handle.get()->data[i], &s) == -1) {
1872 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1873 strerror(errno));
1874 file_sizes[i] = -1;
1875 continue;
1876 }
1877 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001878 }
1879
1880 for (size_t i = 0; i < paths.size(); i++) {
1881 if (file_sizes[i] == -1) {
1882 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001883 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001884 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001885 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001886 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001887 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001888 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001889 }
1890
Felipe Lemed8b94e52016-12-08 10:21:44 -08001891 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001892}
1893
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001894static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001895 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001896 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001897 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1898 " -h: display this help message\n"
1899 " -b: play sound file instead of vibrate, at beginning of job\n"
1900 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001901 " -d: append date to filename\n"
1902 " -p: capture screenshot to filename.png\n"
1903 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001904 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001905 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001906 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001907 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001908 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001909 "progress (requires -B)\n"
1910 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001911 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001912 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001913 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001914}
1915
Wei Liuf87959e2016-08-26 14:51:42 -07001916static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001917 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001918}
1919
Felipe Leme1d486fe2016-10-14 18:06:47 -07001920bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001921 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001922 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001923 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001924 // Final timestamp
1925 char date[80];
1926 time_t the_real_now_please_stand_up = time(nullptr);
1927 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001928 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001929 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001930
Felipe Leme9a523ae2016-10-20 15:10:33 -07001931 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001932 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001933 return false;
1934 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001935 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001936 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001937 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001938 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001939
Felipe Leme0f3fb202016-06-10 17:10:53 -07001940 // Add log file (which contains stderr output) to zip...
1941 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001942 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001943 MYLOGE("Failed to add dumpstate log to .zip file\n");
1944 return false;
1945 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001946 // TODO: Should truncate the existing file.
1947 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001948 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1949 return false;
1950 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001951 fprintf(stderr, "\n");
1952
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001953 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001954 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001955 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001956 return false;
1957 }
1958
Felipe Leme1d486fe2016-10-14 18:06:47 -07001959 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1960 ds.zip_file.reset(nullptr);
1961
Felipe Lemee9d2c542016-11-15 11:48:26 -08001962 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001963 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001964
Felipe Leme1e9edc62015-12-21 16:02:13 -08001965 return true;
1966}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001967
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001968static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001969 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1970 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001971 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001972 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001973 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001974 }
1975
1976 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001977 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001978
1979 std::vector<uint8_t> buffer(65536);
1980 while (1) {
1981 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1982 if (bytes_read == 0) {
1983 break;
1984 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001985 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001986 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001987 }
1988
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001989 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001990 }
1991
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001992 uint8_t hash[SHA256_DIGEST_LENGTH];
1993 SHA256_Final(hash, &ctx);
1994
1995 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1996 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001997 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001998 }
1999 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2000 return std::string(hash_buffer);
2001}
2002
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002003static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2004 // clang-format off
2005 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2006 "--receiver-foreground", "--receiver-include-background", "-a", action};
2007 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002008
2009 am.insert(am.end(), args.begin(), args.end());
2010
Felipe Leme8d2410e2017-02-08 09:46:08 -08002011 RunCommand("", am,
2012 CommandOptions::WithTimeout(20)
2013 .Log("Sending broadcast: '%s'\n")
2014 .Always()
2015 .DropRoot()
2016 .RedirectStderr()
2017 .Build());
2018}
2019
Felipe Leme35b8cf12017-02-10 15:47:29 -08002020static void Vibrate(int duration_ms) {
2021 // clang-format off
Chris Friese7e95fb2019-06-14 14:47:59 +00002022 RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002023 CommandOptions::WithTimeout(10)
2024 .Log("Vibrate: '%s'\n")
2025 .Always()
2026 .Build());
2027 // clang-format on
2028}
2029
Nandana Dutt979388e2018-11-30 16:48:55 +00002030static void MaybeResolveSymlink(std::string* path) {
2031 std::string resolved_path;
2032 if (android::base::Readlink(*path, &resolved_path)) {
2033 *path = resolved_path;
2034 }
2035}
2036
Nandana Dutt4be45d12018-09-26 15:04:23 +01002037/*
2038 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2039 * if we are writing zip files and adds the version file.
2040 */
2041static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002042 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2043
Nandana Dutt4be45d12018-09-26 15:04:23 +01002044 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2045 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002046 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002047 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002048 char date[80];
2049 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2050 ds.name_ = date;
2051 } else {
2052 ds.name_ = "undated";
2053 }
2054
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002055 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002056 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002057 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002058 ds.base_name_ += "-wifi";
2059 }
2060
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002061 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002062 ds.screenshot_path_ = ds.GetPath(".png");
2063 }
2064 ds.tmp_path_ = ds.GetPath(".tmp");
2065 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2066
Nandana Dutt54dbd672019-01-11 12:58:05 +00002067 std::string destination = ds.options_->bugreport_fd.get() != -1
2068 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002069 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002070 MYLOGD(
2071 "Bugreport dir: %s\n"
2072 "Base name: %s\n"
2073 "Suffix: %s\n"
2074 "Log path: %s\n"
2075 "Temporary path: %s\n"
2076 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002077 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2078 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002079
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002080 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002081 ds.path_ = ds.GetPath(".zip");
2082 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2083 create_parent_dirs(ds.path_.c_str());
2084 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2085 if (ds.zip_file == nullptr) {
2086 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2087 } else {
2088 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2089 }
2090 ds.AddTextZipEntry("version.txt", ds.version_);
2091 }
2092}
2093
2094/*
2095 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2096 * printing zipped file status, etc.
2097 */
2098static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002099 /* check if user changed the suffix using system properties */
2100 std::string name =
2101 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2102 bool change_suffix = false;
2103 if (!name.empty()) {
2104 /* must whitelist which characters are allowed, otherwise it could cross directories */
2105 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2106 if (std::regex_match(name.c_str(), valid_regex)) {
2107 change_suffix = true;
2108 } else {
2109 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2110 }
2111 }
2112 if (change_suffix) {
2113 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2114 ds.name_ = name;
2115 if (!ds.screenshot_path_.empty()) {
2116 std::string new_screenshot_path = ds.GetPath(".png");
2117 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2118 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2119 new_screenshot_path.c_str(), strerror(errno));
2120 } else {
2121 ds.screenshot_path_ = new_screenshot_path;
2122 }
2123 }
2124 }
2125
2126 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002127 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002128 if (!ds.FinishZipFile()) {
2129 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2130 do_text_file = true;
2131 } else {
2132 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002133 // If the user has changed the suffix, we need to change the zip file name.
2134 std::string new_path = ds.GetPath(".zip");
2135 if (ds.path_ != new_path) {
2136 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2137 if (rename(ds.path_.c_str(), new_path.c_str())) {
2138 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2139 strerror(errno));
2140 } else {
2141 ds.path_ = new_path;
2142 }
2143 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002144 }
2145 }
2146 if (do_text_file) {
2147 ds.path_ = ds.GetPath(".txt");
2148 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2149 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2150 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2151 ds.path_.clear();
2152 }
2153 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002154 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002155 if (do_text_file) {
2156 dprintf(ds.control_socket_fd_,
2157 "FAIL:could not create zip file, check %s "
2158 "for more details\n",
2159 ds.log_path_.c_str());
2160 } else {
2161 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2162 }
2163 }
2164}
2165
2166/* Broadcasts that we are done with the bugreport */
2167static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002168 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002169 if (!ds.path_.empty()) {
2170 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002171 // clang-format off
2172
2173 std::vector<std::string> am_args = {
2174 "--receiver-permission", "android.permission.DUMP",
2175 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2176 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2177 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002178 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002179 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2180 };
2181 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002182 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002183 am_args.push_back("--es");
2184 am_args.push_back("android.intent.extra.SCREENSHOT");
2185 am_args.push_back(ds.screenshot_path_);
2186 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002187 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002188 am_args.push_back("--es");
2189 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002190 am_args.push_back(ds.options_->notification_title);
2191 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002192 am_args.push_back("--es");
2193 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002194 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002195 }
2196 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002197 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002198 am_args.push_back("--es");
2199 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002200 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002201 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2202 } else {
2203 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2204 }
2205 } else {
2206 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2207 }
2208}
2209
Nandana Dutt58d72e22018-11-16 10:30:48 +00002210static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2211 switch (mode) {
2212 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2213 return "BUGREPORT_FULL";
2214 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2215 return "BUGREPORT_INTERACTIVE";
2216 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2217 return "BUGREPORT_REMOTE";
2218 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2219 return "BUGREPORT_WEAR";
2220 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2221 return "BUGREPORT_TELEPHONY";
2222 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2223 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002224 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2225 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002226 }
2227}
2228
2229static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002230 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002231 switch (mode) {
2232 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2233 options->do_broadcast = true;
2234 options->do_fb = true;
2235 break;
2236 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002237 // Currently, the dumpstate binder is only used by Shell to update progress.
2238 options->do_start_service = true;
2239 options->do_progress_updates = true;
2240 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002241 options->do_broadcast = true;
2242 break;
2243 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002244 options->do_vibrate = false;
2245 options->is_remote_mode = true;
2246 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002247 options->do_broadcast = true;
2248 break;
2249 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002250 options->do_start_service = true;
2251 options->do_progress_updates = true;
2252 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002253 options->do_fb = true;
2254 options->do_broadcast = true;
2255 break;
2256 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002257 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002258 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002259 options->do_broadcast = true;
2260 break;
2261 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002262 options->wifi_only = true;
2263 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002264 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002265 options->do_broadcast = true;
2266 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002267 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2268 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002269 }
2270}
2271
2272static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002273 // If the system property is not set, it's assumed to be a default bugreport.
2274 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002275
2276 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2277 if (!extra_options.empty()) {
2278 // Framework uses a system property to override some command-line args.
2279 // Currently, it contains the type of the requested bugreport.
2280 if (extra_options == "bugreportplus") {
2281 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002282 } else if (extra_options == "bugreportfull") {
2283 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002284 } else if (extra_options == "bugreportremote") {
2285 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2286 } else if (extra_options == "bugreportwear") {
2287 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2288 } else if (extra_options == "bugreporttelephony") {
2289 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2290 } else if (extra_options == "bugreportwifi") {
2291 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002292 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002293 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002294 }
2295 // Reset the property
2296 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2297 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002298 return mode;
2299}
2300
2301// TODO: Move away from system properties when we have options passed via binder calls.
2302/* Sets runtime options from the system properties and then clears those properties. */
2303static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2304 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2305 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002306
2307 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2308 if (!options->notification_title.empty()) {
2309 // Reset the property
2310 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2311
Nandana Duttdd8cca32018-11-14 10:10:29 +00002312 options->notification_description =
2313 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002314 if (!options->notification_description.empty()) {
2315 // Reset the property
2316 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2317 }
2318 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2319 options->notification_description.c_str());
2320 }
2321}
2322
Nandana Dutt58d72e22018-11-16 10:30:48 +00002323static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2324 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2325 MYLOGI("do_add_date: %d\n", options.do_add_date);
2326 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2327 MYLOGI("use_socket: %d\n", options.use_socket);
2328 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2329 MYLOGI("do_fb: %d\n", options.do_fb);
2330 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2331 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2332 MYLOGI("show_header_only: %d\n", options.show_header_only);
2333 MYLOGI("do_start_service: %d\n", options.do_start_service);
2334 MYLOGI("telephony_only: %d\n", options.telephony_only);
2335 MYLOGI("wifi_only: %d\n", options.wifi_only);
2336 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002337 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002338 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2339 MYLOGI("args: %s\n", options.args.c_str());
2340 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2341 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2342}
2343
Nandana Dutt54dbd672019-01-11 12:58:05 +00002344void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2345 const android::base::unique_fd& bugreport_fd_in,
2346 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002347 // In the new API world, date is always added; output is always a zip file.
2348 // TODO(111441001): remove these options once they are obsolete.
2349 do_add_date = true;
2350 do_zip_file = true;
2351
Nandana Dutt54dbd672019-01-11 12:58:05 +00002352 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2353 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2354 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002355
2356 extra_options = ModeToString(bugreport_mode);
2357 SetOptionsFromMode(bugreport_mode, this);
2358}
2359
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002360Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2361 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002362 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002363 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002364 switch (c) {
2365 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002366 case 'd': do_add_date = true; break;
2367 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002368 // o=use_outfile not supported anymore.
2369 // TODO(b/111441001): Remove when all callers have migrated.
2370 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002371 case 's': use_socket = true; break;
2372 case 'S': use_control_socket = true; break;
2373 case 'v': show_header_only = true; break;
2374 case 'q': do_vibrate = false; break;
2375 case 'p': do_fb = true; break;
2376 case 'P': do_progress_updates = true; break;
2377 case 'R': is_remote_mode = true; break;
2378 case 'B': do_broadcast = true; break;
2379 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002380 case 'w':
2381 // This was already processed
2382 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002383 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002384 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002385 break;
2386 default:
2387 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002388 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002389 break;
2390 // clang-format on
2391 }
2392 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002393
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002394 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002395 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002396 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002397 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002398 }
2399 }
2400
2401 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2402 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002403
2404 SetOptionsFromProperties(this);
2405 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002406}
2407
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002408bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002409 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002410 return false;
2411 }
2412
Nandana Dutt9a76d202019-01-21 15:56:48 +00002413 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002414 return false;
2415 }
2416
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002417 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002418 return false;
2419 }
2420
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002421 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002422 return false;
2423 }
2424
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002425 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002426 return false;
2427 }
2428 return true;
2429}
2430
Nandana Dutt197661d2018-11-16 16:40:21 +00002431void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2432 options_ = std::move(options);
2433}
2434
Nandana Duttd2f5f082019-01-18 17:13:52 +00002435Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2436 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002437 if (listener_ != nullptr) {
2438 switch (status) {
2439 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002440 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002441 break;
2442 case Dumpstate::RunStatus::HELP:
2443 break;
2444 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002445 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002446 break;
2447 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002448 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2449 break;
2450 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2451 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2452 break;
2453 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2454 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002455 break;
2456 }
2457 }
2458 return status;
2459}
2460
Nandana Dutt979388e2018-11-30 16:48:55 +00002461/*
2462 * Dumps relevant information to a bugreport based on the given options.
2463 *
2464 * The bugreport can be dumped to a file or streamed to a socket.
2465 *
2466 * How dumping to file works:
2467 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2468 * stderr is redirected a log file.
2469 *
2470 * The temporary bugreport is then populated via printfs, dumping contents of files and
2471 * output of commands to stdout.
2472 *
2473 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2474 * text file.
2475 *
2476 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2477 * gets added to the archive.
2478 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002479 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2480 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002481 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002482Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2483 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002484 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002485 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002486 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002487 return RunStatus::INVALID_INPUT;
2488 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002489 /* set as high priority, and protect from OOM killer */
2490 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002491
Felipe Lemed071c682016-10-20 16:48:00 -07002492 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002493 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002494 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002495 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002496 } else {
2497 /* fallback to kernels <= 2.6.35 */
2498 oom_adj = fopen("/proc/self/oom_adj", "we");
2499 if (oom_adj) {
2500 fputs("-17", oom_adj);
2501 fclose(oom_adj);
2502 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002503 }
2504
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002505 if (version_ == VERSION_DEFAULT) {
2506 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002507 }
2508
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002509 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002510 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002511 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002512 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002513 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002514 }
2515
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002516 if (options_->show_header_only) {
2517 PrintHeader();
2518 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002519 }
2520
Nandana Duttd2f5f082019-01-18 17:13:52 +00002521 if (options_->bugreport_fd.get() != -1) {
2522 // If the output needs to be copied over to the caller's fd, get user consent.
2523 android::String16 package(calling_package.c_str());
2524 CheckUserConsent(calling_uid, package);
2525 }
2526
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002527 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002528 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002529
2530 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002531 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002532 is_redirecting
2533 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2534 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002535 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002536
Felipe Lemed071c682016-10-20 16:48:00 -07002537 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002538 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002539 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002540 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2541
2542 MYLOGI("begin\n");
2543
Sahana Raof35ed432019-07-12 10:47:52 +01002544 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2545 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2546 } else {
2547 // Wake lock will be released automatically on process death
2548 MYLOGD("Wake lock acquired.\n");
2549 }
2550
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002551 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002552
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002553 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002554 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002555 MYLOGI("Starting 'dumpstate' service\n");
2556 android::status_t ret;
2557 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2558 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2559 }
2560 }
2561
Felipe Lemef0292972016-11-22 13:57:05 -08002562 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002563 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2564 }
2565
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002566 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2567 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002568
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002569 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002570
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002571 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002572
Christopher Ferrised9354f2014-10-01 17:35:01 -07002573 // If we are going to use a socket, do it as early as possible
2574 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002575 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002576 if (!redirect_to_socket(stdout, "dumpstate")) {
2577 return ERROR;
2578 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002579 }
2580
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002581 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002582 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002583 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002584 if (control_socket_fd_ == -1) {
2585 return ERROR;
2586 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002587 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002588 }
2589
Felipe Leme71bbfc52015-11-23 14:14:51 -08002590 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002591 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002592
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002593 if (options_->do_progress_updates) {
2594 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002595 // clang-format off
2596 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002597 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002598 "--es", "android.intent.extra.NAME", name_,
2599 "--ei", "android.intent.extra.ID", std::to_string(id_),
2600 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2601 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002602 };
2603 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002604 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002605 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002606 if (options_->use_control_socket) {
2607 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002608 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002609 }
2610 }
2611
Nick Kralevichf3599b32016-01-25 15:05:16 -08002612 /* read /proc/cmdline before dropping root */
2613 FILE *cmdline = fopen("/proc/cmdline", "re");
2614 if (cmdline) {
2615 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2616 fclose(cmdline);
2617 }
2618
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002619 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002620 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002621 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002622
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002623 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002624 MYLOGI("taking early screenshot\n");
2625 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002626 }
2627
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002628 if (options_->do_zip_file && zip_file != nullptr) {
2629 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2630 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002631 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002632 }
2633 }
2634
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002635 int dup_stdout_fd;
2636 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002637 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002638 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002639 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002640 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2641 return ERROR;
2642 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002643 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2644 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2645 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002646 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002647
2648 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2649 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002650 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002651 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002652 /* TODO: rather than generating a text file now and zipping it later,
2653 it would be more efficient to redirect stdout to the zip entry
2654 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002655 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2656 return ERROR;
2657 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002658 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002659 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002660 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002661 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002662 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002663
2664 // Don't buffer stdout
2665 setvbuf(stdout, nullptr, _IONBF, 0);
2666
Felipe Leme608385d2016-02-01 10:35:38 -08002667 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2668 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002669 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002670 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002671
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002672 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002673 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002674 DumpstateBoard();
2675 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002676 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002677 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002678 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002679 RunStatus s = DumpstateDefault();
2680 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002681 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002682 HandleUserConsentDenied();
2683 }
2684 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002685 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002686 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002687
Felipe Leme55b42a62015-11-10 17:39:08 -08002688 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002689 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002690 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002691 }
2692
Nandana Duttd2f5f082019-01-18 17:13:52 +00002693 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002694 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002695 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002696 }
2697
Nandana Duttd2f5f082019-01-18 17:13:52 +00002698 // Share the final file with the caller if the user has consented.
2699 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2700 if (options_->bugreport_fd.get() != -1) {
2701 status = CopyBugreportIfUserConsented();
2702 if (status != Dumpstate::RunStatus::OK &&
2703 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2704 // Do an early return if there were errors. We make an exception for consent
2705 // timing out because it's possible the user got distracted. In this case the
2706 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002707 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002708 return status;
2709 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002710 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002711 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2712 options_->screenshot_fd.get());
2713 if (copy_succeeded) {
2714 android::os::UnlinkAndLogOnError(screenshot_path_);
2715 }
2716 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002717 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2718 MYLOGI(
2719 "Did not receive user consent yet."
2720 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002721 const String16 incidentcompanion("incidentcompanion");
2722 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2723 if (ics != nullptr) {
2724 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2725 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2726 consent_callback_.get());
2727 } else {
2728 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2729 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002730 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002731 }
2732
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002733 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002734 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002735 for (int i = 0; i < 3; i++) {
2736 Vibrate(75);
2737 usleep((75 + 50) * 1000);
2738 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002739 }
2740
Jeff Brown1dc94e32014-09-11 14:15:27 -07002741 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002742 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002743 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002744 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002745 }
2746
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002747 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2748 progress_->GetInitialMax());
2749 progress_->Save();
2750 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002751
Felipe Leme107a05f2016-03-08 15:11:15 -08002752 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002753 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002754 }
2755
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002756 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002757 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002758 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002759 }
2760
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002761 tombstone_data_.clear();
2762 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002763
Nandana Duttd2f5f082019-01-18 17:13:52 +00002764 return (consent_callback_ != nullptr &&
2765 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2766 ? USER_CONSENT_TIMED_OUT
2767 : RunStatus::OK;
2768}
2769
2770void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2771 consent_callback_ = new ConsentCallback();
2772 const String16 incidentcompanion("incidentcompanion");
2773 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2774 if (ics != nullptr) {
2775 MYLOGD("Checking user consent via incidentcompanion service\n");
2776 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002777 calling_uid, calling_package, String16(), String16(),
2778 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002779 } else {
2780 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2781 }
2782}
2783
Nandana Dutt5c390032019-03-12 10:52:56 +00002784bool Dumpstate::IsUserConsentDenied() const {
2785 return ds.consent_callback_ != nullptr &&
2786 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2787}
2788
Nandana Duttd2f5f082019-01-18 17:13:52 +00002789void Dumpstate::CleanupFiles() {
2790 android::os::UnlinkAndLogOnError(tmp_path_);
2791 android::os::UnlinkAndLogOnError(screenshot_path_);
2792 android::os::UnlinkAndLogOnError(path_);
2793}
2794
2795Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2796 MYLOGD("User denied consent; deleting files and returning\n");
2797 CleanupFiles();
2798 return USER_CONSENT_DENIED;
2799}
2800
2801Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2802 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2803 // user consent.
2804 UserConsentResult consent_result = consent_callback_->getResult();
2805 if (consent_result == UserConsentResult::UNAVAILABLE) {
2806 // User has not responded yet.
2807 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2808 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2809 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2810 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2811 sleep(delay_seconds);
2812 }
2813 consent_result = consent_callback_->getResult();
2814 }
2815 if (consent_result == UserConsentResult::DENIED) {
2816 // User has explicitly denied sharing with the app. To be safe delete the
2817 // internal bugreport & tmp files.
2818 return HandleUserConsentDenied();
2819 }
2820 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002821 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2822 if (copy_succeeded) {
2823 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002824 }
2825 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2826 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2827 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2828 // Since we do not have user consent to share the bugreport it does not get
2829 // copied over to the calling app but remains in the internal directory from
2830 // where the user can manually pull it.
2831 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2832 }
2833 // Unknown result; must be a programming error.
2834 MYLOGE("Unknown user consent result:%d\n", consent_result);
2835 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002836}
2837
Nandana Duttf02564e2019-02-15 15:24:24 +00002838Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002839 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2840 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2841 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002842 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002843 // When directly running dumpstate binary, the output is not expected to be written
2844 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002845 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002846
2847 // calling_uid and calling_package are for user consent to share the bugreport with
2848 // an app; they are irrelvant here because bugreport is only written to a local
2849 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002850 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002851 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002852 return status;
2853}
2854
2855/* Main entry point for dumpstate binary. */
2856int run_main(int argc, char* argv[]) {
2857 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002858
2859 switch (status) {
2860 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002861 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002862 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002863 ShowUsage();
2864 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002865 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002866 fprintf(stderr, "Invalid combination of args\n");
2867 ShowUsage();
2868 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002869 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002870 FALLTHROUGH_INTENDED;
2871 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2872 FALLTHROUGH_INTENDED;
2873 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002874 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002875 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002876}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002877
2878// TODO(111441001): Default DumpOptions to sensible values.
2879Dumpstate::Dumpstate(const std::string& version)
2880 : pid_(getpid()),
2881 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002882 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002883 version_(version),
2884 now_(time(nullptr)) {
2885}
2886
2887Dumpstate& Dumpstate::GetInstance() {
2888 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2889 return singleton_;
2890}
2891
Nandana Dutt8d945c02019-08-14 13:30:07 +01002892DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2893 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002894 if (!title_.empty()) {
2895 started_ = Nanotime();
2896 }
2897}
2898
2899DurationReporter::~DurationReporter() {
2900 if (!title_.empty()) {
2901 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002902 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002903 return;
2904 }
2905 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2906 if (logcat_only_) {
2907 return;
2908 }
2909 // Use "Yoda grammar" to make it easier to grep|sort sections.
2910 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2911 }
2912}
2913
2914const int32_t Progress::kDefaultMax = 5000;
2915
2916Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2917}
2918
2919Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2920 : Progress(initial_max, growth_factor, "") {
2921 progress_ = progress;
2922}
2923
2924Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2925 : initial_max_(initial_max),
2926 progress_(0),
2927 max_(initial_max),
2928 growth_factor_(growth_factor),
2929 n_runs_(0),
2930 average_max_(0),
2931 path_(path) {
2932 if (!path_.empty()) {
2933 Load();
2934 }
2935}
2936
2937void Progress::Load() {
2938 MYLOGD("Loading stats from %s\n", path_.c_str());
2939 std::string content;
2940 if (!android::base::ReadFileToString(path_, &content)) {
2941 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2942 return;
2943 }
2944 if (content.empty()) {
2945 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2946 return;
2947 }
2948 std::vector<std::string> lines = android::base::Split(content, "\n");
2949
2950 if (lines.size() < 1) {
2951 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2952 (int)lines.size(), max_);
2953 return;
2954 }
2955 char* ptr;
2956 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2957 average_max_ = strtol(ptr, nullptr, 10);
2958 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2959 average_max_ > STATS_MAX_AVERAGE) {
2960 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2961 initial_max_ = Progress::kDefaultMax;
2962 } else {
2963 initial_max_ = average_max_;
2964 }
2965 max_ = initial_max_;
2966
2967 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2968}
2969
2970void Progress::Save() {
2971 int32_t total = n_runs_ * average_max_ + progress_;
2972 int32_t runs = n_runs_ + 1;
2973 int32_t average = floor(((float)total) / runs);
2974 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2975 path_.c_str());
2976 if (path_.empty()) {
2977 return;
2978 }
2979
2980 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2981 if (!android::base::WriteStringToFile(content, path_)) {
2982 MYLOGE("Could not save stats on %s\n", path_.c_str());
2983 }
2984}
2985
2986int32_t Progress::Get() const {
2987 return progress_;
2988}
2989
2990bool Progress::Inc(int32_t delta_sec) {
2991 bool changed = false;
2992 if (delta_sec >= 0) {
2993 progress_ += delta_sec;
2994 if (progress_ > max_) {
2995 int32_t old_max = max_;
2996 max_ = floor((float)progress_ * growth_factor_);
2997 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2998 changed = true;
2999 }
3000 }
3001 return changed;
3002}
3003
3004int32_t Progress::GetMax() const {
3005 return max_;
3006}
3007
3008int32_t Progress::GetInitialMax() const {
3009 return initial_max_;
3010}
3011
3012void Progress::Dump(int fd, const std::string& prefix) const {
3013 const char* pr = prefix.c_str();
3014 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3015 dprintf(fd, "%smax: %d\n", pr, max_);
3016 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3017 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3018 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3019 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3020 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3021}
3022
3023bool Dumpstate::IsZipping() const {
3024 return zip_writer_ != nullptr;
3025}
3026
3027std::string Dumpstate::GetPath(const std::string& suffix) const {
3028 return GetPath(bugreport_internal_dir_, suffix);
3029}
3030
3031std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3032 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3033 name_.c_str(), suffix.c_str());
3034}
3035
3036void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3037 progress_ = std::move(progress);
3038}
3039
3040void for_each_userid(void (*func)(int), const char *header) {
3041 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3042 "for_each_userid(%s)", header);
3043 DurationReporter duration_reporter(title);
3044 if (PropertiesHelper::IsDryRun()) return;
3045
3046 DIR *d;
3047 struct dirent *de;
3048
3049 if (header) printf("\n------ %s ------\n", header);
3050 func(0);
3051
3052 if (!(d = opendir("/data/system/users"))) {
3053 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3054 return;
3055 }
3056
3057 while ((de = readdir(d))) {
3058 int userid;
3059 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3060 continue;
3061 }
3062 func(userid);
3063 }
3064
3065 closedir(d);
3066}
3067
3068static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3069 DIR *d;
3070 struct dirent *de;
3071
3072 if (!(d = opendir("/proc"))) {
3073 printf("Failed to open /proc (%s)\n", strerror(errno));
3074 return;
3075 }
3076
3077 if (header) printf("\n------ %s ------\n", header);
3078 while ((de = readdir(d))) {
3079 if (ds.IsUserConsentDenied()) {
3080 MYLOGE(
3081 "Returning early because user denied consent to share bugreport with calling app.");
3082 closedir(d);
3083 return;
3084 }
3085 int pid;
3086 int fd;
3087 char cmdpath[255];
3088 char cmdline[255];
3089
3090 if (!(pid = atoi(de->d_name))) {
3091 continue;
3092 }
3093
3094 memset(cmdline, 0, sizeof(cmdline));
3095
3096 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3097 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3098 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3099 close(fd);
3100 if (cmdline[0]) {
3101 helper(pid, cmdline, arg);
3102 continue;
3103 }
3104 }
3105
3106 // if no cmdline, a kernel thread has comm
3107 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3108 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3109 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3110 close(fd);
3111 if (cmdline[1]) {
3112 cmdline[0] = '[';
3113 size_t len = strcspn(cmdline, "\f\b\r\n");
3114 cmdline[len] = ']';
3115 cmdline[len+1] = '\0';
3116 }
3117 }
3118 if (!cmdline[0]) {
3119 strcpy(cmdline, "N/A");
3120 }
3121 helper(pid, cmdline, arg);
3122 }
3123
3124 closedir(d);
3125}
3126
3127static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3128 for_each_pid_func *func = (for_each_pid_func*) arg;
3129 func(pid, cmdline);
3130}
3131
3132void for_each_pid(for_each_pid_func func, const char *header) {
3133 std::string title = header == nullptr ? "for_each_pid"
3134 : android::base::StringPrintf("for_each_pid(%s)", header);
3135 DurationReporter duration_reporter(title);
3136 if (PropertiesHelper::IsDryRun()) return;
3137
3138 __for_each_pid(for_each_pid_helper, header, (void *) func);
3139}
3140
3141static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3142 DIR *d;
3143 struct dirent *de;
3144 char taskpath[255];
3145 for_each_tid_func *func = (for_each_tid_func *) arg;
3146
3147 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3148
3149 if (!(d = opendir(taskpath))) {
3150 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3151 return;
3152 }
3153
3154 func(pid, pid, cmdline);
3155
3156 while ((de = readdir(d))) {
3157 if (ds.IsUserConsentDenied()) {
3158 MYLOGE(
3159 "Returning early because user denied consent to share bugreport with calling app.");
3160 closedir(d);
3161 return;
3162 }
3163 int tid;
3164 int fd;
3165 char commpath[255];
3166 char comm[255];
3167
3168 if (!(tid = atoi(de->d_name))) {
3169 continue;
3170 }
3171
3172 if (tid == pid)
3173 continue;
3174
3175 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3176 memset(comm, 0, sizeof(comm));
3177 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3178 strcpy(comm, "N/A");
3179 } else {
3180 char *c;
3181 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3182 close(fd);
3183
3184 c = strrchr(comm, '\n');
3185 if (c) {
3186 *c = '\0';
3187 }
3188 }
3189 func(pid, tid, comm);
3190 }
3191
3192 closedir(d);
3193}
3194
3195void for_each_tid(for_each_tid_func func, const char *header) {
3196 std::string title = header == nullptr ? "for_each_tid"
3197 : android::base::StringPrintf("for_each_tid(%s)", header);
3198 DurationReporter duration_reporter(title);
3199
3200 if (PropertiesHelper::IsDryRun()) return;
3201
3202 __for_each_pid(for_each_tid_helper, header, (void *) func);
3203}
3204
3205void show_wchan(int pid, int tid, const char *name) {
3206 if (PropertiesHelper::IsDryRun()) return;
3207
3208 char path[255];
3209 char buffer[255];
3210 int fd, ret, save_errno;
3211 char name_buffer[255];
3212
3213 memset(buffer, 0, sizeof(buffer));
3214
3215 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3216 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3217 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3218 return;
3219 }
3220
3221 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3222 save_errno = errno;
3223 close(fd);
3224
3225 if (ret < 0) {
3226 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3227 return;
3228 }
3229
3230 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3231 pid == tid ? 0 : 3, "", name);
3232
3233 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3234
3235 return;
3236}
3237
3238// print time in centiseconds
3239static void snprcent(char *buffer, size_t len, size_t spc,
3240 unsigned long long time) {
3241 static long hz; // cache discovered hz
3242
3243 if (hz <= 0) {
3244 hz = sysconf(_SC_CLK_TCK);
3245 if (hz <= 0) {
3246 hz = 1000;
3247 }
3248 }
3249
3250 // convert to centiseconds
3251 time = (time * 100 + (hz / 2)) / hz;
3252
3253 char str[16];
3254
3255 snprintf(str, sizeof(str), " %llu.%02u",
3256 time / 100, (unsigned)(time % 100));
3257 size_t offset = strlen(buffer);
3258 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3259 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3260}
3261
3262// print permille as a percent
3263static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3264 char str[16];
3265
3266 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3267 size_t offset = strlen(buffer);
3268 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3269 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3270}
3271
3272void show_showtime(int pid, const char *name) {
3273 if (PropertiesHelper::IsDryRun()) return;
3274
3275 char path[255];
3276 char buffer[1023];
3277 int fd, ret, save_errno;
3278
3279 memset(buffer, 0, sizeof(buffer));
3280
3281 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3282 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3283 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3284 return;
3285 }
3286
3287 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3288 save_errno = errno;
3289 close(fd);
3290
3291 if (ret < 0) {
3292 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3293 return;
3294 }
3295
3296 // field 14 is utime
3297 // field 15 is stime
3298 // field 42 is iotime
3299 unsigned long long utime = 0, stime = 0, iotime = 0;
3300 if (sscanf(buffer,
3301 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3302 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3303 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3304 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3305 &utime, &stime, &iotime) != 3) {
3306 return;
3307 }
3308
3309 unsigned long long total = utime + stime;
3310 if (!total) {
3311 return;
3312 }
3313
3314 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3315 if (permille > 1000) {
3316 permille = 1000;
3317 }
3318
3319 // try to beautify and stabilize columns at <80 characters
3320 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3321 if ((name[0] != '[') || utime) {
3322 snprcent(buffer, sizeof(buffer), 57, utime);
3323 }
3324 snprcent(buffer, sizeof(buffer), 65, stime);
3325 if ((name[0] != '[') || iotime) {
3326 snprcent(buffer, sizeof(buffer), 73, iotime);
3327 }
3328 if (iotime) {
3329 snprdec(buffer, sizeof(buffer), 79, permille);
3330 }
3331 puts(buffer); // adds a trailing newline
3332
3333 return;
3334}
3335
3336void do_dmesg() {
3337 const char *title = "KERNEL LOG (dmesg)";
3338 DurationReporter duration_reporter(title);
3339 printf("------ %s ------\n", title);
3340
3341 if (PropertiesHelper::IsDryRun()) return;
3342
3343 /* Get size of kernel buffer */
3344 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3345 if (size <= 0) {
3346 printf("Unexpected klogctl return value: %d\n\n", size);
3347 return;
3348 }
3349 char *buf = (char *) malloc(size + 1);
3350 if (buf == nullptr) {
3351 printf("memory allocation failed\n\n");
3352 return;
3353 }
3354 int retval = klogctl(KLOG_READ_ALL, buf, size);
3355 if (retval < 0) {
3356 printf("klogctl failure\n\n");
3357 free(buf);
3358 return;
3359 }
3360 buf[retval] = '\0';
3361 printf("%s\n\n", buf);
3362 free(buf);
3363 return;
3364}
3365
3366void do_showmap(int pid, const char *name) {
3367 char title[255];
3368 char arg[255];
3369
3370 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3371 snprintf(arg, sizeof(arg), "%d", pid);
3372 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3373}
3374
3375int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3376 DurationReporter duration_reporter(title);
3377
3378 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3379
3380 UpdateProgress(WEIGHT_FILE);
3381
3382 return status;
3383}
3384
3385int read_file_as_long(const char *path, long int *output) {
3386 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3387 if (fd < 0) {
3388 int err = errno;
3389 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3390 return -1;
3391 }
3392 char buffer[50];
3393 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3394 if (bytes_read == -1) {
3395 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3396 return -2;
3397 }
3398 if (bytes_read == 0) {
3399 MYLOGE("File %s is empty\n", path);
3400 return -3;
3401 }
3402 *output = atoi(buffer);
3403 return 0;
3404}
3405
3406/* calls skip to gate calling dump_from_fd recursively
3407 * in the specified directory. dump_from_fd defaults to
3408 * dump_file_from_fd above when set to NULL. skip defaults
3409 * to false when set to NULL. dump_from_fd will always be
3410 * called with title NULL.
3411 */
3412int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3413 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3414 DurationReporter duration_reporter(title);
3415 DIR *dirp;
3416 struct dirent *d;
3417 char *newpath = nullptr;
3418 const char *slash = "/";
3419 int retval = 0;
3420
3421 if (!title.empty()) {
3422 printf("------ %s (%s) ------\n", title.c_str(), dir);
3423 }
3424 if (PropertiesHelper::IsDryRun()) return 0;
3425
3426 if (dir[strlen(dir) - 1] == '/') {
3427 ++slash;
3428 }
3429 dirp = opendir(dir);
3430 if (dirp == nullptr) {
3431 retval = -errno;
3432 MYLOGE("%s: %s\n", dir, strerror(errno));
3433 return retval;
3434 }
3435
3436 if (!dump_from_fd) {
3437 dump_from_fd = dump_file_from_fd;
3438 }
3439 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3440 if ((d->d_name[0] == '.')
3441 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3442 || (d->d_name[1] == '\0'))) {
3443 continue;
3444 }
3445 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3446 (d->d_type == DT_DIR) ? "/" : "");
3447 if (!newpath) {
3448 retval = -errno;
3449 continue;
3450 }
3451 if (skip && (*skip)(newpath)) {
3452 continue;
3453 }
3454 if (d->d_type == DT_DIR) {
3455 int ret = dump_files("", newpath, skip, dump_from_fd);
3456 if (ret < 0) {
3457 retval = ret;
3458 }
3459 continue;
3460 }
3461 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3462 if (fd.get() < 0) {
3463 retval = -1;
3464 printf("*** %s: %s\n", newpath, strerror(errno));
3465 continue;
3466 }
3467 (*dump_from_fd)(nullptr, newpath, fd.get());
3468 }
3469 closedir(dirp);
3470 if (!title.empty()) {
3471 printf("\n");
3472 }
3473 return retval;
3474}
3475
3476/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3477 * it's possible to avoid issues where opening the file itself can get
3478 * stuck.
3479 */
3480int dump_file_from_fd(const char *title, const char *path, int fd) {
3481 if (PropertiesHelper::IsDryRun()) return 0;
3482
3483 int flags = fcntl(fd, F_GETFL);
3484 if (flags == -1) {
3485 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3486 return -1;
3487 } else if (!(flags & O_NONBLOCK)) {
3488 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3489 return -1;
3490 }
3491 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3492}
3493
3494int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003495 const CommandOptions& options, bool verbose_duration) {
3496 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003497
3498 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3499
3500 /* TODO: for now we're simplifying the progress calculation by using the
3501 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3502 * where its weight should be much higher proportionally to its timeout.
3503 * Ideally, it should use a options.EstimatedDuration() instead...*/
3504 UpdateProgress(options.Timeout());
3505
3506 return status;
3507}
3508
3509void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3510 const CommandOptions& options, long dumpsysTimeoutMs) {
3511 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3512 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3513 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3514 RunCommand(title, dumpsys, options);
3515}
3516
3517int open_socket(const char *service) {
3518 int s = android_get_control_socket(service);
3519 if (s < 0) {
3520 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3521 return -1;
3522 }
3523 fcntl(s, F_SETFD, FD_CLOEXEC);
3524
3525 // Set backlog to 0 to make sure that queue size will be minimum.
3526 // In Linux, because the minimum queue will be 1, connect() will be blocked
3527 // if the other clients already called connect() and the connection request was not accepted.
3528 if (listen(s, 0) < 0) {
3529 MYLOGE("listen(control socket): %s\n", strerror(errno));
3530 return -1;
3531 }
3532
3533 struct sockaddr addr;
3534 socklen_t alen = sizeof(addr);
3535 int fd = accept(s, &addr, &alen);
3536
3537 // Close socket just after accept(), to make sure that connect() by client will get error
3538 // when the socket is used by the other services.
3539 // There is still a race condition possibility between accept and close, but there is no way
3540 // to close-on-accept atomically.
3541 // See detail; b/123306389#comment25
3542 close(s);
3543
3544 if (fd < 0) {
3545 MYLOGE("accept(control socket): %s\n", strerror(errno));
3546 return -1;
3547 }
3548
3549 return fd;
3550}
3551
3552/* redirect output to a service control socket */
3553bool redirect_to_socket(FILE* redirect, const char* service) {
3554 int fd = open_socket(service);
3555 if (fd == -1) {
3556 return false;
3557 }
3558 fflush(redirect);
3559 // TODO: handle dup2 failure
3560 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3561 close(fd);
3562 return true;
3563}
3564
3565// TODO: should call is_valid_output_file and/or be merged into it.
3566void create_parent_dirs(const char *path) {
3567 char *chp = const_cast<char *> (path);
3568
3569 /* skip initial slash */
3570 if (chp[0] == '/')
3571 chp++;
3572
3573 /* create leading directories, if necessary */
3574 struct stat dir_stat;
3575 while (chp && chp[0]) {
3576 chp = strchr(chp, '/');
3577 if (chp) {
3578 *chp = 0;
3579 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3580 MYLOGI("Creating directory %s\n", path);
3581 if (mkdir(path, 0770)) { /* drwxrwx--- */
3582 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3583 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3584 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3585 }
3586 }
3587 *chp++ = '/';
3588 }
3589 }
3590}
3591
3592bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3593 create_parent_dirs(path);
3594
3595 int fd = TEMP_FAILURE_RETRY(open(path,
3596 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3597 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3598 if (fd < 0) {
3599 MYLOGE("%s: %s\n", path, strerror(errno));
3600 return false;
3601 }
3602
3603 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3604 close(fd);
3605 return true;
3606}
3607
3608bool redirect_to_file(FILE* redirect, char* path) {
3609 return _redirect_to_file(redirect, path, O_TRUNC);
3610}
3611
3612bool redirect_to_existing_file(FILE* redirect, char* path) {
3613 return _redirect_to_file(redirect, path, O_APPEND);
3614}
3615
3616void dump_route_tables() {
3617 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3618 if (PropertiesHelper::IsDryRun()) return;
3619 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3620 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3621 FILE* fp = fopen(RT_TABLES_PATH, "re");
3622 if (!fp) {
3623 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3624 return;
3625 }
3626 char table[16];
3627 // Each line has an integer (the table number), a space, and a string (the table name). We only
3628 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3629 // Add a fixed max limit so this doesn't go awry.
3630 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3631 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3632 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3633 }
3634 fclose(fp);
3635}
3636
3637// TODO: make this function thread safe if sections are generated in parallel.
3638void Dumpstate::UpdateProgress(int32_t delta_sec) {
3639 if (progress_ == nullptr) {
3640 MYLOGE("UpdateProgress: progress_ not set\n");
3641 return;
3642 }
3643
3644 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003645 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003646
3647 // ...but only notifiy listeners when necessary.
3648 if (!options_->do_progress_updates) return;
3649
3650 int progress = progress_->Get();
3651 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003652 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003653
Nandana Duttf02cd782019-06-14 14:25:13 +01003654 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003655 return;
3656 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003657 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003658
3659 if (control_socket_fd_ >= 0) {
3660 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3661 fsync(control_socket_fd_);
3662 }
3663
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003664 if (listener_ != nullptr) {
3665 if (percent % 5 == 0) {
3666 // We don't want to spam logcat, so only log multiples of 5.
3667 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3668 percent);
3669 } else {
3670 // stderr is ignored on normal invocations, but useful when calling
3671 // /system/bin/dumpstate directly for debuggging.
3672 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3673 progress, max, percent);
3674 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003675
3676 listener_->onProgress(percent);
3677 }
3678}
3679
3680void Dumpstate::TakeScreenshot(const std::string& path) {
3681 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3682 int status =
3683 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3684 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3685 if (status == 0) {
3686 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3687 } else {
3688 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3689 }
3690}
3691
3692bool is_dir(const char* pathname) {
3693 struct stat info;
3694 if (stat(pathname, &info) == -1) {
3695 return false;
3696 }
3697 return S_ISDIR(info.st_mode);
3698}
3699
3700time_t get_mtime(int fd, time_t default_mtime) {
3701 struct stat info;
3702 if (fstat(fd, &info) == -1) {
3703 return default_mtime;
3704 }
3705 return info.st_mtime;
3706}