blob: 584d7c50dba02919c3e5066f3d82c04723b07865 [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010022#include <inttypes.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <limits.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010025#include <math.h>
26#include <poll.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080031#include <sys/poll.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010037#include <signal.h>
38#include <stdarg.h>
39#include <string.h>
40#include <sys/capability.h>
41#include <sys/inotify.h>
42#include <sys/klog.h>
43#include <time.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <unistd.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070045
46#include <chrono>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070047#include <cmath>
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +000048#include <fstream>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070049#include <functional>
50#include <future>
Narayan Kamath8f788292017-05-25 13:20:39 +010051#include <memory>
Hridya Valsarajuac582cd2019-08-05 15:39:54 -070052#include <numeric>
Narayan Kamath8f788292017-05-25 13:20:39 +010053#include <regex>
54#include <set>
55#include <string>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070056#include <utility>
Narayan Kamath8f788292017-05-25 13:20:39 +010057#include <vector>
Colin Crossf45fa6b2012-03-26 12:38:26 -070058
Felipe Leme96c2bbb2016-09-26 09:21:21 -070059#include <android-base/file.h>
60#include <android-base/properties.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070061#include <android-base/scopeguard.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080062#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070063#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070064#include <android-base/unique_fd.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010065#include <android/content/pm/IPackageManagerNative.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080066#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080067#include <android/hidl/manager/1.0/IServiceManager.h>
Nandana Duttd2f5f082019-01-18 17:13:52 +000068#include <android/os/IIncidentCompanion.h>
Nikita Ioffea325a572019-05-16 19:49:47 +010069#include <binder/IServiceManager.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080070#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070071#include <cutils/properties.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010072#include <cutils/sockets.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000073#include <debuggerd/client.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080074#include <dumpsys.h>
Nandana Duttfaafd522019-03-11 09:23:09 +000075#include <dumputils/dump_utils.h>
Sahana Raof35ed432019-07-12 10:47:52 +010076#include <hardware_legacy/power.h>
Steven Moreland44cd9482018-01-04 16:24:13 -080077#include <hidl/ServiceManagement.h>
Abhijeet Kaurcf234e82019-07-01 14:53:55 +010078#include <log/log.h>
Felipe Leme75876a22016-10-27 16:31:27 -070079#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070080#include <private/android_filesystem_config.h>
81#include <private/android_logger.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080082#include <serviceutils/PriorityDumper.h>
Luis Hector Chavez7aecd382018-03-19 11:16:59 -070083#include <utils/StrongPointer.h>
Felipe Lemef0292972016-11-22 13:57:05 -080084#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070085#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070086#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080087
Steven Morelandcb7ef822016-11-29 13:20:37 -080088using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
Vishnu Naire97d6122018-01-18 13:58:56 -080089using ::std::literals::chrono_literals::operator""ms;
90using ::std::literals::chrono_literals::operator""s;
Steven Morelandcb7ef822016-11-29 13:20:37 -080091
Felipe Leme47e9be22016-12-21 15:37:07 -080092// TODO: remove once moved to namespace
Vishnu Naire97d6122018-01-18 13:58:56 -080093using android::defaultServiceManager;
94using android::Dumpsys;
95using android::INVALID_OPERATION;
96using android::IServiceManager;
97using android::OK;
98using android::sp;
99using android::status_t;
100using android::String16;
101using android::String8;
102using android::TIMED_OUT;
103using android::UNKNOWN_ERROR;
104using android::Vector;
Nandana Dutt979388e2018-11-30 16:48:55 +0000105using android::base::StringPrintf;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000106using android::os::IDumpstateListener;
Felipe Leme47e9be22016-12-21 15:37:07 -0800107using android::os::dumpstate::CommandOptions;
108using android::os::dumpstate::DumpFileToFd;
Vishnu Naire97d6122018-01-18 13:58:56 -0800109using android::os::dumpstate::PropertiesHelper;
Felipe Leme47e9be22016-12-21 15:37:07 -0800110
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100111// Keep in sync with
112// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
113static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
114
115/* Most simple commands have 10 as timeout, so 5 is a good estimate */
116static const int32_t WEIGHT_FILE = 5;
117
118// TODO: temporary variables and functions used during C++ refactoring
119static Dumpstate& ds = Dumpstate::GetInstance();
120static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +0100121 const CommandOptions& options = CommandOptions::DEFAULT,
122 bool verbose_duration = false) {
123 return ds.RunCommand(title, full_command, options, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +0100124}
125
126// Reasonable value for max stats.
127static const int STATS_MAX_N_RUNS = 1000;
128static const long STATS_MAX_AVERAGE = 100000;
129
130CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
131
Nandana Duttd2f5f082019-01-18 17:13:52 +0000132typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
133
Colin Crossf45fa6b2012-03-26 12:38:26 -0700134/* read before root is shed */
135static char cmdline_buf[16384] = "(unknown)";
Yi Kong19d5c002018-07-20 13:39:55 -0700136static const char *dump_traces_path = nullptr;
Nandana Duttd2f5f082019-01-18 17:13:52 +0000137static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700138
Felipe Leme1d486fe2016-10-14 18:06:47 -0700139// TODO: variables and functions below should be part of dumpstate object
140
Felipe Leme635ca312016-01-05 14:23:02 -0800141static std::set<std::string> mount_points;
142void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -0800143
Todd Poynor2a83daa2013-11-22 15:44:22 -0800144#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700145#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Wei Wang509bb5d2017-06-09 14:42:12 -0700146#define BLK_DEV_SYS_DIR "/sys/block"
Todd Poynor2a83daa2013-11-22 15:44:22 -0800147
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -0700149#define RECOVERY_DATA_DIR "/data/misc/recovery"
Tianjie Xu75d53362018-04-11 16:42:28 -0700150#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -0700151#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +0100152#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
153#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Benedict Wong8f9d8a42019-01-03 16:19:38 -0800154#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
Erik Kline08165202016-05-30 11:55:44 +0900155#define WLUTIL "/vendor/xbin/wlutil"
Vishnu Nair36b4cdb2017-11-17 10:27:05 -0800156#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700157
Narayan Kamath8f788292017-05-25 13:20:39 +0100158// TODO(narayan): Since this information has to be kept in sync
159// with tombstoned, we should just put it in a common header.
160//
161// File: system/core/debuggerd/tombstoned/tombstoned.cpp
Narayan Kamathbd863722017-06-01 18:50:12 +0100162static const std::string TOMBSTONE_DIR = "/data/tombstones/";
163static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
164static const std::string ANR_DIR = "/data/anr/";
165static const std::string ANR_FILE_PREFIX = "anr_";
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700166
Felipe Lemee844a9d2016-09-21 15:01:39 -0700167// TODO: temporary variables and functions used during C++ refactoring
Nandana Dutt979388e2018-11-30 16:48:55 +0000168
Nandana Dutt5c390032019-03-12 10:52:56 +0000169#define RETURN_IF_USER_DENIED_CONSENT() \
170 if (ds.IsUserConsentDenied()) { \
171 MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
172 return Dumpstate::RunStatus::USER_CONSENT_DENIED; \
173 }
174
175// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
176// if consent is found to be denied.
177#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
178 RETURN_IF_USER_DENIED_CONSENT(); \
179 func_ptr(__VA_ARGS__); \
180 RETURN_IF_USER_DENIED_CONSENT();
181
Sahana Raof35ed432019-07-12 10:47:52 +0100182static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
183
Nandana Dutt979388e2018-11-30 16:48:55 +0000184namespace android {
185namespace os {
186namespace {
187
188static int Open(std::string path, int flags, mode_t mode = 0) {
189 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
190 if (fd == -1) {
191 MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
192 }
193 return fd;
194}
195
Nandana Dutt979388e2018-11-30 16:48:55 +0000196
197static int OpenForRead(std::string path) {
198 return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
199}
200
201bool CopyFile(int in_fd, int out_fd) {
202 char buf[4096];
203 ssize_t byte_count;
204 while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
205 if (!android::base::WriteFully(out_fd, buf, byte_count)) {
206 return false;
207 }
208 }
209 return (byte_count != -1);
210}
211
212static bool CopyFileToFd(const std::string& input_file, int out_fd) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000213 MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
Nandana Dutt979388e2018-11-30 16:48:55 +0000214
215 // Obtain a handle to the source file.
216 android::base::unique_fd in_fd(OpenForRead(input_file));
217 if (out_fd != -1 && in_fd.get() != -1) {
218 if (CopyFile(in_fd.get(), out_fd)) {
219 return true;
220 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000221 MYLOGE("Failed to copy file: %s\n", strerror(errno));
Nandana Dutt979388e2018-11-30 16:48:55 +0000222 }
223 return false;
224}
225
Nandana Duttd2f5f082019-01-18 17:13:52 +0000226static bool UnlinkAndLogOnError(const std::string& file) {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000227 if (unlink(file.c_str())) {
228 MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
Nandana Duttd2f5f082019-01-18 17:13:52 +0000229 return false;
230 }
231 return true;
232}
Nandana Dutt979388e2018-11-30 16:48:55 +0000233
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +0000234static bool IsFileEmpty(const std::string& file_path) {
235 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
236 if(file.bad()) {
237 MYLOGE("Cannot open file: %s\n", file_path.c_str());
238 return true;
239 }
240 return file.tellg() <= 0;
241}
242
Nikita Ioffea325a572019-05-16 19:49:47 +0100243int64_t GetModuleMetadataVersion() {
244 auto binder = defaultServiceManager()->getService(android::String16("package_native"));
245 if (binder == nullptr) {
246 MYLOGE("Failed to retrieve package_native service");
247 return 0L;
248 }
249 auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
250 std::string package_name;
251 auto status = package_service->getModuleMetadataPackageName(&package_name);
252 if (!status.isOk()) {
253 MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
254 return 0L;
255 }
Nandana Duttdb379fa2019-10-09 16:54:41 +0100256 MYLOGD("Module metadata package name: %s\n", package_name.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100257 int64_t version_code;
258 status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
259 &version_code);
260 if (!status.isOk()) {
261 MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
262 return 0L;
263 }
264 return version_code;
265}
266
Nandana Dutt979388e2018-11-30 16:48:55 +0000267} // namespace
268} // namespace os
269} // namespace android
270
Felipe Leme678727a2016-09-21 17:22:11 -0700271static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -0800272 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Vishnu Nair6921f802017-11-22 09:17:23 -0800273 long dumpsysTimeoutMs = 0) {
274 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
Felipe Leme678727a2016-09-21 17:22:11 -0700275}
276static int DumpFile(const std::string& title, const std::string& path) {
277 return ds.DumpFile(title, path);
278}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800279
Felipe Lemee844a9d2016-09-21 15:01:39 -0700280// Relative directory (inside the zip) for all files copied as-is into the bugreport.
281static const std::string ZIP_ROOT_DIR = "FS";
282
Vishnu Naire97d6122018-01-18 13:58:56 -0800283static const std::string kProtoPath = "proto/";
284static const std::string kProtoExt = ".proto";
Jie Song9fbfad02017-06-20 16:29:42 -0700285static const std::string kDumpstateBoardFiles[] = {
286 "dumpstate_board.txt",
Felipe Leme95d6ca52017-08-01 16:35:56 -0700287 "dumpstate_board.bin"
Jie Song9fbfad02017-06-20 16:29:42 -0700288};
289static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
290
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700291static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700292static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700293static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Naveen Kallab53a1c92017-03-16 18:17:25 -0700294static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
295static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700296
Felipe Lemef0292972016-11-22 13:57:05 -0800297static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
298
Narayan Kamath8f788292017-05-25 13:20:39 +0100299/*
Narayan Kamathbd863722017-06-01 18:50:12 +0100300 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
301 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
302 * is set, the vector only contains files that were written in the last 30 minutes.
Narayan Kamath8f788292017-05-25 13:20:39 +0100303 */
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700304static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
305 const std::string& file_prefix,
Elliott Hughesdb6d2112019-09-26 15:24:51 -0700306 bool limit_by_mtime) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100307 const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
308
Narayan Kamathbd863722017-06-01 18:50:12 +0100309 std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
Narayan Kamath8f788292017-05-25 13:20:39 +0100310
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700311 if (dump_dir == nullptr) {
312 MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700313 return std::vector<DumpData>();
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700314 }
315
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700316 std::vector<DumpData> dump_data;
Narayan Kamathbd863722017-06-01 18:50:12 +0100317 struct dirent* entry = nullptr;
318 while ((entry = readdir(dump_dir.get()))) {
319 if (entry->d_type != DT_REG) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100320 continue;
321 }
322
Narayan Kamathbd863722017-06-01 18:50:12 +0100323 const std::string base_name(entry->d_name);
324 if (base_name.find(file_prefix) != 0) {
325 continue;
326 }
327
328 const std::string abs_path = dir_path + base_name;
329 android::base::unique_fd fd(
330 TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
331 if (fd == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700332 MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamathbd863722017-06-01 18:50:12 +0100333 break;
334 }
335
336 struct stat st = {};
337 if (fstat(fd, &st) == -1) {
Luis Hector Chavezd0512712018-03-14 12:15:56 -0700338 MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
Narayan Kamath8f788292017-05-25 13:20:39 +0100339 continue;
340 }
341
Narayan Kamath3f31b632018-02-22 19:42:36 +0000342 if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
Narayan Kamathbd863722017-06-01 18:50:12 +0100343 MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100344 continue;
345 }
346
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700347 dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700348 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100349
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700350 return dump_data;
Narayan Kamath8f788292017-05-25 13:20:39 +0100351}
352
Narayan Kamathbd863722017-06-01 18:50:12 +0100353static bool AddDumps(const std::vector<DumpData>::const_iterator start,
354 const std::vector<DumpData>::const_iterator end,
355 const char* type_name, const bool add_to_zip) {
Narayan Kamath8f788292017-05-25 13:20:39 +0100356 bool dumped = false;
Narayan Kamathbd863722017-06-01 18:50:12 +0100357 for (auto it = start; it != end; ++it) {
358 const std::string& name = it->name;
359 const int fd = it->fd;
Narayan Kamath8f788292017-05-25 13:20:39 +0100360 dumped = true;
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100361
362 // Seek to the beginning of the file before dumping any data. A given
363 // DumpData entry might be dumped multiple times in the report.
364 //
365 // For example, the most recent ANR entry is dumped to the body of the
366 // main entry and it also shows up as a separate entry in the bugreport
367 // ZIP file.
368 if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
369 MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
370 strerror(errno));
371 }
372
Narayan Kamath8f788292017-05-25 13:20:39 +0100373 if (ds.IsZipping() && add_to_zip) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800374 if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100375 MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
Narayan Kamath8f788292017-05-25 13:20:39 +0100376 }
377 } else {
378 dump_file_from_fd(type_name, name.c_str(), fd);
379 }
Narayan Kamath8f788292017-05-25 13:20:39 +0100380 }
381
382 return dumped;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700383}
384
Felipe Leme635ca312016-01-05 14:23:02 -0800385// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700386void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800387 char path[PATH_MAX];
388
389 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
390 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700391 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800392 char linkname[PATH_MAX];
393 ssize_t r = readlink(path, linkname, PATH_MAX);
394 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800395 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800396 return;
397 }
398 linkname[r] = '\0';
399
400 if (mount_points.find(linkname) == mount_points.end()) {
401 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700402 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700403 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800404 mount_points.insert(linkname);
405 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800406 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800407 }
408 }
409}
410
411void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700412 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700413 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800414 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800415 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700416 for_each_pid(do_mountinfo, nullptr);
417 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800418}
419
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700420static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
421{
422 DIR *d;
423 struct dirent *de;
424 char path[PATH_MAX];
425
426 d = opendir(driverpath);
Yi Kong19d5c002018-07-20 13:39:55 -0700427 if (d == nullptr) {
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700428 return;
429 }
430
431 while ((de = readdir(d))) {
432 if (de->d_type != DT_LNK) {
433 continue;
434 }
435 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700436 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700437 }
438
439 closedir(d);
440}
441
Mark Salyzyn326842f2015-04-30 09:49:41 -0700442static bool skip_not_stat(const char *path) {
443 static const char stat[] = "/stat";
444 size_t len = strlen(path);
445 if (path[len - 1] == '/') { /* Directory? */
446 return false;
447 }
448 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
449}
450
Felipe Leme4c2d6632016-09-28 14:32:00 -0700451static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800452 return false;
453}
454
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700455unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700456
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800457//
458// stat offsets
459// Name units description
460// ---- ----- -----------
461// read I/Os requests number of read I/Os processed
462#define __STAT_READ_IOS 0
463// read merges requests number of read I/Os merged with in-queue I/O
464#define __STAT_READ_MERGES 1
465// read sectors sectors number of sectors read
466#define __STAT_READ_SECTORS 2
467// read ticks milliseconds total wait time for read requests
468#define __STAT_READ_TICKS 3
469// write I/Os requests number of write I/Os processed
470#define __STAT_WRITE_IOS 4
471// write merges requests number of write I/Os merged with in-queue I/O
472#define __STAT_WRITE_MERGES 5
473// write sectors sectors number of sectors written
474#define __STAT_WRITE_SECTORS 6
475// write ticks milliseconds total wait time for write requests
476#define __STAT_WRITE_TICKS 7
477// in_flight requests number of I/Os currently in flight
478#define __STAT_IN_FLIGHT 8
479// io_ticks milliseconds total time this block device has been active
480#define __STAT_IO_TICKS 9
481// time_in_queue milliseconds total wait time for all requests
482#define __STAT_IN_QUEUE 10
483#define __STAT_NUMBER_FIELD 11
484//
485// read I/Os, write I/Os
486// =====================
487//
488// These values increment when an I/O request completes.
489//
490// read merges, write merges
491// =========================
492//
493// These values increment when an I/O request is merged with an
494// already-queued I/O request.
495//
496// read sectors, write sectors
497// ===========================
498//
499// These values count the number of sectors read from or written to this
500// block device. The "sectors" in question are the standard UNIX 512-byte
501// sectors, not any device- or filesystem-specific block size. The
502// counters are incremented when the I/O completes.
503#define SECTOR_SIZE 512
504//
505// read ticks, write ticks
506// =======================
507//
508// These values count the number of milliseconds that I/O requests have
509// waited on this block device. If there are multiple I/O requests waiting,
510// these values will increase at a rate greater than 1000/second; for
511// example, if 60 read requests wait for an average of 30 ms, the read_ticks
512// field will increase by 60*30 = 1800.
513//
514// in_flight
515// =========
516//
517// This value counts the number of I/O requests that have been issued to
518// the device driver but have not yet completed. It does not include I/O
519// requests that are in the queue but not yet issued to the device driver.
520//
521// io_ticks
522// ========
523//
524// This value counts the number of milliseconds during which the device has
525// had I/O requests queued.
526//
527// time_in_queue
528// =============
529//
530// This value counts the number of milliseconds that I/O requests have waited
531// on this block device. If there are multiple I/O requests waiting, this
532// value will increase as the product of the number of milliseconds times the
533// number of requests waiting (see "read ticks" above for an example).
534#define S_TO_MS 1000
535//
536
Mark Salyzyn326842f2015-04-30 09:49:41 -0700537static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800538 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700539 bool z;
Yi Kong19d5c002018-07-20 13:39:55 -0700540 char *cp, *buffer = nullptr;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700541 size_t i = 0;
Josh Gao7c4258c2018-06-25 13:40:08 -0700542 FILE *fp = fdopen(dup(fd), "rb");
Mark Salyzyn326842f2015-04-30 09:49:41 -0700543 getline(&buffer, &i, fp);
544 fclose(fp);
545 if (!buffer) {
546 return -errno;
547 }
548 i = strlen(buffer);
549 while ((i > 0) && (buffer[i - 1] == '\n')) {
550 buffer[--i] = '\0';
551 }
552 if (!*buffer) {
553 free(buffer);
554 return 0;
555 }
556 z = true;
557 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800558 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700559 if (fields[i] != 0) {
560 z = false;
561 }
562 }
563 if (z) { /* never accessed */
564 free(buffer);
565 return 0;
566 }
567
Wei Wang509bb5d2017-06-09 14:42:12 -0700568 if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
569 path += sizeof(BLK_DEV_SYS_DIR) - 1;
Mark Salyzyn326842f2015-04-30 09:49:41 -0700570 }
Wei Wang1dc1ef52017-06-12 11:28:37 -0700571
572 printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
573 "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
574 "W-wait", "in-fli", "activ", "T-wait", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700575 free(buffer);
576
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800577 if (fields[__STAT_IO_TICKS]) {
578 unsigned long read_perf = 0;
579 unsigned long read_ios = 0;
580 if (fields[__STAT_READ_TICKS]) {
581 unsigned long long divisor = fields[__STAT_READ_TICKS]
582 * fields[__STAT_IO_TICKS];
583 read_perf = ((unsigned long long)SECTOR_SIZE
584 * fields[__STAT_READ_SECTORS]
585 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
586 / divisor;
587 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
588 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
589 / divisor;
590 }
591
592 unsigned long write_perf = 0;
593 unsigned long write_ios = 0;
594 if (fields[__STAT_WRITE_TICKS]) {
595 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
596 * fields[__STAT_IO_TICKS];
597 write_perf = ((unsigned long long)SECTOR_SIZE
598 * fields[__STAT_WRITE_SECTORS]
599 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
600 / divisor;
601 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
602 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
603 / divisor;
604 }
605
606 unsigned queue = (fields[__STAT_IN_QUEUE]
607 + (fields[__STAT_IO_TICKS] >> 1))
608 / fields[__STAT_IO_TICKS];
609
610 if (!write_perf && !write_ios) {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700611 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800612 } else {
Wei Wang1dc1ef52017-06-12 11:28:37 -0700613 printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
Felipe Lemed8b94e52016-12-08 10:21:44 -0800614 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800615 }
616
617 /* bugreport timeout factor adjustment */
618 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
619 worst_write_perf = write_perf;
620 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700621 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700622 return 0;
623}
624
Yao Chenbe3bbc12018-01-17 16:31:10 -0800625static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
626
627/* timeout in ms to read a list of buffers */
628static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
629 unsigned long timeout_ms = 0;
630 for (const auto& buffer : buffers) {
631 log_id_t id = android_name_to_log_id(buffer.c_str());
632 unsigned long property_size = __android_logger_get_buffer_size(id);
633 /* Engineering margin is ten-fold our guess */
634 timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
635 }
636 return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700637}
638
Nandana Duttd2f5f082019-01-18 17:13:52 +0000639Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
640}
641
642android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
643 std::lock_guard<std::mutex> lock(lock_);
644 result_ = APPROVED;
645 MYLOGD("User approved consent to share bugreport\n");
646 return android::binder::Status::ok();
647}
648
649android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
650 std::lock_guard<std::mutex> lock(lock_);
651 result_ = DENIED;
652 MYLOGW("User denied consent to share bugreport\n");
653 return android::binder::Status::ok();
654}
655
656UserConsentResult Dumpstate::ConsentCallback::getResult() {
657 std::lock_guard<std::mutex> lock(lock_);
658 return result_;
659}
660
661uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
662 return Nanotime() - start_time_;
663}
664
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700665void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700666 std::string build, fingerprint, radio, bootloader, network;
667 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700668
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700669 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
670 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700671 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
672 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
673 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700674 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700675
Felipe Lemed8b94e52016-12-08 10:21:44 -0800676 printf("========================================================\n");
677 printf("== dumpstate: %s\n", date);
678 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700679
Felipe Lemed8b94e52016-12-08 10:21:44 -0800680 printf("\n");
681 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700682 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800683 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
684 printf("Bootloader: %s\n", bootloader.c_str());
685 printf("Radio: %s\n", radio.c_str());
686 printf("Network: %s\n", network.c_str());
Nikita Ioffea325a572019-05-16 19:49:47 +0100687 int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
688 if (module_metadata_version != 0) {
689 printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
690 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700691
Felipe Lemed8b94e52016-12-08 10:21:44 -0800692 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800693 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800694 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme7709f8a2017-12-05 09:30:09 -0800695 printf("Uptime: ");
696 RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
697 CommandOptions::WithTimeout(1).Always().Build());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800698 printf("Bugreport format version: %s\n", version_.c_str());
699 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
Nandana Dutt5fb117b2018-09-27 09:23:36 +0100700 PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
Felipe Lemed8b94e52016-12-08 10:21:44 -0800701 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800702}
703
Felipe Leme24b66ee2016-06-16 10:55:26 -0700704// List of file extensions that can cause a zip file attachment to be rejected by some email
705// service providers.
706static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
707 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
708 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
709 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
710};
711
Vishnu Naire97d6122018-01-18 13:58:56 -0800712status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
713 std::chrono::milliseconds timeout = 0ms) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700714 if (!IsZipping()) {
715 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
716 entry_name.c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -0800717 return INVALID_OPERATION;
Felipe Leme111b9d02016-02-03 09:28:24 -0800718 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700719 std::string valid_name = entry_name;
720
721 // Rename extension if necessary.
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700722 size_t idx = entry_name.rfind('.');
Felipe Leme24b66ee2016-06-16 10:55:26 -0700723 if (idx != std::string::npos) {
724 std::string extension = entry_name.substr(idx);
725 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
726 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
727 valid_name = entry_name + ".renamed";
728 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
729 }
730 }
731
Felipe Leme6fe9db62016-02-12 09:04:16 -0800732 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
733 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700734 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
735 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700736 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700737 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700738 ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800739 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800740 }
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000741 bool finished_entry = false;
742 auto finish_entry = [this, &finished_entry] {
743 if (!finished_entry) {
744 // This should only be called when we're going to return an earlier error,
745 // which would've been logged. This may imply the file is already corrupt
746 // and any further logging from FinishEntry is more likely to mislead than
747 // not.
748 this->zip_writer_->FinishEntry();
749 }
750 };
751 auto scope_guard = android::base::make_scope_guard(finish_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800752 auto start = std::chrono::steady_clock::now();
753 auto end = start + timeout;
754 struct pollfd pfd = {fd, POLLIN};
Felipe Lemee82a27d2016-01-05 13:35:44 -0800755
Felipe Leme770410d2016-01-26 17:07:14 -0800756 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800757 while (1) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800758 if (timeout.count() > 0) {
759 // lambda to recalculate the timeout.
760 auto time_left_ms = [end]() {
761 auto now = std::chrono::steady_clock::now();
762 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
763 return std::max(diff.count(), 0LL);
764 };
765
766 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
767 if (rc < 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000768 MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
769 entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800770 return -errno;
771 } else if (rc == 0) {
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000772 MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
Vishnu Naire97d6122018-01-18 13:58:56 -0800773 entry_name.c_str(), strerror(errno), timeout.count());
774 return TIMED_OUT;
775 }
776 }
777
Zach Riggle22200402016-08-18 01:01:24 -0400778 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800779 if (bytes_read == 0) {
780 break;
781 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800782 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Vishnu Naire97d6122018-01-18 13:58:56 -0800783 return -errno;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800784 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700785 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800786 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700787 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800788 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800789 }
790 }
791
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700792 err = zip_writer_->FinishEntry();
Narayan Kamath895f8fc2019-02-08 18:18:08 +0000793 finished_entry = true;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700794 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700795 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Vishnu Naire97d6122018-01-18 13:58:56 -0800796 return UNKNOWN_ERROR;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800797 }
798
Vishnu Naire97d6122018-01-18 13:58:56 -0800799 return OK;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800800}
801
Felipe Leme1d486fe2016-10-14 18:06:47 -0700802bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
803 android::base::unique_fd fd(
804 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700805 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800806 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800807 return false;
808 }
809
Vishnu Naire97d6122018-01-18 13:58:56 -0800810 return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800811}
812
813/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700814static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800815 return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800816}
817
Felipe Leme1d486fe2016-10-14 18:06:47 -0700818void Dumpstate::AddDir(const std::string& dir, bool recursive) {
819 if (!IsZipping()) {
820 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800821 return;
822 }
Felipe Leme678727a2016-09-21 17:22:11 -0700823 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800824 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700825 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800826}
827
Felipe Leme1d486fe2016-10-14 18:06:47 -0700828bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
829 if (!IsZipping()) {
830 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
831 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800832 return false;
833 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800834 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700835 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700836 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700837 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700838 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800839 return false;
840 }
841
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700842 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700843 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700844 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700845 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800846 return false;
847 }
848
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700849 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700850 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700851 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800852 return false;
853 }
854
855 return true;
856}
857
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800858static void DoKmsg() {
859 struct stat st;
860 if (!stat(PSTORE_LAST_KMSG, &st)) {
861 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
862 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
863 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
864 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
865 } else {
866 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
867 DumpFile("LAST KMSG", "/proc/last_kmsg");
868 }
869}
870
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800871static void DoKernelLogcat() {
Yao Chenbe3bbc12018-01-17 16:31:10 -0800872 unsigned long timeout_ms = logcat_timeout({"kernel"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800873 RunCommand(
874 "KERNEL LOG",
875 {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
876 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
877}
878
Nandana Duttdb379fa2019-10-09 16:54:41 +0100879static void DoSystemLogcat(time_t since) {
880 char since_str[80];
881 strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
882
883 unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
884 RunCommand("SYSTEM LOG",
885 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
886 since_str},
887 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
888}
889
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800890static void DoLogcat() {
Vishnu Nair6921f802017-11-22 09:17:23 -0800891 unsigned long timeout_ms;
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800892 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
893 // calculate timeout
Yao Chenbe3bbc12018-01-17 16:31:10 -0800894 timeout_ms = logcat_timeout({"main", "system", "crash"});
Tony Makae737652017-03-30 17:47:09 +0100895 RunCommand("SYSTEM LOG",
Vishnu Nair6921f802017-11-22 09:17:23 -0800896 {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
897 CommandOptions::WithTimeoutInMs(timeout_ms).Build());
Yao Chenbe3bbc12018-01-17 16:31:10 -0800898 timeout_ms = logcat_timeout({"events"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800899 RunCommand(
900 "EVENT LOG",
901 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100902 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800903 timeout_ms = logcat_timeout({"stats"});
904 RunCommand(
905 "STATS LOG",
906 {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100907 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Yao Chenbe3bbc12018-01-17 16:31:10 -0800908 timeout_ms = logcat_timeout({"radio"});
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800909 RunCommand(
910 "RADIO LOG",
911 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
Nandana Dutt8d945c02019-08-14 13:30:07 +0100912 CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800913
914 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
915
916 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -0800917 RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
918 "-v", "uid", "-d", "*:v"});
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800919}
920
Mike Ma5c267872019-08-21 11:31:34 -0700921static void DumpIncidentReport() {
922 if (!ds.IsZipping()) {
923 MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
924 return;
925 }
926 DurationReporter duration_reporter("INCIDENT REPORT");
927 const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
928 auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
929 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
930 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
931 if (fd < 0) {
932 MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
933 return;
934 }
935 RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
936 bool empty = 0 == lseek(fd, 0, SEEK_END);
937 if (!empty) {
938 // Use a different name from "incident.proto"
939 // /proto/incident.proto is reserved for incident service dump
940 // i.e. metadata for debugging.
941 ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
942 }
943 unlink(path.c_str());
944}
945
Jayachandran Ca94c7172017-06-10 15:08:12 -0700946static void DumpIpTablesAsRoot() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700947 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
948 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900949 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700950 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900951 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
952 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
953 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
954 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700955}
956
David Andersond9ba4752018-12-11 18:26:59 -0800957static void DumpDynamicPartitionInfo() {
958 if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
959 return;
960 }
961
962 RunCommand("LPDUMP", {"lpdump", "--all"});
David Anderson6650ade2019-10-02 15:18:59 -0700963 RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
David Andersond9ba4752018-12-11 18:26:59 -0800964}
965
Narayan Kamath8f788292017-05-25 13:20:39 +0100966static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
967 MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
968 anr_traces_dir.c_str());
969
970 // If we're here, dump_traces_path will always be a temporary file
971 // (created with mkostemp or similar) that contains dumps taken earlier
972 // on in the process.
973 if (dump_traces_path != nullptr) {
974 if (add_to_zip) {
975 ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
976 } else {
977 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
978 dump_traces_path);
979 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
980 }
981
982 const int ret = unlink(dump_traces_path);
983 if (ret == -1) {
984 MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
985 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700986 }
987 }
988
Narayan Kamathbd863722017-06-01 18:50:12 +0100989 // Add a specific message for the first ANR Dump.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700990 if (ds.anr_data_.size() > 0) {
991 AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
Narayan Kamathbd863722017-06-01 18:50:12 +0100992 "VM TRACES AT LAST ANR", add_to_zip);
993
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100994 // The "last" ANR will always be included as separate entry in the zip file. In addition,
995 // it will be present in the body of the main entry if |add_to_zip| == false.
996 //
997 // Historical ANRs are always included as separate entries in the bugreport zip file.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -0700998 AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
Narayan Kamath6b9516c2017-10-27 11:15:51 +0100999 "HISTORICAL ANR", true /* add_to_zip */);
Narayan Kamathbd863722017-06-01 18:50:12 +01001000 } else {
Narayan Kamath8f788292017-05-25 13:20:39 +01001001 printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
1002 }
1003}
1004
1005static void AddAnrTraceFiles() {
1006 const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
1007
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001008 std::string anr_traces_dir = "/data/anr";
Narayan Kamath8f788292017-05-25 13:20:39 +01001009
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001010 AddAnrTraceDir(add_to_zip, anr_traces_dir);
Narayan Kamath8f788292017-05-25 13:20:39 +01001011
Makoto Onuki83ec63f2019-01-31 17:08:59 -08001012 RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
1013
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001014 // Slow traces for slow operations.
Felipe Lemee184f662016-10-27 10:04:47 -07001015 struct stat st;
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001016 int i = 0;
1017 while (true) {
1018 const std::string slow_trace_path =
1019 anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
1020 if (stat(slow_trace_path.c_str(), &st)) {
1021 // No traces file at this index, done with the files.
1022 break;
Felipe Lemee184f662016-10-27 10:04:47 -07001023 }
Elliott Hughes69fe5ec2018-03-23 11:04:25 -07001024 ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
1025 i++;
Felipe Lemee184f662016-10-27 10:04:47 -07001026 }
1027}
1028
Wei Wang509bb5d2017-06-09 14:42:12 -07001029static void DumpBlockStatFiles() {
1030 DurationReporter duration_reporter("DUMP BLOCK STAT");
Wei Wang509bb5d2017-06-09 14:42:12 -07001031
Wei Wang1dc1ef52017-06-12 11:28:37 -07001032 std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
1033
1034 if (dirptr == nullptr) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001035 MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
1036 return;
1037 }
1038
1039 printf("------ DUMP BLOCK STAT ------\n\n");
Wei Wang1dc1ef52017-06-12 11:28:37 -07001040 while (struct dirent *d = readdir(dirptr.get())) {
Wei Wang509bb5d2017-06-09 14:42:12 -07001041 if ((d->d_name[0] == '.')
1042 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
1043 || (d->d_name[1] == '\0'))) {
1044 continue;
1045 }
1046 const std::string new_path =
1047 android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
1048 printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
1049 dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
1050 printf("\n");
1051 }
Wei Wang1dc1ef52017-06-12 11:28:37 -07001052 return;
Wei Wang509bb5d2017-06-09 14:42:12 -07001053}
Jayachandran Ca94c7172017-06-10 15:08:12 -07001054
1055static void DumpPacketStats() {
1056 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1057 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1058 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1059 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1060 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
1061}
1062
1063static void DumpIpAddrAndRules() {
1064 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
1065 RunCommand("NETWORK INTERFACES", {"ip", "link"});
1066 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1067 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
1068 RunCommand("IP RULES", {"ip", "rule", "show"});
1069 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
1070}
1071
Nandana Dutt5c390032019-03-12 10:52:56 +00001072static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
1073 std::chrono::milliseconds timeout,
1074 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001075 auto start = std::chrono::steady_clock::now();
Vishnu Naire97d6122018-01-18 13:58:56 -08001076 sp<android::IServiceManager> sm = defaultServiceManager();
1077 Dumpsys dumpsys(sm.get());
Vishnu Naire97d6122018-01-18 13:58:56 -08001078 Vector<String16> args;
1079 Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
Vishnu Naire97d6122018-01-18 13:58:56 -08001080 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
1081 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001082 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001083 std::string path(title);
1084 path.append(" - ").append(String8(service).c_str());
Vishnu Naire97d6122018-01-18 13:58:56 -08001085 size_t bytes_written = 0;
Steven Moreland5a30d342019-10-08 13:53:28 -07001086 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001087 if (status == OK) {
1088 dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
1089 std::chrono::duration<double> elapsed_seconds;
1090 status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
1091 /* as_proto = */ false, elapsed_seconds, bytes_written);
Vishnu Naire97d6122018-01-18 13:58:56 -08001092 dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
1093 bool dump_complete = (status == OK);
1094 dumpsys.stopDumpThread(dump_complete);
1095 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001096
1097 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1098 std::chrono::steady_clock::now() - start);
1099 if (elapsed_duration > timeout) {
1100 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1101 elapsed_duration.count());
1102 break;
1103 }
1104 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001105 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001106}
1107
Vishnu Nair64afc022018-02-01 15:29:34 -08001108static void RunDumpsysText(const std::string& title, int priority,
1109 std::chrono::milliseconds timeout,
1110 std::chrono::milliseconds service_timeout) {
1111 DurationReporter duration_reporter(title);
1112 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1113 fsync(STDOUT_FILENO);
1114 RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
1115}
1116
1117/* Dump all services registered with Normal or Default priority. */
Nandana Dutt5c390032019-03-12 10:52:56 +00001118static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
1119 std::chrono::milliseconds timeout,
1120 std::chrono::milliseconds service_timeout) {
Vishnu Nair64afc022018-02-01 15:29:34 -08001121 DurationReporter duration_reporter(title);
1122 dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
1123 fsync(STDOUT_FILENO);
1124 RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
1125 service_timeout);
Nandana Dutt5c390032019-03-12 10:52:56 +00001126
1127 RETURN_IF_USER_DENIED_CONSENT();
1128
1129 return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
1130 service_timeout);
Vishnu Nair64afc022018-02-01 15:29:34 -08001131}
1132
Nandana Dutt5c390032019-03-12 10:52:56 +00001133static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
1134 std::chrono::milliseconds timeout,
1135 std::chrono::milliseconds service_timeout) {
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001136 if (!ds.IsZipping()) {
1137 MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
Nandana Dutt5c390032019-03-12 10:52:56 +00001138 return Dumpstate::RunStatus::OK;
Luis Hector Chavez1e27b082018-03-22 15:36:42 -07001139 }
Vishnu Naire97d6122018-01-18 13:58:56 -08001140 sp<android::IServiceManager> sm = defaultServiceManager();
1141 Dumpsys dumpsys(sm.get());
1142 Vector<String16> args;
1143 Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
1144 DurationReporter duration_reporter(title);
1145
1146 auto start = std::chrono::steady_clock::now();
1147 Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
1148 for (const String16& service : services) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001149 RETURN_IF_USER_DENIED_CONSENT();
Vishnu Naire97d6122018-01-18 13:58:56 -08001150 std::string path(kProtoPath);
1151 path.append(String8(service).c_str());
1152 if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
1153 path.append("_CRITICAL");
1154 } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
1155 path.append("_HIGH");
1156 }
1157 path.append(kProtoExt);
Steven Moreland5a30d342019-10-08 13:53:28 -07001158 status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
Vishnu Naire97d6122018-01-18 13:58:56 -08001159 if (status == OK) {
1160 status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
1161 bool dumpTerminated = (status == OK);
1162 dumpsys.stopDumpThread(dumpTerminated);
1163 }
1164 ZipWriter::FileEntry file_entry;
1165 ds.zip_writer_->GetLastEntry(&file_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -08001166
1167 auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
1168 std::chrono::steady_clock::now() - start);
1169 if (elapsed_duration > timeout) {
1170 MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
1171 elapsed_duration.count());
1172 break;
1173 }
1174 }
Nandana Dutt5c390032019-03-12 10:52:56 +00001175 return Dumpstate::RunStatus::OK;
Vishnu Naire97d6122018-01-18 13:58:56 -08001176}
1177
Nandana Dutta7db6342018-11-21 14:53:34 +00001178// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001179static Dumpstate::RunStatus RunDumpsysCritical() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001180 RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1181 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Nandana Dutt5c390032019-03-12 10:52:56 +00001182
1183 RETURN_IF_USER_DENIED_CONSENT();
1184
1185 return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
1186 /* timeout= */ 5s, /* service_timeout= */ 500ms);
Vishnu Nair780b1282017-10-10 13:57:24 -07001187}
1188
1189// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001190static Dumpstate::RunStatus RunDumpsysHigh() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001191 // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
1192 // high priority. Reduce timeout once they are able to dump in a shorter time or
1193 // moved to a parallel task.
1194 RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1195 /* timeout= */ 90s, /* service_timeout= */ 30s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001196
1197 RETURN_IF_USER_DENIED_CONSENT();
1198
1199 return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
1200 /* timeout= */ 5s, /* service_timeout= */ 1s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001201}
1202
1203// Runs dumpsys on services that must dump but can take up to 10s to dump.
Nandana Dutt5c390032019-03-12 10:52:56 +00001204static Dumpstate::RunStatus RunDumpsysNormal() {
Vishnu Nair64afc022018-02-01 15:29:34 -08001205 RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
Nandana Dutt5c390032019-03-12 10:52:56 +00001206
1207 RETURN_IF_USER_DENIED_CONSENT();
1208
1209 return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
1210 /* timeout= */ 90s, /* service_timeout= */ 10s);
Vishnu Nair780b1282017-10-10 13:57:24 -07001211}
1212
Steven Moreland44cd9482018-01-04 16:24:13 -08001213static void DumpHals() {
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001214 if (!ds.IsZipping()) {
1215 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
1216 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
1217 return;
1218 }
1219 DurationReporter duration_reporter("DUMP HALS");
1220 RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
Greg Kaiser3dfeda32019-05-16 10:32:51 -07001221 CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001222
Steven Moreland44cd9482018-01-04 16:24:13 -08001223 using android::hidl::manager::V1_0::IServiceManager;
1224 using android::hardware::defaultServiceManager;
1225
1226 sp<IServiceManager> sm = defaultServiceManager();
1227 if (sm == nullptr) {
1228 MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
1229 return;
1230 }
1231
1232 auto ret = sm->list([&](const auto& interfaces) {
1233 for (const std::string& interface : interfaces) {
1234 std::string cleanName = interface;
1235 std::replace_if(cleanName.begin(),
1236 cleanName.end(),
1237 [](char c) {
1238 return !isalnum(c) &&
1239 std::string("@-_:.").find(c) == std::string::npos;
1240 }, '_');
Nandana Dutt979388e2018-11-30 16:48:55 +00001241 const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
Steven Moreland44cd9482018-01-04 16:24:13 -08001242
1243 {
1244 auto fd = android::base::unique_fd(
1245 TEMP_FAILURE_RETRY(open(path.c_str(),
1246 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1247 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1248 if (fd < 0) {
1249 MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
1250 continue;
1251 }
1252 RunCommandToFd(fd,
1253 "",
Steven Morelandc81cd3c2018-01-18 14:36:26 -08001254 {"lshal", "debug", "-E", interface},
Steven Moreland44cd9482018-01-04 16:24:13 -08001255 CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
1256
1257 bool empty = 0 == lseek(fd, 0, SEEK_END);
1258 if (!empty) {
1259 ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
1260 }
1261 }
1262
1263 unlink(path.c_str());
1264 }
1265 });
1266
1267 if (!ret.isOk()) {
1268 MYLOGE("Could not list hals from hwservicemanager.\n");
1269 }
1270}
1271
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001272static void DumpExternalFragmentationInfo() {
1273 struct stat st;
1274 if (stat("/proc/buddyinfo", &st) != 0) {
1275 MYLOGE("Unable to dump external fragmentation info\n");
1276 return;
1277 }
1278
1279 printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
1280 std::ifstream ifs("/proc/buddyinfo");
1281 auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
1282 for (std::string line; std::getline(ifs, line);) {
1283 std::smatch match_results;
1284 if (std::regex_match(line, match_results, unusable_index_regex)) {
1285 std::stringstream free_pages(std::string{match_results[3]});
1286 std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
1287 std::istream_iterator<int>());
1288
1289 int total_free_pages = 0;
1290 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1291 total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
1292 }
1293
1294 printf("Node %s, zone %8s", match_results[1].str().c_str(),
1295 match_results[2].str().c_str());
1296
1297 int usable_free_pages = total_free_pages;
1298 for (size_t i = 0; i < free_pages_per_order.size(); i++) {
1299 auto unusable_index = (total_free_pages - usable_free_pages) /
1300 static_cast<double>(total_free_pages);
1301 printf(" %5.3f", unusable_index);
1302 usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
1303 }
1304
1305 printf("\n");
1306 }
1307 }
1308 printf("\n");
1309}
1310
Nandana Dutt5c390032019-03-12 10:52:56 +00001311// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
1312// via the consent they are shown. Ignores other errors that occur while running various
1313// commands. The consent checking is currently done around long running tasks, which happen to
1314// be distributed fairly evenly throughout the function.
1315static Dumpstate::RunStatus dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001316 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001317
Nandana Dutt5c390032019-03-12 10:52:56 +00001318 // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
1319 // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
1320 // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -07001321 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001322 RunCommand("UPTIME", {"uptime"});
Wei Wang509bb5d2017-06-09 14:42:12 -07001323 DumpBlockStatFiles();
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001324 DumpFile("MEMORY INFO", "/proc/meminfo");
1325 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001326 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001327
1328 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
1329
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001330 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
1331 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
1332 DumpFile("SLAB INFO", "/proc/slabinfo");
1333 DumpFile("ZONEINFO", "/proc/zoneinfo");
1334 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
1335 DumpFile("BUDDYINFO", "/proc/buddyinfo");
Hridya Valsarajuac582cd2019-08-05 15:39:54 -07001336 DumpExternalFragmentationInfo();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001337
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001338 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
1339 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001340
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001341 RunCommand("PROCESSES AND THREADS",
Yohei Yukawa591a72d2017-10-05 21:36:35 -07001342 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001343
1344 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
1345 CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001346
Nandana Dutt6ad9a602019-03-11 16:33:24 +00001347 DumpHals();
Steven Moreland81b429e2017-01-31 19:50:46 -08001348
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001349 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -07001350 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001351 struct stat s;
1352 if (stat("/proc/modules", &s) != 0) {
1353 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
1354 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001355 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -07001356 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001357
Siarhei Vishniakou4a0a8772017-12-05 16:22:49 -08001358 if (__android_logger_property_get_bool(
1359 "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
1360 DoKernelLogcat();
1361 } else {
1362 do_dmesg();
1363 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001364
Felipe Lemef0292972016-11-22 13:57:05 -08001365 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Nandana Dutt5c390032019-03-12 10:52:56 +00001366
1367 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
1368
Jeff Brown1dc94e32014-09-11 14:15:27 -07001369 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -08001370 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371
Ajay Panicker2ff8e872017-04-27 14:04:32 -07001372 /* Dump Bluetooth HCI logs */
1373 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -07001374
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07001375 if (ds.options_->do_fb && !ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001376 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001377 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001378 }
1379
Felipe Lemee184f662016-10-27 10:04:47 -07001380 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001381
Narayan Kamath8f788292017-05-25 13:20:39 +01001382 // NOTE: tombstones are always added as separate entries in the zip archive
1383 // and are not interspersed with the main report.
Luis Hector Chavez5f6ee4a2018-03-14 15:12:46 -07001384 const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
Narayan Kamathbd863722017-06-01 18:50:12 +01001385 "TOMBSTONE", true /* add_to_zip */);
Narayan Kamath8f788292017-05-25 13:20:39 +01001386 if (!tombstones_dumped) {
1387 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001388 }
1389
Jayachandran Ca94c7172017-06-10 15:08:12 -07001390 DumpPacketStats();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001391
Chenbo Feng276a3b62018-08-07 11:44:49 -07001392 RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
1393
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001394 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001395
Jayachandran Ca94c7172017-06-10 15:08:12 -07001396 DumpIpAddrAndRules();
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001397
1398 dump_route_tables();
1399
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001400 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1401 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1402 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001403
Nandana Dutt5c390032019-03-12 10:52:56 +00001404 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001405
Elliott Hughes23ccc622017-02-28 10:14:22 -08001406 RunCommand("SYSTEM PROPERTIES", {"getprop"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001407
Jin Qianf334d662017-10-10 14:41:37 -07001408 RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
ynwangf649a6e2016-07-17 21:56:00 -07001409
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001410 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001411
Colin Crossf45fa6b2012-03-26 12:38:26 -07001412 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001413 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1414 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1415 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1416 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1417 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001418
Vishnu Nair36b4cdb2017-11-17 10:27:05 -08001419 /* Add window and surface trace files. */
1420 if (!PropertiesHelper::IsUserBuild()) {
1421 ds.AddDir(WMTRACE_DATA_DIR, false);
1422 }
1423
Nandana Dutt5c390032019-03-12 10:52:56 +00001424 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001425
Steven Moreland7440ddb2016-12-15 16:13:39 -08001426 /* Migrate the ril_dumpstate to a device specific dumpstate? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001427 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1428 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001429 // su does not exist on user builds, so try running without it.
1430 // This way any implementations of vril-dump that do not require
1431 // root can run on user builds.
1432 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001433 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001434 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001435 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001436 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001437 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001438 }
1439
Felipe Lemed8b94e52016-12-08 10:21:44 -08001440 printf("========================================================\n");
1441 printf("== Android Framework Services\n");
1442 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001443
Nandana Dutt5c390032019-03-12 10:52:56 +00001444 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001445
Felipe Lemed8b94e52016-12-08 10:21:44 -08001446 printf("========================================================\n");
1447 printf("== Checkins\n");
1448 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001449
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001450 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
Nandana Dutt5c390032019-03-12 10:52:56 +00001451
1452 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
1453
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001454 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1455 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1456 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1457 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001458
Felipe Lemed8b94e52016-12-08 10:21:44 -08001459 printf("========================================================\n");
1460 printf("== Running Application Activities\n");
1461 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001462
Makoto Onuki60780982018-04-16 15:34:00 -07001463 // The following dumpsys internally collects output from running apps, so it can take a long
1464 // time. So let's extend the timeout.
1465
1466 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
1467
1468 RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001469
Felipe Lemed8b94e52016-12-08 10:21:44 -08001470 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001471 printf("== Running Application Services (platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001472 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001473
Vishnu Nairc6e6ea72018-07-02 14:20:06 -07001474 RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
Makoto Onuki60780982018-04-16 15:34:00 -07001475 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001476
Felipe Lemed8b94e52016-12-08 10:21:44 -08001477 printf("========================================================\n");
Makoto Onuki60780982018-04-16 15:34:00 -07001478 printf("== Running Application Services (non-platform)\n");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001479 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001480
Makoto Onuki60780982018-04-16 15:34:00 -07001481 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1482 DUMPSYS_COMPONENTS_OPTIONS);
1483
1484 printf("========================================================\n");
1485 printf("== Running Application Providers (platform)\n");
1486 printf("========================================================\n");
1487
1488 RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
1489 DUMPSYS_COMPONENTS_OPTIONS);
1490
1491 printf("========================================================\n");
1492 printf("== Running Application Providers (non-platform)\n");
1493 printf("========================================================\n");
1494
1495 RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
1496 DUMPSYS_COMPONENTS_OPTIONS);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001497
Adrian Roos8b397ab2017-04-04 16:35:44 -07001498 printf("========================================================\n");
1499 printf("== Dropbox crashes\n");
1500 printf("========================================================\n");
1501
1502 RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
1503 RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
1504
Felipe Lemed8b94e52016-12-08 10:21:44 -08001505 printf("========================================================\n");
1506 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1507 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1508 printf("========================================================\n");
1509 printf("== dumpstate: done (id %d)\n", ds.id_);
1510 printf("========================================================\n");
Bookatz38472142018-09-28 10:20:24 -07001511
1512 printf("========================================================\n");
1513 printf("== Obtaining statsd metadata\n");
1514 printf("========================================================\n");
1515 // This differs from the usual dumpsys stats, which is the stats report data.
1516 RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
Mike Ma5c267872019-08-21 11:31:34 -07001517
1518 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
1519
Nandana Dutt5c390032019-03-12 10:52:56 +00001520 return Dumpstate::RunStatus::OK;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001521}
1522
Nandana Dutt5c390032019-03-12 10:52:56 +00001523/*
1524 * Dumps state for the default case; drops root after it's no longer necessary.
1525 *
1526 * Returns RunStatus::OK if everything went fine.
1527 * Returns RunStatus::ERROR if there was an error.
1528 * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
1529 * with the caller.
1530 */
1531static Dumpstate::RunStatus DumpstateDefault() {
Nandana Duttcf419a72019-03-14 10:40:17 +00001532 // Invoking the following dumpsys calls before DumpTraces() to try and
Nandana Dutt4be45d12018-09-26 15:04:23 +01001533 // keep the system stats as close to its initial state as possible.
Nandana Dutt5c390032019-03-12 10:52:56 +00001534 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001535
Nandana Duttdb379fa2019-10-09 16:54:41 +01001536 // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
1537 // buffer.
1538 DoLogcat();
1539 // Capture timestamp after first logcat to use in next logcat
1540 time_t logcat_ts = time(nullptr);
1541
Nandana Dutt4be45d12018-09-26 15:04:23 +01001542 /* collect stack traces from Dalvik and native processes (needs root) */
Nandana Duttcf419a72019-03-14 10:40:17 +00001543 RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
Nandana Dutt4be45d12018-09-26 15:04:23 +01001544
1545 /* Run some operations that require root. */
1546 ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
1547 ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
1548
1549 ds.AddDir(RECOVERY_DIR, true);
1550 ds.AddDir(RECOVERY_DATA_DIR, true);
1551 ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
1552 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1553 if (!PropertiesHelper::IsUserBuild()) {
1554 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1555 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1556 }
1557 add_mountinfo();
1558 DumpIpTablesAsRoot();
David Andersond9ba4752018-12-11 18:26:59 -08001559 DumpDynamicPartitionInfo();
Nandana Dutt4be45d12018-09-26 15:04:23 +01001560
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001561 // Capture any IPSec policies in play. No keys are exposed here.
Nandana Dutt4be45d12018-09-26 15:04:23 +01001562 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
1563
Benedict Wong8f9d8a42019-01-03 16:19:38 -08001564 // Dump IPsec stats. No keys are exposed here.
1565 DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
1566
Nandana Dutt4be45d12018-09-26 15:04:23 +01001567 // Run ss as root so we can see socket marks.
1568 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
1569
1570 // Run iotop as root to show top 100 IO threads
1571 RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
1572
Erick Reyese68df822019-02-11 14:46:36 -08001573 // Gather shared memory buffer info if the product implements it
1574 struct stat st;
1575 if (!stat("/product/bin/dmabuf_dump", &st)) {
1576 RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
1577 }
1578
Minchan Kim22c6a1e2019-09-30 15:58:10 -07001579 DumpFile("PSI cpu", "/proc/pressure/cpu");
1580 DumpFile("PSI memory", "/proc/pressure/memory");
1581 DumpFile("PSI io", "/proc/pressure/io");
1582
Nandana Dutt4be45d12018-09-26 15:04:23 +01001583 if (!DropRootUser()) {
Nandana Dutt5c390032019-03-12 10:52:56 +00001584 return Dumpstate::RunStatus::ERROR;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001585 }
1586
Nandana Dutt5c390032019-03-12 10:52:56 +00001587 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttdb379fa2019-10-09 16:54:41 +01001588 Dumpstate::RunStatus status = dumpstate();
1589 // Capture logcat since the last time we did it.
1590 DoSystemLogcat(logcat_ts);
1591 return status;
Nandana Dutt4be45d12018-09-26 15:04:23 +01001592}
1593
mukesh agrawal253dad42018-01-23 21:59:59 -08001594// This method collects common dumpsys for telephony and wifi
1595static void DumpstateRadioCommon() {
Jayachandran Ca94c7172017-06-10 15:08:12 -07001596 DumpIpTablesAsRoot();
1597
Jayachandran C69968272019-07-08 09:46:05 -07001598 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1599
Jayachandran Ca94c7172017-06-10 15:08:12 -07001600 if (!DropRootUser()) {
1601 return;
1602 }
1603
1604 do_dmesg();
1605 DoLogcat();
1606 DumpPacketStats();
1607 DoKmsg();
1608 DumpIpAddrAndRules();
1609 dump_route_tables();
Jayachandran C69968272019-07-08 09:46:05 -07001610 DumpHals();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001611
1612 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
1613 CommandOptions::WithTimeout(10).Build());
mukesh agrawal253dad42018-01-23 21:59:59 -08001614}
1615
1616// This method collects dumpsys for telephony debugging only
1617static void DumpstateTelephonyOnly() {
1618 DurationReporter duration_reporter("DUMPSTATE");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001619 const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
mukesh agrawal253dad42018-01-23 21:59:59 -08001620
1621 DumpstateRadioCommon();
Jayachandran Ca94c7172017-06-10 15:08:12 -07001622
1623 RunCommand("SYSTEM PROPERTIES", {"getprop"});
1624
1625 printf("========================================================\n");
1626 printf("== Android Framework Services\n");
1627 printf("========================================================\n");
1628
Vishnu Nair652cc802017-11-30 15:18:30 -08001629 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1630 SEC_TO_MSEC(10));
Chiachang Wang85e0db32019-03-25 08:59:55 +08001631 RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
1632 SEC_TO_MSEC(10));
1633 RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
Vishnu Nair652cc802017-11-30 15:18:30 -08001634 RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
1635 SEC_TO_MSEC(10));
Amruth Ramachandrand25a9142018-04-02 16:16:09 -07001636 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1637 SEC_TO_MSEC(10));
Sooraj Sasindrane8d98912018-04-20 11:31:55 -07001638 RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
1639 SEC_TO_MSEC(10));
Jayachandran Ca94c7172017-06-10 15:08:12 -07001640
1641 printf("========================================================\n");
1642 printf("== Running Application Services\n");
1643 printf("========================================================\n");
1644
1645 RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
1646
1647 printf("========================================================\n");
Sooraj Sasindrana0829e72018-05-19 15:52:17 -07001648 printf("== Running Application Services (non-platform)\n");
1649 printf("========================================================\n");
1650
1651 RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
1652 DUMPSYS_COMPONENTS_OPTIONS);
1653
1654 printf("========================================================\n");
Kelly Rossmoyer769babb2018-08-21 18:06:38 -07001655 printf("== Checkins\n");
1656 printf("========================================================\n");
1657
1658 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1659
1660 printf("========================================================\n");
Jayachandran Ca94c7172017-06-10 15:08:12 -07001661 printf("== dumpstate: done (id %d)\n", ds.id_);
1662 printf("========================================================\n");
1663}
1664
mukesh agrawal253dad42018-01-23 21:59:59 -08001665// This method collects dumpsys for wifi debugging only
1666static void DumpstateWifiOnly() {
1667 DurationReporter duration_reporter("DUMPSTATE");
1668
1669 DumpstateRadioCommon();
1670
1671 printf("========================================================\n");
1672 printf("== Android Framework Services\n");
1673 printf("========================================================\n");
1674
1675 RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
1676 SEC_TO_MSEC(10));
1677 RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
1678 SEC_TO_MSEC(10));
1679
1680 printf("========================================================\n");
1681 printf("== dumpstate: done (id %d)\n", ds.id_);
1682 printf("========================================================\n");
1683}
1684
Nandana Duttcf419a72019-03-14 10:40:17 +00001685Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
Nandana Duttfaafd522019-03-11 09:23:09 +00001686 DurationReporter duration_reporter("DUMP TRACES");
1687
1688 const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
1689 const size_t buf_size = temp_file_pattern.length() + 1;
1690 std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
1691 memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
1692
1693 // Create a new, empty file to receive all trace dumps.
1694 //
1695 // TODO: This can be simplified once we remove support for the old style
1696 // dumps. We can have a file descriptor passed in to dump_traces instead
1697 // of creating a file, closing it and then reopening it again.
1698 android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
1699 if (fd < 0) {
1700 MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001701 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001702 }
1703
1704 // Nobody should have access to this temporary file except dumpstate, but we
1705 // temporarily grant 'read' to 'others' here because this file is created
1706 // when tombstoned is still running as root, but dumped after dropping. This
1707 // can go away once support for old style dumping has.
1708 const int chmod_ret = fchmod(fd, 0666);
1709 if (chmod_ret < 0) {
1710 MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001711 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001712 }
1713
1714 std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
1715 if (proc.get() == nullptr) {
1716 MYLOGE("opendir /proc failed: %s\n", strerror(errno));
Nandana Duttcf419a72019-03-14 10:40:17 +00001717 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001718 }
1719
1720 // Number of times process dumping has timed out. If we encounter too many
1721 // failures, we'll give up.
1722 int timeout_failures = 0;
1723 bool dalvik_found = false;
1724
1725 const std::set<int> hal_pids = get_interesting_hal_pids();
1726
1727 struct dirent* d;
1728 while ((d = readdir(proc.get()))) {
Nandana Duttcf419a72019-03-14 10:40:17 +00001729 RETURN_IF_USER_DENIED_CONSENT();
Nandana Duttfaafd522019-03-11 09:23:09 +00001730 int pid = atoi(d->d_name);
1731 if (pid <= 0) {
1732 continue;
1733 }
1734
1735 const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
1736 std::string exe;
1737 if (!android::base::Readlink(link_name, &exe)) {
1738 continue;
1739 }
1740
1741 bool is_java_process;
1742 if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
1743 // Don't bother dumping backtraces for the zygote.
1744 if (IsZygote(pid)) {
1745 continue;
1746 }
1747
1748 dalvik_found = true;
1749 is_java_process = true;
1750 } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
1751 is_java_process = false;
1752 } else {
1753 // Probably a native process we don't care about, continue.
1754 continue;
1755 }
1756
1757 // If 3 backtrace dumps fail in a row, consider debuggerd dead.
1758 if (timeout_failures == 3) {
1759 dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
1760 break;
1761 }
1762
1763 const uint64_t start = Nanotime();
1764 const int ret = dump_backtrace_to_file_timeout(
1765 pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
1766 is_java_process ? 5 : 20, fd);
1767
1768 if (ret == -1) {
1769 // For consistency, the header and footer to this message match those
1770 // dumped by debuggerd in the success case.
1771 dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
1772 dprintf(fd, "Dump failed, likely due to a timeout.\n");
1773 dprintf(fd, "---- end %d ----", pid);
1774 timeout_failures++;
1775 continue;
1776 }
1777
1778 // We've successfully dumped stack traces, reset the failure count
1779 // and write a summary of the elapsed time to the file and continue with the
1780 // next process.
1781 timeout_failures = 0;
1782
1783 dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
1784 pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
1785 }
1786
1787 if (!dalvik_found) {
1788 MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
1789 }
1790
Nandana Duttcf419a72019-03-14 10:40:17 +00001791 *path = file_name_buf.release();
1792 return RunStatus::OK;
Nandana Duttfaafd522019-03-11 09:23:09 +00001793}
1794
Felipe Leme6f674ae2016-11-18 17:10:33 -08001795void Dumpstate::DumpstateBoard() {
1796 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001797 printf("========================================================\n");
1798 printf("== Board\n");
1799 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001800
Felipe Leme6f674ae2016-11-18 17:10:33 -08001801 if (!IsZipping()) {
Steven Moreland7440ddb2016-12-15 16:13:39 -08001802 MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001803 return;
1804 }
1805
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001806 std::vector<std::string> paths;
1807 std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
Jie Song9fbfad02017-06-20 16:29:42 -07001808 for (int i = 0; i < NUM_OF_DUMPS; i++) {
Nandana Dutt979388e2018-11-30 16:48:55 +00001809 paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
1810 kDumpstateBoardFiles[i].c_str()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001811 remover.emplace_back(android::base::make_scope_guard(
1812 std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001813 }
Jie Song9fbfad02017-06-20 16:29:42 -07001814
Wei Wang587eac92018-04-05 12:17:20 -07001815 sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
1816 if (dumpstate_device == nullptr) {
1817 MYLOGE("No IDumpstateDevice implementation\n");
1818 return;
1819 }
1820
1821 using ScopedNativeHandle =
1822 std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
1823 ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
1824 [](native_handle_t* handle) {
1825 native_handle_close(handle);
1826 native_handle_delete(handle);
1827 });
1828 if (handle == nullptr) {
1829 MYLOGE("Could not create native_handle\n");
1830 return;
1831 }
1832
Nandana Dutt5c390032019-03-12 10:52:56 +00001833 // TODO(128270426): Check for consent in between?
Wei Wang587eac92018-04-05 12:17:20 -07001834 for (size_t i = 0; i < paths.size(); i++) {
1835 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
1836
1837 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
1838 open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1839 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1840 if (fd < 0) {
1841 MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
1842 return;
1843 }
1844 handle.get()->data[i] = fd.release();
1845 }
1846
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001847 // Given that bugreport is required to diagnose failures, it's better to
Wei Wang587eac92018-04-05 12:17:20 -07001848 // set an arbitrary amount of timeout for IDumpstateDevice than to block the
1849 // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
1850 // and grab whatever dumped
1851 std::packaged_task<bool()>
1852 dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001853 android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
1854 if (!status.isOk()) {
1855 MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
Wei Wang587eac92018-04-05 12:17:20 -07001856 return false;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001857 }
Wei Wang587eac92018-04-05 12:17:20 -07001858 return true;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001859 });
Wei Wang587eac92018-04-05 12:17:20 -07001860
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001861 auto result = dumpstate_task.get_future();
1862 std::thread(std::move(dumpstate_task)).detach();
Wei Wang587eac92018-04-05 12:17:20 -07001863
1864 constexpr size_t timeout_sec = 30;
1865 if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
1866 MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
1867 if (!android::base::SetProperty("ctl.interface_restart",
1868 android::base::StringPrintf("%s/default",
1869 IDumpstateDevice::descriptor))) {
1870 MYLOGE("Couldn't restart dumpstate HAL\n");
1871 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001872 }
Wei Wang587eac92018-04-05 12:17:20 -07001873 // Wait some time for init to kill dumpstate vendor HAL
1874 constexpr size_t killing_timeout_sec = 10;
1875 if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
1876 MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
1877 "there might be racing in content\n", killing_timeout_sec);
1878 }
1879
1880 auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
1881 for (size_t i = 0; i < paths.size(); i++) {
1882 struct stat s;
1883 if (fstat(handle.get()->data[i], &s) == -1) {
1884 MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
1885 strerror(errno));
1886 file_sizes[i] = -1;
1887 continue;
1888 }
1889 file_sizes[i] = s.st_size;
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001890 }
1891
1892 for (size_t i = 0; i < paths.size(); i++) {
1893 if (file_sizes[i] == -1) {
1894 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001895 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001896 if (file_sizes[i] == 0) {
Jie Song9fbfad02017-06-20 16:29:42 -07001897 MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001898 continue;
Jie Song9fbfad02017-06-20 16:29:42 -07001899 }
Luis Hector Chavez7aecd382018-03-19 11:16:59 -07001900 AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
Jie Song9fbfad02017-06-20 16:29:42 -07001901 }
1902
Felipe Lemed8b94e52016-12-08 10:21:44 -08001903 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001904}
1905
Nandana Dutt12ae14a2019-01-09 10:35:53 +00001906static void ShowUsage() {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001907 fprintf(stderr,
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001908 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001909 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1910 " -h: display this help message\n"
1911 " -b: play sound file instead of vibrate, at beginning of job\n"
1912 " -e: play sound file instead of vibrate, at end of job\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001913 " -d: append date to filename\n"
1914 " -p: capture screenshot to filename.png\n"
1915 " -z: generate zipped file\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001916 " -s: write output to control socket (for init)\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001917 " -S: write file location to control socket (for init; requires -z)\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001918 " -q: disable vibrate\n"
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001919 " -B: send broadcast when finished\n"
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001920 " -P: send broadcast when started and update system properties on "
Abhijeet Kaurbb55a3b2019-06-13 18:07:25 +01001921 "progress (requires -B)\n"
1922 " -R: take bugreport in remote mode (requires -z, -d and -B, "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001923 "shouldn't be used with -P)\n"
Nandana Dutt235864b2019-01-22 12:10:16 +00001924 " -w: start binder service and make it wait for a call to startBugreport\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001925 " -v: prints the dumpstate header and exit\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001926}
1927
Wei Liuf87959e2016-08-26 14:51:42 -07001928static void register_sig_handler() {
Luis Hector Chavez558e1ef2018-03-22 15:39:17 -07001929 signal(SIGPIPE, SIG_IGN);
Wei Liuf87959e2016-08-26 14:51:42 -07001930}
1931
Felipe Leme1d486fe2016-10-14 18:06:47 -07001932bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001933 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001934 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001935 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001936 // Final timestamp
1937 char date[80];
1938 time_t the_real_now_please_stand_up = time(nullptr);
1939 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001940 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001941 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001942
Felipe Leme9a523ae2016-10-20 15:10:33 -07001943 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001944 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001945 return false;
1946 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001947 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001948 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001949 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001950 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001951
Felipe Leme0f3fb202016-06-10 17:10:53 -07001952 // Add log file (which contains stderr output) to zip...
1953 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001954 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001955 MYLOGE("Failed to add dumpstate log to .zip file\n");
1956 return false;
1957 }
Nandana Dutt979388e2018-11-30 16:48:55 +00001958 // TODO: Should truncate the existing file.
1959 // ... and re-open it for further logging.
Nandana Dutta344cb62019-02-22 15:12:35 +00001960 if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
1961 return false;
1962 }
Felipe Leme0f3fb202016-06-10 17:10:53 -07001963 fprintf(stderr, "\n");
1964
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001965 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001966 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001967 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001968 return false;
1969 }
1970
Felipe Leme1d486fe2016-10-14 18:06:47 -07001971 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1972 ds.zip_file.reset(nullptr);
1973
Felipe Lemee9d2c542016-11-15 11:48:26 -08001974 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
Nandana Dutt16d1aee2019-02-15 16:13:53 +00001975 android::os::UnlinkAndLogOnError(tmp_path_);
Felipe Lemec4eee562016-04-21 15:42:55 -07001976
Felipe Leme1e9edc62015-12-21 16:02:13 -08001977 return true;
1978}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001979
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -07001980static std::string SHA256_file_hash(const std::string& filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001981 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1982 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001983 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001984 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001985 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001986 }
1987
1988 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001989 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001990
1991 std::vector<uint8_t> buffer(65536);
1992 while (1) {
1993 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1994 if (bytes_read == 0) {
1995 break;
1996 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001997 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Yi Kong19d5c002018-07-20 13:39:55 -07001998 return nullptr;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001999 }
2000
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002001 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002002 }
2003
Elliott Hughesc4dc1412016-04-12 16:28:31 -07002004 uint8_t hash[SHA256_DIGEST_LENGTH];
2005 SHA256_Final(hash, &ctx);
2006
2007 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
2008 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00002009 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00002010 }
2011 hash_buffer[sizeof(hash_buffer) - 1] = 0;
2012 return std::string(hash_buffer);
2013}
2014
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002015static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
2016 // clang-format off
2017 std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
2018 "--receiver-foreground", "--receiver-include-background", "-a", action};
2019 // clang-format on
Felipe Leme8d2410e2017-02-08 09:46:08 -08002020
2021 am.insert(am.end(), args.begin(), args.end());
2022
Felipe Leme8d2410e2017-02-08 09:46:08 -08002023 RunCommand("", am,
2024 CommandOptions::WithTimeout(20)
2025 .Log("Sending broadcast: '%s'\n")
2026 .Always()
2027 .DropRoot()
2028 .RedirectStderr()
2029 .Build());
2030}
2031
Felipe Leme35b8cf12017-02-10 15:47:29 -08002032static void Vibrate(int duration_ms) {
2033 // clang-format off
Chris Fries0c3de872019-09-14 15:49:41 +00002034 RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
Felipe Leme35b8cf12017-02-10 15:47:29 -08002035 CommandOptions::WithTimeout(10)
2036 .Log("Vibrate: '%s'\n")
2037 .Always()
2038 .Build());
2039 // clang-format on
2040}
2041
Nandana Dutt979388e2018-11-30 16:48:55 +00002042static void MaybeResolveSymlink(std::string* path) {
2043 std::string resolved_path;
2044 if (android::base::Readlink(*path, &resolved_path)) {
2045 *path = resolved_path;
2046 }
2047}
2048
Nandana Dutt4be45d12018-09-26 15:04:23 +01002049/*
2050 * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
2051 * if we are writing zip files and adds the version file.
2052 */
2053static void PrepareToWriteToFile() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002054 MaybeResolveSymlink(&ds.bugreport_internal_dir_);
2055
Nandana Dutt4be45d12018-09-26 15:04:23 +01002056 std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
2057 std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002058 ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002059 if (ds.options_->do_add_date) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002060 char date[80];
2061 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
2062 ds.name_ = date;
2063 } else {
2064 ds.name_ = "undated";
2065 }
2066
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002067 if (ds.options_->telephony_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002068 ds.base_name_ += "-telephony";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002069 } else if (ds.options_->wifi_only) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002070 ds.base_name_ += "-wifi";
2071 }
2072
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002073 if (ds.options_->do_fb) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002074 ds.screenshot_path_ = ds.GetPath(".png");
2075 }
2076 ds.tmp_path_ = ds.GetPath(".tmp");
2077 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
2078
Nandana Dutt54dbd672019-01-11 12:58:05 +00002079 std::string destination = ds.options_->bugreport_fd.get() != -1
2080 ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
Nandana Dutt9a76d202019-01-21 15:56:48 +00002081 : ds.bugreport_internal_dir_.c_str();
Nandana Dutt4be45d12018-09-26 15:04:23 +01002082 MYLOGD(
2083 "Bugreport dir: %s\n"
2084 "Base name: %s\n"
2085 "Suffix: %s\n"
2086 "Log path: %s\n"
2087 "Temporary path: %s\n"
2088 "Screenshot path: %s\n",
Nandana Dutt9a76d202019-01-21 15:56:48 +00002089 destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
2090 ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002091
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002092 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002093 ds.path_ = ds.GetPath(".zip");
2094 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
2095 create_parent_dirs(ds.path_.c_str());
2096 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
2097 if (ds.zip_file == nullptr) {
2098 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
2099 } else {
2100 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
2101 }
2102 ds.AddTextZipEntry("version.txt", ds.version_);
2103 }
2104}
2105
2106/*
2107 * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
2108 * printing zipped file status, etc.
2109 */
2110static void FinalizeFile() {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002111 /* check if user changed the suffix using system properties */
2112 std::string name =
2113 android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
2114 bool change_suffix = false;
2115 if (!name.empty()) {
2116 /* must whitelist which characters are allowed, otherwise it could cross directories */
2117 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
2118 if (std::regex_match(name.c_str(), valid_regex)) {
2119 change_suffix = true;
2120 } else {
2121 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
2122 }
2123 }
2124 if (change_suffix) {
2125 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
2126 ds.name_ = name;
2127 if (!ds.screenshot_path_.empty()) {
2128 std::string new_screenshot_path = ds.GetPath(".png");
2129 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
2130 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
2131 new_screenshot_path.c_str(), strerror(errno));
2132 } else {
2133 ds.screenshot_path_ = new_screenshot_path;
2134 }
2135 }
2136 }
2137
2138 bool do_text_file = true;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002139 if (ds.options_->do_zip_file) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002140 if (!ds.FinishZipFile()) {
2141 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
2142 do_text_file = true;
2143 } else {
2144 do_text_file = false;
Nandana Dutt383d0c12018-11-30 15:54:56 +00002145 // If the user has changed the suffix, we need to change the zip file name.
2146 std::string new_path = ds.GetPath(".zip");
2147 if (ds.path_ != new_path) {
2148 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
2149 if (rename(ds.path_.c_str(), new_path.c_str())) {
2150 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
2151 strerror(errno));
2152 } else {
2153 ds.path_ = new_path;
2154 }
2155 }
Nandana Dutt4be45d12018-09-26 15:04:23 +01002156 }
2157 }
2158 if (do_text_file) {
2159 ds.path_ = ds.GetPath(".txt");
2160 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
2161 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
2162 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
2163 ds.path_.clear();
2164 }
2165 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002166 if (ds.options_->use_control_socket) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002167 if (do_text_file) {
2168 dprintf(ds.control_socket_fd_,
2169 "FAIL:could not create zip file, check %s "
2170 "for more details\n",
2171 ds.log_path_.c_str());
2172 } else {
2173 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
2174 }
2175 }
2176}
2177
2178/* Broadcasts that we are done with the bugreport */
2179static void SendBugreportFinishedBroadcast() {
Nandana Dutt979388e2018-11-30 16:48:55 +00002180 // TODO(b/111441001): use callback instead of broadcast.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002181 if (!ds.path_.empty()) {
2182 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Nandana Dutt4be45d12018-09-26 15:04:23 +01002183 // clang-format off
2184
2185 std::vector<std::string> am_args = {
2186 "--receiver-permission", "android.permission.DUMP",
2187 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
2188 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
2189 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Nandana Dutt9a76d202019-01-21 15:56:48 +00002190 "--es", "android.intent.extra.BUGREPORT", ds.path_,
Nandana Dutt4be45d12018-09-26 15:04:23 +01002191 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
2192 };
2193 // clang-format on
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002194 if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002195 am_args.push_back("--es");
2196 am_args.push_back("android.intent.extra.SCREENSHOT");
2197 am_args.push_back(ds.screenshot_path_);
2198 }
Nandana Dutt15b89d72018-11-16 14:14:12 +00002199 if (!ds.options_->notification_title.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002200 am_args.push_back("--es");
2201 am_args.push_back("android.intent.extra.TITLE");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002202 am_args.push_back(ds.options_->notification_title);
2203 if (!ds.options_->notification_description.empty()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002204 am_args.push_back("--es");
2205 am_args.push_back("android.intent.extra.DESCRIPTION");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002206 am_args.push_back(ds.options_->notification_description);
Nandana Dutt4be45d12018-09-26 15:04:23 +01002207 }
2208 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002209 if (ds.options_->is_remote_mode) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002210 am_args.push_back("--es");
2211 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Nandana Dutt9a76d202019-01-21 15:56:48 +00002212 am_args.push_back(SHA256_file_hash(ds.path_));
Nandana Dutt4be45d12018-09-26 15:04:23 +01002213 SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
2214 } else {
2215 SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
2216 }
2217 } else {
2218 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
2219 }
2220}
2221
Nandana Dutt58d72e22018-11-16 10:30:48 +00002222static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
2223 switch (mode) {
2224 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2225 return "BUGREPORT_FULL";
2226 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
2227 return "BUGREPORT_INTERACTIVE";
2228 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
2229 return "BUGREPORT_REMOTE";
2230 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
2231 return "BUGREPORT_WEAR";
2232 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
2233 return "BUGREPORT_TELEPHONY";
2234 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
2235 return "BUGREPORT_WIFI";
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002236 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2237 return "BUGREPORT_DEFAULT";
Nandana Dutt58d72e22018-11-16 10:30:48 +00002238 }
2239}
2240
2241static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
Abhijeet Kaur8ca245e2018-12-12 10:34:21 +00002242 options->extra_options = ModeToString(mode);
Nandana Dutt58d72e22018-11-16 10:30:48 +00002243 switch (mode) {
2244 case Dumpstate::BugreportMode::BUGREPORT_FULL:
2245 options->do_broadcast = true;
2246 options->do_fb = true;
2247 break;
2248 case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002249 // Currently, the dumpstate binder is only used by Shell to update progress.
2250 options->do_start_service = true;
2251 options->do_progress_updates = true;
2252 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002253 options->do_broadcast = true;
2254 break;
2255 case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002256 options->do_vibrate = false;
2257 options->is_remote_mode = true;
2258 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002259 options->do_broadcast = true;
2260 break;
2261 case Dumpstate::BugreportMode::BUGREPORT_WEAR:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002262 options->do_start_service = true;
2263 options->do_progress_updates = true;
2264 options->do_zip_file = true;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002265 options->do_fb = true;
2266 options->do_broadcast = true;
2267 break;
2268 case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002269 options->telephony_only = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002270 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002271 options->do_broadcast = true;
2272 break;
2273 case Dumpstate::BugreportMode::BUGREPORT_WIFI:
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002274 options->wifi_only = true;
2275 options->do_zip_file = true;
Abhijeet Kaurd3cca0d2019-03-25 12:04:16 +00002276 options->do_fb = false;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002277 options->do_broadcast = true;
2278 break;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002279 case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
2280 break;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002281 }
2282}
2283
2284static Dumpstate::BugreportMode getBugreportModeFromProperty() {
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002285 // If the system property is not set, it's assumed to be a default bugreport.
2286 Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002287
2288 std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
2289 if (!extra_options.empty()) {
2290 // Framework uses a system property to override some command-line args.
2291 // Currently, it contains the type of the requested bugreport.
2292 if (extra_options == "bugreportplus") {
2293 mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
Abhijeet Kaur904e0e02018-12-05 14:03:01 +00002294 } else if (extra_options == "bugreportfull") {
2295 mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
Nandana Dutt58d72e22018-11-16 10:30:48 +00002296 } else if (extra_options == "bugreportremote") {
2297 mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
2298 } else if (extra_options == "bugreportwear") {
2299 mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
2300 } else if (extra_options == "bugreporttelephony") {
2301 mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
2302 } else if (extra_options == "bugreportwifi") {
2303 mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002304 } else {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002305 MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002306 }
2307 // Reset the property
2308 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
2309 }
Nandana Dutt58d72e22018-11-16 10:30:48 +00002310 return mode;
2311}
2312
2313// TODO: Move away from system properties when we have options passed via binder calls.
2314/* Sets runtime options from the system properties and then clears those properties. */
2315static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
2316 Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
2317 SetOptionsFromMode(mode, options);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002318
2319 options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
2320 if (!options->notification_title.empty()) {
2321 // Reset the property
2322 android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
2323
Nandana Duttdd8cca32018-11-14 10:10:29 +00002324 options->notification_description =
2325 android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002326 if (!options->notification_description.empty()) {
2327 // Reset the property
2328 android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
2329 }
2330 MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
2331 options->notification_description.c_str());
2332 }
2333}
2334
Nandana Dutt58d72e22018-11-16 10:30:48 +00002335static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
2336 MYLOGI("do_zip_file: %d\n", options.do_zip_file);
2337 MYLOGI("do_add_date: %d\n", options.do_add_date);
2338 MYLOGI("do_vibrate: %d\n", options.do_vibrate);
2339 MYLOGI("use_socket: %d\n", options.use_socket);
2340 MYLOGI("use_control_socket: %d\n", options.use_control_socket);
2341 MYLOGI("do_fb: %d\n", options.do_fb);
2342 MYLOGI("do_broadcast: %d\n", options.do_broadcast);
2343 MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
2344 MYLOGI("show_header_only: %d\n", options.show_header_only);
2345 MYLOGI("do_start_service: %d\n", options.do_start_service);
2346 MYLOGI("telephony_only: %d\n", options.telephony_only);
2347 MYLOGI("wifi_only: %d\n", options.wifi_only);
2348 MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
Nandana Dutt54dbd672019-01-11 12:58:05 +00002349 MYLOGI("fd: %d\n", options.bugreport_fd.get());
Nandana Dutt58d72e22018-11-16 10:30:48 +00002350 MYLOGI("extra_options: %s\n", options.extra_options.c_str());
2351 MYLOGI("args: %s\n", options.args.c_str());
2352 MYLOGI("notification_title: %s\n", options.notification_title.c_str());
2353 MYLOGI("notification_description: %s\n", options.notification_description.c_str());
2354}
2355
Nandana Dutt54dbd672019-01-11 12:58:05 +00002356void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
2357 const android::base::unique_fd& bugreport_fd_in,
2358 const android::base::unique_fd& screenshot_fd_in) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002359 // In the new API world, date is always added; output is always a zip file.
2360 // TODO(111441001): remove these options once they are obsolete.
2361 do_add_date = true;
2362 do_zip_file = true;
2363
Nandana Dutt54dbd672019-01-11 12:58:05 +00002364 // Duplicate the fds because the passed in fds don't outlive the binder transaction.
2365 bugreport_fd.reset(dup(bugreport_fd_in.get()));
2366 screenshot_fd.reset(dup(screenshot_fd_in.get()));
Nandana Dutt58d72e22018-11-16 10:30:48 +00002367
2368 extra_options = ModeToString(bugreport_mode);
2369 SetOptionsFromMode(bugreport_mode, this);
2370}
2371
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002372Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
2373 RunStatus status = RunStatus::OK;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002374 int c;
Nandana Dutt235864b2019-01-22 12:10:16 +00002375 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002376 switch (c) {
2377 // clang-format off
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002378 case 'd': do_add_date = true; break;
2379 case 'z': do_zip_file = true; break;
Nandana Dutt9a76d202019-01-21 15:56:48 +00002380 // o=use_outfile not supported anymore.
2381 // TODO(b/111441001): Remove when all callers have migrated.
2382 case 'o': break;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002383 case 's': use_socket = true; break;
2384 case 'S': use_control_socket = true; break;
2385 case 'v': show_header_only = true; break;
2386 case 'q': do_vibrate = false; break;
2387 case 'p': do_fb = true; break;
2388 case 'P': do_progress_updates = true; break;
2389 case 'R': is_remote_mode = true; break;
2390 case 'B': do_broadcast = true; break;
2391 case 'V': break; // compatibility no-op
Nandana Dutt235864b2019-01-22 12:10:16 +00002392 case 'w':
2393 // This was already processed
2394 break;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002395 case 'h':
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002396 status = RunStatus::HELP;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002397 break;
2398 default:
2399 fprintf(stderr, "Invalid option: %c\n", c);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002400 status = RunStatus::INVALID_INPUT;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002401 break;
2402 // clang-format on
2403 }
2404 }
Felipe Leme8fecfdd2016-02-09 10:40:07 -08002405
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002406 for (int i = 0; i < argc; i++) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002407 args += argv[i];
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002408 if (i < argc - 1) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002409 args += " ";
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002410 }
2411 }
2412
2413 // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
2414 optind = 1;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002415
2416 SetOptionsFromProperties(this);
2417 return status;
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002418}
2419
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002420bool Dumpstate::DumpOptions::ValidateOptions() const {
Nandana Dutt54dbd672019-01-11 12:58:05 +00002421 if (bugreport_fd.get() != -1 && !do_zip_file) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002422 return false;
2423 }
2424
Nandana Dutt9a76d202019-01-21 15:56:48 +00002425 if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002426 return false;
2427 }
2428
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002429 if (use_control_socket && !do_zip_file) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002430 return false;
2431 }
2432
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002433 if (do_progress_updates && !do_broadcast) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002434 return false;
2435 }
2436
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002437 if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002438 return false;
2439 }
2440 return true;
2441}
2442
Nandana Dutt197661d2018-11-16 16:40:21 +00002443void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
2444 options_ = std::move(options);
2445}
2446
Nandana Duttd2f5f082019-01-18 17:13:52 +00002447Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
2448 Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002449 if (listener_ != nullptr) {
2450 switch (status) {
2451 case Dumpstate::RunStatus::OK:
Nandana Duttcc4ead82019-01-23 08:29:23 +00002452 listener_->onFinished();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002453 break;
2454 case Dumpstate::RunStatus::HELP:
2455 break;
2456 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002457 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002458 break;
2459 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002460 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
2461 break;
2462 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2463 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
2464 break;
2465 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
2466 listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
Nandana Duttbabf6c72019-01-15 14:11:12 +00002467 break;
2468 }
2469 }
2470 return status;
2471}
2472
Nandana Dutt979388e2018-11-30 16:48:55 +00002473/*
2474 * Dumps relevant information to a bugreport based on the given options.
2475 *
2476 * The bugreport can be dumped to a file or streamed to a socket.
2477 *
2478 * How dumping to file works:
2479 * stdout is redirected to a temporary file. This will later become the main bugreport entry.
2480 * stderr is redirected a log file.
2481 *
2482 * The temporary bugreport is then populated via printfs, dumping contents of files and
2483 * output of commands to stdout.
2484 *
2485 * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
2486 * text file.
2487 *
2488 * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
2489 * gets added to the archive.
2490 *
Nandana Dutt9a76d202019-01-21 15:56:48 +00002491 * Bugreports are first generated in a local directory and later copied to the caller's fd if
2492 * supplied.
Nandana Dutt979388e2018-11-30 16:48:55 +00002493 */
Nandana Duttd2f5f082019-01-18 17:13:52 +00002494Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
2495 const std::string& calling_package) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002496 LogDumpOptions(*options_);
Nandana Dutt197661d2018-11-16 16:40:21 +00002497 if (!options_->ValidateOptions()) {
Nandana Dutt58d72e22018-11-16 10:30:48 +00002498 MYLOGE("Invalid options specified\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002499 return RunStatus::INVALID_INPUT;
2500 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002501 /* set as high priority, and protect from OOM killer */
2502 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002503
Felipe Lemed071c682016-10-20 16:48:00 -07002504 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07002505 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002506 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002507 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07002508 } else {
2509 /* fallback to kernels <= 2.6.35 */
2510 oom_adj = fopen("/proc/self/oom_adj", "we");
2511 if (oom_adj) {
2512 fputs("-17", oom_adj);
2513 fclose(oom_adj);
2514 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002515 }
2516
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002517 if (version_ == VERSION_DEFAULT) {
2518 version_ = VERSION_CURRENT;
Michal Karpinski4db754f2015-12-11 18:04:32 +00002519 }
2520
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002521 if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
Vishnu Nair64afc022018-02-01 15:29:34 -08002522 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002523 version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
Vishnu Nair64afc022018-02-01 15:29:34 -08002524 VERSION_SPLIT_ANR.c_str());
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002525 return RunStatus::INVALID_INPUT;
Felipe Lemed071c682016-10-20 16:48:00 -07002526 }
2527
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002528 if (options_->show_header_only) {
2529 PrintHeader();
2530 return RunStatus::OK;
Felipe Lemed071c682016-10-20 16:48:00 -07002531 }
2532
Nandana Duttd2f5f082019-01-18 17:13:52 +00002533 if (options_->bugreport_fd.get() != -1) {
2534 // If the output needs to be copied over to the caller's fd, get user consent.
2535 android::String16 package(calling_package.c_str());
2536 CheckUserConsent(calling_uid, package);
2537 }
2538
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002539 // Redirect output if needed
Nandana Dutt9a76d202019-01-21 15:56:48 +00002540 bool is_redirecting = options_->OutputToFile();
Felipe Leme7447d7c2016-11-03 18:12:22 -07002541
2542 // TODO: temporarily set progress until it's part of the Dumpstate constructor
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002543 std::string stats_path =
Nandana Dutt979388e2018-11-30 16:48:55 +00002544 is_redirecting
2545 ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
2546 : "";
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002547 progress_.reset(new Progress(stats_path));
Felipe Leme7447d7c2016-11-03 18:12:22 -07002548
Felipe Lemed071c682016-10-20 16:48:00 -07002549 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07002550 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002551 id_ = ++last_id;
Felipe Lemed071c682016-10-20 16:48:00 -07002552 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
2553
2554 MYLOGI("begin\n");
2555
Sahana Raof35ed432019-07-12 10:47:52 +01002556 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
2557 MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno));
2558 } else {
2559 // Wake lock will be released automatically on process death
2560 MYLOGD("Wake lock acquired.\n");
2561 }
2562
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08002563 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07002564
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002565 // TODO(b/111441001): maybe skip if already started?
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002566 if (options_->do_start_service) {
Felipe Leme75876a22016-10-27 16:31:27 -07002567 MYLOGI("Starting 'dumpstate' service\n");
2568 android::status_t ret;
2569 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
2570 MYLOGE("Unable to start DumpstateService: %d\n", ret);
2571 }
2572 }
2573
Felipe Lemef0292972016-11-22 13:57:05 -08002574 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07002575 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
2576 }
2577
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002578 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
2579 options_->extra_options.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07002580
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002581 MYLOGI("bugreport format version: %s\n", version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08002582
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002583 do_early_screenshot_ = options_->do_progress_updates;
Felipe Lemee338bf62015-12-07 14:03:50 -08002584
Christopher Ferrised9354f2014-10-01 17:35:01 -07002585 // If we are going to use a socket, do it as early as possible
2586 // to avoid timeouts from bugreport.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002587 if (options_->use_socket) {
Nandana Dutta344cb62019-02-22 15:12:35 +00002588 if (!redirect_to_socket(stdout, "dumpstate")) {
2589 return ERROR;
2590 }
Christopher Ferrised9354f2014-10-01 17:35:01 -07002591 }
2592
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002593 if (options_->use_control_socket) {
Felipe Leme2628e9e2016-04-12 16:36:51 -07002594 MYLOGD("Opening control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002595 control_socket_fd_ = open_socket("dumpstate");
Nandana Dutta344cb62019-02-22 15:12:35 +00002596 if (control_socket_fd_ == -1) {
2597 return ERROR;
2598 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002599 options_->do_progress_updates = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07002600 }
2601
Felipe Leme71bbfc52015-11-23 14:14:51 -08002602 if (is_redirecting) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002603 PrepareToWriteToFile();
Felipe Leme1e9edc62015-12-21 16:02:13 -08002604
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002605 if (options_->do_progress_updates) {
2606 if (options_->do_broadcast) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002607 // clang-format off
2608 std::vector<std::string> am_args = {
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002609 "--receiver-permission", "android.permission.DUMP",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002610 "--es", "android.intent.extra.NAME", name_,
2611 "--ei", "android.intent.extra.ID", std::to_string(id_),
2612 "--ei", "android.intent.extra.PID", std::to_string(pid_),
2613 "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002614 };
2615 // clang-format on
Felipe Lemea4ef1f02017-02-15 17:27:40 -08002616 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07002617 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002618 if (options_->use_control_socket) {
2619 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07002620 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08002621 }
2622 }
2623
Nick Kralevichf3599b32016-01-25 15:05:16 -08002624 /* read /proc/cmdline before dropping root */
2625 FILE *cmdline = fopen("/proc/cmdline", "re");
2626 if (cmdline) {
2627 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
2628 fclose(cmdline);
2629 }
2630
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002631 if (options_->do_vibrate) {
Felipe Leme35b8cf12017-02-10 15:47:29 -08002632 Vibrate(150);
John Michelau1f794c42012-09-17 11:20:19 -05002633 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002634
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002635 if (options_->do_fb && do_early_screenshot_) {
Greg Kaiser3ddc3fa2019-05-23 16:14:52 -07002636 MYLOGI("taking early screenshot\n");
2637 TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08002638 }
2639
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002640 if (options_->do_zip_file && zip_file != nullptr) {
2641 if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
2642 MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07002643 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08002644 }
2645 }
2646
Nandana Dutt3f8c7172018-09-25 12:01:54 +01002647 int dup_stdout_fd;
2648 int dup_stderr_fd;
Felipe Leme71bbfc52015-11-23 14:14:51 -08002649 if (is_redirecting) {
Nandana Dutt979388e2018-11-30 16:48:55 +00002650 // Redirect stderr to log_path_ for debugging.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002651 TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
Nandana Dutta344cb62019-02-22 15:12:35 +00002652 if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
2653 return ERROR;
2654 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002655 if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
2656 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
2657 strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002658 }
Nandana Dutt979388e2018-11-30 16:48:55 +00002659
2660 // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
2661 // moved into zip file later, if zipping.
Vishnu Nair20cf5032018-01-05 13:15:49 -08002662 TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
Nandana Dutt979388e2018-11-30 16:48:55 +00002663 // TODO: why not write to a file instead of stdout to overcome this problem?
Felipe Leme6e01fa62015-11-11 19:35:14 -08002664 /* TODO: rather than generating a text file now and zipping it later,
2665 it would be more efficient to redirect stdout to the zip entry
2666 directly, but the libziparchive doesn't support that option yet. */
Nandana Dutta344cb62019-02-22 15:12:35 +00002667 if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
2668 return ERROR;
2669 }
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002670 if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08002671 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002672 tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08002673 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002674 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08002675
2676 // Don't buffer stdout
2677 setvbuf(stdout, nullptr, _IONBF, 0);
2678
Felipe Leme608385d2016-02-01 10:35:38 -08002679 // NOTE: there should be no stdout output until now, otherwise it would break the header.
2680 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08002681 // duration is logged into MYLOG instead.
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002682 PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002683
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002684 if (options_->telephony_only) {
Jayachandran Ca94c7172017-06-10 15:08:12 -07002685 DumpstateTelephonyOnly();
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002686 DumpstateBoard();
2687 } else if (options_->wifi_only) {
mukesh agrawal253dad42018-01-23 21:59:59 -08002688 DumpstateWifiOnly();
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002689 } else {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002690 // Dump state for the default case. This also drops root.
Nandana Dutt5c390032019-03-12 10:52:56 +00002691 RunStatus s = DumpstateDefault();
2692 if (s != RunStatus::OK) {
Nandana Duttaac6f582019-07-26 14:32:47 +01002693 if (s == RunStatus::USER_CONSENT_DENIED) {
Nandana Dutt5c390032019-03-12 10:52:56 +00002694 HandleUserConsentDenied();
2695 }
2696 return s;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08002697 }
Zhengyin Qian068ecc72016-08-10 16:48:14 -07002698 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07002699
Felipe Leme55b42a62015-11-10 17:39:08 -08002700 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08002701 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002702 TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
Colin Crossf45fa6b2012-03-26 12:38:26 -07002703 }
2704
Nandana Duttd2f5f082019-01-18 17:13:52 +00002705 // Rename, and/or zip the (now complete) .tmp file within the internal directory.
Nandana Dutt9a76d202019-01-21 15:56:48 +00002706 if (options_->OutputToFile()) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002707 FinalizeFile();
Colin Crossf45fa6b2012-03-26 12:38:26 -07002708 }
2709
Nandana Duttd2f5f082019-01-18 17:13:52 +00002710 // Share the final file with the caller if the user has consented.
2711 Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
2712 if (options_->bugreport_fd.get() != -1) {
2713 status = CopyBugreportIfUserConsented();
2714 if (status != Dumpstate::RunStatus::OK &&
2715 status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2716 // Do an early return if there were errors. We make an exception for consent
2717 // timing out because it's possible the user got distracted. In this case the
2718 // bugreport is not shared but made available for manual retrieval.
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002719 MYLOGI("User denied consent. Returning\n");
Nandana Duttd2f5f082019-01-18 17:13:52 +00002720 return status;
2721 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002722 if (options_->do_fb && options_->screenshot_fd.get() != -1) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002723 bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
2724 options_->screenshot_fd.get());
2725 if (copy_succeeded) {
2726 android::os::UnlinkAndLogOnError(screenshot_path_);
2727 }
2728 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002729 if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
2730 MYLOGI(
2731 "Did not receive user consent yet."
2732 " Will not copy the bugreport artifacts to caller.\n");
Abhijeet Kaur57627412019-04-17 16:00:09 +01002733 const String16 incidentcompanion("incidentcompanion");
2734 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2735 if (ics != nullptr) {
2736 MYLOGD("Canceling user consent request via incidentcompanion service\n");
2737 android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
2738 consent_callback_.get());
2739 } else {
2740 MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
2741 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +00002742 }
Nandana Duttd2f5f082019-01-18 17:13:52 +00002743 }
2744
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002745 /* vibrate a few but shortly times to let user know it's finished */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002746 if (options_->do_vibrate) {
Takuya Ogawa47f644e2017-12-20 18:09:09 +09002747 for (int i = 0; i < 3; i++) {
2748 Vibrate(75);
2749 usleep((75 + 50) * 1000);
2750 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08002751 }
2752
Jeff Brown1dc94e32014-09-11 14:15:27 -07002753 /* tell activity manager we're done */
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002754 if (options_->do_broadcast) {
Nandana Dutt4be45d12018-09-26 15:04:23 +01002755 SendBugreportFinishedBroadcast();
Nandana Duttbabf6c72019-01-15 14:11:12 +00002756 // Note that listener_ is notified in Run();
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07002757 }
2758
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002759 MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
2760 progress_->GetInitialMax());
2761 progress_->Save();
2762 MYLOGI("done (id %d)\n", id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07002763
Felipe Leme107a05f2016-03-08 15:11:15 -08002764 if (is_redirecting) {
Vishnu Nair20cf5032018-01-05 13:15:49 -08002765 TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
Felipe Leme107a05f2016-03-08 15:11:15 -08002766 }
2767
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002768 if (options_->use_control_socket && control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07002769 MYLOGD("Closing control socket\n");
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002770 close(control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07002771 }
2772
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002773 tombstone_data_.clear();
2774 anr_data_.clear();
Narayan Kamath6b9516c2017-10-27 11:15:51 +01002775
Nandana Duttd2f5f082019-01-18 17:13:52 +00002776 return (consent_callback_ != nullptr &&
2777 consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
2778 ? USER_CONSENT_TIMED_OUT
2779 : RunStatus::OK;
2780}
2781
2782void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
2783 consent_callback_ = new ConsentCallback();
2784 const String16 incidentcompanion("incidentcompanion");
2785 sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
2786 if (ics != nullptr) {
2787 MYLOGD("Checking user consent via incidentcompanion service\n");
2788 android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
Joe Onorato1c36d752019-03-17 18:26:43 -07002789 calling_uid, calling_package, String16(), String16(),
2790 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
Nandana Duttd2f5f082019-01-18 17:13:52 +00002791 } else {
2792 MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
2793 }
2794}
2795
Nandana Dutt5c390032019-03-12 10:52:56 +00002796bool Dumpstate::IsUserConsentDenied() const {
2797 return ds.consent_callback_ != nullptr &&
2798 ds.consent_callback_->getResult() == UserConsentResult::DENIED;
2799}
2800
Nandana Duttd2f5f082019-01-18 17:13:52 +00002801void Dumpstate::CleanupFiles() {
2802 android::os::UnlinkAndLogOnError(tmp_path_);
2803 android::os::UnlinkAndLogOnError(screenshot_path_);
2804 android::os::UnlinkAndLogOnError(path_);
2805}
2806
2807Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
2808 MYLOGD("User denied consent; deleting files and returning\n");
2809 CleanupFiles();
2810 return USER_CONSENT_DENIED;
2811}
2812
2813Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
2814 // If the caller has asked to copy the bugreport over to their directory, we need explicit
2815 // user consent.
2816 UserConsentResult consent_result = consent_callback_->getResult();
2817 if (consent_result == UserConsentResult::UNAVAILABLE) {
2818 // User has not responded yet.
2819 uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
2820 if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
2821 uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
2822 MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
2823 sleep(delay_seconds);
2824 }
2825 consent_result = consent_callback_->getResult();
2826 }
2827 if (consent_result == UserConsentResult::DENIED) {
2828 // User has explicitly denied sharing with the app. To be safe delete the
2829 // internal bugreport & tmp files.
2830 return HandleUserConsentDenied();
2831 }
2832 if (consent_result == UserConsentResult::APPROVED) {
Nandana Dutte78c3d72019-01-29 16:10:45 +00002833 bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
2834 if (copy_succeeded) {
2835 android::os::UnlinkAndLogOnError(path_);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002836 }
2837 return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
2838 } else if (consent_result == UserConsentResult::UNAVAILABLE) {
2839 // consent_result is still UNAVAILABLE. The user has likely not responded yet.
2840 // Since we do not have user consent to share the bugreport it does not get
2841 // copied over to the calling app but remains in the internal directory from
2842 // where the user can manually pull it.
2843 return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
2844 }
2845 // Unknown result; must be a programming error.
2846 MYLOGE("Unknown user consent result:%d\n", consent_result);
2847 return Dumpstate::RunStatus::ERROR;
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002848}
2849
Nandana Duttf02564e2019-02-15 15:24:24 +00002850Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002851 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
2852 Dumpstate::RunStatus status = options->Initialize(argc, argv);
2853 if (status == Dumpstate::RunStatus::OK) {
Nandana Duttf02564e2019-02-15 15:24:24 +00002854 SetOptions(std::move(options));
Nandana Duttd2f5f082019-01-18 17:13:52 +00002855 // When directly running dumpstate binary, the output is not expected to be written
2856 // to any external file descriptor.
Nandana Duttf02564e2019-02-15 15:24:24 +00002857 assert(options_->bugreport_fd.get() == -1);
Nandana Duttd2f5f082019-01-18 17:13:52 +00002858
2859 // calling_uid and calling_package are for user consent to share the bugreport with
2860 // an app; they are irrelvant here because bugreport is only written to a local
2861 // directory, and not shared.
Nandana Duttf02564e2019-02-15 15:24:24 +00002862 status = Run(-1 /* calling_uid */, "" /* calling_package */);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002863 }
Nandana Duttf02564e2019-02-15 15:24:24 +00002864 return status;
2865}
2866
2867/* Main entry point for dumpstate binary. */
2868int run_main(int argc, char* argv[]) {
2869 Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002870
2871 switch (status) {
2872 case Dumpstate::RunStatus::OK:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002873 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002874 case Dumpstate::RunStatus::HELP:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002875 ShowUsage();
2876 exit(0);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002877 case Dumpstate::RunStatus::INVALID_INPUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002878 fprintf(stderr, "Invalid combination of args\n");
2879 ShowUsage();
2880 exit(1);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002881 case Dumpstate::RunStatus::ERROR:
Nandana Duttd2f5f082019-01-18 17:13:52 +00002882 FALLTHROUGH_INTENDED;
2883 case Dumpstate::RunStatus::USER_CONSENT_DENIED:
2884 FALLTHROUGH_INTENDED;
2885 case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
Nandana Dutt12ae14a2019-01-09 10:35:53 +00002886 exit(2);
Nandana Dutt5fb117b2018-09-27 09:23:36 +01002887 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07002888}
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002889
2890// TODO(111441001): Default DumpOptions to sensible values.
2891Dumpstate::Dumpstate(const std::string& version)
2892 : pid_(getpid()),
2893 options_(new Dumpstate::DumpOptions()),
Nandana Duttf02cd782019-06-14 14:25:13 +01002894 last_reported_percent_progress_(0),
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002895 version_(version),
2896 now_(time(nullptr)) {
2897}
2898
2899Dumpstate& Dumpstate::GetInstance() {
2900 static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
2901 return singleton_;
2902}
2903
Nandana Dutt8d945c02019-08-14 13:30:07 +01002904DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
2905 : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002906 if (!title_.empty()) {
2907 started_ = Nanotime();
2908 }
2909}
2910
2911DurationReporter::~DurationReporter() {
2912 if (!title_.empty()) {
2913 float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
Nandana Dutt8d945c02019-08-14 13:30:07 +01002914 if (elapsed < .5f && !verbose_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01002915 return;
2916 }
2917 MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
2918 if (logcat_only_) {
2919 return;
2920 }
2921 // Use "Yoda grammar" to make it easier to grep|sort sections.
2922 printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
2923 }
2924}
2925
2926const int32_t Progress::kDefaultMax = 5000;
2927
2928Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
2929}
2930
2931Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
2932 : Progress(initial_max, growth_factor, "") {
2933 progress_ = progress;
2934}
2935
2936Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
2937 : initial_max_(initial_max),
2938 progress_(0),
2939 max_(initial_max),
2940 growth_factor_(growth_factor),
2941 n_runs_(0),
2942 average_max_(0),
2943 path_(path) {
2944 if (!path_.empty()) {
2945 Load();
2946 }
2947}
2948
2949void Progress::Load() {
2950 MYLOGD("Loading stats from %s\n", path_.c_str());
2951 std::string content;
2952 if (!android::base::ReadFileToString(path_, &content)) {
2953 MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
2954 return;
2955 }
2956 if (content.empty()) {
2957 MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
2958 return;
2959 }
2960 std::vector<std::string> lines = android::base::Split(content, "\n");
2961
2962 if (lines.size() < 1) {
2963 MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
2964 (int)lines.size(), max_);
2965 return;
2966 }
2967 char* ptr;
2968 n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
2969 average_max_ = strtol(ptr, nullptr, 10);
2970 if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
2971 average_max_ > STATS_MAX_AVERAGE) {
2972 MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
2973 initial_max_ = Progress::kDefaultMax;
2974 } else {
2975 initial_max_ = average_max_;
2976 }
2977 max_ = initial_max_;
2978
2979 MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
2980}
2981
2982void Progress::Save() {
2983 int32_t total = n_runs_ * average_max_ + progress_;
2984 int32_t runs = n_runs_ + 1;
2985 int32_t average = floor(((float)total) / runs);
2986 MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
2987 path_.c_str());
2988 if (path_.empty()) {
2989 return;
2990 }
2991
2992 std::string content = android::base::StringPrintf("%d %d\n", runs, average);
2993 if (!android::base::WriteStringToFile(content, path_)) {
2994 MYLOGE("Could not save stats on %s\n", path_.c_str());
2995 }
2996}
2997
2998int32_t Progress::Get() const {
2999 return progress_;
3000}
3001
3002bool Progress::Inc(int32_t delta_sec) {
3003 bool changed = false;
3004 if (delta_sec >= 0) {
3005 progress_ += delta_sec;
3006 if (progress_ > max_) {
3007 int32_t old_max = max_;
3008 max_ = floor((float)progress_ * growth_factor_);
3009 MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
3010 changed = true;
3011 }
3012 }
3013 return changed;
3014}
3015
3016int32_t Progress::GetMax() const {
3017 return max_;
3018}
3019
3020int32_t Progress::GetInitialMax() const {
3021 return initial_max_;
3022}
3023
3024void Progress::Dump(int fd, const std::string& prefix) const {
3025 const char* pr = prefix.c_str();
3026 dprintf(fd, "%sprogress: %d\n", pr, progress_);
3027 dprintf(fd, "%smax: %d\n", pr, max_);
3028 dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
3029 dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
3030 dprintf(fd, "%spath: %s\n", pr, path_.c_str());
3031 dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
3032 dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
3033}
3034
3035bool Dumpstate::IsZipping() const {
3036 return zip_writer_ != nullptr;
3037}
3038
3039std::string Dumpstate::GetPath(const std::string& suffix) const {
3040 return GetPath(bugreport_internal_dir_, suffix);
3041}
3042
3043std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
3044 return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
3045 name_.c_str(), suffix.c_str());
3046}
3047
3048void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
3049 progress_ = std::move(progress);
3050}
3051
3052void for_each_userid(void (*func)(int), const char *header) {
3053 std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
3054 "for_each_userid(%s)", header);
3055 DurationReporter duration_reporter(title);
3056 if (PropertiesHelper::IsDryRun()) return;
3057
3058 DIR *d;
3059 struct dirent *de;
3060
3061 if (header) printf("\n------ %s ------\n", header);
3062 func(0);
3063
3064 if (!(d = opendir("/data/system/users"))) {
3065 printf("Failed to open /data/system/users (%s)\n", strerror(errno));
3066 return;
3067 }
3068
3069 while ((de = readdir(d))) {
3070 int userid;
3071 if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
3072 continue;
3073 }
3074 func(userid);
3075 }
3076
3077 closedir(d);
3078}
3079
3080static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
3081 DIR *d;
3082 struct dirent *de;
3083
3084 if (!(d = opendir("/proc"))) {
3085 printf("Failed to open /proc (%s)\n", strerror(errno));
3086 return;
3087 }
3088
3089 if (header) printf("\n------ %s ------\n", header);
3090 while ((de = readdir(d))) {
3091 if (ds.IsUserConsentDenied()) {
3092 MYLOGE(
3093 "Returning early because user denied consent to share bugreport with calling app.");
3094 closedir(d);
3095 return;
3096 }
3097 int pid;
3098 int fd;
3099 char cmdpath[255];
3100 char cmdline[255];
3101
3102 if (!(pid = atoi(de->d_name))) {
3103 continue;
3104 }
3105
3106 memset(cmdline, 0, sizeof(cmdline));
3107
3108 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
3109 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3110 TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
3111 close(fd);
3112 if (cmdline[0]) {
3113 helper(pid, cmdline, arg);
3114 continue;
3115 }
3116 }
3117
3118 // if no cmdline, a kernel thread has comm
3119 snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
3120 if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
3121 TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
3122 close(fd);
3123 if (cmdline[1]) {
3124 cmdline[0] = '[';
3125 size_t len = strcspn(cmdline, "\f\b\r\n");
3126 cmdline[len] = ']';
3127 cmdline[len+1] = '\0';
3128 }
3129 }
3130 if (!cmdline[0]) {
3131 strcpy(cmdline, "N/A");
3132 }
3133 helper(pid, cmdline, arg);
3134 }
3135
3136 closedir(d);
3137}
3138
3139static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
3140 for_each_pid_func *func = (for_each_pid_func*) arg;
3141 func(pid, cmdline);
3142}
3143
3144void for_each_pid(for_each_pid_func func, const char *header) {
3145 std::string title = header == nullptr ? "for_each_pid"
3146 : android::base::StringPrintf("for_each_pid(%s)", header);
3147 DurationReporter duration_reporter(title);
3148 if (PropertiesHelper::IsDryRun()) return;
3149
3150 __for_each_pid(for_each_pid_helper, header, (void *) func);
3151}
3152
3153static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
3154 DIR *d;
3155 struct dirent *de;
3156 char taskpath[255];
3157 for_each_tid_func *func = (for_each_tid_func *) arg;
3158
3159 snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid);
3160
3161 if (!(d = opendir(taskpath))) {
3162 printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
3163 return;
3164 }
3165
3166 func(pid, pid, cmdline);
3167
3168 while ((de = readdir(d))) {
3169 if (ds.IsUserConsentDenied()) {
3170 MYLOGE(
3171 "Returning early because user denied consent to share bugreport with calling app.");
3172 closedir(d);
3173 return;
3174 }
3175 int tid;
3176 int fd;
3177 char commpath[255];
3178 char comm[255];
3179
3180 if (!(tid = atoi(de->d_name))) {
3181 continue;
3182 }
3183
3184 if (tid == pid)
3185 continue;
3186
3187 snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid);
3188 memset(comm, 0, sizeof(comm));
3189 if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
3190 strcpy(comm, "N/A");
3191 } else {
3192 char *c;
3193 TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
3194 close(fd);
3195
3196 c = strrchr(comm, '\n');
3197 if (c) {
3198 *c = '\0';
3199 }
3200 }
3201 func(pid, tid, comm);
3202 }
3203
3204 closedir(d);
3205}
3206
3207void for_each_tid(for_each_tid_func func, const char *header) {
3208 std::string title = header == nullptr ? "for_each_tid"
3209 : android::base::StringPrintf("for_each_tid(%s)", header);
3210 DurationReporter duration_reporter(title);
3211
3212 if (PropertiesHelper::IsDryRun()) return;
3213
3214 __for_each_pid(for_each_tid_helper, header, (void *) func);
3215}
3216
3217void show_wchan(int pid, int tid, const char *name) {
3218 if (PropertiesHelper::IsDryRun()) return;
3219
3220 char path[255];
3221 char buffer[255];
3222 int fd, ret, save_errno;
3223 char name_buffer[255];
3224
3225 memset(buffer, 0, sizeof(buffer));
3226
3227 snprintf(path, sizeof(path), "/proc/%d/wchan", tid);
3228 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3229 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3230 return;
3231 }
3232
3233 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3234 save_errno = errno;
3235 close(fd);
3236
3237 if (ret < 0) {
3238 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3239 return;
3240 }
3241
3242 snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
3243 pid == tid ? 0 : 3, "", name);
3244
3245 printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
3246
3247 return;
3248}
3249
3250// print time in centiseconds
3251static void snprcent(char *buffer, size_t len, size_t spc,
3252 unsigned long long time) {
3253 static long hz; // cache discovered hz
3254
3255 if (hz <= 0) {
3256 hz = sysconf(_SC_CLK_TCK);
3257 if (hz <= 0) {
3258 hz = 1000;
3259 }
3260 }
3261
3262 // convert to centiseconds
3263 time = (time * 100 + (hz / 2)) / hz;
3264
3265 char str[16];
3266
3267 snprintf(str, sizeof(str), " %llu.%02u",
3268 time / 100, (unsigned)(time % 100));
3269 size_t offset = strlen(buffer);
3270 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3271 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3272}
3273
3274// print permille as a percent
3275static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
3276 char str[16];
3277
3278 snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
3279 size_t offset = strlen(buffer);
3280 snprintf(buffer + offset, (len > offset) ? len - offset : 0,
3281 "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
3282}
3283
3284void show_showtime(int pid, const char *name) {
3285 if (PropertiesHelper::IsDryRun()) return;
3286
3287 char path[255];
3288 char buffer[1023];
3289 int fd, ret, save_errno;
3290
3291 memset(buffer, 0, sizeof(buffer));
3292
3293 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
3294 if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
3295 printf("Failed to open '%s' (%s)\n", path, strerror(errno));
3296 return;
3297 }
3298
3299 ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3300 save_errno = errno;
3301 close(fd);
3302
3303 if (ret < 0) {
3304 printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
3305 return;
3306 }
3307
3308 // field 14 is utime
3309 // field 15 is stime
3310 // field 42 is iotime
3311 unsigned long long utime = 0, stime = 0, iotime = 0;
3312 if (sscanf(buffer,
3313 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d "
3314 "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d "
3315 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
3316 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ",
3317 &utime, &stime, &iotime) != 3) {
3318 return;
3319 }
3320
3321 unsigned long long total = utime + stime;
3322 if (!total) {
3323 return;
3324 }
3325
3326 unsigned permille = (iotime * 1000 + (total / 2)) / total;
3327 if (permille > 1000) {
3328 permille = 1000;
3329 }
3330
3331 // try to beautify and stabilize columns at <80 characters
3332 snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
3333 if ((name[0] != '[') || utime) {
3334 snprcent(buffer, sizeof(buffer), 57, utime);
3335 }
3336 snprcent(buffer, sizeof(buffer), 65, stime);
3337 if ((name[0] != '[') || iotime) {
3338 snprcent(buffer, sizeof(buffer), 73, iotime);
3339 }
3340 if (iotime) {
3341 snprdec(buffer, sizeof(buffer), 79, permille);
3342 }
3343 puts(buffer); // adds a trailing newline
3344
3345 return;
3346}
3347
3348void do_dmesg() {
3349 const char *title = "KERNEL LOG (dmesg)";
3350 DurationReporter duration_reporter(title);
3351 printf("------ %s ------\n", title);
3352
3353 if (PropertiesHelper::IsDryRun()) return;
3354
3355 /* Get size of kernel buffer */
3356 int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
3357 if (size <= 0) {
3358 printf("Unexpected klogctl return value: %d\n\n", size);
3359 return;
3360 }
3361 char *buf = (char *) malloc(size + 1);
3362 if (buf == nullptr) {
3363 printf("memory allocation failed\n\n");
3364 return;
3365 }
3366 int retval = klogctl(KLOG_READ_ALL, buf, size);
3367 if (retval < 0) {
3368 printf("klogctl failure\n\n");
3369 free(buf);
3370 return;
3371 }
3372 buf[retval] = '\0';
3373 printf("%s\n\n", buf);
3374 free(buf);
3375 return;
3376}
3377
3378void do_showmap(int pid, const char *name) {
3379 char title[255];
3380 char arg[255];
3381
3382 snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
3383 snprintf(arg, sizeof(arg), "%d", pid);
3384 RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
3385}
3386
3387int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
3388 DurationReporter duration_reporter(title);
3389
3390 int status = DumpFileToFd(STDOUT_FILENO, title, path);
3391
3392 UpdateProgress(WEIGHT_FILE);
3393
3394 return status;
3395}
3396
3397int read_file_as_long(const char *path, long int *output) {
3398 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
3399 if (fd < 0) {
3400 int err = errno;
3401 MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
3402 return -1;
3403 }
3404 char buffer[50];
3405 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
3406 if (bytes_read == -1) {
3407 MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
3408 return -2;
3409 }
3410 if (bytes_read == 0) {
3411 MYLOGE("File %s is empty\n", path);
3412 return -3;
3413 }
3414 *output = atoi(buffer);
3415 return 0;
3416}
3417
3418/* calls skip to gate calling dump_from_fd recursively
3419 * in the specified directory. dump_from_fd defaults to
3420 * dump_file_from_fd above when set to NULL. skip defaults
3421 * to false when set to NULL. dump_from_fd will always be
3422 * called with title NULL.
3423 */
3424int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
3425 int (*dump_from_fd)(const char* title, const char* path, int fd)) {
3426 DurationReporter duration_reporter(title);
3427 DIR *dirp;
3428 struct dirent *d;
3429 char *newpath = nullptr;
3430 const char *slash = "/";
3431 int retval = 0;
3432
3433 if (!title.empty()) {
3434 printf("------ %s (%s) ------\n", title.c_str(), dir);
3435 }
3436 if (PropertiesHelper::IsDryRun()) return 0;
3437
3438 if (dir[strlen(dir) - 1] == '/') {
3439 ++slash;
3440 }
3441 dirp = opendir(dir);
3442 if (dirp == nullptr) {
3443 retval = -errno;
3444 MYLOGE("%s: %s\n", dir, strerror(errno));
3445 return retval;
3446 }
3447
3448 if (!dump_from_fd) {
3449 dump_from_fd = dump_file_from_fd;
3450 }
3451 for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
3452 if ((d->d_name[0] == '.')
3453 && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
3454 || (d->d_name[1] == '\0'))) {
3455 continue;
3456 }
3457 asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
3458 (d->d_type == DT_DIR) ? "/" : "");
3459 if (!newpath) {
3460 retval = -errno;
3461 continue;
3462 }
3463 if (skip && (*skip)(newpath)) {
3464 continue;
3465 }
3466 if (d->d_type == DT_DIR) {
3467 int ret = dump_files("", newpath, skip, dump_from_fd);
3468 if (ret < 0) {
3469 retval = ret;
3470 }
3471 continue;
3472 }
3473 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
3474 if (fd.get() < 0) {
3475 retval = -1;
3476 printf("*** %s: %s\n", newpath, strerror(errno));
3477 continue;
3478 }
3479 (*dump_from_fd)(nullptr, newpath, fd.get());
3480 }
3481 closedir(dirp);
3482 if (!title.empty()) {
3483 printf("\n");
3484 }
3485 return retval;
3486}
3487
3488/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
3489 * it's possible to avoid issues where opening the file itself can get
3490 * stuck.
3491 */
3492int dump_file_from_fd(const char *title, const char *path, int fd) {
3493 if (PropertiesHelper::IsDryRun()) return 0;
3494
3495 int flags = fcntl(fd, F_GETFL);
3496 if (flags == -1) {
3497 printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
3498 return -1;
3499 } else if (!(flags & O_NONBLOCK)) {
3500 printf("*** %s: fd must have O_NONBLOCK set.\n", path);
3501 return -1;
3502 }
3503 return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
3504}
3505
3506int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Nandana Dutt8d945c02019-08-14 13:30:07 +01003507 const CommandOptions& options, bool verbose_duration) {
3508 DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003509
3510 int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
3511
3512 /* TODO: for now we're simplifying the progress calculation by using the
3513 * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
3514 * where its weight should be much higher proportionally to its timeout.
3515 * Ideally, it should use a options.EstimatedDuration() instead...*/
3516 UpdateProgress(options.Timeout());
3517
3518 return status;
3519}
3520
3521void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
3522 const CommandOptions& options, long dumpsysTimeoutMs) {
3523 long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
3524 std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
3525 dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
3526 RunCommand(title, dumpsys, options);
3527}
3528
3529int open_socket(const char *service) {
3530 int s = android_get_control_socket(service);
3531 if (s < 0) {
3532 MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
3533 return -1;
3534 }
3535 fcntl(s, F_SETFD, FD_CLOEXEC);
3536
3537 // Set backlog to 0 to make sure that queue size will be minimum.
3538 // In Linux, because the minimum queue will be 1, connect() will be blocked
3539 // if the other clients already called connect() and the connection request was not accepted.
3540 if (listen(s, 0) < 0) {
3541 MYLOGE("listen(control socket): %s\n", strerror(errno));
3542 return -1;
3543 }
3544
3545 struct sockaddr addr;
3546 socklen_t alen = sizeof(addr);
Abhijeet Kaur2113cae2019-09-13 09:24:15 +01003547 int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003548
3549 // Close socket just after accept(), to make sure that connect() by client will get error
3550 // when the socket is used by the other services.
3551 // There is still a race condition possibility between accept and close, but there is no way
3552 // to close-on-accept atomically.
3553 // See detail; b/123306389#comment25
3554 close(s);
3555
3556 if (fd < 0) {
3557 MYLOGE("accept(control socket): %s\n", strerror(errno));
3558 return -1;
3559 }
3560
3561 return fd;
3562}
3563
3564/* redirect output to a service control socket */
3565bool redirect_to_socket(FILE* redirect, const char* service) {
3566 int fd = open_socket(service);
3567 if (fd == -1) {
3568 return false;
3569 }
3570 fflush(redirect);
3571 // TODO: handle dup2 failure
3572 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3573 close(fd);
3574 return true;
3575}
3576
3577// TODO: should call is_valid_output_file and/or be merged into it.
3578void create_parent_dirs(const char *path) {
3579 char *chp = const_cast<char *> (path);
3580
3581 /* skip initial slash */
3582 if (chp[0] == '/')
3583 chp++;
3584
3585 /* create leading directories, if necessary */
3586 struct stat dir_stat;
3587 while (chp && chp[0]) {
3588 chp = strchr(chp, '/');
3589 if (chp) {
3590 *chp = 0;
3591 if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
3592 MYLOGI("Creating directory %s\n", path);
3593 if (mkdir(path, 0770)) { /* drwxrwx--- */
3594 MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno));
3595 } else if (chown(path, AID_SHELL, AID_SHELL)) {
3596 MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
3597 }
3598 }
3599 *chp++ = '/';
3600 }
3601 }
3602}
3603
3604bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
3605 create_parent_dirs(path);
3606
3607 int fd = TEMP_FAILURE_RETRY(open(path,
3608 O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
3609 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
3610 if (fd < 0) {
3611 MYLOGE("%s: %s\n", path, strerror(errno));
3612 return false;
3613 }
3614
3615 TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
3616 close(fd);
3617 return true;
3618}
3619
3620bool redirect_to_file(FILE* redirect, char* path) {
3621 return _redirect_to_file(redirect, path, O_TRUNC);
3622}
3623
3624bool redirect_to_existing_file(FILE* redirect, char* path) {
3625 return _redirect_to_file(redirect, path, O_APPEND);
3626}
3627
3628void dump_route_tables() {
3629 DurationReporter duration_reporter("DUMP ROUTE TABLES");
3630 if (PropertiesHelper::IsDryRun()) return;
3631 const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
3632 ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
3633 FILE* fp = fopen(RT_TABLES_PATH, "re");
3634 if (!fp) {
3635 printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
3636 return;
3637 }
3638 char table[16];
3639 // Each line has an integer (the table number), a space, and a string (the table name). We only
3640 // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
3641 // Add a fixed max limit so this doesn't go awry.
3642 for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
3643 RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
3644 RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
3645 }
3646 fclose(fp);
3647}
3648
3649// TODO: make this function thread safe if sections are generated in parallel.
3650void Dumpstate::UpdateProgress(int32_t delta_sec) {
3651 if (progress_ == nullptr) {
3652 MYLOGE("UpdateProgress: progress_ not set\n");
3653 return;
3654 }
3655
3656 // Always update progess so stats can be tuned...
Nandana Duttf02cd782019-06-14 14:25:13 +01003657 progress_->Inc(delta_sec);
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003658
3659 // ...but only notifiy listeners when necessary.
3660 if (!options_->do_progress_updates) return;
3661
3662 int progress = progress_->Get();
3663 int max = progress_->GetMax();
Nandana Duttf02cd782019-06-14 14:25:13 +01003664 int percent = 100 * progress / max;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003665
Nandana Duttf02cd782019-06-14 14:25:13 +01003666 if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003667 return;
3668 }
Nandana Duttf02cd782019-06-14 14:25:13 +01003669 last_reported_percent_progress_ = percent;
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003670
3671 if (control_socket_fd_ >= 0) {
3672 dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
3673 fsync(control_socket_fd_);
3674 }
3675
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003676 if (listener_ != nullptr) {
3677 if (percent % 5 == 0) {
3678 // We don't want to spam logcat, so only log multiples of 5.
3679 MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
3680 percent);
3681 } else {
3682 // stderr is ignored on normal invocations, but useful when calling
3683 // /system/bin/dumpstate directly for debuggging.
3684 fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
3685 progress, max, percent);
3686 }
Abhijeet Kaurcf234e82019-07-01 14:53:55 +01003687
3688 listener_->onProgress(percent);
3689 }
3690}
3691
3692void Dumpstate::TakeScreenshot(const std::string& path) {
3693 const std::string& real_path = path.empty() ? screenshot_path_ : path;
3694 int status =
3695 RunCommand("", {"/system/bin/screencap", "-p", real_path},
3696 CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
3697 if (status == 0) {
3698 MYLOGD("Screenshot saved on %s\n", real_path.c_str());
3699 } else {
3700 MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
3701 }
3702}
3703
3704bool is_dir(const char* pathname) {
3705 struct stat info;
3706 if (stat(pathname, &info) == -1) {
3707 return false;
3708 }
3709 return S_ISDIR(info.st_mode);
3710}
3711
3712time_t get_mtime(int fd, time_t default_mtime) {
3713 struct stat info;
3714 if (fstat(fd, &info) == -1) {
3715 return default_mtime;
3716 }
3717 return info.st_mtime;
3718}