blob: 7c03ccfd9c25bebeda7852d2d174aee86fb83ead [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 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100256 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100257 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.
Narayan Kamath8f788292017-05-25 13:20:39 +0100303 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700304static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
305 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700306 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100307 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
308
Narayan Kamathbd863722017-06-01 18:50:12 +0100309 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100310
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700311 if (dump_dir == nullptr) {
312 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700313 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700314 }
315
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700316 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100317 struct dirent* entry = nullptr;
318 while ((entry = readdir(dump_dir.get()))) {
319 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100320 continue;
321 }
322
Narayan Kamathbd863722017-06-01 18:50:12 +0100323 const std::string base_name(entry->d_name);
324 if (base_name.find(file_prefix) != 0) {
325 continue;
326 }
327
328 const std::string abs_path = dir_path + base_name;
329 android::base::unique_fd fd(
330 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
331 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700332 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100333 break;
334 }
335
336 struct stat st = {};
337 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700338 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100339 continue;
340 }
341
Narayan Kamath3f31b632018-02-22 19:42:36 +0000342 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100343 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100344 continue;
345 }
346
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700347 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700348 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100349
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700350 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100351}
352
Narayan Kamathbd863722017-06-01 18:50:12 +0100353static bool AddDumps(const std::vector<DumpData>::const_iterator start,
354 const std::vector<DumpData>::const_iterator end,
355 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100356 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100357 for (auto it = start; it != end; ++it) {
358 const std::string& name = it->name;
359 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100360 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100361
362 // Seek to the beginning of the file before dumping any data. A given
363 // DumpData entry might be dumped multiple times in the report.
364 //
365 // For example, the most recent ANR entry is dumped to the body of the
366 // main entry and it also shows up as a separate entry in the bugreport
367 // ZIP file.
368 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
369 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
370 strerror(errno));
371 }
372
Narayan Kamath8f788292017-05-25 13:20:39 +0100373 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800374 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100375 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100376 }
377 } else {
378 dump_file_from_fd(type_name, name.c_str(), fd);
379 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100380 }
381
382 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700383}
384
Felipe Leme635ca312016-01-05 14:23:02 -0800385// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700386void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800387 char path[PATH_MAX];
388
389 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
390 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700391 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800392 char linkname[PATH_MAX];
393 ssize_t r = readlink(path, linkname, PATH_MAX);
394 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800395 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800396 return;
397 }
398 linkname[r] = '\0';
399
400 if (mount_points.find(linkname) == mount_points.end()) {
401 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700402 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700403 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800404 mount_points.insert(linkname);
405 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800406 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800407 }
408 }
409}
410
411void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700412 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700413 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800414 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800415 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700416 for_each_pid(do_mountinfo, nullptr);
417 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800418}
419
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700420static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
421{
422 DIR *d;
423 struct dirent *de;
424 char path[PATH_MAX];
425
426 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700427 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700428 return;
429 }
430
431 while ((de = readdir(d))) {
432 if (de->d_type != DT_LNK) {
433 continue;
434 }
435 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700436 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700437 }
438
439 closedir(d);
440}
441
Mark Salyzyn326842f2015-04-30 09:49:41 -0700442static bool skip_not_stat(const char *path) {
443 static const char stat[] = "/stat";
444 size_t len = strlen(path);
445 if (path[len - 1] == '/') { /* Directory? */
446 return false;
447 }
448 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
449}
450
Felipe Leme4c2d6632016-09-28 14:32:00 -0700451static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800452 return false;
453}
454
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700455unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700456
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800457//
458// stat offsets
459// Name units description
460// ---- ----- -----------
461// read I/Os requests number of read I/Os processed
462#define __STAT_READ_IOS 0
463// read merges requests number of read I/Os merged with in-queue I/O
464#define __STAT_READ_MERGES 1
465// read sectors sectors number of sectors read
466#define __STAT_READ_SECTORS 2
467// read ticks milliseconds total wait time for read requests
468#define __STAT_READ_TICKS 3
469// write I/Os requests number of write I/Os processed
470#define __STAT_WRITE_IOS 4
471// write merges requests number of write I/Os merged with in-queue I/O
472#define __STAT_WRITE_MERGES 5
473// write sectors sectors number of sectors written
474#define __STAT_WRITE_SECTORS 6
475// write ticks milliseconds total wait time for write requests
476#define __STAT_WRITE_TICKS 7
477// in_flight requests number of I/Os currently in flight
478#define __STAT_IN_FLIGHT 8
479// io_ticks milliseconds total time this block device has been active
480#define __STAT_IO_TICKS 9
481// time_in_queue milliseconds total wait time for all requests
482#define __STAT_IN_QUEUE 10
483#define __STAT_NUMBER_FIELD 11
484//
485// read I/Os, write I/Os
486// =====================
487//
488// These values increment when an I/O request completes.
489//
490// read merges, write merges
491// =========================
492//
493// These values increment when an I/O request is merged with an
494// already-queued I/O request.
495//
496// read sectors, write sectors
497// ===========================
498//
499// These values count the number of sectors read from or written to this
500// block device. The "sectors" in question are the standard UNIX 512-byte
501// sectors, not any device- or filesystem-specific block size. The
502// counters are incremented when the I/O completes.
503#define SECTOR_SIZE 512
504//
505// read ticks, write ticks
506// =======================
507//
508// These values count the number of milliseconds that I/O requests have
509// waited on this block device. If there are multiple I/O requests waiting,
510// these values will increase at a rate greater than 1000/second; for
511// example, if 60 read requests wait for an average of 30 ms, the read_ticks
512// field will increase by 60*30 = 1800.
513//
514// in_flight
515// =========
516//
517// This value counts the number of I/O requests that have been issued to
518// the device driver but have not yet completed. It does not include I/O
519// requests that are in the queue but not yet issued to the device driver.
520//
521// io_ticks
522// ========
523//
524// This value counts the number of milliseconds during which the device has
525// had I/O requests queued.
526//
527// time_in_queue
528// =============
529//
530// This value counts the number of milliseconds that I/O requests have waited
531// on this block device. If there are multiple I/O requests waiting, this
532// value will increase as the product of the number of milliseconds times the
533// number of requests waiting (see "read ticks" above for an example).
534#define S_TO_MS 1000
535//
536
Mark Salyzyn326842f2015-04-30 09:49:41 -0700537static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800538 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700539 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700540 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700541 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700542 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700543 getline(&buffer, &i, fp);
544 fclose(fp);
545 if (!buffer) {
546 return -errno;
547 }
548 i = strlen(buffer);
549 while ((i > 0) && (buffer[i - 1] == '\n')) {
550 buffer[--i] = '\0';
551 }
552 if (!*buffer) {
553 free(buffer);
554 return 0;
555 }
556 z = true;
557 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800558 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700559 if (fields[i] != 0) {
560 z = false;
561 }
562 }
563 if (z) { /* never accessed */
564 free(buffer);
565 return 0;
566 }
567
Wei Wang509bb5d2017-06-09 14:42:12 -0700568 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
569 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700570 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700571
572 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
573 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
574 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700575 free(buffer);
576
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800577 if (fields[__STAT_IO_TICKS]) {
578 unsigned long read_perf = 0;
579 unsigned long read_ios = 0;
580 if (fields[__STAT_READ_TICKS]) {
581 unsigned long long divisor = fields[__STAT_READ_TICKS]
582 * fields[__STAT_IO_TICKS];
583 read_perf = ((unsigned long long)SECTOR_SIZE
584 * fields[__STAT_READ_SECTORS]
585 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
586 / divisor;
587 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
588 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
589 / divisor;
590 }
591
592 unsigned long write_perf = 0;
593 unsigned long write_ios = 0;
594 if (fields[__STAT_WRITE_TICKS]) {
595 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
596 * fields[__STAT_IO_TICKS];
597 write_perf = ((unsigned long long)SECTOR_SIZE
598 * fields[__STAT_WRITE_SECTORS]
599 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
600 / divisor;
601 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
602 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
603 / divisor;
604 }
605
606 unsigned queue = (fields[__STAT_IN_QUEUE]
607 + (fields[__STAT_IO_TICKS] >> 1))
608 / fields[__STAT_IO_TICKS];
609
610 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700611 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 -0800612 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700613 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 -0800614 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800615 }
616
617 /* bugreport timeout factor adjustment */
618 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
619 worst_write_perf = write_perf;
620 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700621 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700622 return 0;
623}
624
Yao Chenbe3bbc12018-01-17 16:31:10 -0800625static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
626
627/* timeout in ms to read a list of buffers */
628static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
629 unsigned long timeout_ms = 0;
630 for (const auto& buffer : buffers) {
631 log_id_t id = android_name_to_log_id(buffer.c_str());
632 unsigned long property_size = __android_logger_get_buffer_size(id);
633 /* Engineering margin is ten-fold our guess */
634 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
635 }
636 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700637}
638
Nandana Duttd2f5f082019-01-18 17:13:52 +0000639Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
640}
641
642android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
643 std::lock_guard<std::mutex> lock(lock_);
644 result_ = APPROVED;
645 MYLOGD("User approved consent to share bugreport\n");
646 return android::binder::Status::ok();
647}
648
649android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
650 std::lock_guard<std::mutex> lock(lock_);
651 result_ = DENIED;
652 MYLOGW("User denied consent to share bugreport\n");
653 return android::binder::Status::ok();
654}
655
656UserConsentResult Dumpstate::ConsentCallback::getResult() {
657 std::lock_guard<std::mutex> lock(lock_);
658 return result_;
659}
660
661uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
662 return Nanotime() - start_time_;
663}
664
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700665void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700666 std::string build, fingerprint, radio, bootloader, network;
667 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700668
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700669 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
670 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700671 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
672 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
673 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700674 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700675
Felipe Lemed8b94e52016-12-08 10:21:44 -0800676 printf("========================================================\n");
677 printf("== dumpstate: %s\n", date);
678 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700679
Felipe Lemed8b94e52016-12-08 10:21:44 -0800680 printf("\n");
681 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700682 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800683 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
684 printf("Bootloader: %s\n", bootloader.c_str());
685 printf("Radio: %s\n", radio.c_str());
686 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100687 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
688 if (module_metadata_version != 0) {
689 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
690 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700691
Felipe Lemed8b94e52016-12-08 10:21:44 -0800692 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800693 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800694 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800695 printf("Uptime: ");
696 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
697 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800698 printf("Bugreport format version: %s\n", version_.c_str());
699 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 +0100700 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800701 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800702}
703
Felipe Leme24b66ee2016-06-16 10:55:26 -0700704// List of file extensions that can cause a zip file attachment to be rejected by some email
705// service providers.
706static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
707 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
708 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
709 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
710};
711
Vishnu Naire97d6122018-01-18 13:58:56 -0800712status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
713 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700714 if (!IsZipping()) {
715 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
716 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800717 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800718 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700719 std::string valid_name = entry_name;
720
721 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700722 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700723 if (idx != std::string::npos) {
724 std::string extension = entry_name.substr(idx);
725 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
726 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
727 valid_name = entry_name + ".renamed";
728 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
729 }
730 }
731
Felipe Leme6fe9db62016-02-12 09:04:16 -0800732 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
733 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700734 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
735 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700736 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700737 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700738 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800739 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800740 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000741 bool finished_entry = false;
742 auto finish_entry = [this, &finished_entry] {
743 if (!finished_entry) {
744 // This should only be called when we're going to return an earlier error,
745 // which would've been logged. This may imply the file is already corrupt
746 // and any further logging from FinishEntry is more likely to mislead than
747 // not.
748 this->zip_writer_->FinishEntry();
749 }
750 };
751 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800752 auto start = std::chrono::steady_clock::now();
753 auto end = start + timeout;
754 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800755
Felipe Leme770410d2016-01-26 17:07:14 -0800756 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800757 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800758 if (timeout.count() > 0) {
759 // lambda to recalculate the timeout.
760 auto time_left_ms = [end]() {
761 auto now = std::chrono::steady_clock::now();
762 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
763 return std::max(diff.count(), 0LL);
764 };
765
766 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
767 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000768 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
769 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800770 return -errno;
771 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000772 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800773 entry_name.c_str(), strerror(errno), timeout.count());
774 return TIMED_OUT;
775 }
776 }
777
Zach Riggle22200402016-08-18 01:01:24 -0400778 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800779 if (bytes_read == 0) {
780 break;
781 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800782 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800783 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800784 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700785 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700787 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800788 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800789 }
790 }
791
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700792 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000793 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700794 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700795 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800796 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800797 }
798
Vishnu Naire97d6122018-01-18 13:58:56 -0800799 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800800}
801
Felipe Leme1d486fe2016-10-14 18:06:47 -0700802bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
803 android::base::unique_fd fd(
804 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700805 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800806 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800807 return false;
808 }
809
Vishnu Naire97d6122018-01-18 13:58:56 -0800810 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800811}
812
813/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700814static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800815 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800816}
817
Felipe Leme1d486fe2016-10-14 18:06:47 -0700818void Dumpstate::AddDir(const std::string& dir, bool recursive) {
819 if (!IsZipping()) {
820 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800821 return;
822 }
Felipe Leme678727a2016-09-21 17:22:11 -0700823 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800824 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700825 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800826}
827
Felipe Leme1d486fe2016-10-14 18:06:47 -0700828bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
829 if (!IsZipping()) {
830 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
831 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800832 return false;
833 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800834 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700835 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700836 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700837 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700838 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800839 return false;
840 }
841
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700842 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700843 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700844 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700845 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800846 return false;
847 }
848
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700849 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700850 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700851 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800852 return false;
853 }
854
855 return true;
856}
857
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800858static void DoKmsg() {
859 struct stat st;
860 if (!stat(PSTORE_LAST_KMSG, &st)) {
861 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
862 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
863 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
864 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
865 } else {
866 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
867 DumpFile("LAST KMSG", "/proc/last_kmsg");
868 }
869}
870
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800871static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800872 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800873 RunCommand(
874 "KERNEL LOG",
875 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
876 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
877}
878
Nandana Duttdb379fa2019-10-09 16:54:41 +0100879static void DoSystemLogcat(time_t since) {
880 char since_str[80];
881 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
882
883 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
884 RunCommand("SYSTEM LOG",
885 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
886 since_str},
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;
Steven Moreland5a30d342019-10-08 13:53:28 -07001085 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001086 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);
Steven Moreland5a30d342019-10-08 13:53:28 -07001157 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001158 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 Lemee184f662016-10-27 10:04:47 -07001379 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001380
Narayan Kamath8f788292017-05-25 13:20:39 +01001381 // NOTE: tombstones are always added as separate entries in the zip archive
1382 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001383 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001384 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001385 if (!tombstones_dumped) {
1386 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001387 }
1388
Jayachandran Ca94c7172017-06-10 15:08:12 -07001389 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001390
Chenbo Feng276a3b62018-08-07 11:44:49 -07001391 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1392
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001393 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001394
Jayachandran Ca94c7172017-06-10 15:08:12 -07001395 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001396
1397 dump_route_tables();
1398
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001399 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1400 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1401 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001402
Nandana Dutt5c390032019-03-12 10:52:56 +00001403 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001404
Elliott Hughes23ccc622017-02-28 10:14:22 -08001405 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001406
Jin Qianf334d662017-10-10 14:41:37 -07001407 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001408
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001409 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001410
Colin Crossf45fa6b2012-03-26 12:38:26 -07001411 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001412 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1413 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1414 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1415 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1416 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001417
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001418 /* Add window and surface trace files. */
1419 if (!PropertiesHelper::IsUserBuild()) {
1420 ds.AddDir(WMTRACE_DATA_DIR, false);
1421 }
1422
Nandana Dutt5c390032019-03-12 10:52:56 +00001423 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001424
Steven Moreland7440ddb2016-12-15 16:13:39 -08001425 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001426 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1427 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001428 // su does not exist on user builds, so try running without it.
1429 // This way any implementations of vril-dump that do not require
1430 // root can run on user builds.
1431 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001432 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001433 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001434 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001435 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001436 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001437 }
1438
Felipe Lemed8b94e52016-12-08 10:21:44 -08001439 printf("========================================================\n");
1440 printf("== Android Framework Services\n");
1441 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001442
Nandana Dutt5c390032019-03-12 10:52:56 +00001443 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001444
Felipe Lemed8b94e52016-12-08 10:21:44 -08001445 printf("========================================================\n");
1446 printf("== Checkins\n");
1447 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001448
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001449 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001450
1451 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1452
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001453 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1454 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1455 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1456 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001457
Felipe Lemed8b94e52016-12-08 10:21:44 -08001458 printf("========================================================\n");
1459 printf("== Running Application Activities\n");
1460 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001461
Makoto Onuki60780982018-04-16 15:34:00 -07001462 // The following dumpsys internally collects output from running apps, so it can take a long
1463 // time. So let's extend the timeout.
1464
1465 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1466
1467 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001468
Felipe Lemed8b94e52016-12-08 10:21:44 -08001469 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001470 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001471 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001472
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001473 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001474 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001475
Felipe Lemed8b94e52016-12-08 10:21:44 -08001476 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001477 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001478 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001479
Makoto Onuki60780982018-04-16 15:34:00 -07001480 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1481 DUMPSYS_COMPONENTS_OPTIONS);
1482
1483 printf("========================================================\n");
1484 printf("== Running Application Providers (platform)\n");
1485 printf("========================================================\n");
1486
1487 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1488 DUMPSYS_COMPONENTS_OPTIONS);
1489
1490 printf("========================================================\n");
1491 printf("== Running Application Providers (non-platform)\n");
1492 printf("========================================================\n");
1493
1494 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1495 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001496
Adrian Roos8b397ab2017-04-04 16:35:44 -07001497 printf("========================================================\n");
1498 printf("== Dropbox crashes\n");
1499 printf("========================================================\n");
1500
1501 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1502 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1503
Felipe Lemed8b94e52016-12-08 10:21:44 -08001504 printf("========================================================\n");
1505 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1506 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1507 printf("========================================================\n");
1508 printf("== dumpstate: done (id %d)\n", ds.id_);
1509 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001510
1511 printf("========================================================\n");
1512 printf("== Obtaining statsd metadata\n");
1513 printf("========================================================\n");
1514 // This differs from the usual dumpsys stats, which is the stats report data.
1515 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001516
1517 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1518
Nandana Dutt5c390032019-03-12 10:52:56 +00001519 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001520}
1521
Nandana Dutt5c390032019-03-12 10:52:56 +00001522/*
1523 * Dumps state for the default case; drops root after it's no longer necessary.
1524 *
1525 * Returns RunStatus::OK if everything went fine.
1526 * Returns RunStatus::ERROR if there was an error.
1527 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1528 * with the caller.
1529 */
1530static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001531 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001532 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001533 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001534
Nandana Duttdb379fa2019-10-09 16:54:41 +01001535 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1536 // buffer.
1537 DoLogcat();
1538 // Capture timestamp after first logcat to use in next logcat
1539 time_t logcat_ts = time(nullptr);
1540
Nandana Dutt4be45d12018-09-26 15:04:23 +01001541 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001542 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001543
1544 /* Run some operations that require root. */
1545 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1546 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1547
1548 ds.AddDir(RECOVERY_DIR, true);
1549 ds.AddDir(RECOVERY_DATA_DIR, true);
1550 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1551 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1552 if (!PropertiesHelper::IsUserBuild()) {
1553 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1554 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1555 }
1556 add_mountinfo();
1557 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001558 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001559
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001560 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001561 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1562
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001563 // Dump IPsec stats. No keys are exposed here.
1564 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1565
Nandana Dutt4be45d12018-09-26 15:04:23 +01001566 // Run ss as root so we can see socket marks.
1567 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1568
1569 // Run iotop as root to show top 100 IO threads
1570 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1571
Erick Reyese68df822019-02-11 14:46:36 -08001572 // Gather shared memory buffer info if the product implements it
1573 struct stat st;
1574 if (!stat("/product/bin/dmabuf_dump", &st)) {
1575 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1576 }
1577
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001578 DumpFile("PSI cpu", "/proc/pressure/cpu");
1579 DumpFile("PSI memory", "/proc/pressure/memory");
1580 DumpFile("PSI io", "/proc/pressure/io");
1581
Nandana Dutt4be45d12018-09-26 15:04:23 +01001582 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001583 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001584 }
1585
Nandana Dutt5c390032019-03-12 10:52:56 +00001586 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001587 Dumpstate::RunStatus status = dumpstate();
1588 // Capture logcat since the last time we did it.
1589 DoSystemLogcat(logcat_ts);
1590 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001591}
1592
mukesh agrawal253dad42018-01-23 21:59:59 -08001593// This method collects common dumpsys for telephony and wifi
1594static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001595 DumpIpTablesAsRoot();
1596
Jayachandran Cb4389d92019-07-08 09:46:05 -07001597 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1598
Jayachandran Ca94c7172017-06-10 15:08:12 -07001599 if (!DropRootUser()) {
1600 return;
1601 }
1602
1603 do_dmesg();
1604 DoLogcat();
1605 DumpPacketStats();
1606 DoKmsg();
1607 DumpIpAddrAndRules();
1608 dump_route_tables();
Jayachandran Cb4389d92019-07-08 09:46:05 -07001609 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001610
1611 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1612 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001613}
1614
1615// This method collects dumpsys for telephony debugging only
1616static void DumpstateTelephonyOnly() {
1617 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001618 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001619
1620 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001621
1622 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1623
1624 printf("========================================================\n");
1625 printf("== Android Framework Services\n");
1626 printf("========================================================\n");
1627
Vishnu Nair652cc802017-11-30 15:18:30 -08001628 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1629 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001630 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1631 SEC_TO_MSEC(10));
1632 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001633 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1634 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001635 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1636 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001637 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1638 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001639
1640 printf("========================================================\n");
1641 printf("== Running Application Services\n");
1642 printf("========================================================\n");
1643
1644 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1645
1646 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001647 printf("== Running Application Services (non-platform)\n");
1648 printf("========================================================\n");
1649
1650 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1651 DUMPSYS_COMPONENTS_OPTIONS);
1652
1653 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001654 printf("== Checkins\n");
1655 printf("========================================================\n");
1656
1657 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1658
1659 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001660 printf("== dumpstate: done (id %d)\n", ds.id_);
1661 printf("========================================================\n");
1662}
1663
mukesh agrawal253dad42018-01-23 21:59:59 -08001664// This method collects dumpsys for wifi debugging only
1665static void DumpstateWifiOnly() {
1666 DurationReporter duration_reporter("DUMPSTATE");
1667
1668 DumpstateRadioCommon();
1669
1670 printf("========================================================\n");
1671 printf("== Android Framework Services\n");
1672 printf("========================================================\n");
1673
1674 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1675 SEC_TO_MSEC(10));
1676 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1677 SEC_TO_MSEC(10));
1678
1679 printf("========================================================\n");
1680 printf("== dumpstate: done (id %d)\n", ds.id_);
1681 printf("========================================================\n");
1682}
1683
Nandana Duttcf419a72019-03-14 10:40:17 +00001684Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001685 DurationReporter duration_reporter("DUMP TRACES");
1686
1687 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1688 const size_t buf_size = temp_file_pattern.length() + 1;
1689 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1690 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1691
1692 // Create a new, empty file to receive all trace dumps.
1693 //
1694 // TODO: This can be simplified once we remove support for the old style
1695 // dumps. We can have a file descriptor passed in to dump_traces instead
1696 // of creating a file, closing it and then reopening it again.
1697 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1698 if (fd < 0) {
1699 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001700 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001701 }
1702
1703 // Nobody should have access to this temporary file except dumpstate, but we
1704 // temporarily grant 'read' to 'others' here because this file is created
1705 // when tombstoned is still running as root, but dumped after dropping. This
1706 // can go away once support for old style dumping has.
1707 const int chmod_ret = fchmod(fd, 0666);
1708 if (chmod_ret < 0) {
1709 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001710 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001711 }
1712
1713 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1714 if (proc.get() == nullptr) {
1715 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001716 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001717 }
1718
1719 // Number of times process dumping has timed out. If we encounter too many
1720 // failures, we'll give up.
1721 int timeout_failures = 0;
1722 bool dalvik_found = false;
1723
1724 const std::set<int> hal_pids = get_interesting_hal_pids();
1725
1726 struct dirent* d;
1727 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001728 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001729 int pid = atoi(d->d_name);
1730 if (pid <= 0) {
1731 continue;
1732 }
1733
1734 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1735 std::string exe;
1736 if (!android::base::Readlink(link_name, &exe)) {
1737 continue;
1738 }
1739
1740 bool is_java_process;
1741 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1742 // Don't bother dumping backtraces for the zygote.
1743 if (IsZygote(pid)) {
1744 continue;
1745 }
1746
1747 dalvik_found = true;
1748 is_java_process = true;
1749 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1750 is_java_process = false;
1751 } else {
1752 // Probably a native process we don't care about, continue.
1753 continue;
1754 }
1755
1756 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1757 if (timeout_failures == 3) {
1758 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1759 break;
1760 }
1761
1762 const uint64_t start = Nanotime();
1763 const int ret = dump_backtrace_to_file_timeout(
1764 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1765 is_java_process ? 5 : 20, fd);
1766
1767 if (ret == -1) {
1768 // For consistency, the header and footer to this message match those
1769 // dumped by debuggerd in the success case.
1770 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1771 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1772 dprintf(fd, "---- end %d ----", pid);
1773 timeout_failures++;
1774 continue;
1775 }
1776
1777 // We've successfully dumped stack traces, reset the failure count
1778 // and write a summary of the elapsed time to the file and continue with the
1779 // next process.
1780 timeout_failures = 0;
1781
1782 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1783 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1784 }
1785
1786 if (!dalvik_found) {
1787 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1788 }
1789
Nandana Duttcf419a72019-03-14 10:40:17 +00001790 *path = file_name_buf.release();
1791 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001792}
1793
Felipe Leme6f674ae2016-11-18 17:10:33 -08001794void Dumpstate::DumpstateBoard() {
1795 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001796 printf("========================================================\n");
1797 printf("== Board\n");
1798 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001799
Felipe Leme6f674ae2016-11-18 17:10:33 -08001800 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001801 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001802 return;
1803 }
1804
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001805 std::vector<std::string> paths;
1806 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001807 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001808 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1809 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001810 remover.emplace_back(android::base::make_scope_guard(
1811 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001812 }
Jie Song9fbfad02017-06-20 16:29:42 -07001813
Wei Wang587eac92018-04-05 12:17:20 -07001814 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1815 if (dumpstate_device == nullptr) {
1816 MYLOGE("No IDumpstateDevice implementation\n");
1817 return;
1818 }
1819
1820 using ScopedNativeHandle =
1821 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1822 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1823 [](native_handle_t* handle) {
1824 native_handle_close(handle);
1825 native_handle_delete(handle);
1826 });
1827 if (handle == nullptr) {
1828 MYLOGE("Could not create native_handle\n");
1829 return;
1830 }
1831
Nandana Dutt5c390032019-03-12 10:52:56 +00001832 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001833 for (size_t i = 0; i < paths.size(); i++) {
1834 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1835
1836 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1837 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1838 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1839 if (fd < 0) {
1840 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1841 return;
1842 }
1843 handle.get()->data[i] = fd.release();
1844 }
1845
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001846 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001847 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1848 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1849 // and grab whatever dumped
1850 std::packaged_task<bool()>
1851 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001852 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1853 if (!status.isOk()) {
1854 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001855 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001856 }
Wei Wang587eac92018-04-05 12:17:20 -07001857 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001858 });
Wei Wang587eac92018-04-05 12:17:20 -07001859
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001860 auto result = dumpstate_task.get_future();
1861 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001862
1863 constexpr size_t timeout_sec = 30;
1864 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1865 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1866 if (!android::base::SetProperty("ctl.interface_restart",
1867 android::base::StringPrintf("%s/default",
1868 IDumpstateDevice::descriptor))) {
1869 MYLOGE("Couldn't restart dumpstate HAL\n");
1870 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001871 }
Wei Wang587eac92018-04-05 12:17:20 -07001872 // Wait some time for init to kill dumpstate vendor HAL
1873 constexpr size_t killing_timeout_sec = 10;
1874 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1875 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1876 "there might be racing in content\n", killing_timeout_sec);
1877 }
1878
1879 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1880 for (size_t i = 0; i < paths.size(); i++) {
1881 struct stat s;
1882 if (fstat(handle.get()->data[i], &s) == -1) {
1883 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1884 strerror(errno));
1885 file_sizes[i] = -1;
1886 continue;
1887 }
1888 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001889 }
1890
1891 for (size_t i = 0; i < paths.size(); i++) {
1892 if (file_sizes[i] == -1) {
1893 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001894 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001895 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001896 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001897 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001898 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001899 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001900 }
1901
Felipe Lemed8b94e52016-12-08 10:21:44 -08001902 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001903}
1904
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001905static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001906 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001907 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001908 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1909 " -h: display this help message\n"
1910 " -b: play sound file instead of vibrate, at beginning of job\n"
1911 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001912 " -d: append date to filename\n"
1913 " -p: capture screenshot to filename.png\n"
1914 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001915 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001916 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001917 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001918 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001919 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001920 "progress (requires -B)\n"
1921 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001922 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001923 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001924 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001925}
1926
Wei Liuf87959e2016-08-26 14:51:42 -07001927static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001928 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001929}
1930
Felipe Leme1d486fe2016-10-14 18:06:47 -07001931bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001932 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001933 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001934 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001935 // Final timestamp
1936 char date[80];
1937 time_t the_real_now_please_stand_up = time(nullptr);
1938 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001939 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001940 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001941
Felipe Leme9a523ae2016-10-20 15:10:33 -07001942 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001943 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001944 return false;
1945 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001946 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001947 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001948 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001949 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001950
Felipe Leme0f3fb202016-06-10 17:10:53 -07001951 // Add log file (which contains stderr output) to zip...
1952 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001953 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001954 MYLOGE("Failed to add dumpstate log to .zip file\n");
1955 return false;
1956 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001957 // TODO: Should truncate the existing file.
1958 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001959 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1960 return false;
1961 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001962 fprintf(stderr, "\n");
1963
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001964 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001965 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001966 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001967 return false;
1968 }
1969
Felipe Leme1d486fe2016-10-14 18:06:47 -07001970 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1971 ds.zip_file.reset(nullptr);
1972
Felipe Lemee9d2c542016-11-15 11:48:26 -08001973 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001974 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001975
Felipe Leme1e9edc62015-12-21 16:02:13 -08001976 return true;
1977}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001978
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001979static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001980 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1981 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001982 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001983 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001984 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001985 }
1986
1987 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001988 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001989
1990 std::vector<uint8_t> buffer(65536);
1991 while (1) {
1992 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1993 if (bytes_read == 0) {
1994 break;
1995 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001996 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001997 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001998 }
1999
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002000 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002001 }
2002
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002003 uint8_t hash[SHA256_DIGEST_LENGTH];
2004 SHA256_Final(hash, &ctx);
2005
2006 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
2007 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00002008 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002009 }
2010 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2011 return std::string(hash_buffer);
2012}
2013
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002014static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2015 // clang-format off
2016 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2017 "--receiver-foreground", "--receiver-include-background", "-a", action};
2018 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002019
2020 am.insert(am.end(), args.begin(), args.end());
2021
Felipe Leme8d2410e2017-02-08 09:46:08 -08002022 RunCommand("", am,
2023 CommandOptions::WithTimeout(20)
2024 .Log("Sending broadcast: '%s'\n")
2025 .Always()
2026 .DropRoot()
2027 .RedirectStderr()
2028 .Build());
2029}
2030
Felipe Leme35b8cf12017-02-10 15:47:29 -08002031static void Vibrate(int duration_ms) {
2032 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002033 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002034 CommandOptions::WithTimeout(10)
2035 .Log("Vibrate: '%s'\n")
2036 .Always()
2037 .Build());
2038 // clang-format on
2039}
2040
Nandana Dutt979388e2018-11-30 16:48:55 +00002041static void MaybeResolveSymlink(std::string* path) {
2042 std::string resolved_path;
2043 if (android::base::Readlink(*path, &resolved_path)) {
2044 *path = resolved_path;
2045 }
2046}
2047
Nandana Dutt4be45d12018-09-26 15:04:23 +01002048/*
2049 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2050 * if we are writing zip files and adds the version file.
2051 */
2052static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002053 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2054
Nandana Dutt4be45d12018-09-26 15:04:23 +01002055 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2056 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002057 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002058 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002059 char date[80];
2060 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2061 ds.name_ = date;
2062 } else {
2063 ds.name_ = "undated";
2064 }
2065
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002066 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002067 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002068 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002069 ds.base_name_ += "-wifi";
2070 }
2071
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002072 if (ds.options_->do_fb) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002073 ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 }
2075 ds.tmp_path_ = ds.GetPath(".tmp");
2076 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2077
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002078 std::string destination = ds.CalledByApi()
Nandana Dutt54dbd672019-01-11 12:58:05 +00002079 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002080 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002081 MYLOGD(
2082 "Bugreport dir: %s\n"
2083 "Base name: %s\n"
2084 "Suffix: %s\n"
2085 "Log path: %s\n"
2086 "Temporary path: %s\n"
2087 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002088 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2089 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002090
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002091 if (ds.options_->do_zip_file) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002092 ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002093 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2094 create_parent_dirs(ds.path_.c_str());
2095 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2096 if (ds.zip_file == nullptr) {
2097 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2098 } else {
2099 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2100 }
2101 ds.AddTextZipEntry("version.txt", ds.version_);
2102 }
2103}
2104
2105/*
2106 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2107 * printing zipped file status, etc.
2108 */
2109static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002110 /* check if user changed the suffix using system properties */
2111 std::string name =
2112 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2113 bool change_suffix = false;
2114 if (!name.empty()) {
2115 /* must whitelist which characters are allowed, otherwise it could cross directories */
2116 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2117 if (std::regex_match(name.c_str(), valid_regex)) {
2118 change_suffix = true;
2119 } else {
2120 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2121 }
2122 }
2123 if (change_suffix) {
2124 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2125 ds.name_ = name;
2126 if (!ds.screenshot_path_.empty()) {
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002127 std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
Nandana Dutt4be45d12018-09-26 15:04:23 +01002128 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2129 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2130 new_screenshot_path.c_str(), strerror(errno));
2131 } else {
2132 ds.screenshot_path_ = new_screenshot_path;
2133 }
2134 }
2135 }
2136
2137 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002138 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002139 if (!ds.FinishZipFile()) {
2140 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2141 do_text_file = true;
2142 } else {
2143 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002144 // If the user has changed the suffix, we need to change the zip file name.
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002145 std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
Nandana Dutt383d0c12018-11-30 15:54:56 +00002146 if (ds.path_ != new_path) {
2147 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2148 if (rename(ds.path_.c_str(), new_path.c_str())) {
2149 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2150 strerror(errno));
2151 } else {
2152 ds.path_ = new_path;
2153 }
2154 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002155 }
2156 }
2157 if (do_text_file) {
2158 ds.path_ = ds.GetPath(".txt");
2159 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2160 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2161 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2162 ds.path_.clear();
2163 }
2164 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002165 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002166 if (do_text_file) {
2167 dprintf(ds.control_socket_fd_,
2168 "FAIL:could not create zip file, check %s "
2169 "for more details\n",
2170 ds.log_path_.c_str());
2171 } else {
2172 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2173 }
2174 }
2175}
2176
2177/* Broadcasts that we are done with the bugreport */
2178static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002179 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002180 if (!ds.path_.empty()) {
2181 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002182 // clang-format off
2183
2184 std::vector<std::string> am_args = {
2185 "--receiver-permission", "android.permission.DUMP",
2186 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2187 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2188 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002189 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002190 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2191 };
2192 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002193 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002194 am_args.push_back("--es");
2195 am_args.push_back("android.intent.extra.SCREENSHOT");
2196 am_args.push_back(ds.screenshot_path_);
2197 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002198 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002199 am_args.push_back("--es");
2200 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002201 am_args.push_back(ds.options_->notification_title);
2202 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002203 am_args.push_back("--es");
2204 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002205 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002206 }
2207 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002208 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002209 am_args.push_back("--es");
2210 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002211 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002212 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2213 } else {
2214 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2215 }
2216 } else {
2217 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2218 }
2219}
2220
Nandana Dutt58d72e22018-11-16 10:30:48 +00002221static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2222 switch (mode) {
2223 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2224 return "BUGREPORT_FULL";
2225 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2226 return "BUGREPORT_INTERACTIVE";
2227 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2228 return "BUGREPORT_REMOTE";
2229 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2230 return "BUGREPORT_WEAR";
2231 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2232 return "BUGREPORT_TELEPHONY";
2233 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2234 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002235 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2236 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002237 }
2238}
2239
2240static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002241 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002242 switch (mode) {
2243 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2244 options->do_broadcast = true;
2245 options->do_fb = true;
2246 break;
2247 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002248 // Currently, the dumpstate binder is only used by Shell to update progress.
2249 options->do_start_service = true;
2250 options->do_progress_updates = true;
2251 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002252 options->do_broadcast = true;
2253 break;
2254 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002255 options->do_vibrate = false;
2256 options->is_remote_mode = true;
2257 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002258 options->do_broadcast = true;
2259 break;
2260 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002261 options->do_start_service = true;
2262 options->do_progress_updates = true;
2263 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002264 options->do_fb = true;
2265 options->do_broadcast = true;
2266 break;
2267 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002268 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002269 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002270 options->do_broadcast = true;
2271 break;
2272 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002273 options->wifi_only = true;
2274 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002275 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002276 options->do_broadcast = true;
2277 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002278 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2279 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002280 }
2281}
2282
2283static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002284 // If the system property is not set, it's assumed to be a default bugreport.
2285 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002286
2287 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2288 if (!extra_options.empty()) {
2289 // Framework uses a system property to override some command-line args.
2290 // Currently, it contains the type of the requested bugreport.
2291 if (extra_options == "bugreportplus") {
2292 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002293 } else if (extra_options == "bugreportfull") {
2294 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002295 } else if (extra_options == "bugreportremote") {
2296 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2297 } else if (extra_options == "bugreportwear") {
2298 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2299 } else if (extra_options == "bugreporttelephony") {
2300 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2301 } else if (extra_options == "bugreportwifi") {
2302 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002303 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002304 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002305 }
2306 // Reset the property
2307 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2308 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002309 return mode;
2310}
2311
2312// TODO: Move away from system properties when we have options passed via binder calls.
2313/* Sets runtime options from the system properties and then clears those properties. */
2314static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2315 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2316 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002317
2318 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2319 if (!options->notification_title.empty()) {
2320 // Reset the property
2321 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2322
Nandana Duttdd8cca32018-11-14 10:10:29 +00002323 options->notification_description =
2324 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002325 if (!options->notification_description.empty()) {
2326 // Reset the property
2327 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2328 }
2329 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2330 options->notification_description.c_str());
2331 }
2332}
2333
Nandana Dutt58d72e22018-11-16 10:30:48 +00002334static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2335 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2336 MYLOGI("do_add_date: %d\n", options.do_add_date);
2337 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2338 MYLOGI("use_socket: %d\n", options.use_socket);
2339 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2340 MYLOGI("do_fb: %d\n", options.do_fb);
2341 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2342 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2343 MYLOGI("show_header_only: %d\n", options.show_header_only);
2344 MYLOGI("do_start_service: %d\n", options.do_start_service);
2345 MYLOGI("telephony_only: %d\n", options.telephony_only);
2346 MYLOGI("wifi_only: %d\n", options.wifi_only);
2347 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002348 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002349 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2350 MYLOGI("args: %s\n", options.args.c_str());
2351 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2352 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2353}
2354
Nandana Dutt54dbd672019-01-11 12:58:05 +00002355void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2356 const android::base::unique_fd& bugreport_fd_in,
2357 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002358 // In the new API world, date is always added; output is always a zip file.
2359 // TODO(111441001): remove these options once they are obsolete.
2360 do_add_date = true;
2361 do_zip_file = true;
2362
Nandana Dutt54dbd672019-01-11 12:58:05 +00002363 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2364 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2365 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002366
2367 extra_options = ModeToString(bugreport_mode);
2368 SetOptionsFromMode(bugreport_mode, this);
2369}
2370
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002371Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2372 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002373 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002374 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002375 switch (c) {
2376 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002377 case 'd': do_add_date = true; break;
2378 case 'z': do_zip_file = true; break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002379 case 's': use_socket = true; break;
2380 case 'S': use_control_socket = true; break;
2381 case 'v': show_header_only = true; break;
2382 case 'q': do_vibrate = false; break;
2383 case 'p': do_fb = true; break;
2384 case 'P': do_progress_updates = true; break;
2385 case 'R': is_remote_mode = true; break;
2386 case 'B': do_broadcast = true; break;
2387 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002388 case 'w':
2389 // This was already processed
2390 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002391 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002392 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002393 break;
2394 default:
2395 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002396 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002397 break;
2398 // clang-format on
2399 }
2400 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002401
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002402 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002403 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002404 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002405 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002406 }
2407 }
2408
2409 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2410 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002411
2412 SetOptionsFromProperties(this);
2413 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002414}
2415
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002416bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002417 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002418 return false;
2419 }
2420
Nandana Dutt9a76d202019-01-21 15:56:48 +00002421 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002422 return false;
2423 }
2424
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002425 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002426 return false;
2427 }
2428
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002429 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002430 return false;
2431 }
2432
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002433 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002434 return false;
2435 }
2436 return true;
2437}
2438
Nandana Dutt197661d2018-11-16 16:40:21 +00002439void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2440 options_ = std::move(options);
2441}
2442
Nandana Duttd2f5f082019-01-18 17:13:52 +00002443Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2444 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002445 if (listener_ != nullptr) {
2446 switch (status) {
2447 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002448 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002449 break;
2450 case Dumpstate::RunStatus::HELP:
2451 break;
2452 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002453 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002454 break;
2455 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002456 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2457 break;
2458 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2459 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2460 break;
2461 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2462 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002463 break;
2464 }
2465 }
2466 return status;
2467}
2468
Nandana Dutt979388e2018-11-30 16:48:55 +00002469/*
2470 * Dumps relevant information to a bugreport based on the given options.
2471 *
2472 * The bugreport can be dumped to a file or streamed to a socket.
2473 *
2474 * How dumping to file works:
2475 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2476 * stderr is redirected a log file.
2477 *
2478 * The temporary bugreport is then populated via printfs, dumping contents of files and
2479 * output of commands to stdout.
2480 *
2481 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2482 * text file.
2483 *
2484 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2485 * gets added to the archive.
2486 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002487 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2488 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002489 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002490Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2491 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002492 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002493 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002494 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002495 return RunStatus::INVALID_INPUT;
2496 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002497 /* set as high priority, and protect from OOM killer */
2498 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002499
Felipe Lemed071c682016-10-20 16:48:00 -07002500 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002501 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002502 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002503 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002504 } else {
2505 /* fallback to kernels <= 2.6.35 */
2506 oom_adj = fopen("/proc/self/oom_adj", "we");
2507 if (oom_adj) {
2508 fputs("-17", oom_adj);
2509 fclose(oom_adj);
2510 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002511 }
2512
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002513 if (version_ == VERSION_DEFAULT) {
2514 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002515 }
2516
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002517 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002518 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002519 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002520 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002521 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002522 }
2523
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002524 if (options_->show_header_only) {
2525 PrintHeader();
2526 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002527 }
2528
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002529 MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
2530 calling_uid, calling_package.c_str());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002531 if (options_->bugreport_fd.get() != -1) {
2532 // If the output needs to be copied over to the caller's fd, get user consent.
2533 android::String16 package(calling_package.c_str());
2534 CheckUserConsent(calling_uid, package);
2535 }
2536
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002537 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002538 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002539
2540 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002541 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002542 is_redirecting
2543 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2544 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002545 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002546
Felipe Lemed071c682016-10-20 16:48:00 -07002547 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002548 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002549 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002550 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2551
2552 MYLOGI("begin\n");
2553
Sahana Raof35ed432019-07-12 10:47:52 +01002554 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2555 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2556 } else {
2557 // Wake lock will be released automatically on process death
2558 MYLOGD("Wake lock acquired.\n");
2559 }
2560
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002561 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002562
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002563 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002564 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002565 MYLOGI("Starting 'dumpstate' service\n");
2566 android::status_t ret;
2567 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2568 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2569 }
2570 }
2571
Felipe Lemef0292972016-11-22 13:57:05 -08002572 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002573 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2574 }
2575
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002576 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2577 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002578
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002579 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002580
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002581 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002582
Christopher Ferrised9354f2014-10-01 17:35:01 -07002583 // If we are going to use a socket, do it as early as possible
2584 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002585 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002586 if (!redirect_to_socket(stdout, "dumpstate")) {
2587 return ERROR;
2588 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002589 }
2590
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002591 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002592 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002593 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002594 if (control_socket_fd_ == -1) {
2595 return ERROR;
2596 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002597 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002598 }
2599
Felipe Leme71bbfc52015-11-23 14:14:51 -08002600 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002601 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002602
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002603 if (options_->do_progress_updates) {
2604 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002605 // clang-format off
2606 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002607 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002608 "--es", "android.intent.extra.NAME", name_,
2609 "--ei", "android.intent.extra.ID", std::to_string(id_),
2610 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2611 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002612 };
2613 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002614 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002615 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002616 if (options_->use_control_socket) {
2617 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002618 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002619 }
2620 }
2621
Nick Kralevichf3599b32016-01-25 15:05:16 -08002622 /* read /proc/cmdline before dropping root */
2623 FILE *cmdline = fopen("/proc/cmdline", "re");
2624 if (cmdline) {
2625 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2626 fclose(cmdline);
2627 }
2628
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002629 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002630 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002631 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002632
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002633 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002634 MYLOGI("taking early screenshot\n");
2635 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002636 }
2637
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002638 if (options_->do_zip_file && zip_file != nullptr) {
2639 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2640 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002641 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002642 }
2643 }
2644
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002645 int dup_stdout_fd;
2646 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002647 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002648 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002649 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002650 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2651 return ERROR;
2652 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002653 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2654 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2655 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002656 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002657
2658 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2659 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002660 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002661 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002662 /* TODO: rather than generating a text file now and zipping it later,
2663 it would be more efficient to redirect stdout to the zip entry
2664 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002665 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2666 return ERROR;
2667 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002668 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002669 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002670 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002671 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002672 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002673
2674 // Don't buffer stdout
2675 setvbuf(stdout, nullptr, _IONBF, 0);
2676
Felipe Leme608385d2016-02-01 10:35:38 -08002677 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2678 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002679 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002680 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002681
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002682 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002683 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002684 DumpstateBoard();
2685 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002686 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002687 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002688 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002689 RunStatus s = DumpstateDefault();
2690 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002691 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002692 HandleUserConsentDenied();
2693 }
2694 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002695 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002696 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002697
Felipe Leme55b42a62015-11-10 17:39:08 -08002698 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002699 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002700 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002701 }
2702
Nandana Duttd2f5f082019-01-18 17:13:52 +00002703 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002704 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002705 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002706 }
2707
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002708 // Share the final file with the caller if the user has consented or Shell is the caller.
Nandana Duttd2f5f082019-01-18 17:13:52 +00002709 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2710 if (options_->bugreport_fd.get() != -1) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002711 status = CopyBugreportIfUserConsented(calling_uid);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002712 if (status != Dumpstate::RunStatus::OK &&
2713 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2714 // Do an early return if there were errors. We make an exception for consent
2715 // timing out because it's possible the user got distracted. In this case the
2716 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002717 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002718 return status;
2719 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002720 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002721 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2722 options_->screenshot_fd.get());
2723 if (copy_succeeded) {
2724 android::os::UnlinkAndLogOnError(screenshot_path_);
2725 }
2726 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002727 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2728 MYLOGI(
2729 "Did not receive user consent yet."
2730 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002731 const String16 incidentcompanion("incidentcompanion");
2732 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2733 if (ics != nullptr) {
2734 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2735 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2736 consent_callback_.get());
2737 } else {
2738 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2739 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002740 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002741 }
2742
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002743 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002744 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002745 for (int i = 0; i < 3; i++) {
2746 Vibrate(75);
2747 usleep((75 + 50) * 1000);
2748 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002749 }
2750
Jeff Brown1dc94e32014-09-11 14:15:27 -07002751 /* tell activity manager we're done */
Abhijeet Kaur69b479a2019-09-03 13:40:27 +01002752 if (options_->do_broadcast && !CalledByApi()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002753 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002754 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002755 }
2756
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002757 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2758 progress_->GetInitialMax());
2759 progress_->Save();
2760 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002761
Felipe Leme107a05f2016-03-08 15:11:15 -08002762 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002763 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002764 }
2765
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002766 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002767 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002768 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002769 }
2770
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002771 tombstone_data_.clear();
2772 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002773
Nandana Duttd2f5f082019-01-18 17:13:52 +00002774 return (consent_callback_ != nullptr &&
2775 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2776 ? USER_CONSENT_TIMED_OUT
2777 : RunStatus::OK;
2778}
2779
2780void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002781 if (calling_uid == AID_SHELL) {
2782 return;
2783 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002784 consent_callback_ = new ConsentCallback();
2785 const String16 incidentcompanion("incidentcompanion");
2786 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2787 if (ics != nullptr) {
2788 MYLOGD("Checking user consent via incidentcompanion service\n");
2789 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002790 calling_uid, calling_package, String16(), String16(),
2791 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002792 } else {
2793 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2794 }
2795}
2796
Nandana Dutt5c390032019-03-12 10:52:56 +00002797bool Dumpstate::IsUserConsentDenied() const {
2798 return ds.consent_callback_ != nullptr &&
2799 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2800}
2801
Abhijeet Kaur359b1ff2019-07-26 16:01:36 +01002802bool Dumpstate::CalledByApi() const {
2803 return ds.options_->bugreport_fd.get() != -1 ? true : false;
2804}
2805
Nandana Duttd2f5f082019-01-18 17:13:52 +00002806void Dumpstate::CleanupFiles() {
2807 android::os::UnlinkAndLogOnError(tmp_path_);
2808 android::os::UnlinkAndLogOnError(screenshot_path_);
2809 android::os::UnlinkAndLogOnError(path_);
2810}
2811
2812Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2813 MYLOGD("User denied consent; deleting files and returning\n");
2814 CleanupFiles();
2815 return USER_CONSENT_DENIED;
2816}
2817
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002818Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
Nandana Duttd2f5f082019-01-18 17:13:52 +00002819 // If the caller has asked to copy the bugreport over to their directory, we need explicit
Abhijeet Kaur3172b532019-10-15 15:07:03 +01002820 // user consent (unless the caller is Shell).
2821 UserConsentResult consent_result;
2822 if (calling_uid == AID_SHELL) {
2823 consent_result = UserConsentResult::APPROVED;
2824 } else {
2825 consent_result = consent_callback_->getResult();
2826 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002827 if (consent_result == UserConsentResult::UNAVAILABLE) {
2828 // User has not responded yet.
2829 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2830 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2831 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2832 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2833 sleep(delay_seconds);
2834 }
2835 consent_result = consent_callback_->getResult();
2836 }
2837 if (consent_result == UserConsentResult::DENIED) {
2838 // User has explicitly denied sharing with the app. To be safe delete the
2839 // internal bugreport & tmp files.
2840 return HandleUserConsentDenied();
2841 }
2842 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002843 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2844 if (copy_succeeded) {
2845 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002846 }
2847 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2848 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2849 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2850 // Since we do not have user consent to share the bugreport it does not get
2851 // copied over to the calling app but remains in the internal directory from
2852 // where the user can manually pull it.
2853 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2854 }
2855 // Unknown result; must be a programming error.
2856 MYLOGE("Unknown user consent result:%d\n", consent_result);
2857 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002858}
2859
Nandana Duttf02564e2019-02-15 15:24:24 +00002860Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002861 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2862 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2863 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002864 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002865 // When directly running dumpstate binary, the output is not expected to be written
2866 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002867 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002868
2869 // calling_uid and calling_package are for user consent to share the bugreport with
2870 // an app; they are irrelvant here because bugreport is only written to a local
2871 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002872 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002873 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002874 return status;
2875}
2876
2877/* Main entry point for dumpstate binary. */
2878int run_main(int argc, char* argv[]) {
2879 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002880
2881 switch (status) {
2882 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002883 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002884 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002885 ShowUsage();
2886 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002887 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002888 fprintf(stderr, "Invalid combination of args\n");
2889 ShowUsage();
2890 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002891 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002892 FALLTHROUGH_INTENDED;
2893 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2894 FALLTHROUGH_INTENDED;
2895 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002896 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002897 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002898}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002899
2900// TODO(111441001): Default DumpOptions to sensible values.
2901Dumpstate::Dumpstate(const std::string& version)
2902 : pid_(getpid()),
2903 options_(new Dumpstate::DumpOptions()),
Nandana Dutt402a8392019-06-14 14:25:13 +01002904 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002905 version_(version),
2906 now_(time(nullptr)) {
2907}
2908
2909Dumpstate& Dumpstate::GetInstance() {
2910 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2911 return singleton_;
2912}
2913
Nandana Dutt8d945c02019-08-14 13:30:07 +01002914DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2915 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002916 if (!title_.empty()) {
2917 started_ = Nanotime();
2918 }
2919}
2920
2921DurationReporter::~DurationReporter() {
2922 if (!title_.empty()) {
2923 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002924 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002925 return;
2926 }
2927 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2928 if (logcat_only_) {
2929 return;
2930 }
2931 // Use "Yoda grammar" to make it easier to grep|sort sections.
2932 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2933 }
2934}
2935
2936const int32_t Progress::kDefaultMax = 5000;
2937
2938Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2939}
2940
2941Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2942 : Progress(initial_max, growth_factor, "") {
2943 progress_ = progress;
2944}
2945
2946Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2947 : initial_max_(initial_max),
2948 progress_(0),
2949 max_(initial_max),
2950 growth_factor_(growth_factor),
2951 n_runs_(0),
2952 average_max_(0),
2953 path_(path) {
2954 if (!path_.empty()) {
2955 Load();
2956 }
2957}
2958
2959void Progress::Load() {
2960 MYLOGD("Loading stats from %s\n", path_.c_str());
2961 std::string content;
2962 if (!android::base::ReadFileToString(path_, &content)) {
2963 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2964 return;
2965 }
2966 if (content.empty()) {
2967 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2968 return;
2969 }
2970 std::vector<std::string> lines = android::base::Split(content, "\n");
2971
2972 if (lines.size() < 1) {
2973 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2974 (int)lines.size(), max_);
2975 return;
2976 }
2977 char* ptr;
2978 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2979 average_max_ = strtol(ptr, nullptr, 10);
2980 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2981 average_max_ > STATS_MAX_AVERAGE) {
2982 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2983 initial_max_ = Progress::kDefaultMax;
2984 } else {
2985 initial_max_ = average_max_;
2986 }
2987 max_ = initial_max_;
2988
2989 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2990}
2991
2992void Progress::Save() {
2993 int32_t total = n_runs_ * average_max_ + progress_;
2994 int32_t runs = n_runs_ + 1;
2995 int32_t average = floor(((float)total) / runs);
2996 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2997 path_.c_str());
2998 if (path_.empty()) {
2999 return;
3000 }
3001
3002 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
3003 if (!android::base::WriteStringToFile(content, path_)) {
3004 MYLOGE("Could not save stats on %s\n", path_.c_str());
3005 }
3006}
3007
3008int32_t Progress::Get() const {
3009 return progress_;
3010}
3011
3012bool Progress::Inc(int32_t delta_sec) {
3013 bool changed = false;
3014 if (delta_sec >= 0) {
3015 progress_ += delta_sec;
3016 if (progress_ > max_) {
3017 int32_t old_max = max_;
3018 max_ = floor((float)progress_ * growth_factor_);
3019 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
3020 changed = true;
3021 }
3022 }
3023 return changed;
3024}
3025
3026int32_t Progress::GetMax() const {
3027 return max_;
3028}
3029
3030int32_t Progress::GetInitialMax() const {
3031 return initial_max_;
3032}
3033
3034void Progress::Dump(int fd, const std::string& prefix) const {
3035 const char* pr = prefix.c_str();
3036 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3037 dprintf(fd, "%smax: %d\n", pr, max_);
3038 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3039 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3040 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3041 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3042 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3043}
3044
3045bool Dumpstate::IsZipping() const {
3046 return zip_writer_ != nullptr;
3047}
3048
3049std::string Dumpstate::GetPath(const std::string& suffix) const {
3050 return GetPath(bugreport_internal_dir_, suffix);
3051}
3052
3053std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3054 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3055 name_.c_str(), suffix.c_str());
3056}
3057
3058void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3059 progress_ = std::move(progress);
3060}
3061
3062void for_each_userid(void (*func)(int), const char *header) {
3063 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3064 "for_each_userid(%s)", header);
3065 DurationReporter duration_reporter(title);
3066 if (PropertiesHelper::IsDryRun()) return;
3067
3068 DIR *d;
3069 struct dirent *de;
3070
3071 if (header) printf("\n------ %s ------\n", header);
3072 func(0);
3073
3074 if (!(d = opendir("/data/system/users"))) {
3075 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3076 return;
3077 }
3078
3079 while ((de = readdir(d))) {
3080 int userid;
3081 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3082 continue;
3083 }
3084 func(userid);
3085 }
3086
3087 closedir(d);
3088}
3089
3090static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3091 DIR *d;
3092 struct dirent *de;
3093
3094 if (!(d = opendir("/proc"))) {
3095 printf("Failed to open /proc (%s)\n", strerror(errno));
3096 return;
3097 }
3098
3099 if (header) printf("\n------ %s ------\n", header);
3100 while ((de = readdir(d))) {
3101 if (ds.IsUserConsentDenied()) {
3102 MYLOGE(
3103 "Returning early because user denied consent to share bugreport with calling app.");
3104 closedir(d);
3105 return;
3106 }
3107 int pid;
3108 int fd;
3109 char cmdpath[255];
3110 char cmdline[255];
3111
3112 if (!(pid = atoi(de->d_name))) {
3113 continue;
3114 }
3115
3116 memset(cmdline, 0, sizeof(cmdline));
3117
3118 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3119 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3120 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3121 close(fd);
3122 if (cmdline[0]) {
3123 helper(pid, cmdline, arg);
3124 continue;
3125 }
3126 }
3127
3128 // if no cmdline, a kernel thread has comm
3129 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3130 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3131 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3132 close(fd);
3133 if (cmdline[1]) {
3134 cmdline[0] = '[';
3135 size_t len = strcspn(cmdline, "\f\b\r\n");
3136 cmdline[len] = ']';
3137 cmdline[len+1] = '\0';
3138 }
3139 }
3140 if (!cmdline[0]) {
3141 strcpy(cmdline, "N/A");
3142 }
3143 helper(pid, cmdline, arg);
3144 }
3145
3146 closedir(d);
3147}
3148
3149static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3150 for_each_pid_func *func = (for_each_pid_func*) arg;
3151 func(pid, cmdline);
3152}
3153
3154void for_each_pid(for_each_pid_func func, const char *header) {
3155 std::string title = header == nullptr ? "for_each_pid"
3156 : android::base::StringPrintf("for_each_pid(%s)", header);
3157 DurationReporter duration_reporter(title);
3158 if (PropertiesHelper::IsDryRun()) return;
3159
3160 __for_each_pid(for_each_pid_helper, header, (void *) func);
3161}
3162
3163static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3164 DIR *d;
3165 struct dirent *de;
3166 char taskpath[255];
3167 for_each_tid_func *func = (for_each_tid_func *) arg;
3168
3169 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3170
3171 if (!(d = opendir(taskpath))) {
3172 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3173 return;
3174 }
3175
3176 func(pid, pid, cmdline);
3177
3178 while ((de = readdir(d))) {
3179 if (ds.IsUserConsentDenied()) {
3180 MYLOGE(
3181 "Returning early because user denied consent to share bugreport with calling app.");
3182 closedir(d);
3183 return;
3184 }
3185 int tid;
3186 int fd;
3187 char commpath[255];
3188 char comm[255];
3189
3190 if (!(tid = atoi(de->d_name))) {
3191 continue;
3192 }
3193
3194 if (tid == pid)
3195 continue;
3196
3197 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3198 memset(comm, 0, sizeof(comm));
3199 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3200 strcpy(comm, "N/A");
3201 } else {
3202 char *c;
3203 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3204 close(fd);
3205
3206 c = strrchr(comm, '\n');
3207 if (c) {
3208 *c = '\0';
3209 }
3210 }
3211 func(pid, tid, comm);
3212 }
3213
3214 closedir(d);
3215}
3216
3217void for_each_tid(for_each_tid_func func, const char *header) {
3218 std::string title = header == nullptr ? "for_each_tid"
3219 : android::base::StringPrintf("for_each_tid(%s)", header);
3220 DurationReporter duration_reporter(title);
3221
3222 if (PropertiesHelper::IsDryRun()) return;
3223
3224 __for_each_pid(for_each_tid_helper, header, (void *) func);
3225}
3226
3227void show_wchan(int pid, int tid, const char *name) {
3228 if (PropertiesHelper::IsDryRun()) return;
3229
3230 char path[255];
3231 char buffer[255];
3232 int fd, ret, save_errno;
3233 char name_buffer[255];
3234
3235 memset(buffer, 0, sizeof(buffer));
3236
3237 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3238 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3239 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3240 return;
3241 }
3242
3243 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3244 save_errno = errno;
3245 close(fd);
3246
3247 if (ret < 0) {
3248 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3249 return;
3250 }
3251
3252 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3253 pid == tid ? 0 : 3, "", name);
3254
3255 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3256
3257 return;
3258}
3259
3260// print time in centiseconds
3261static void snprcent(char *buffer, size_t len, size_t spc,
3262 unsigned long long time) {
3263 static long hz; // cache discovered hz
3264
3265 if (hz <= 0) {
3266 hz = sysconf(_SC_CLK_TCK);
3267 if (hz <= 0) {
3268 hz = 1000;
3269 }
3270 }
3271
3272 // convert to centiseconds
3273 time = (time * 100 + (hz / 2)) / hz;
3274
3275 char str[16];
3276
3277 snprintf(str, sizeof(str), " %llu.%02u",
3278 time / 100, (unsigned)(time % 100));
3279 size_t offset = strlen(buffer);
3280 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3281 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3282}
3283
3284// print permille as a percent
3285static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3286 char str[16];
3287
3288 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3289 size_t offset = strlen(buffer);
3290 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3291 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3292}
3293
3294void show_showtime(int pid, const char *name) {
3295 if (PropertiesHelper::IsDryRun()) return;
3296
3297 char path[255];
3298 char buffer[1023];
3299 int fd, ret, save_errno;
3300
3301 memset(buffer, 0, sizeof(buffer));
3302
3303 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3304 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3305 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3306 return;
3307 }
3308
3309 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3310 save_errno = errno;
3311 close(fd);
3312
3313 if (ret < 0) {
3314 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3315 return;
3316 }
3317
3318 // field 14 is utime
3319 // field 15 is stime
3320 // field 42 is iotime
3321 unsigned long long utime = 0, stime = 0, iotime = 0;
3322 if (sscanf(buffer,
3323 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3324 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3325 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3326 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3327 &utime, &stime, &iotime) != 3) {
3328 return;
3329 }
3330
3331 unsigned long long total = utime + stime;
3332 if (!total) {
3333 return;
3334 }
3335
3336 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3337 if (permille > 1000) {
3338 permille = 1000;
3339 }
3340
3341 // try to beautify and stabilize columns at <80 characters
3342 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3343 if ((name[0] != '[') || utime) {
3344 snprcent(buffer, sizeof(buffer), 57, utime);
3345 }
3346 snprcent(buffer, sizeof(buffer), 65, stime);
3347 if ((name[0] != '[') || iotime) {
3348 snprcent(buffer, sizeof(buffer), 73, iotime);
3349 }
3350 if (iotime) {
3351 snprdec(buffer, sizeof(buffer), 79, permille);
3352 }
3353 puts(buffer); // adds a trailing newline
3354
3355 return;
3356}
3357
3358void do_dmesg() {
3359 const char *title = "KERNEL LOG (dmesg)";
3360 DurationReporter duration_reporter(title);
3361 printf("------ %s ------\n", title);
3362
3363 if (PropertiesHelper::IsDryRun()) return;
3364
3365 /* Get size of kernel buffer */
3366 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3367 if (size <= 0) {
3368 printf("Unexpected klogctl return value: %d\n\n", size);
3369 return;
3370 }
3371 char *buf = (char *) malloc(size + 1);
3372 if (buf == nullptr) {
3373 printf("memory allocation failed\n\n");
3374 return;
3375 }
3376 int retval = klogctl(KLOG_READ_ALL, buf, size);
3377 if (retval < 0) {
3378 printf("klogctl failure\n\n");
3379 free(buf);
3380 return;
3381 }
3382 buf[retval] = '\0';
3383 printf("%s\n\n", buf);
3384 free(buf);
3385 return;
3386}
3387
3388void do_showmap(int pid, const char *name) {
3389 char title[255];
3390 char arg[255];
3391
3392 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3393 snprintf(arg, sizeof(arg), "%d", pid);
3394 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3395}
3396
3397int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3398 DurationReporter duration_reporter(title);
3399
3400 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3401
3402 UpdateProgress(WEIGHT_FILE);
3403
3404 return status;
3405}
3406
3407int read_file_as_long(const char *path, long int *output) {
3408 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3409 if (fd < 0) {
3410 int err = errno;
3411 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3412 return -1;
3413 }
3414 char buffer[50];
3415 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3416 if (bytes_read == -1) {
3417 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3418 return -2;
3419 }
3420 if (bytes_read == 0) {
3421 MYLOGE("File %s is empty\n", path);
3422 return -3;
3423 }
3424 *output = atoi(buffer);
3425 return 0;
3426}
3427
3428/* calls skip to gate calling dump_from_fd recursively
3429 * in the specified directory. dump_from_fd defaults to
3430 * dump_file_from_fd above when set to NULL. skip defaults
3431 * to false when set to NULL. dump_from_fd will always be
3432 * called with title NULL.
3433 */
3434int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3435 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3436 DurationReporter duration_reporter(title);
3437 DIR *dirp;
3438 struct dirent *d;
3439 char *newpath = nullptr;
3440 const char *slash = "/";
3441 int retval = 0;
3442
3443 if (!title.empty()) {
3444 printf("------ %s (%s) ------\n", title.c_str(), dir);
3445 }
3446 if (PropertiesHelper::IsDryRun()) return 0;
3447
3448 if (dir[strlen(dir) - 1] == '/') {
3449 ++slash;
3450 }
3451 dirp = opendir(dir);
3452 if (dirp == nullptr) {
3453 retval = -errno;
3454 MYLOGE("%s: %s\n", dir, strerror(errno));
3455 return retval;
3456 }
3457
3458 if (!dump_from_fd) {
3459 dump_from_fd = dump_file_from_fd;
3460 }
3461 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3462 if ((d->d_name[0] == '.')
3463 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3464 || (d->d_name[1] == '\0'))) {
3465 continue;
3466 }
3467 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3468 (d->d_type == DT_DIR) ? "/" : "");
3469 if (!newpath) {
3470 retval = -errno;
3471 continue;
3472 }
3473 if (skip && (*skip)(newpath)) {
3474 continue;
3475 }
3476 if (d->d_type == DT_DIR) {
3477 int ret = dump_files("", newpath, skip, dump_from_fd);
3478 if (ret < 0) {
3479 retval = ret;
3480 }
3481 continue;
3482 }
3483 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3484 if (fd.get() < 0) {
3485 retval = -1;
3486 printf("*** %s: %s\n", newpath, strerror(errno));
3487 continue;
3488 }
3489 (*dump_from_fd)(nullptr, newpath, fd.get());
3490 }
3491 closedir(dirp);
3492 if (!title.empty()) {
3493 printf("\n");
3494 }
3495 return retval;
3496}
3497
3498/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3499 * it's possible to avoid issues where opening the file itself can get
3500 * stuck.
3501 */
3502int dump_file_from_fd(const char *title, const char *path, int fd) {
3503 if (PropertiesHelper::IsDryRun()) return 0;
3504
3505 int flags = fcntl(fd, F_GETFL);
3506 if (flags == -1) {
3507 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3508 return -1;
3509 } else if (!(flags & O_NONBLOCK)) {
3510 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3511 return -1;
3512 }
3513 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3514}
3515
3516int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003517 const CommandOptions& options, bool verbose_duration) {
3518 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003519
3520 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3521
3522 /* TODO: for now we're simplifying the progress calculation by using the
3523 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3524 * where its weight should be much higher proportionally to its timeout.
3525 * Ideally, it should use a options.EstimatedDuration() instead...*/
3526 UpdateProgress(options.Timeout());
3527
3528 return status;
3529}
3530
3531void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3532 const CommandOptions& options, long dumpsysTimeoutMs) {
3533 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3534 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3535 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3536 RunCommand(title, dumpsys, options);
3537}
3538
3539int open_socket(const char *service) {
3540 int s = android_get_control_socket(service);
3541 if (s < 0) {
3542 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3543 return -1;
3544 }
3545 fcntl(s, F_SETFD, FD_CLOEXEC);
3546
3547 // Set backlog to 0 to make sure that queue size will be minimum.
3548 // In Linux, because the minimum queue will be 1, connect() will be blocked
3549 // if the other clients already called connect() and the connection request was not accepted.
3550 if (listen(s, 0) < 0) {
3551 MYLOGE("listen(control socket): %s\n", strerror(errno));
3552 return -1;
3553 }
3554
3555 struct sockaddr addr;
3556 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003557 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003558
3559 // Close socket just after accept(), to make sure that connect() by client will get error
3560 // when the socket is used by the other services.
3561 // There is still a race condition possibility between accept and close, but there is no way
3562 // to close-on-accept atomically.
3563 // See detail; b/123306389#comment25
3564 close(s);
3565
3566 if (fd < 0) {
3567 MYLOGE("accept(control socket): %s\n", strerror(errno));
3568 return -1;
3569 }
3570
3571 return fd;
3572}
3573
3574/* redirect output to a service control socket */
3575bool redirect_to_socket(FILE* redirect, const char* service) {
3576 int fd = open_socket(service);
3577 if (fd == -1) {
3578 return false;
3579 }
3580 fflush(redirect);
3581 // TODO: handle dup2 failure
3582 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3583 close(fd);
3584 return true;
3585}
3586
3587// TODO: should call is_valid_output_file and/or be merged into it.
3588void create_parent_dirs(const char *path) {
3589 char *chp = const_cast<char *> (path);
3590
3591 /* skip initial slash */
3592 if (chp[0] == '/')
3593 chp++;
3594
3595 /* create leading directories, if necessary */
3596 struct stat dir_stat;
3597 while (chp && chp[0]) {
3598 chp = strchr(chp, '/');
3599 if (chp) {
3600 *chp = 0;
3601 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3602 MYLOGI("Creating directory %s\n", path);
3603 if (mkdir(path, 0770)) { /* drwxrwx--- */
3604 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3605 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3606 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3607 }
3608 }
3609 *chp++ = '/';
3610 }
3611 }
3612}
3613
3614bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3615 create_parent_dirs(path);
3616
3617 int fd = TEMP_FAILURE_RETRY(open(path,
3618 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3619 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3620 if (fd < 0) {
3621 MYLOGE("%s: %s\n", path, strerror(errno));
3622 return false;
3623 }
3624
3625 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3626 close(fd);
3627 return true;
3628}
3629
3630bool redirect_to_file(FILE* redirect, char* path) {
3631 return _redirect_to_file(redirect, path, O_TRUNC);
3632}
3633
3634bool redirect_to_existing_file(FILE* redirect, char* path) {
3635 return _redirect_to_file(redirect, path, O_APPEND);
3636}
3637
3638void dump_route_tables() {
3639 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3640 if (PropertiesHelper::IsDryRun()) return;
3641 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3642 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3643 FILE* fp = fopen(RT_TABLES_PATH, "re");
3644 if (!fp) {
3645 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3646 return;
3647 }
3648 char table[16];
3649 // Each line has an integer (the table number), a space, and a string (the table name). We only
3650 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3651 // Add a fixed max limit so this doesn't go awry.
3652 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3653 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3654 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3655 }
3656 fclose(fp);
3657}
3658
3659// TODO: make this function thread safe if sections are generated in parallel.
3660void Dumpstate::UpdateProgress(int32_t delta_sec) {
3661 if (progress_ == nullptr) {
3662 MYLOGE("UpdateProgress: progress_ not set\n");
3663 return;
3664 }
3665
3666 // Always update progess so stats can be tuned...
Nandana Dutt402a8392019-06-14 14:25:13 +01003667 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003668
3669 // ...but only notifiy listeners when necessary.
3670 if (!options_->do_progress_updates) return;
3671
3672 int progress = progress_->Get();
3673 int max = progress_->GetMax();
Nandana Dutt402a8392019-06-14 14:25:13 +01003674 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003675
Nandana Dutt402a8392019-06-14 14:25:13 +01003676 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003677 return;
3678 }
Nandana Dutt402a8392019-06-14 14:25:13 +01003679 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003680
3681 if (control_socket_fd_ >= 0) {
3682 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3683 fsync(control_socket_fd_);
3684 }
3685
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003686 if (listener_ != nullptr) {
3687 if (percent % 5 == 0) {
3688 // We don't want to spam logcat, so only log multiples of 5.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003689 MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003690 } else {
3691 // stderr is ignored on normal invocations, but useful when calling
3692 // /system/bin/dumpstate directly for debuggging.
Abhijeet Kaured5d6a62019-10-07 15:02:05 +01003693 fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003694 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003695
3696 listener_->onProgress(percent);
3697 }
3698}
3699
3700void Dumpstate::TakeScreenshot(const std::string& path) {
3701 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3702 int status =
3703 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3704 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3705 if (status == 0) {
3706 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3707 } else {
3708 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3709 }
3710}
3711
3712bool is_dir(const char* pathname) {
3713 struct stat info;
3714 if (stat(pathname, &info) == -1) {
3715 return false;
3716 }
3717 return S_ISDIR(info.st_mode);
3718}
3719
3720time_t get_mtime(int fd, time_t default_mtime) {
3721 struct stat info;
3722 if (fstat(fd, &info) == -1) {
3723 return default_mtime;
3724 }
3725 return info.st_mtime;
3726}