blob: fa9050d5717a751bb8f4c81a01f64571d05cc771 [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010022#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010025#include <math.h>
26#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080031#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010037#include <signal.h>
38#include <stdarg.h>
39#include <string.h>
40#include <sys/capability.h>
41#include <sys/inotify.h>
42#include <sys/klog.h>
43#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070045
46#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070047#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000048#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070049#include <functional>
50#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010051#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070052#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <regex>
54#include <set>
55#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070056#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010057#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070058
Felipe Leme96c2bbb2016-09-26 09:21:21 -070059#include <android-base/file.h>
60#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070061#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080062#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070063#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070064#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010065#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080066#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080067#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000068#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010069#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080070#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070071#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010072#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080074#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000075#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010076#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080077#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010078#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070079#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070080#include <private/android_filesystem_config.h>
81#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070083#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080084#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070085#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070086#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080087
Steven Morelandcb7ef822016-11-29 13:20:37 -080088using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080089using ::std::literals::chrono_literals::operator""ms;
90using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080091
Felipe Leme47e9be22016-12-21 15:37:07 -080092// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080093using android::defaultServiceManager;
94using android::Dumpsys;
95using android::INVALID_OPERATION;
96using android::IServiceManager;
97using android::OK;
98using android::sp;
99using android::status_t;
100using android::String16;
101using android::String8;
102using android::TIMED_OUT;
103using android::UNKNOWN_ERROR;
104using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000105using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000106using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107using android::os::dumpstate::CommandOptions;
108using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100124}
125
126// Reasonable value for max stats.
127static const int STATS_MAX_N_RUNS = 1000;
128static const long STATS_MAX_AVERAGE = 100000;
129
130CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
Nandana Duttd2f5f082019-01-18 17:13:52 +0000132typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134/* read before root is shed */
135static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700136static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000137static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700138
Felipe Leme1d486fe2016-10-14 18:06:47 -0700139// TODO: variables and functions below should be part of dumpstate object
140
Felipe Leme635ca312016-01-05 14:23:02 -0800141static std::set<std::string> mount_points;
142void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800143
Todd Poynor2a83daa2013-11-22 15:44:22 -0800144#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700145#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700146#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800147
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700149#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700150#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700151#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100152#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
153#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800154#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900155#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800156#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700157
Narayan Kamath8f788292017-05-25 13:20:39 +0100158// TODO(narayan): Since this information has to be kept in sync
159// with tombstoned, we should just put it in a common header.
160//
161// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100162static const std::string TOMBSTONE_DIR = "/data/tombstones/";
163static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
164static const std::string ANR_DIR = "/data/anr/";
165static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700166
Felipe Lemee844a9d2016-09-21 15:01:39 -0700167// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000168
Nandana Dutt5c390032019-03-12 10:52:56 +0000169#define RETURN_IF_USER_DENIED_CONSENT() \
170 if (ds.IsUserConsentDenied()) { \
171 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
172 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
173 }
174
175// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
176// if consent is found to be denied.
177#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
178 RETURN_IF_USER_DENIED_CONSENT(); \
179 func_ptr(__VA_ARGS__); \
180 RETURN_IF_USER_DENIED_CONSENT();
181
Sahana Raof35ed432019-07-12 10:47:52 +0100182static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
183
Nandana Dutt979388e2018-11-30 16:48:55 +0000184namespace android {
185namespace os {
186namespace {
187
188static int Open(std::string path, int flags, mode_t mode = 0) {
189 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
190 if (fd == -1) {
191 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
192 }
193 return fd;
194}
195
Nandana Dutt979388e2018-11-30 16:48:55 +0000196
197static int OpenForRead(std::string path) {
198 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
199}
200
201bool CopyFile(int in_fd, int out_fd) {
202 char buf[4096];
203 ssize_t byte_count;
204 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
205 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
206 return false;
207 }
208 }
209 return (byte_count != -1);
210}
211
212static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000213 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000214
215 // Obtain a handle to the source file.
216 android::base::unique_fd in_fd(OpenForRead(input_file));
217 if (out_fd != -1 && in_fd.get() != -1) {
218 if (CopyFile(in_fd.get(), out_fd)) {
219 return true;
220 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000221 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000222 }
223 return false;
224}
225
Nandana Duttd2f5f082019-01-18 17:13:52 +0000226static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000227 if (unlink(file.c_str())) {
228 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000229 return false;
230 }
231 return true;
232}
Nandana Dutt979388e2018-11-30 16:48:55 +0000233
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000234static bool IsFileEmpty(const std::string& file_path) {
235 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
236 if(file.bad()) {
237 MYLOGE("Cannot open file: %s\n", file_path.c_str());
238 return true;
239 }
240 return file.tellg() <= 0;
241}
242
Nikita Ioffea325a572019-05-16 19:49:47 +0100243int64_t GetModuleMetadataVersion() {
244 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
245 if (binder == nullptr) {
246 MYLOGE("Failed to retrieve package_native service");
247 return 0L;
248 }
249 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
250 std::string package_name;
251 auto status = package_service->getModuleMetadataPackageName(&package_name);
252 if (!status.isOk()) {
253 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
254 return 0L;
255 }
256 MYLOGD("Module metadata package name: %s", package_name.c_str());
257 int64_t version_code;
258 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
259 &version_code);
260 if (!status.isOk()) {
261 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
262 return 0L;
263 }
264 return version_code;
265}
266
Nandana Dutt979388e2018-11-30 16:48:55 +0000267} // namespace
268} // namespace os
269} // namespace android
270
Felipe Leme678727a2016-09-21 17:22:11 -0700271static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800272 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800273 long dumpsysTimeoutMs = 0) {
274 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700275}
276static int DumpFile(const std::string& title, const std::string& path) {
277 return ds.DumpFile(title, path);
278}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800279
Felipe Lemee844a9d2016-09-21 15:01:39 -0700280// Relative directory (inside the zip) for all files copied as-is into the bugreport.
281static const std::string ZIP_ROOT_DIR = "FS";
282
Vishnu Naire97d6122018-01-18 13:58:56 -0800283static const std::string kProtoPath = "proto/";
284static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700285static const std::string kDumpstateBoardFiles[] = {
286 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700287 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700288};
289static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
290
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700291static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700292static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700293static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700294static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
295static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700296
Felipe Lemef0292972016-11-22 13:57:05 -0800297static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
298
Narayan Kamath8f788292017-05-25 13:20:39 +0100299/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100300 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
301 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
302 * is set, the vector only contains files that were written in the last 30 minutes.
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
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800879static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800880 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800881 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
882 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800883 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100884 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800885 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
886 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800887 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800888 RunCommand(
889 "EVENT LOG",
890 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100891 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800892 timeout_ms = logcat_timeout({"stats"});
893 RunCommand(
894 "STATS LOG",
895 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100896 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800897 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800898 RunCommand(
899 "RADIO LOG",
900 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100901 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800902
903 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
904
905 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800906 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
907 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800908}
909
Mike Ma5c267872019-08-21 11:31:34 -0700910static void DumpIncidentReport() {
911 if (!ds.IsZipping()) {
912 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
913 return;
914 }
915 DurationReporter duration_reporter("INCIDENT REPORT");
916 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
917 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
918 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
919 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
920 if (fd < 0) {
921 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
922 return;
923 }
924 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
925 bool empty = 0 == lseek(fd, 0, SEEK_END);
926 if (!empty) {
927 // Use a different name from "incident.proto"
928 // /proto/incident.proto is reserved for incident service dump
929 // i.e. metadata for debugging.
930 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
931 }
932 unlink(path.c_str());
933}
934
Jayachandran Ca94c7172017-06-10 15:08:12 -0700935static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700936 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
937 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900938 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700939 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900940 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
941 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
942 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
943 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700944}
945
David Andersond9ba4752018-12-11 18:26:59 -0800946static void DumpDynamicPartitionInfo() {
947 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
948 return;
949 }
950
951 RunCommand("LPDUMP", {"lpdump", "--all"});
952}
953
Narayan Kamath8f788292017-05-25 13:20:39 +0100954static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
955 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
956 anr_traces_dir.c_str());
957
958 // If we're here, dump_traces_path will always be a temporary file
959 // (created with mkostemp or similar) that contains dumps taken earlier
960 // on in the process.
961 if (dump_traces_path != nullptr) {
962 if (add_to_zip) {
963 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
964 } else {
965 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
966 dump_traces_path);
967 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
968 }
969
970 const int ret = unlink(dump_traces_path);
971 if (ret == -1) {
972 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
973 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700974 }
975 }
976
Narayan Kamathbd863722017-06-01 18:50:12 +0100977 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700978 if (ds.anr_data_.size() > 0) {
979 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100980 "VM TRACES AT LAST ANR", add_to_zip);
981
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100982 // The "last" ANR will always be included as separate entry in the zip file. In addition,
983 // it will be present in the body of the main entry if |add_to_zip| == false.
984 //
985 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700986 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100987 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +0100988 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +0100989 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
990 }
991}
992
993static void AddAnrTraceFiles() {
994 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
995
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700996 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +0100997
Elliott Hughes69fe5ec2018-03-23 11:04:25 -0700998 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100999
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001000 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1001
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001002 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001003 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001004 int i = 0;
1005 while (true) {
1006 const std::string slow_trace_path =
1007 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1008 if (stat(slow_trace_path.c_str(), &st)) {
1009 // No traces file at this index, done with the files.
1010 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001011 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001012 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1013 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001014 }
1015}
1016
Wei Wang509bb5d2017-06-09 14:42:12 -07001017static void DumpBlockStatFiles() {
1018 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001019
Wei Wang1dc1ef52017-06-12 11:28:37 -07001020 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1021
1022 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001023 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1024 return;
1025 }
1026
1027 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001028 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001029 if ((d->d_name[0] == '.')
1030 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1031 || (d->d_name[1] == '\0'))) {
1032 continue;
1033 }
1034 const std::string new_path =
1035 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1036 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1037 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1038 printf("\n");
1039 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001040 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001041}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001042
1043static void DumpPacketStats() {
1044 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1045 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1046 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1047 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1048 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1049}
1050
1051static void DumpIpAddrAndRules() {
1052 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1053 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1054 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1055 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1056 RunCommand("IP RULES", {"ip", "rule", "show"});
1057 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1058}
1059
Nandana Dutt5c390032019-03-12 10:52:56 +00001060static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1061 std::chrono::milliseconds timeout,
1062 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001063 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001064 sp<android::IServiceManager> sm = defaultServiceManager();
1065 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001066 Vector<String16> args;
1067 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001068 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1069 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001070 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001071 std::string path(title);
1072 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001073 size_t bytes_written = 0;
Steven Morelanda6ddb9a2019-09-27 16:41:02 +00001074 status_t status = dumpsys.startDumpThread(service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001075 if (status == OK) {
1076 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1077 std::chrono::duration<double> elapsed_seconds;
1078 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1079 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001080 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1081 bool dump_complete = (status == OK);
1082 dumpsys.stopDumpThread(dump_complete);
1083 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001084
1085 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1086 std::chrono::steady_clock::now() - start);
1087 if (elapsed_duration > timeout) {
1088 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1089 elapsed_duration.count());
1090 break;
1091 }
1092 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001093 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001094}
1095
Vishnu Nair64afc022018-02-01 15:29:34 -08001096static void RunDumpsysText(const std::string& title, int priority,
1097 std::chrono::milliseconds timeout,
1098 std::chrono::milliseconds service_timeout) {
1099 DurationReporter duration_reporter(title);
1100 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1101 fsync(STDOUT_FILENO);
1102 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1103}
1104
1105/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001106static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1107 std::chrono::milliseconds timeout,
1108 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001109 DurationReporter duration_reporter(title);
1110 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1111 fsync(STDOUT_FILENO);
1112 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1113 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001114
1115 RETURN_IF_USER_DENIED_CONSENT();
1116
1117 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1118 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001119}
1120
Nandana Dutt5c390032019-03-12 10:52:56 +00001121static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1122 std::chrono::milliseconds timeout,
1123 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001124 if (!ds.IsZipping()) {
1125 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001126 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001127 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001128 sp<android::IServiceManager> sm = defaultServiceManager();
1129 Dumpsys dumpsys(sm.get());
1130 Vector<String16> args;
1131 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1132 DurationReporter duration_reporter(title);
1133
1134 auto start = std::chrono::steady_clock::now();
1135 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1136 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001137 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001138 std::string path(kProtoPath);
1139 path.append(String8(service).c_str());
1140 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1141 path.append("_CRITICAL");
1142 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1143 path.append("_HIGH");
1144 }
1145 path.append(kProtoExt);
Steven Morelanda6ddb9a2019-09-27 16:41:02 +00001146 status_t status = dumpsys.startDumpThread(service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001147 if (status == OK) {
1148 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1149 bool dumpTerminated = (status == OK);
1150 dumpsys.stopDumpThread(dumpTerminated);
1151 }
1152 ZipWriter::FileEntry file_entry;
1153 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001154
1155 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1156 std::chrono::steady_clock::now() - start);
1157 if (elapsed_duration > timeout) {
1158 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1159 elapsed_duration.count());
1160 break;
1161 }
1162 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001163 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001164}
1165
Nandana Dutta7db6342018-11-21 14:53:34 +00001166// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001167static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001168 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1169 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001170
1171 RETURN_IF_USER_DENIED_CONSENT();
1172
1173 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1174 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001175}
1176
1177// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001178static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001179 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1180 // high priority. Reduce timeout once they are able to dump in a shorter time or
1181 // moved to a parallel task.
1182 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1183 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001184
1185 RETURN_IF_USER_DENIED_CONSENT();
1186
1187 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1188 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001189}
1190
1191// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001192static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001193 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001194
1195 RETURN_IF_USER_DENIED_CONSENT();
1196
1197 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1198 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001199}
1200
Steven Moreland44cd9482018-01-04 16:24:13 -08001201static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001202 if (!ds.IsZipping()) {
1203 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1204 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1205 return;
1206 }
1207 DurationReporter duration_reporter("DUMP HALS");
1208 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001209 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001210
Steven Moreland44cd9482018-01-04 16:24:13 -08001211 using android::hidl::manager::V1_0::IServiceManager;
1212 using android::hardware::defaultServiceManager;
1213
1214 sp<IServiceManager> sm = defaultServiceManager();
1215 if (sm == nullptr) {
1216 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1217 return;
1218 }
1219
1220 auto ret = sm->list([&](const auto& interfaces) {
1221 for (const std::string& interface : interfaces) {
1222 std::string cleanName = interface;
1223 std::replace_if(cleanName.begin(),
1224 cleanName.end(),
1225 [](char c) {
1226 return !isalnum(c) &&
1227 std::string("@-_:.").find(c) == std::string::npos;
1228 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001229 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001230
1231 {
1232 auto fd = android::base::unique_fd(
1233 TEMP_FAILURE_RETRY(open(path.c_str(),
1234 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1235 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1236 if (fd < 0) {
1237 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1238 continue;
1239 }
1240 RunCommandToFd(fd,
1241 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001242 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001243 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1244
1245 bool empty = 0 == lseek(fd, 0, SEEK_END);
1246 if (!empty) {
1247 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1248 }
1249 }
1250
1251 unlink(path.c_str());
1252 }
1253 });
1254
1255 if (!ret.isOk()) {
1256 MYLOGE("Could not list hals from hwservicemanager.\n");
1257 }
1258}
1259
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001260static void DumpExternalFragmentationInfo() {
1261 struct stat st;
1262 if (stat("/proc/buddyinfo", &st) != 0) {
1263 MYLOGE("Unable to dump external fragmentation info\n");
1264 return;
1265 }
1266
1267 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1268 std::ifstream ifs("/proc/buddyinfo");
1269 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1270 for (std::string line; std::getline(ifs, line);) {
1271 std::smatch match_results;
1272 if (std::regex_match(line, match_results, unusable_index_regex)) {
1273 std::stringstream free_pages(std::string{match_results[3]});
1274 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1275 std::istream_iterator<int>());
1276
1277 int total_free_pages = 0;
1278 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1279 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1280 }
1281
1282 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1283 match_results[2].str().c_str());
1284
1285 int usable_free_pages = total_free_pages;
1286 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1287 auto unusable_index = (total_free_pages - usable_free_pages) /
1288 static_cast<double>(total_free_pages);
1289 printf(" %5.3f", unusable_index);
1290 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1291 }
1292
1293 printf("\n");
1294 }
1295 }
1296 printf("\n");
1297}
1298
Nandana Dutt5c390032019-03-12 10:52:56 +00001299// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1300// via the consent they are shown. Ignores other errors that occur while running various
1301// commands. The consent checking is currently done around long running tasks, which happen to
1302// be distributed fairly evenly throughout the function.
1303static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001304 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001305
Nandana Dutt5c390032019-03-12 10:52:56 +00001306 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1307 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1308 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001309 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001310 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001311 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001312 DumpFile("MEMORY INFO", "/proc/meminfo");
1313 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001314 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001315
1316 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1317
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001318 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1319 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1320 DumpFile("SLAB INFO", "/proc/slabinfo");
1321 DumpFile("ZONEINFO", "/proc/zoneinfo");
1322 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1323 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001324 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001325
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001326 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1327 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001328
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001329 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001330 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001331
1332 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1333 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001334
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001335 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001336
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001337 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001338 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001339 struct stat s;
1340 if (stat("/proc/modules", &s) != 0) {
1341 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1342 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001343 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001344 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001345
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001346 if (__android_logger_property_get_bool(
1347 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1348 DoKernelLogcat();
1349 } else {
1350 do_dmesg();
1351 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001352
Felipe Lemef0292972016-11-22 13:57:05 -08001353 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001354
1355 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1356
Jeff Brown1dc94e32014-09-11 14:15:27 -07001357 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001358 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001359
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001360 /* Dump Bluetooth HCI logs */
1361 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001362
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001363 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001364 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001365 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001366 }
1367
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001368 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001369
Felipe Lemee184f662016-10-27 10:04:47 -07001370 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371
Narayan Kamath8f788292017-05-25 13:20:39 +01001372 // NOTE: tombstones are always added as separate entries in the zip archive
1373 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001374 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001375 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001376 if (!tombstones_dumped) {
1377 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001378 }
1379
Jayachandran Ca94c7172017-06-10 15:08:12 -07001380 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001381
Chenbo Feng276a3b62018-08-07 11:44:49 -07001382 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1383
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001384 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001385
Jayachandran Ca94c7172017-06-10 15:08:12 -07001386 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001387
1388 dump_route_tables();
1389
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001390 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1391 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1392 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393
Nandana Dutt5c390032019-03-12 10:52:56 +00001394 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001395
Elliott Hughes23ccc622017-02-28 10:14:22 -08001396 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001397
Jin Qianf334d662017-10-10 14:41:37 -07001398 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001399
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001400 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001401
Colin Crossf45fa6b2012-03-26 12:38:26 -07001402 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001403 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1404 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1405 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1406 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1407 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001408
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001409 /* Add window and surface trace files. */
1410 if (!PropertiesHelper::IsUserBuild()) {
1411 ds.AddDir(WMTRACE_DATA_DIR, false);
1412 }
1413
Nandana Dutt5c390032019-03-12 10:52:56 +00001414 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001415
Steven Moreland7440ddb2016-12-15 16:13:39 -08001416 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001417 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1418 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001419 // su does not exist on user builds, so try running without it.
1420 // This way any implementations of vril-dump that do not require
1421 // root can run on user builds.
1422 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001423 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001424 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001425 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001426 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001427 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001428 }
1429
Felipe Lemed8b94e52016-12-08 10:21:44 -08001430 printf("========================================================\n");
1431 printf("== Android Framework Services\n");
1432 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001433
Nandana Dutt5c390032019-03-12 10:52:56 +00001434 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001435
Felipe Lemed8b94e52016-12-08 10:21:44 -08001436 printf("========================================================\n");
1437 printf("== Checkins\n");
1438 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001439
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001440 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001441
1442 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1443
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001444 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1445 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1446 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1447 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001448
Felipe Lemed8b94e52016-12-08 10:21:44 -08001449 printf("========================================================\n");
1450 printf("== Running Application Activities\n");
1451 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001452
Makoto Onuki60780982018-04-16 15:34:00 -07001453 // The following dumpsys internally collects output from running apps, so it can take a long
1454 // time. So let's extend the timeout.
1455
1456 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1457
1458 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001459
Felipe Lemed8b94e52016-12-08 10:21:44 -08001460 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001461 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001462 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001463
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001464 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001465 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001466
Felipe Lemed8b94e52016-12-08 10:21:44 -08001467 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001468 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001469 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001470
Makoto Onuki60780982018-04-16 15:34:00 -07001471 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1472 DUMPSYS_COMPONENTS_OPTIONS);
1473
1474 printf("========================================================\n");
1475 printf("== Running Application Providers (platform)\n");
1476 printf("========================================================\n");
1477
1478 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1479 DUMPSYS_COMPONENTS_OPTIONS);
1480
1481 printf("========================================================\n");
1482 printf("== Running Application Providers (non-platform)\n");
1483 printf("========================================================\n");
1484
1485 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1486 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001487
Adrian Roos8b397ab2017-04-04 16:35:44 -07001488 printf("========================================================\n");
1489 printf("== Dropbox crashes\n");
1490 printf("========================================================\n");
1491
1492 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1493 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1494
Felipe Lemed8b94e52016-12-08 10:21:44 -08001495 printf("========================================================\n");
1496 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1497 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1498 printf("========================================================\n");
1499 printf("== dumpstate: done (id %d)\n", ds.id_);
1500 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001501
1502 printf("========================================================\n");
1503 printf("== Obtaining statsd metadata\n");
1504 printf("========================================================\n");
1505 // This differs from the usual dumpsys stats, which is the stats report data.
1506 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001507
1508 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1509
Nandana Dutt5c390032019-03-12 10:52:56 +00001510 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001511}
1512
Nandana Dutt5c390032019-03-12 10:52:56 +00001513/*
1514 * Dumps state for the default case; drops root after it's no longer necessary.
1515 *
1516 * Returns RunStatus::OK if everything went fine.
1517 * Returns RunStatus::ERROR if there was an error.
1518 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1519 * with the caller.
1520 */
1521static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001522 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001523 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001524 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001525
1526 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001527 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001528
1529 /* Run some operations that require root. */
1530 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1531 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1532
1533 ds.AddDir(RECOVERY_DIR, true);
1534 ds.AddDir(RECOVERY_DATA_DIR, true);
1535 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1536 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1537 if (!PropertiesHelper::IsUserBuild()) {
1538 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1539 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1540 }
1541 add_mountinfo();
1542 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001543 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001544
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001545 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001546 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1547
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001548 // Dump IPsec stats. No keys are exposed here.
1549 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1550
Nandana Dutt4be45d12018-09-26 15:04:23 +01001551 // Run ss as root so we can see socket marks.
1552 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1553
1554 // Run iotop as root to show top 100 IO threads
1555 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1556
Erick Reyese68df822019-02-11 14:46:36 -08001557 // Gather shared memory buffer info if the product implements it
1558 struct stat st;
1559 if (!stat("/product/bin/dmabuf_dump", &st)) {
1560 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1561 }
1562
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001563 DumpFile("PSI cpu", "/proc/pressure/cpu");
1564 DumpFile("PSI memory", "/proc/pressure/memory");
1565 DumpFile("PSI io", "/proc/pressure/io");
1566
Nandana Dutt4be45d12018-09-26 15:04:23 +01001567 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001568 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001569 }
1570
Nandana Dutt5c390032019-03-12 10:52:56 +00001571 RETURN_IF_USER_DENIED_CONSENT();
1572 return dumpstate();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001573}
1574
mukesh agrawal253dad42018-01-23 21:59:59 -08001575// This method collects common dumpsys for telephony and wifi
1576static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001577 DumpIpTablesAsRoot();
1578
Jayachandran C69968272019-07-08 09:46:05 -07001579 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1580
Jayachandran Ca94c7172017-06-10 15:08:12 -07001581 if (!DropRootUser()) {
1582 return;
1583 }
1584
1585 do_dmesg();
1586 DoLogcat();
1587 DumpPacketStats();
1588 DoKmsg();
1589 DumpIpAddrAndRules();
1590 dump_route_tables();
Jayachandran C69968272019-07-08 09:46:05 -07001591 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001592
1593 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1594 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001595}
1596
1597// This method collects dumpsys for telephony debugging only
1598static void DumpstateTelephonyOnly() {
1599 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001600 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001601
1602 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001603
1604 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1605
1606 printf("========================================================\n");
1607 printf("== Android Framework Services\n");
1608 printf("========================================================\n");
1609
Vishnu Nair652cc802017-11-30 15:18:30 -08001610 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1611 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001612 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1613 SEC_TO_MSEC(10));
1614 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001615 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1616 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001617 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1618 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001619 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1620 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001621
1622 printf("========================================================\n");
1623 printf("== Running Application Services\n");
1624 printf("========================================================\n");
1625
1626 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1627
1628 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001629 printf("== Running Application Services (non-platform)\n");
1630 printf("========================================================\n");
1631
1632 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1633 DUMPSYS_COMPONENTS_OPTIONS);
1634
1635 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001636 printf("== Checkins\n");
1637 printf("========================================================\n");
1638
1639 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1640
1641 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001642 printf("== dumpstate: done (id %d)\n", ds.id_);
1643 printf("========================================================\n");
1644}
1645
mukesh agrawal253dad42018-01-23 21:59:59 -08001646// This method collects dumpsys for wifi debugging only
1647static void DumpstateWifiOnly() {
1648 DurationReporter duration_reporter("DUMPSTATE");
1649
1650 DumpstateRadioCommon();
1651
1652 printf("========================================================\n");
1653 printf("== Android Framework Services\n");
1654 printf("========================================================\n");
1655
1656 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1657 SEC_TO_MSEC(10));
1658 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1659 SEC_TO_MSEC(10));
1660
1661 printf("========================================================\n");
1662 printf("== dumpstate: done (id %d)\n", ds.id_);
1663 printf("========================================================\n");
1664}
1665
Nandana Duttcf419a72019-03-14 10:40:17 +00001666Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001667 DurationReporter duration_reporter("DUMP TRACES");
1668
1669 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1670 const size_t buf_size = temp_file_pattern.length() + 1;
1671 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1672 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1673
1674 // Create a new, empty file to receive all trace dumps.
1675 //
1676 // TODO: This can be simplified once we remove support for the old style
1677 // dumps. We can have a file descriptor passed in to dump_traces instead
1678 // of creating a file, closing it and then reopening it again.
1679 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1680 if (fd < 0) {
1681 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001682 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001683 }
1684
1685 // Nobody should have access to this temporary file except dumpstate, but we
1686 // temporarily grant 'read' to 'others' here because this file is created
1687 // when tombstoned is still running as root, but dumped after dropping. This
1688 // can go away once support for old style dumping has.
1689 const int chmod_ret = fchmod(fd, 0666);
1690 if (chmod_ret < 0) {
1691 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001692 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001693 }
1694
1695 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1696 if (proc.get() == nullptr) {
1697 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001698 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001699 }
1700
1701 // Number of times process dumping has timed out. If we encounter too many
1702 // failures, we'll give up.
1703 int timeout_failures = 0;
1704 bool dalvik_found = false;
1705
1706 const std::set<int> hal_pids = get_interesting_hal_pids();
1707
1708 struct dirent* d;
1709 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001710 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001711 int pid = atoi(d->d_name);
1712 if (pid <= 0) {
1713 continue;
1714 }
1715
1716 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1717 std::string exe;
1718 if (!android::base::Readlink(link_name, &exe)) {
1719 continue;
1720 }
1721
1722 bool is_java_process;
1723 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1724 // Don't bother dumping backtraces for the zygote.
1725 if (IsZygote(pid)) {
1726 continue;
1727 }
1728
1729 dalvik_found = true;
1730 is_java_process = true;
1731 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1732 is_java_process = false;
1733 } else {
1734 // Probably a native process we don't care about, continue.
1735 continue;
1736 }
1737
1738 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1739 if (timeout_failures == 3) {
1740 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1741 break;
1742 }
1743
1744 const uint64_t start = Nanotime();
1745 const int ret = dump_backtrace_to_file_timeout(
1746 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1747 is_java_process ? 5 : 20, fd);
1748
1749 if (ret == -1) {
1750 // For consistency, the header and footer to this message match those
1751 // dumped by debuggerd in the success case.
1752 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1753 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1754 dprintf(fd, "---- end %d ----", pid);
1755 timeout_failures++;
1756 continue;
1757 }
1758
1759 // We've successfully dumped stack traces, reset the failure count
1760 // and write a summary of the elapsed time to the file and continue with the
1761 // next process.
1762 timeout_failures = 0;
1763
1764 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1765 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1766 }
1767
1768 if (!dalvik_found) {
1769 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1770 }
1771
Nandana Duttcf419a72019-03-14 10:40:17 +00001772 *path = file_name_buf.release();
1773 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001774}
1775
Felipe Leme6f674ae2016-11-18 17:10:33 -08001776void Dumpstate::DumpstateBoard() {
1777 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001778 printf("========================================================\n");
1779 printf("== Board\n");
1780 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001781
Felipe Leme6f674ae2016-11-18 17:10:33 -08001782 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001783 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001784 return;
1785 }
1786
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001787 std::vector<std::string> paths;
1788 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001789 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001790 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1791 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001792 remover.emplace_back(android::base::make_scope_guard(
1793 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001794 }
Jie Song9fbfad02017-06-20 16:29:42 -07001795
Wei Wang587eac92018-04-05 12:17:20 -07001796 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1797 if (dumpstate_device == nullptr) {
1798 MYLOGE("No IDumpstateDevice implementation\n");
1799 return;
1800 }
1801
1802 using ScopedNativeHandle =
1803 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1804 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1805 [](native_handle_t* handle) {
1806 native_handle_close(handle);
1807 native_handle_delete(handle);
1808 });
1809 if (handle == nullptr) {
1810 MYLOGE("Could not create native_handle\n");
1811 return;
1812 }
1813
Nandana Dutt5c390032019-03-12 10:52:56 +00001814 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001815 for (size_t i = 0; i < paths.size(); i++) {
1816 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1817
1818 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1819 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1820 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1821 if (fd < 0) {
1822 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1823 return;
1824 }
1825 handle.get()->data[i] = fd.release();
1826 }
1827
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001828 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001829 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1830 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1831 // and grab whatever dumped
1832 std::packaged_task<bool()>
1833 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001834 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1835 if (!status.isOk()) {
1836 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001837 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001838 }
Wei Wang587eac92018-04-05 12:17:20 -07001839 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001840 });
Wei Wang587eac92018-04-05 12:17:20 -07001841
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001842 auto result = dumpstate_task.get_future();
1843 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001844
1845 constexpr size_t timeout_sec = 30;
1846 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1847 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1848 if (!android::base::SetProperty("ctl.interface_restart",
1849 android::base::StringPrintf("%s/default",
1850 IDumpstateDevice::descriptor))) {
1851 MYLOGE("Couldn't restart dumpstate HAL\n");
1852 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001853 }
Wei Wang587eac92018-04-05 12:17:20 -07001854 // Wait some time for init to kill dumpstate vendor HAL
1855 constexpr size_t killing_timeout_sec = 10;
1856 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1857 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1858 "there might be racing in content\n", killing_timeout_sec);
1859 }
1860
1861 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1862 for (size_t i = 0; i < paths.size(); i++) {
1863 struct stat s;
1864 if (fstat(handle.get()->data[i], &s) == -1) {
1865 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1866 strerror(errno));
1867 file_sizes[i] = -1;
1868 continue;
1869 }
1870 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001871 }
1872
1873 for (size_t i = 0; i < paths.size(); i++) {
1874 if (file_sizes[i] == -1) {
1875 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001876 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001877 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001878 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001879 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001880 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001881 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001882 }
1883
Felipe Lemed8b94e52016-12-08 10:21:44 -08001884 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001885}
1886
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001887static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001888 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001889 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001890 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1891 " -h: display this help message\n"
1892 " -b: play sound file instead of vibrate, at beginning of job\n"
1893 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001894 " -d: append date to filename\n"
1895 " -p: capture screenshot to filename.png\n"
1896 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001897 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001898 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001899 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001900 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001901 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001902 "progress (requires -B)\n"
1903 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001904 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001905 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001906 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001907}
1908
Wei Liuf87959e2016-08-26 14:51:42 -07001909static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001910 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001911}
1912
Felipe Leme1d486fe2016-10-14 18:06:47 -07001913bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001914 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001915 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001916 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001917 // Final timestamp
1918 char date[80];
1919 time_t the_real_now_please_stand_up = time(nullptr);
1920 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001921 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001922 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001923
Felipe Leme9a523ae2016-10-20 15:10:33 -07001924 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001925 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001926 return false;
1927 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001928 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001929 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001930 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001931 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001932
Felipe Leme0f3fb202016-06-10 17:10:53 -07001933 // Add log file (which contains stderr output) to zip...
1934 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001935 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001936 MYLOGE("Failed to add dumpstate log to .zip file\n");
1937 return false;
1938 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001939 // TODO: Should truncate the existing file.
1940 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001941 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1942 return false;
1943 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001944 fprintf(stderr, "\n");
1945
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001946 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001947 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001948 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001949 return false;
1950 }
1951
Felipe Leme1d486fe2016-10-14 18:06:47 -07001952 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1953 ds.zip_file.reset(nullptr);
1954
Felipe Lemee9d2c542016-11-15 11:48:26 -08001955 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001956 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001957
Felipe Leme1e9edc62015-12-21 16:02:13 -08001958 return true;
1959}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001960
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001961static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001962 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1963 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001964 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001965 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001966 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001967 }
1968
1969 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001970 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001971
1972 std::vector<uint8_t> buffer(65536);
1973 while (1) {
1974 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1975 if (bytes_read == 0) {
1976 break;
1977 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001978 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001979 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001980 }
1981
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001982 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001983 }
1984
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001985 uint8_t hash[SHA256_DIGEST_LENGTH];
1986 SHA256_Final(hash, &ctx);
1987
1988 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1989 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001990 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001991 }
1992 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1993 return std::string(hash_buffer);
1994}
1995
Felipe Lemea4ef1f02017-02-15 17:27:40 -08001996static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
1997 // clang-format off
1998 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
1999 "--receiver-foreground", "--receiver-include-background", "-a", action};
2000 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002001
2002 am.insert(am.end(), args.begin(), args.end());
2003
Felipe Leme8d2410e2017-02-08 09:46:08 -08002004 RunCommand("", am,
2005 CommandOptions::WithTimeout(20)
2006 .Log("Sending broadcast: '%s'\n")
2007 .Always()
2008 .DropRoot()
2009 .RedirectStderr()
2010 .Build());
2011}
2012
Felipe Leme35b8cf12017-02-10 15:47:29 -08002013static void Vibrate(int duration_ms) {
2014 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002015 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002016 CommandOptions::WithTimeout(10)
2017 .Log("Vibrate: '%s'\n")
2018 .Always()
2019 .Build());
2020 // clang-format on
2021}
2022
Nandana Dutt979388e2018-11-30 16:48:55 +00002023static void MaybeResolveSymlink(std::string* path) {
2024 std::string resolved_path;
2025 if (android::base::Readlink(*path, &resolved_path)) {
2026 *path = resolved_path;
2027 }
2028}
2029
Nandana Dutt4be45d12018-09-26 15:04:23 +01002030/*
2031 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2032 * if we are writing zip files and adds the version file.
2033 */
2034static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002035 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2036
Nandana Dutt4be45d12018-09-26 15:04:23 +01002037 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2038 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002039 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002040 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002041 char date[80];
2042 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2043 ds.name_ = date;
2044 } else {
2045 ds.name_ = "undated";
2046 }
2047
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002048 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002049 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002050 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002051 ds.base_name_ += "-wifi";
2052 }
2053
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002054 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002055 ds.screenshot_path_ = ds.GetPath(".png");
2056 }
2057 ds.tmp_path_ = ds.GetPath(".tmp");
2058 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2059
Nandana Dutt54dbd672019-01-11 12:58:05 +00002060 std::string destination = ds.options_->bugreport_fd.get() != -1
2061 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002062 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002063 MYLOGD(
2064 "Bugreport dir: %s\n"
2065 "Base name: %s\n"
2066 "Suffix: %s\n"
2067 "Log path: %s\n"
2068 "Temporary path: %s\n"
2069 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002070 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2071 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002072
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002073 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 ds.path_ = ds.GetPath(".zip");
2075 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2076 create_parent_dirs(ds.path_.c_str());
2077 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2078 if (ds.zip_file == nullptr) {
2079 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2080 } else {
2081 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2082 }
2083 ds.AddTextZipEntry("version.txt", ds.version_);
2084 }
2085}
2086
2087/*
2088 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2089 * printing zipped file status, etc.
2090 */
2091static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002092 /* check if user changed the suffix using system properties */
2093 std::string name =
2094 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2095 bool change_suffix = false;
2096 if (!name.empty()) {
2097 /* must whitelist which characters are allowed, otherwise it could cross directories */
2098 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2099 if (std::regex_match(name.c_str(), valid_regex)) {
2100 change_suffix = true;
2101 } else {
2102 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2103 }
2104 }
2105 if (change_suffix) {
2106 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2107 ds.name_ = name;
2108 if (!ds.screenshot_path_.empty()) {
2109 std::string new_screenshot_path = ds.GetPath(".png");
2110 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2111 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2112 new_screenshot_path.c_str(), strerror(errno));
2113 } else {
2114 ds.screenshot_path_ = new_screenshot_path;
2115 }
2116 }
2117 }
2118
2119 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002120 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002121 if (!ds.FinishZipFile()) {
2122 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2123 do_text_file = true;
2124 } else {
2125 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002126 // If the user has changed the suffix, we need to change the zip file name.
2127 std::string new_path = ds.GetPath(".zip");
2128 if (ds.path_ != new_path) {
2129 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2130 if (rename(ds.path_.c_str(), new_path.c_str())) {
2131 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2132 strerror(errno));
2133 } else {
2134 ds.path_ = new_path;
2135 }
2136 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002137 }
2138 }
2139 if (do_text_file) {
2140 ds.path_ = ds.GetPath(".txt");
2141 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2142 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2143 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2144 ds.path_.clear();
2145 }
2146 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002147 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002148 if (do_text_file) {
2149 dprintf(ds.control_socket_fd_,
2150 "FAIL:could not create zip file, check %s "
2151 "for more details\n",
2152 ds.log_path_.c_str());
2153 } else {
2154 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2155 }
2156 }
2157}
2158
2159/* Broadcasts that we are done with the bugreport */
2160static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002161 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002162 if (!ds.path_.empty()) {
2163 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002164 // clang-format off
2165
2166 std::vector<std::string> am_args = {
2167 "--receiver-permission", "android.permission.DUMP",
2168 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2169 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2170 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002171 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002172 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2173 };
2174 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002175 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002176 am_args.push_back("--es");
2177 am_args.push_back("android.intent.extra.SCREENSHOT");
2178 am_args.push_back(ds.screenshot_path_);
2179 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002180 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002181 am_args.push_back("--es");
2182 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002183 am_args.push_back(ds.options_->notification_title);
2184 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002185 am_args.push_back("--es");
2186 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002187 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002188 }
2189 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002190 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002191 am_args.push_back("--es");
2192 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002193 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002194 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2195 } else {
2196 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2197 }
2198 } else {
2199 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2200 }
2201}
2202
Nandana Dutt58d72e22018-11-16 10:30:48 +00002203static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2204 switch (mode) {
2205 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2206 return "BUGREPORT_FULL";
2207 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2208 return "BUGREPORT_INTERACTIVE";
2209 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2210 return "BUGREPORT_REMOTE";
2211 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2212 return "BUGREPORT_WEAR";
2213 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2214 return "BUGREPORT_TELEPHONY";
2215 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2216 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002217 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2218 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002219 }
2220}
2221
2222static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002223 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002224 switch (mode) {
2225 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2226 options->do_broadcast = true;
2227 options->do_fb = true;
2228 break;
2229 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002230 // Currently, the dumpstate binder is only used by Shell to update progress.
2231 options->do_start_service = true;
2232 options->do_progress_updates = true;
2233 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002234 options->do_broadcast = true;
2235 break;
2236 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002237 options->do_vibrate = false;
2238 options->is_remote_mode = true;
2239 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002240 options->do_broadcast = true;
2241 break;
2242 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002243 options->do_start_service = true;
2244 options->do_progress_updates = true;
2245 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002246 options->do_fb = true;
2247 options->do_broadcast = true;
2248 break;
2249 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002250 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002251 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002252 options->do_broadcast = true;
2253 break;
2254 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002255 options->wifi_only = true;
2256 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002257 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002258 options->do_broadcast = true;
2259 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002260 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2261 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002262 }
2263}
2264
2265static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002266 // If the system property is not set, it's assumed to be a default bugreport.
2267 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002268
2269 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2270 if (!extra_options.empty()) {
2271 // Framework uses a system property to override some command-line args.
2272 // Currently, it contains the type of the requested bugreport.
2273 if (extra_options == "bugreportplus") {
2274 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002275 } else if (extra_options == "bugreportfull") {
2276 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002277 } else if (extra_options == "bugreportremote") {
2278 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2279 } else if (extra_options == "bugreportwear") {
2280 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2281 } else if (extra_options == "bugreporttelephony") {
2282 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2283 } else if (extra_options == "bugreportwifi") {
2284 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002285 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002286 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002287 }
2288 // Reset the property
2289 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2290 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002291 return mode;
2292}
2293
2294// TODO: Move away from system properties when we have options passed via binder calls.
2295/* Sets runtime options from the system properties and then clears those properties. */
2296static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2297 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2298 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002299
2300 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2301 if (!options->notification_title.empty()) {
2302 // Reset the property
2303 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2304
Nandana Duttdd8cca32018-11-14 10:10:29 +00002305 options->notification_description =
2306 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002307 if (!options->notification_description.empty()) {
2308 // Reset the property
2309 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2310 }
2311 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2312 options->notification_description.c_str());
2313 }
2314}
2315
Nandana Dutt58d72e22018-11-16 10:30:48 +00002316static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2317 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2318 MYLOGI("do_add_date: %d\n", options.do_add_date);
2319 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2320 MYLOGI("use_socket: %d\n", options.use_socket);
2321 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2322 MYLOGI("do_fb: %d\n", options.do_fb);
2323 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2324 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2325 MYLOGI("show_header_only: %d\n", options.show_header_only);
2326 MYLOGI("do_start_service: %d\n", options.do_start_service);
2327 MYLOGI("telephony_only: %d\n", options.telephony_only);
2328 MYLOGI("wifi_only: %d\n", options.wifi_only);
2329 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002330 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002331 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2332 MYLOGI("args: %s\n", options.args.c_str());
2333 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2334 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2335}
2336
Nandana Dutt54dbd672019-01-11 12:58:05 +00002337void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2338 const android::base::unique_fd& bugreport_fd_in,
2339 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002340 // In the new API world, date is always added; output is always a zip file.
2341 // TODO(111441001): remove these options once they are obsolete.
2342 do_add_date = true;
2343 do_zip_file = true;
2344
Nandana Dutt54dbd672019-01-11 12:58:05 +00002345 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2346 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2347 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002348
2349 extra_options = ModeToString(bugreport_mode);
2350 SetOptionsFromMode(bugreport_mode, this);
2351}
2352
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002353Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2354 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002355 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002356 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002357 switch (c) {
2358 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002359 case 'd': do_add_date = true; break;
2360 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002361 // o=use_outfile not supported anymore.
2362 // TODO(b/111441001): Remove when all callers have migrated.
2363 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002364 case 's': use_socket = true; break;
2365 case 'S': use_control_socket = true; break;
2366 case 'v': show_header_only = true; break;
2367 case 'q': do_vibrate = false; break;
2368 case 'p': do_fb = true; break;
2369 case 'P': do_progress_updates = true; break;
2370 case 'R': is_remote_mode = true; break;
2371 case 'B': do_broadcast = true; break;
2372 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002373 case 'w':
2374 // This was already processed
2375 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002376 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002377 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002378 break;
2379 default:
2380 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002381 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002382 break;
2383 // clang-format on
2384 }
2385 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002386
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002387 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002388 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002389 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002390 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002391 }
2392 }
2393
2394 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2395 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002396
2397 SetOptionsFromProperties(this);
2398 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002399}
2400
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002401bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002402 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002403 return false;
2404 }
2405
Nandana Dutt9a76d202019-01-21 15:56:48 +00002406 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002407 return false;
2408 }
2409
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002410 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002411 return false;
2412 }
2413
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002414 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002415 return false;
2416 }
2417
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002418 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002419 return false;
2420 }
2421 return true;
2422}
2423
Nandana Dutt197661d2018-11-16 16:40:21 +00002424void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2425 options_ = std::move(options);
2426}
2427
Nandana Duttd2f5f082019-01-18 17:13:52 +00002428Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2429 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002430 if (listener_ != nullptr) {
2431 switch (status) {
2432 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002433 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002434 break;
2435 case Dumpstate::RunStatus::HELP:
2436 break;
2437 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002438 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002439 break;
2440 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002441 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2442 break;
2443 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2444 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2445 break;
2446 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2447 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002448 break;
2449 }
2450 }
2451 return status;
2452}
2453
Nandana Dutt979388e2018-11-30 16:48:55 +00002454/*
2455 * Dumps relevant information to a bugreport based on the given options.
2456 *
2457 * The bugreport can be dumped to a file or streamed to a socket.
2458 *
2459 * How dumping to file works:
2460 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2461 * stderr is redirected a log file.
2462 *
2463 * The temporary bugreport is then populated via printfs, dumping contents of files and
2464 * output of commands to stdout.
2465 *
2466 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2467 * text file.
2468 *
2469 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2470 * gets added to the archive.
2471 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002472 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2473 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002474 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002475Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2476 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002477 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002478 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002479 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002480 return RunStatus::INVALID_INPUT;
2481 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002482 /* set as high priority, and protect from OOM killer */
2483 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002484
Felipe Lemed071c682016-10-20 16:48:00 -07002485 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002486 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002487 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002488 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002489 } else {
2490 /* fallback to kernels <= 2.6.35 */
2491 oom_adj = fopen("/proc/self/oom_adj", "we");
2492 if (oom_adj) {
2493 fputs("-17", oom_adj);
2494 fclose(oom_adj);
2495 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002496 }
2497
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002498 if (version_ == VERSION_DEFAULT) {
2499 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002500 }
2501
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002502 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002503 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002504 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002505 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002506 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002507 }
2508
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002509 if (options_->show_header_only) {
2510 PrintHeader();
2511 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002512 }
2513
Nandana Duttd2f5f082019-01-18 17:13:52 +00002514 if (options_->bugreport_fd.get() != -1) {
2515 // If the output needs to be copied over to the caller's fd, get user consent.
2516 android::String16 package(calling_package.c_str());
2517 CheckUserConsent(calling_uid, package);
2518 }
2519
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002520 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002521 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002522
2523 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002524 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002525 is_redirecting
2526 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2527 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002528 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002529
Felipe Lemed071c682016-10-20 16:48:00 -07002530 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002531 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002532 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002533 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2534
2535 MYLOGI("begin\n");
2536
Sahana Raof35ed432019-07-12 10:47:52 +01002537 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2538 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2539 } else {
2540 // Wake lock will be released automatically on process death
2541 MYLOGD("Wake lock acquired.\n");
2542 }
2543
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002544 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002545
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002546 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002547 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002548 MYLOGI("Starting 'dumpstate' service\n");
2549 android::status_t ret;
2550 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2551 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2552 }
2553 }
2554
Felipe Lemef0292972016-11-22 13:57:05 -08002555 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002556 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2557 }
2558
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002559 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2560 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002561
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002562 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002563
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002564 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002565
Christopher Ferrised9354f2014-10-01 17:35:01 -07002566 // If we are going to use a socket, do it as early as possible
2567 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002568 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002569 if (!redirect_to_socket(stdout, "dumpstate")) {
2570 return ERROR;
2571 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002572 }
2573
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002574 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002575 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002576 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002577 if (control_socket_fd_ == -1) {
2578 return ERROR;
2579 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002580 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002581 }
2582
Felipe Leme71bbfc52015-11-23 14:14:51 -08002583 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002584 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002585
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002586 if (options_->do_progress_updates) {
2587 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002588 // clang-format off
2589 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002590 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002591 "--es", "android.intent.extra.NAME", name_,
2592 "--ei", "android.intent.extra.ID", std::to_string(id_),
2593 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2594 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002595 };
2596 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002597 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002598 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002599 if (options_->use_control_socket) {
2600 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002601 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002602 }
2603 }
2604
Nick Kralevichf3599b32016-01-25 15:05:16 -08002605 /* read /proc/cmdline before dropping root */
2606 FILE *cmdline = fopen("/proc/cmdline", "re");
2607 if (cmdline) {
2608 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2609 fclose(cmdline);
2610 }
2611
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002612 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002613 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002614 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002615
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002616 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002617 MYLOGI("taking early screenshot\n");
2618 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002619 }
2620
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002621 if (options_->do_zip_file && zip_file != nullptr) {
2622 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2623 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002624 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002625 }
2626 }
2627
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002628 int dup_stdout_fd;
2629 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002630 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002631 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002632 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002633 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2634 return ERROR;
2635 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002636 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2637 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2638 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002639 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002640
2641 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2642 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002643 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002644 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002645 /* TODO: rather than generating a text file now and zipping it later,
2646 it would be more efficient to redirect stdout to the zip entry
2647 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002648 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2649 return ERROR;
2650 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002651 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002652 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002653 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002654 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002655 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002656
2657 // Don't buffer stdout
2658 setvbuf(stdout, nullptr, _IONBF, 0);
2659
Felipe Leme608385d2016-02-01 10:35:38 -08002660 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2661 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002662 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002663 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002664
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002665 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002666 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002667 DumpstateBoard();
2668 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002669 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002670 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002671 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002672 RunStatus s = DumpstateDefault();
2673 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002674 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002675 HandleUserConsentDenied();
2676 }
2677 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002678 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002679 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002680
Felipe Leme55b42a62015-11-10 17:39:08 -08002681 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002682 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002683 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002684 }
2685
Nandana Duttd2f5f082019-01-18 17:13:52 +00002686 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002687 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002688 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002689 }
2690
Nandana Duttd2f5f082019-01-18 17:13:52 +00002691 // Share the final file with the caller if the user has consented.
2692 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2693 if (options_->bugreport_fd.get() != -1) {
2694 status = CopyBugreportIfUserConsented();
2695 if (status != Dumpstate::RunStatus::OK &&
2696 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2697 // Do an early return if there were errors. We make an exception for consent
2698 // timing out because it's possible the user got distracted. In this case the
2699 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002700 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002701 return status;
2702 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002703 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002704 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2705 options_->screenshot_fd.get());
2706 if (copy_succeeded) {
2707 android::os::UnlinkAndLogOnError(screenshot_path_);
2708 }
2709 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002710 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2711 MYLOGI(
2712 "Did not receive user consent yet."
2713 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002714 const String16 incidentcompanion("incidentcompanion");
2715 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2716 if (ics != nullptr) {
2717 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2718 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2719 consent_callback_.get());
2720 } else {
2721 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2722 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002723 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002724 }
2725
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002726 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002727 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002728 for (int i = 0; i < 3; i++) {
2729 Vibrate(75);
2730 usleep((75 + 50) * 1000);
2731 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002732 }
2733
Jeff Brown1dc94e32014-09-11 14:15:27 -07002734 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002735 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002736 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002737 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002738 }
2739
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002740 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2741 progress_->GetInitialMax());
2742 progress_->Save();
2743 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002744
Felipe Leme107a05f2016-03-08 15:11:15 -08002745 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002746 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002747 }
2748
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002749 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002750 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002751 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002752 }
2753
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002754 tombstone_data_.clear();
2755 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002756
Nandana Duttd2f5f082019-01-18 17:13:52 +00002757 return (consent_callback_ != nullptr &&
2758 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2759 ? USER_CONSENT_TIMED_OUT
2760 : RunStatus::OK;
2761}
2762
2763void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2764 consent_callback_ = new ConsentCallback();
2765 const String16 incidentcompanion("incidentcompanion");
2766 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2767 if (ics != nullptr) {
2768 MYLOGD("Checking user consent via incidentcompanion service\n");
2769 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002770 calling_uid, calling_package, String16(), String16(),
2771 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002772 } else {
2773 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2774 }
2775}
2776
Nandana Dutt5c390032019-03-12 10:52:56 +00002777bool Dumpstate::IsUserConsentDenied() const {
2778 return ds.consent_callback_ != nullptr &&
2779 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2780}
2781
Nandana Duttd2f5f082019-01-18 17:13:52 +00002782void Dumpstate::CleanupFiles() {
2783 android::os::UnlinkAndLogOnError(tmp_path_);
2784 android::os::UnlinkAndLogOnError(screenshot_path_);
2785 android::os::UnlinkAndLogOnError(path_);
2786}
2787
2788Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2789 MYLOGD("User denied consent; deleting files and returning\n");
2790 CleanupFiles();
2791 return USER_CONSENT_DENIED;
2792}
2793
2794Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2795 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2796 // user consent.
2797 UserConsentResult consent_result = consent_callback_->getResult();
2798 if (consent_result == UserConsentResult::UNAVAILABLE) {
2799 // User has not responded yet.
2800 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2801 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2802 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2803 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2804 sleep(delay_seconds);
2805 }
2806 consent_result = consent_callback_->getResult();
2807 }
2808 if (consent_result == UserConsentResult::DENIED) {
2809 // User has explicitly denied sharing with the app. To be safe delete the
2810 // internal bugreport & tmp files.
2811 return HandleUserConsentDenied();
2812 }
2813 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002814 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2815 if (copy_succeeded) {
2816 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002817 }
2818 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2819 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2820 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2821 // Since we do not have user consent to share the bugreport it does not get
2822 // copied over to the calling app but remains in the internal directory from
2823 // where the user can manually pull it.
2824 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2825 }
2826 // Unknown result; must be a programming error.
2827 MYLOGE("Unknown user consent result:%d\n", consent_result);
2828 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002829}
2830
Nandana Duttf02564e2019-02-15 15:24:24 +00002831Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002832 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2833 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2834 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002835 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002836 // When directly running dumpstate binary, the output is not expected to be written
2837 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002838 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002839
2840 // calling_uid and calling_package are for user consent to share the bugreport with
2841 // an app; they are irrelvant here because bugreport is only written to a local
2842 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002843 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002844 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002845 return status;
2846}
2847
2848/* Main entry point for dumpstate binary. */
2849int run_main(int argc, char* argv[]) {
2850 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002851
2852 switch (status) {
2853 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002854 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002855 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002856 ShowUsage();
2857 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002858 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002859 fprintf(stderr, "Invalid combination of args\n");
2860 ShowUsage();
2861 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002862 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002863 FALLTHROUGH_INTENDED;
2864 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2865 FALLTHROUGH_INTENDED;
2866 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002867 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002868 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002869}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002870
2871// TODO(111441001): Default DumpOptions to sensible values.
2872Dumpstate::Dumpstate(const std::string& version)
2873 : pid_(getpid()),
2874 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002875 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002876 version_(version),
2877 now_(time(nullptr)) {
2878}
2879
2880Dumpstate& Dumpstate::GetInstance() {
2881 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2882 return singleton_;
2883}
2884
Nandana Dutt8d945c02019-08-14 13:30:07 +01002885DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2886 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002887 if (!title_.empty()) {
2888 started_ = Nanotime();
2889 }
2890}
2891
2892DurationReporter::~DurationReporter() {
2893 if (!title_.empty()) {
2894 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002895 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002896 return;
2897 }
2898 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2899 if (logcat_only_) {
2900 return;
2901 }
2902 // Use "Yoda grammar" to make it easier to grep|sort sections.
2903 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2904 }
2905}
2906
2907const int32_t Progress::kDefaultMax = 5000;
2908
2909Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2910}
2911
2912Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2913 : Progress(initial_max, growth_factor, "") {
2914 progress_ = progress;
2915}
2916
2917Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2918 : initial_max_(initial_max),
2919 progress_(0),
2920 max_(initial_max),
2921 growth_factor_(growth_factor),
2922 n_runs_(0),
2923 average_max_(0),
2924 path_(path) {
2925 if (!path_.empty()) {
2926 Load();
2927 }
2928}
2929
2930void Progress::Load() {
2931 MYLOGD("Loading stats from %s\n", path_.c_str());
2932 std::string content;
2933 if (!android::base::ReadFileToString(path_, &content)) {
2934 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2935 return;
2936 }
2937 if (content.empty()) {
2938 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2939 return;
2940 }
2941 std::vector<std::string> lines = android::base::Split(content, "\n");
2942
2943 if (lines.size() < 1) {
2944 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2945 (int)lines.size(), max_);
2946 return;
2947 }
2948 char* ptr;
2949 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2950 average_max_ = strtol(ptr, nullptr, 10);
2951 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2952 average_max_ > STATS_MAX_AVERAGE) {
2953 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2954 initial_max_ = Progress::kDefaultMax;
2955 } else {
2956 initial_max_ = average_max_;
2957 }
2958 max_ = initial_max_;
2959
2960 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2961}
2962
2963void Progress::Save() {
2964 int32_t total = n_runs_ * average_max_ + progress_;
2965 int32_t runs = n_runs_ + 1;
2966 int32_t average = floor(((float)total) / runs);
2967 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2968 path_.c_str());
2969 if (path_.empty()) {
2970 return;
2971 }
2972
2973 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2974 if (!android::base::WriteStringToFile(content, path_)) {
2975 MYLOGE("Could not save stats on %s\n", path_.c_str());
2976 }
2977}
2978
2979int32_t Progress::Get() const {
2980 return progress_;
2981}
2982
2983bool Progress::Inc(int32_t delta_sec) {
2984 bool changed = false;
2985 if (delta_sec >= 0) {
2986 progress_ += delta_sec;
2987 if (progress_ > max_) {
2988 int32_t old_max = max_;
2989 max_ = floor((float)progress_ * growth_factor_);
2990 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
2991 changed = true;
2992 }
2993 }
2994 return changed;
2995}
2996
2997int32_t Progress::GetMax() const {
2998 return max_;
2999}
3000
3001int32_t Progress::GetInitialMax() const {
3002 return initial_max_;
3003}
3004
3005void Progress::Dump(int fd, const std::string& prefix) const {
3006 const char* pr = prefix.c_str();
3007 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3008 dprintf(fd, "%smax: %d\n", pr, max_);
3009 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3010 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3011 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3012 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3013 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3014}
3015
3016bool Dumpstate::IsZipping() const {
3017 return zip_writer_ != nullptr;
3018}
3019
3020std::string Dumpstate::GetPath(const std::string& suffix) const {
3021 return GetPath(bugreport_internal_dir_, suffix);
3022}
3023
3024std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3025 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3026 name_.c_str(), suffix.c_str());
3027}
3028
3029void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3030 progress_ = std::move(progress);
3031}
3032
3033void for_each_userid(void (*func)(int), const char *header) {
3034 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3035 "for_each_userid(%s)", header);
3036 DurationReporter duration_reporter(title);
3037 if (PropertiesHelper::IsDryRun()) return;
3038
3039 DIR *d;
3040 struct dirent *de;
3041
3042 if (header) printf("\n------ %s ------\n", header);
3043 func(0);
3044
3045 if (!(d = opendir("/data/system/users"))) {
3046 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3047 return;
3048 }
3049
3050 while ((de = readdir(d))) {
3051 int userid;
3052 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3053 continue;
3054 }
3055 func(userid);
3056 }
3057
3058 closedir(d);
3059}
3060
3061static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3062 DIR *d;
3063 struct dirent *de;
3064
3065 if (!(d = opendir("/proc"))) {
3066 printf("Failed to open /proc (%s)\n", strerror(errno));
3067 return;
3068 }
3069
3070 if (header) printf("\n------ %s ------\n", header);
3071 while ((de = readdir(d))) {
3072 if (ds.IsUserConsentDenied()) {
3073 MYLOGE(
3074 "Returning early because user denied consent to share bugreport with calling app.");
3075 closedir(d);
3076 return;
3077 }
3078 int pid;
3079 int fd;
3080 char cmdpath[255];
3081 char cmdline[255];
3082
3083 if (!(pid = atoi(de->d_name))) {
3084 continue;
3085 }
3086
3087 memset(cmdline, 0, sizeof(cmdline));
3088
3089 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3090 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3091 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3092 close(fd);
3093 if (cmdline[0]) {
3094 helper(pid, cmdline, arg);
3095 continue;
3096 }
3097 }
3098
3099 // if no cmdline, a kernel thread has comm
3100 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3101 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3102 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3103 close(fd);
3104 if (cmdline[1]) {
3105 cmdline[0] = '[';
3106 size_t len = strcspn(cmdline, "\f\b\r\n");
3107 cmdline[len] = ']';
3108 cmdline[len+1] = '\0';
3109 }
3110 }
3111 if (!cmdline[0]) {
3112 strcpy(cmdline, "N/A");
3113 }
3114 helper(pid, cmdline, arg);
3115 }
3116
3117 closedir(d);
3118}
3119
3120static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3121 for_each_pid_func *func = (for_each_pid_func*) arg;
3122 func(pid, cmdline);
3123}
3124
3125void for_each_pid(for_each_pid_func func, const char *header) {
3126 std::string title = header == nullptr ? "for_each_pid"
3127 : android::base::StringPrintf("for_each_pid(%s)", header);
3128 DurationReporter duration_reporter(title);
3129 if (PropertiesHelper::IsDryRun()) return;
3130
3131 __for_each_pid(for_each_pid_helper, header, (void *) func);
3132}
3133
3134static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3135 DIR *d;
3136 struct dirent *de;
3137 char taskpath[255];
3138 for_each_tid_func *func = (for_each_tid_func *) arg;
3139
3140 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3141
3142 if (!(d = opendir(taskpath))) {
3143 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3144 return;
3145 }
3146
3147 func(pid, pid, cmdline);
3148
3149 while ((de = readdir(d))) {
3150 if (ds.IsUserConsentDenied()) {
3151 MYLOGE(
3152 "Returning early because user denied consent to share bugreport with calling app.");
3153 closedir(d);
3154 return;
3155 }
3156 int tid;
3157 int fd;
3158 char commpath[255];
3159 char comm[255];
3160
3161 if (!(tid = atoi(de->d_name))) {
3162 continue;
3163 }
3164
3165 if (tid == pid)
3166 continue;
3167
3168 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3169 memset(comm, 0, sizeof(comm));
3170 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3171 strcpy(comm, "N/A");
3172 } else {
3173 char *c;
3174 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3175 close(fd);
3176
3177 c = strrchr(comm, '\n');
3178 if (c) {
3179 *c = '\0';
3180 }
3181 }
3182 func(pid, tid, comm);
3183 }
3184
3185 closedir(d);
3186}
3187
3188void for_each_tid(for_each_tid_func func, const char *header) {
3189 std::string title = header == nullptr ? "for_each_tid"
3190 : android::base::StringPrintf("for_each_tid(%s)", header);
3191 DurationReporter duration_reporter(title);
3192
3193 if (PropertiesHelper::IsDryRun()) return;
3194
3195 __for_each_pid(for_each_tid_helper, header, (void *) func);
3196}
3197
3198void show_wchan(int pid, int tid, const char *name) {
3199 if (PropertiesHelper::IsDryRun()) return;
3200
3201 char path[255];
3202 char buffer[255];
3203 int fd, ret, save_errno;
3204 char name_buffer[255];
3205
3206 memset(buffer, 0, sizeof(buffer));
3207
3208 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3209 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3210 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3211 return;
3212 }
3213
3214 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3215 save_errno = errno;
3216 close(fd);
3217
3218 if (ret < 0) {
3219 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3220 return;
3221 }
3222
3223 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3224 pid == tid ? 0 : 3, "", name);
3225
3226 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3227
3228 return;
3229}
3230
3231// print time in centiseconds
3232static void snprcent(char *buffer, size_t len, size_t spc,
3233 unsigned long long time) {
3234 static long hz; // cache discovered hz
3235
3236 if (hz <= 0) {
3237 hz = sysconf(_SC_CLK_TCK);
3238 if (hz <= 0) {
3239 hz = 1000;
3240 }
3241 }
3242
3243 // convert to centiseconds
3244 time = (time * 100 + (hz / 2)) / hz;
3245
3246 char str[16];
3247
3248 snprintf(str, sizeof(str), " %llu.%02u",
3249 time / 100, (unsigned)(time % 100));
3250 size_t offset = strlen(buffer);
3251 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3252 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3253}
3254
3255// print permille as a percent
3256static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3257 char str[16];
3258
3259 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3260 size_t offset = strlen(buffer);
3261 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3262 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3263}
3264
3265void show_showtime(int pid, const char *name) {
3266 if (PropertiesHelper::IsDryRun()) return;
3267
3268 char path[255];
3269 char buffer[1023];
3270 int fd, ret, save_errno;
3271
3272 memset(buffer, 0, sizeof(buffer));
3273
3274 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3275 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3276 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3277 return;
3278 }
3279
3280 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3281 save_errno = errno;
3282 close(fd);
3283
3284 if (ret < 0) {
3285 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3286 return;
3287 }
3288
3289 // field 14 is utime
3290 // field 15 is stime
3291 // field 42 is iotime
3292 unsigned long long utime = 0, stime = 0, iotime = 0;
3293 if (sscanf(buffer,
3294 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3295 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3296 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3297 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3298 &utime, &stime, &iotime) != 3) {
3299 return;
3300 }
3301
3302 unsigned long long total = utime + stime;
3303 if (!total) {
3304 return;
3305 }
3306
3307 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3308 if (permille > 1000) {
3309 permille = 1000;
3310 }
3311
3312 // try to beautify and stabilize columns at <80 characters
3313 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3314 if ((name[0] != '[') || utime) {
3315 snprcent(buffer, sizeof(buffer), 57, utime);
3316 }
3317 snprcent(buffer, sizeof(buffer), 65, stime);
3318 if ((name[0] != '[') || iotime) {
3319 snprcent(buffer, sizeof(buffer), 73, iotime);
3320 }
3321 if (iotime) {
3322 snprdec(buffer, sizeof(buffer), 79, permille);
3323 }
3324 puts(buffer); // adds a trailing newline
3325
3326 return;
3327}
3328
3329void do_dmesg() {
3330 const char *title = "KERNEL LOG (dmesg)";
3331 DurationReporter duration_reporter(title);
3332 printf("------ %s ------\n", title);
3333
3334 if (PropertiesHelper::IsDryRun()) return;
3335
3336 /* Get size of kernel buffer */
3337 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3338 if (size <= 0) {
3339 printf("Unexpected klogctl return value: %d\n\n", size);
3340 return;
3341 }
3342 char *buf = (char *) malloc(size + 1);
3343 if (buf == nullptr) {
3344 printf("memory allocation failed\n\n");
3345 return;
3346 }
3347 int retval = klogctl(KLOG_READ_ALL, buf, size);
3348 if (retval < 0) {
3349 printf("klogctl failure\n\n");
3350 free(buf);
3351 return;
3352 }
3353 buf[retval] = '\0';
3354 printf("%s\n\n", buf);
3355 free(buf);
3356 return;
3357}
3358
3359void do_showmap(int pid, const char *name) {
3360 char title[255];
3361 char arg[255];
3362
3363 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3364 snprintf(arg, sizeof(arg), "%d", pid);
3365 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3366}
3367
3368int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3369 DurationReporter duration_reporter(title);
3370
3371 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3372
3373 UpdateProgress(WEIGHT_FILE);
3374
3375 return status;
3376}
3377
3378int read_file_as_long(const char *path, long int *output) {
3379 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3380 if (fd < 0) {
3381 int err = errno;
3382 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3383 return -1;
3384 }
3385 char buffer[50];
3386 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3387 if (bytes_read == -1) {
3388 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3389 return -2;
3390 }
3391 if (bytes_read == 0) {
3392 MYLOGE("File %s is empty\n", path);
3393 return -3;
3394 }
3395 *output = atoi(buffer);
3396 return 0;
3397}
3398
3399/* calls skip to gate calling dump_from_fd recursively
3400 * in the specified directory. dump_from_fd defaults to
3401 * dump_file_from_fd above when set to NULL. skip defaults
3402 * to false when set to NULL. dump_from_fd will always be
3403 * called with title NULL.
3404 */
3405int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3406 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3407 DurationReporter duration_reporter(title);
3408 DIR *dirp;
3409 struct dirent *d;
3410 char *newpath = nullptr;
3411 const char *slash = "/";
3412 int retval = 0;
3413
3414 if (!title.empty()) {
3415 printf("------ %s (%s) ------\n", title.c_str(), dir);
3416 }
3417 if (PropertiesHelper::IsDryRun()) return 0;
3418
3419 if (dir[strlen(dir) - 1] == '/') {
3420 ++slash;
3421 }
3422 dirp = opendir(dir);
3423 if (dirp == nullptr) {
3424 retval = -errno;
3425 MYLOGE("%s: %s\n", dir, strerror(errno));
3426 return retval;
3427 }
3428
3429 if (!dump_from_fd) {
3430 dump_from_fd = dump_file_from_fd;
3431 }
3432 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3433 if ((d->d_name[0] == '.')
3434 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3435 || (d->d_name[1] == '\0'))) {
3436 continue;
3437 }
3438 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3439 (d->d_type == DT_DIR) ? "/" : "");
3440 if (!newpath) {
3441 retval = -errno;
3442 continue;
3443 }
3444 if (skip && (*skip)(newpath)) {
3445 continue;
3446 }
3447 if (d->d_type == DT_DIR) {
3448 int ret = dump_files("", newpath, skip, dump_from_fd);
3449 if (ret < 0) {
3450 retval = ret;
3451 }
3452 continue;
3453 }
3454 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3455 if (fd.get() < 0) {
3456 retval = -1;
3457 printf("*** %s: %s\n", newpath, strerror(errno));
3458 continue;
3459 }
3460 (*dump_from_fd)(nullptr, newpath, fd.get());
3461 }
3462 closedir(dirp);
3463 if (!title.empty()) {
3464 printf("\n");
3465 }
3466 return retval;
3467}
3468
3469/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3470 * it's possible to avoid issues where opening the file itself can get
3471 * stuck.
3472 */
3473int dump_file_from_fd(const char *title, const char *path, int fd) {
3474 if (PropertiesHelper::IsDryRun()) return 0;
3475
3476 int flags = fcntl(fd, F_GETFL);
3477 if (flags == -1) {
3478 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3479 return -1;
3480 } else if (!(flags & O_NONBLOCK)) {
3481 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3482 return -1;
3483 }
3484 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3485}
3486
3487int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003488 const CommandOptions& options, bool verbose_duration) {
3489 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003490
3491 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3492
3493 /* TODO: for now we're simplifying the progress calculation by using the
3494 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3495 * where its weight should be much higher proportionally to its timeout.
3496 * Ideally, it should use a options.EstimatedDuration() instead...*/
3497 UpdateProgress(options.Timeout());
3498
3499 return status;
3500}
3501
3502void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3503 const CommandOptions& options, long dumpsysTimeoutMs) {
3504 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3505 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3506 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3507 RunCommand(title, dumpsys, options);
3508}
3509
3510int open_socket(const char *service) {
3511 int s = android_get_control_socket(service);
3512 if (s < 0) {
3513 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3514 return -1;
3515 }
3516 fcntl(s, F_SETFD, FD_CLOEXEC);
3517
3518 // Set backlog to 0 to make sure that queue size will be minimum.
3519 // In Linux, because the minimum queue will be 1, connect() will be blocked
3520 // if the other clients already called connect() and the connection request was not accepted.
3521 if (listen(s, 0) < 0) {
3522 MYLOGE("listen(control socket): %s\n", strerror(errno));
3523 return -1;
3524 }
3525
3526 struct sockaddr addr;
3527 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003528 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003529
3530 // Close socket just after accept(), to make sure that connect() by client will get error
3531 // when the socket is used by the other services.
3532 // There is still a race condition possibility between accept and close, but there is no way
3533 // to close-on-accept atomically.
3534 // See detail; b/123306389#comment25
3535 close(s);
3536
3537 if (fd < 0) {
3538 MYLOGE("accept(control socket): %s\n", strerror(errno));
3539 return -1;
3540 }
3541
3542 return fd;
3543}
3544
3545/* redirect output to a service control socket */
3546bool redirect_to_socket(FILE* redirect, const char* service) {
3547 int fd = open_socket(service);
3548 if (fd == -1) {
3549 return false;
3550 }
3551 fflush(redirect);
3552 // TODO: handle dup2 failure
3553 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3554 close(fd);
3555 return true;
3556}
3557
3558// TODO: should call is_valid_output_file and/or be merged into it.
3559void create_parent_dirs(const char *path) {
3560 char *chp = const_cast<char *> (path);
3561
3562 /* skip initial slash */
3563 if (chp[0] == '/')
3564 chp++;
3565
3566 /* create leading directories, if necessary */
3567 struct stat dir_stat;
3568 while (chp && chp[0]) {
3569 chp = strchr(chp, '/');
3570 if (chp) {
3571 *chp = 0;
3572 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3573 MYLOGI("Creating directory %s\n", path);
3574 if (mkdir(path, 0770)) { /* drwxrwx--- */
3575 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3576 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3577 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3578 }
3579 }
3580 *chp++ = '/';
3581 }
3582 }
3583}
3584
3585bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3586 create_parent_dirs(path);
3587
3588 int fd = TEMP_FAILURE_RETRY(open(path,
3589 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3590 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3591 if (fd < 0) {
3592 MYLOGE("%s: %s\n", path, strerror(errno));
3593 return false;
3594 }
3595
3596 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3597 close(fd);
3598 return true;
3599}
3600
3601bool redirect_to_file(FILE* redirect, char* path) {
3602 return _redirect_to_file(redirect, path, O_TRUNC);
3603}
3604
3605bool redirect_to_existing_file(FILE* redirect, char* path) {
3606 return _redirect_to_file(redirect, path, O_APPEND);
3607}
3608
3609void dump_route_tables() {
3610 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3611 if (PropertiesHelper::IsDryRun()) return;
3612 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3613 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3614 FILE* fp = fopen(RT_TABLES_PATH, "re");
3615 if (!fp) {
3616 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3617 return;
3618 }
3619 char table[16];
3620 // Each line has an integer (the table number), a space, and a string (the table name). We only
3621 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3622 // Add a fixed max limit so this doesn't go awry.
3623 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3624 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3625 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3626 }
3627 fclose(fp);
3628}
3629
3630// TODO: make this function thread safe if sections are generated in parallel.
3631void Dumpstate::UpdateProgress(int32_t delta_sec) {
3632 if (progress_ == nullptr) {
3633 MYLOGE("UpdateProgress: progress_ not set\n");
3634 return;
3635 }
3636
3637 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003638 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003639
3640 // ...but only notifiy listeners when necessary.
3641 if (!options_->do_progress_updates) return;
3642
3643 int progress = progress_->Get();
3644 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003645 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003646
Nandana Duttf02cd782019-06-14 14:25:13 +01003647 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003648 return;
3649 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003650 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003651
3652 if (control_socket_fd_ >= 0) {
3653 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3654 fsync(control_socket_fd_);
3655 }
3656
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003657 if (listener_ != nullptr) {
3658 if (percent % 5 == 0) {
3659 // We don't want to spam logcat, so only log multiples of 5.
3660 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3661 percent);
3662 } else {
3663 // stderr is ignored on normal invocations, but useful when calling
3664 // /system/bin/dumpstate directly for debuggging.
3665 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3666 progress, max, percent);
3667 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003668
3669 listener_->onProgress(percent);
3670 }
3671}
3672
3673void Dumpstate::TakeScreenshot(const std::string& path) {
3674 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3675 int status =
3676 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3677 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3678 if (status == 0) {
3679 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3680 } else {
3681 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3682 }
3683}
3684
3685bool is_dir(const char* pathname) {
3686 struct stat info;
3687 if (stat(pathname, &info) == -1) {
3688 return false;
3689 }
3690 return S_ISDIR(info.st_mode);
3691}
3692
3693time_t get_mtime(int fd, time_t default_mtime) {
3694 struct stat info;
3695 if (fstat(fd, &info) == -1) {
3696 return default_mtime;
3697 }
3698 return info.st_mtime;
3699}