blob: d1a96c13d8dab4b0dcc68a4db9d8efe7cd2b38c7 [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 */
16
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070017#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070018#include <errno.h>
19#include <fcntl.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080020#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070021#include <limits.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080022#include <memory>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <regex>
Felipe Leme635ca312016-01-05 14:23:02 -080024#include <set>
Wei Liuf87959e2016-08-26 14:51:42 -070025#include <signal.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070026#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070027#include <stdio.h>
28#include <stdlib.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080029#include <string>
Colin Crossf45fa6b2012-03-26 12:38:26 -070030#include <string.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070031#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032#include <sys/resource.h>
33#include <sys/stat.h>
34#include <sys/time.h>
35#include <sys/wait.h>
36#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070037
Felipe Leme96c2bbb2016-09-26 09:21:21 -070038#include <android-base/file.h>
39#include <android-base/properties.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080040#include <android-base/stringprintf.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070041#include <android-base/unique_fd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070042#include <cutils/properties.h>
Wei Liuf87959e2016-08-26 14:51:42 -070043#include <hardware_legacy/power.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044
45#include "private/android_filesystem_config.h"
46
47#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070048#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070049
50#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080051#include "ziparchive/zip_writer.h"
52
Elliott Hughesc4dc1412016-04-12 16:28:31 -070053#include <openssl/sha.h>
Michal Karpinski4db754f2015-12-11 18:04:32 +000054
Felipe Leme6e01fa62015-11-11 19:35:14 -080055using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070056
57/* read before root is shed */
58static char cmdline_buf[16384] = "(unknown)";
59static const char *dump_traces_path = NULL;
60
Felipe Leme9ce6aa42016-09-21 10:02:25 -070061// Command-line arguments as string
62static std::string args;
63
Felipe Lemeefd7e272016-05-18 09:27:16 -070064// TODO: variables below should be part of dumpstate object
Felipe Leme96c2bbb2016-09-26 09:21:21 -070065static std::string buildType;
Felipe Lemee82a27d2016-01-05 13:35:44 -080066static time_t now;
67static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080068static std::set<std::string> mount_points;
69void add_mountinfo();
Felipe Lemeefd7e272016-05-18 09:27:16 -070070/* suffix of the bugreport files - it's typically the date (when invoked with -d),
71 * although it could be changed by the user using a system property */
72static std::string suffix;
Felipe Leme96c2bbb2016-09-26 09:21:21 -070073static std::string extraOptions;
Felipe Leme78f2c862015-12-21 09:55:22 -080074
Todd Poynor2a83daa2013-11-22 15:44:22 -080075#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -070076#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080077
Wei Liu341938b2016-04-27 16:18:17 -070078#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080079#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070080#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070081#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010082#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
83#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070084#define TOMBSTONE_DIR "/data/tombstones"
85#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
86/* Can accomodate a tombstone number up to 9999. */
87#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
88#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090089#define WLUTIL "/vendor/xbin/wlutil"
Wei Liuf87959e2016-08-26 14:51:42 -070090#define WAKE_LOCK_NAME "dumpstate_wakelock"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070091
92typedef struct {
93 char name[TOMBSTONE_MAX_LEN];
94 int fd;
95} tombstone_data_t;
96
97static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
98
Felipe Lemee844a9d2016-09-21 15:01:39 -070099// TODO: temporary variables and functions used during C++ refactoring
100static Dumpstate& ds = Dumpstate::GetInstance();
Felipe Leme678727a2016-09-21 17:22:11 -0700101static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
102 const CommandOptions& options = CommandOptions::DEFAULT) {
103 return ds.RunCommand(title, fullCommand, options);
104}
105static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
106 const CommandOptions& options = CommandOptions::DEFAULT_DUMPSYS,
107 long dumpsysTimeout = 0) {
108 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
109}
110static int DumpFile(const std::string& title, const std::string& path) {
111 return ds.DumpFile(title, path);
112}
Felipe Leme6ad9c062016-09-28 11:58:36 -0700113bool IsUserBuild() {
114 return ds.IsUserBuild();
115}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800116
Felipe Leme809d74e2016-02-02 12:57:00 -0800117/*
118 * List of supported zip format versions.
119 *
Felipe Leme8268ed22016-08-02 18:18:25 -0700120 * See bugreport-format.md for more info.
Felipe Leme809d74e2016-02-02 12:57:00 -0800121 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -0700122static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800123
Felipe Lemee844a9d2016-09-21 15:01:39 -0700124// Relative directory (inside the zip) for all files copied as-is into the bugreport.
125static const std::string ZIP_ROOT_DIR = "FS";
126
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700127static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700128static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700129
Felipe Leme6ad9c062016-09-28 11:58:36 -0700130bool Dumpstate::IsUserBuild() {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700131 return "user" == buildType;
Felipe Lemec4eee562016-04-21 15:42:55 -0700132}
133
Felipe Lemee844a9d2016-09-21 15:01:39 -0700134bool Dumpstate::IsDryRun() {
135 return dryRun_;
Felipe Leme8268ed22016-08-02 18:18:25 -0700136}
137
Felipe Leme3d305a12016-05-20 11:24:37 -0700138/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
139 * otherwise, gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700140static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800141 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700142 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
143 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800144 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
145 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700146 struct stat st;
Felipe Leme3d305a12016-05-20 11:24:37 -0700147 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800148 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
Felipe Leme3d305a12016-05-20 11:24:37 -0700149 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700150 } else {
Felipe Leme3d305a12016-05-20 11:24:37 -0700151 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700152 data[i].fd = -1;
153 }
154 }
155}
156
Felipe Leme635ca312016-01-05 14:23:02 -0800157// for_each_pid() callback to get mount info about a process.
158void do_mountinfo(int pid, const char *name) {
159 char path[PATH_MAX];
160
161 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
162 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700163 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800164 char linkname[PATH_MAX];
165 ssize_t r = readlink(path, linkname, PATH_MAX);
166 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800167 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800168 return;
169 }
170 linkname[r] = '\0';
171
172 if (mount_points.find(linkname) == mount_points.end()) {
173 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700174 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800175 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
176 mount_points.insert(linkname);
177 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800178 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800179 }
180 }
181}
182
183void add_mountinfo() {
184 if (!zip_writer) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700185 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800186 mount_points.clear();
Felipe Leme678727a2016-09-21 17:22:11 -0700187 DurationReporter durationReporter(title, nullptr);
188 for_each_pid(do_mountinfo, nullptr);
189 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800190}
191
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700192static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
193{
194 DIR *d;
195 struct dirent *de;
196 char path[PATH_MAX];
197
198 d = opendir(driverpath);
199 if (d == NULL) {
200 return;
201 }
202
203 while ((de = readdir(d))) {
204 if (de->d_type != DT_LNK) {
205 continue;
206 }
207 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700208 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700209 }
210
211 closedir(d);
212}
213
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700214// return pid of a userspace process. If not found or error, return 0.
215static unsigned int pid_of_process(const char* ps_name) {
216 DIR *proc_dir;
217 struct dirent *ps;
218 unsigned int pid;
219 std::string cmdline;
220
221 if (!(proc_dir = opendir("/proc"))) {
222 MYLOGE("Can't open /proc\n");
223 return 0;
224 }
225
226 while ((ps = readdir(proc_dir))) {
227 if (!(pid = atoi(ps->d_name))) {
228 continue;
229 }
230 android::base::ReadFileToString("/proc/"
231 + std::string(ps->d_name) + "/cmdline", &cmdline);
232 if (cmdline.find(ps_name) == std::string::npos) {
233 continue;
234 } else {
235 closedir(proc_dir);
236 return pid;
237 }
238 }
239 closedir(proc_dir);
240 return 0;
241}
242
243// dump anrd's trace and add to the zip file.
244// 1. check if anrd is running on this device.
245// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
246// 3. wait until the trace generation completes and add to the zip file.
247static bool dump_anrd_trace() {
248 unsigned int pid;
249 char buf[50], path[PATH_MAX];
250 struct dirent *trace;
251 struct stat st;
252 DIR *trace_dir;
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700253 int retry = 5;
254 long max_ctime = 0, old_mtime;
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700255 long long cur_size = 0;
256 const char *trace_path = "/data/misc/anrd/";
257
258 if (!zip_writer) {
259 MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
260 return false;
261 }
262
263 // find anrd's pid if it is running.
264 pid = pid_of_process("/system/xbin/anrd");
265
266 if (pid > 0) {
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700267 if (stat(trace_path, &st) == 0) {
268 old_mtime = st.st_mtime;
269 } else {
270 MYLOGE("Failed to find: %s\n", trace_path);
271 return false;
272 }
273
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700274 // send SIGUSR1 to the anrd to generate a trace.
275 sprintf(buf, "%u", pid);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700276 if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700277 CommandOptions::WithTimeout(1).Build())) {
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700278 MYLOGE("anrd signal timed out. Please manually collect trace\n");
279 return false;
280 }
281
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700282 while (retry-- > 0 && old_mtime == st.st_mtime) {
283 sleep(1);
284 stat(trace_path, &st);
285 }
286
287 if (retry < 0 && old_mtime == st.st_mtime) {
288 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
289 return false;
290 }
291
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700292 // identify the trace file by its creation time.
293 if (!(trace_dir = opendir(trace_path))) {
294 MYLOGE("Can't open trace file under %s\n", trace_path);
295 }
296 while ((trace = readdir(trace_dir))) {
297 if (strcmp(trace->d_name, ".") == 0
298 || strcmp(trace->d_name, "..") == 0) {
299 continue;
300 }
301 sprintf(path, "%s%s", trace_path, trace->d_name);
302 if (stat(path, &st) == 0) {
303 if (st.st_ctime > max_ctime) {
304 max_ctime = st.st_ctime;
305 sprintf(buf, "%s", trace->d_name);
306 }
307 }
308 }
309 closedir(trace_dir);
310
311 // Wait until the dump completes by checking the size of the trace.
312 if (max_ctime > 0) {
313 sprintf(path, "%s%s", trace_path, buf);
314 while(true) {
315 sleep(1);
316 if (stat(path, &st) == 0) {
317 if (st.st_size == cur_size) {
318 break;
319 } else if (st.st_size > cur_size) {
320 cur_size = st.st_size;
321 } else {
322 return false;
323 }
324 } else {
325 MYLOGE("Cant stat() %s anymore\n", path);
326 return false;
327 }
328 }
329 // Add to the zip file.
330 if (!add_zip_entry("anrd_trace.txt", path)) {
331 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
332 } else {
333 if (remove(path)) {
334 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
335 }
336 return true;
337 }
338 } else {
339 MYLOGE("Can't stats any trace file under %s\n", trace_path);
340 }
341 }
342 return false;
343}
344
Felipe Lemeefd7e272016-05-18 09:27:16 -0700345static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700346 if (!zip_writer) {
347 MYLOGD("Not dumping systrace because zip_writer is not set\n");
348 return;
349 }
Felipe Lemee844a9d2016-09-21 15:01:39 -0700350 std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700351 if (systrace_path.empty()) {
352 MYLOGE("Not dumping systrace because path is empty\n");
353 return;
354 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700355 const char* path = "/sys/kernel/debug/tracing/tracing_on";
356 long int is_tracing;
357 if (read_file_as_long(path, &is_tracing)) {
358 return; // error already logged
359 }
360 if (is_tracing <= 0) {
361 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
362 return;
363 }
364
Felipe Leme14e034a2016-03-30 18:51:03 -0700365 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
366 systrace_path.c_str());
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700367 if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700368 CommandOptions::WithTimeout(120).Build())) {
Felipe Leme14e034a2016-03-30 18:51:03 -0700369 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
Felipe Leme30dbfa12016-09-02 12:43:26 -0700370 // TODO: run_command tries to kill the process, but atrace doesn't die
371 // peacefully; ideally, we should call strace to stop itself, but there is no such option
372 // yet (just a --async_stop, which stops and dump
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700373 // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
Felipe Leme30dbfa12016-09-02 12:43:26 -0700374 // MYLOGE("could not stop systrace ");
375 // }
Felipe Leme14e034a2016-03-30 18:51:03 -0700376 }
377 if (!add_zip_entry("systrace.txt", systrace_path)) {
378 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700379 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700380 if (remove(systrace_path.c_str())) {
381 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
382 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700383 }
384}
385
Felipe Lemeefd7e272016-05-18 09:27:16 -0700386static void dump_raft() {
Felipe Leme6ad9c062016-09-28 11:58:36 -0700387 if (IsUserBuild()) {
Wei Liu341938b2016-04-27 16:18:17 -0700388 return;
389 }
390
Felipe Lemee844a9d2016-09-21 15:01:39 -0700391 std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700392 if (raft_log_path.empty()) {
393 MYLOGD("raft_log_path is empty\n");
394 return;
395 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700396
397 struct stat s;
398 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
399 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
400 return;
401 }
402
Felipe Leme30dbfa12016-09-02 12:43:26 -0700403 CommandOptions options = CommandOptions::WithTimeout(600).Build();
Wei Liu341938b2016-04-27 16:18:17 -0700404 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700405 // Write compressed and encoded raft logs to stdout if not zip_writer.
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700406 RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
Wei Liu341938b2016-04-27 16:18:17 -0700407 return;
408 }
409
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700410 RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_log_path}, options);
Wei Liu341938b2016-04-27 16:18:17 -0700411 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
412 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
413 } else {
414 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700415 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700416 }
417 }
418}
419
Mark Salyzyn326842f2015-04-30 09:49:41 -0700420static bool skip_not_stat(const char *path) {
421 static const char stat[] = "/stat";
422 size_t len = strlen(path);
423 if (path[len - 1] == '/') { /* Directory? */
424 return false;
425 }
426 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
427}
428
Felipe Lemee82a27d2016-01-05 13:35:44 -0800429static bool skip_none(const char *path) {
430 return false;
431}
432
Mark Salyzyn326842f2015-04-30 09:49:41 -0700433static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700434unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700435
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800436//
437// stat offsets
438// Name units description
439// ---- ----- -----------
440// read I/Os requests number of read I/Os processed
441#define __STAT_READ_IOS 0
442// read merges requests number of read I/Os merged with in-queue I/O
443#define __STAT_READ_MERGES 1
444// read sectors sectors number of sectors read
445#define __STAT_READ_SECTORS 2
446// read ticks milliseconds total wait time for read requests
447#define __STAT_READ_TICKS 3
448// write I/Os requests number of write I/Os processed
449#define __STAT_WRITE_IOS 4
450// write merges requests number of write I/Os merged with in-queue I/O
451#define __STAT_WRITE_MERGES 5
452// write sectors sectors number of sectors written
453#define __STAT_WRITE_SECTORS 6
454// write ticks milliseconds total wait time for write requests
455#define __STAT_WRITE_TICKS 7
456// in_flight requests number of I/Os currently in flight
457#define __STAT_IN_FLIGHT 8
458// io_ticks milliseconds total time this block device has been active
459#define __STAT_IO_TICKS 9
460// time_in_queue milliseconds total wait time for all requests
461#define __STAT_IN_QUEUE 10
462#define __STAT_NUMBER_FIELD 11
463//
464// read I/Os, write I/Os
465// =====================
466//
467// These values increment when an I/O request completes.
468//
469// read merges, write merges
470// =========================
471//
472// These values increment when an I/O request is merged with an
473// already-queued I/O request.
474//
475// read sectors, write sectors
476// ===========================
477//
478// These values count the number of sectors read from or written to this
479// block device. The "sectors" in question are the standard UNIX 512-byte
480// sectors, not any device- or filesystem-specific block size. The
481// counters are incremented when the I/O completes.
482#define SECTOR_SIZE 512
483//
484// read ticks, write ticks
485// =======================
486//
487// These values count the number of milliseconds that I/O requests have
488// waited on this block device. If there are multiple I/O requests waiting,
489// these values will increase at a rate greater than 1000/second; for
490// example, if 60 read requests wait for an average of 30 ms, the read_ticks
491// field will increase by 60*30 = 1800.
492//
493// in_flight
494// =========
495//
496// This value counts the number of I/O requests that have been issued to
497// the device driver but have not yet completed. It does not include I/O
498// requests that are in the queue but not yet issued to the device driver.
499//
500// io_ticks
501// ========
502//
503// This value counts the number of milliseconds during which the device has
504// had I/O requests queued.
505//
506// time_in_queue
507// =============
508//
509// This value counts the number of milliseconds that I/O requests have waited
510// on this block device. If there are multiple I/O requests waiting, this
511// value will increase as the product of the number of milliseconds times the
512// number of requests waiting (see "read ticks" above for an example).
513#define S_TO_MS 1000
514//
515
Mark Salyzyn326842f2015-04-30 09:49:41 -0700516static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800517 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700518 bool z;
519 char *cp, *buffer = NULL;
520 size_t i = 0;
521 FILE *fp = fdopen(fd, "rb");
522 getline(&buffer, &i, fp);
523 fclose(fp);
524 if (!buffer) {
525 return -errno;
526 }
527 i = strlen(buffer);
528 while ((i > 0) && (buffer[i - 1] == '\n')) {
529 buffer[--i] = '\0';
530 }
531 if (!*buffer) {
532 free(buffer);
533 return 0;
534 }
535 z = true;
536 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800537 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700538 if (fields[i] != 0) {
539 z = false;
540 }
541 }
542 if (z) { /* never accessed */
543 free(buffer);
544 return 0;
545 }
546
547 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
548 path += sizeof(mmcblk0) - 1;
549 }
550
551 printf("%s: %s\n", path, buffer);
552 free(buffer);
553
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800554 if (fields[__STAT_IO_TICKS]) {
555 unsigned long read_perf = 0;
556 unsigned long read_ios = 0;
557 if (fields[__STAT_READ_TICKS]) {
558 unsigned long long divisor = fields[__STAT_READ_TICKS]
559 * fields[__STAT_IO_TICKS];
560 read_perf = ((unsigned long long)SECTOR_SIZE
561 * fields[__STAT_READ_SECTORS]
562 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
563 / divisor;
564 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
565 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
566 / divisor;
567 }
568
569 unsigned long write_perf = 0;
570 unsigned long write_ios = 0;
571 if (fields[__STAT_WRITE_TICKS]) {
572 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
573 * fields[__STAT_IO_TICKS];
574 write_perf = ((unsigned long long)SECTOR_SIZE
575 * fields[__STAT_WRITE_SECTORS]
576 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
577 / divisor;
578 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
579 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
580 / divisor;
581 }
582
583 unsigned queue = (fields[__STAT_IN_QUEUE]
584 + (fields[__STAT_IO_TICKS] >> 1))
585 / fields[__STAT_IO_TICKS];
586
587 if (!write_perf && !write_ios) {
588 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
589 path, read_perf, read_ios, queue);
590 } else {
591 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
592 path, read_perf, read_ios, write_perf, write_ios, queue);
593 }
594
595 /* bugreport timeout factor adjustment */
596 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
597 worst_write_perf = write_perf;
598 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700599 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700600 return 0;
601}
602
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700603/* Copied policy from system/core/logd/LogBuffer.cpp */
604
605#define LOG_BUFFER_SIZE (256 * 1024)
606#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
607#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
608
609static bool valid_size(unsigned long value) {
610 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
611 return false;
612 }
613
614 long pages = sysconf(_SC_PHYS_PAGES);
615 if (pages < 1) {
616 return true;
617 }
618
619 long pagesize = sysconf(_SC_PAGESIZE);
620 if (pagesize <= 1) {
621 pagesize = PAGE_SIZE;
622 }
623
624 // maximum memory impact a somewhat arbitrary ~3%
625 pages = (pages + 31) / 32;
626 unsigned long maximum = pages * pagesize;
627
628 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
629 return true;
630 }
631
632 return value <= maximum;
633}
634
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700635// TODO: migrate to logd/LogBuffer.cpp or use android::base::GetProperty
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700636static unsigned long property_get_size(const char *key) {
637 unsigned long value;
638 char *cp, property[PROPERTY_VALUE_MAX];
639
640 property_get(key, property, "");
641 value = strtoul(property, &cp, 10);
642
643 switch(*cp) {
644 case 'm':
645 case 'M':
646 value *= 1024;
647 /* FALLTHRU */
648 case 'k':
649 case 'K':
650 value *= 1024;
651 /* FALLTHRU */
652 case '\0':
653 break;
654
655 default:
656 value = 0;
657 }
658
659 if (!valid_size(value)) {
660 value = 0;
661 }
662
663 return value;
664}
665
666/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800667static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700668 static const char global_tuneable[] = "persist.logd.size"; // Settings App
669 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
670 char key[PROP_NAME_MAX];
671 unsigned long property_size, default_size;
672
673 default_size = property_get_size(global_tuneable);
674 if (!default_size) {
675 default_size = property_get_size(global_default);
676 }
677
678 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
679 property_size = property_get_size(key);
680
681 if (!property_size) {
682 snprintf(key, sizeof(key), "%s.%s", global_default, name);
683 property_size = property_get_size(key);
684 }
685
686 if (!property_size) {
687 property_size = default_size;
688 }
689
690 if (!property_size) {
691 property_size = LOG_BUFFER_SIZE;
692 }
693
694 /* Engineering margin is ten-fold our guess */
695 return 10 * (property_size + worst_write_perf) / worst_write_perf;
696}
697
698/* End copy from system/core/logd/LogBuffer.cpp */
699
Colin Crossf45fa6b2012-03-26 12:38:26 -0700700/* dumps the current system state to stdout */
Felipe Lemee844a9d2016-09-21 15:01:39 -0700701void print_header(const std::string& version) {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700702 std::string build, fingerprint, radio, bootloader, network;
703 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700704
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700705 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
706 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
707 buildType = android::base::GetProperty("ro.build.type", "(unknown)");
708 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
709 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
710 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700711 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
712
713 printf("========================================================\n");
714 printf("== dumpstate: %s\n", date);
715 printf("========================================================\n");
716
717 printf("\n");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700718 printf("Build: %s\n", build.c_str());
719 // NOTE: fingerprint entry format is important for other tools.
720 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
721 printf("Bootloader: %s\n", bootloader.c_str());
722 printf("Radio: %s\n", radio.c_str());
723 printf("Network: %s\n", network.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700724
725 printf("Kernel: ");
Felipe Leme678727a2016-09-21 17:22:11 -0700726 DumpFile("", "/proc/version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700727 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800728 printf("Bugreport format version: %s\n", version.c_str());
Felipe Lemee844a9d2016-09-21 15:01:39 -0700729 printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(),
730 ds.dryRun_, args.c_str(), extraOptions.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700731 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800732}
733
Felipe Leme24b66ee2016-06-16 10:55:26 -0700734// List of file extensions that can cause a zip file attachment to be rejected by some email
735// service providers.
736static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
737 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
738 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
739 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
740};
741
Felipe Leme71ca15e2016-05-19 16:18:17 -0700742bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800743 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800744 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
745 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800746 return false;
747 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700748 std::string valid_name = entry_name;
749
750 // Rename extension if necessary.
751 size_t idx = entry_name.rfind(".");
752 if (idx != std::string::npos) {
753 std::string extension = entry_name.substr(idx);
754 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
755 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
756 valid_name = entry_name + ".renamed";
757 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
758 }
759 }
760
Felipe Leme6fe9db62016-02-12 09:04:16 -0800761 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
762 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700763 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800764 ZipWriter::kCompress, get_mtime(fd, now));
765 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700766 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800767 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800768 return false;
769 }
770
Felipe Leme770410d2016-01-26 17:07:14 -0800771 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800772 while (1) {
Zach Riggle22200402016-08-18 01:01:24 -0400773 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800774 if (bytes_read == 0) {
775 break;
776 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800777 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800778 return false;
779 }
780 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
781 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800782 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800783 return false;
784 }
785 }
786
787 err = zip_writer->FinishEntry();
788 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800789 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800790 return false;
791 }
792
793 return true;
794}
795
Felipe Leme71ca15e2016-05-19 16:18:17 -0700796bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -0700797 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK
798 | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700799 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800800 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800801 return false;
802 }
803
804 return add_zip_entry_from_fd(entry_name, fd.get());
805}
806
807/* adds a file to the existing zipped bugreport */
808static int _add_file_from_fd(const char *title, const char *path, int fd) {
809 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
810}
811
Felipe Leme24b66ee2016-06-16 10:55:26 -0700812// TODO: move to util.cpp
Felipe Leme678727a2016-09-21 17:22:11 -0700813void add_dir(const std::string& dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800814 if (!zip_writer) {
Felipe Leme678727a2016-09-21 17:22:11 -0700815 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800816 return;
817 }
Felipe Leme678727a2016-09-21 17:22:11 -0700818 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
819 DurationReporter durationReporter(dir, nullptr);
820 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800821}
822
Felipe Leme809d74e2016-02-02 12:57:00 -0800823/* adds a text entry entry to the existing zip file. */
824static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800825 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800826 MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800827 return false;
828 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800829 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800830 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
831 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800832 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800833 ZipWriter::ErrorCodeString(err));
834 return false;
835 }
836
837 err = zip_writer->WriteBytes(content.c_str(), content.length());
838 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800839 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800840 ZipWriter::ErrorCodeString(err));
841 return false;
842 }
843
844 err = zip_writer->FinishEntry();
845 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800846 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800847 return false;
848 }
849
850 return true;
851}
852
Felipe Lemec0808152016-06-17 17:37:13 -0700853static void dump_iptables() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700854 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
855 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
856 RunCommand("IPTABLE NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700857 /* no ip6 nat */
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700858 RunCommand("IPTABLE MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
859 RunCommand("IP6TABLE MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
860 RunCommand("IPTABLE RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
861 RunCommand("IP6TABLE RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700862}
863
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800864static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme678727a2016-09-21 17:22:11 -0700865 DurationReporter durationReporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800866 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700867
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700868 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700869 RunCommand("UPTIME", {"uptime"});
Mark Salyzyn326842f2015-04-30 09:49:41 -0700870 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800871 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700872 DumpFile("MEMORY INFO", "/proc/meminfo");
873 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700874 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700875 RunCommand("PROCRANK", {"procrank"}, CommandOptions::AS_ROOT_20);
876 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
877 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
878 DumpFile("SLAB INFO", "/proc/slabinfo");
879 DumpFile("ZONEINFO", "/proc/zoneinfo");
880 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
881 DumpFile("BUDDYINFO", "/proc/buddyinfo");
882 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700883
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700884 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
885 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
886 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700887
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700888 RunCommand("PROCESSES AND THREADS",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700889 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700890 RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT_10);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700891
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700892 RunCommand("PRINTENV", {"printenv"});
893 RunCommand("NETSTAT", {"netstat", "-n"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700894 struct stat s;
895 if (stat("/proc/modules", &s) != 0) {
896 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
897 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700898 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700899 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000900
Colin Crossf45fa6b2012-03-26 12:38:26 -0700901 do_dmesg();
902
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700903 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT_10);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700904 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
905 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800906 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700907
Ajay Panickerd886ec42016-09-14 12:26:46 -0700908 /* Dump Bluetooth HCI logs */
909 add_dir("/data/misc/bluetooth/logs", true);
910
Felipe Leme6e01fa62015-11-11 19:35:14 -0800911 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800912 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800913 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800914 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700915 }
916
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700917 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700918 // calculate timeout
919 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
920 if (timeout < 20000) {
921 timeout = 20000;
922 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700923 RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700924 CommandOptions::WithTimeout(timeout / 1000).Build());
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800925 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700926 if (timeout < 20000) {
927 timeout = 20000;
928 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700929 RunCommand("EVENT LOG",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700930 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
931 CommandOptions::WithTimeout(timeout / 1000).Build());
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700932 timeout = logcat_timeout("radio");
933 if (timeout < 20000) {
934 timeout = 20000;
935 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700936 RunCommand("RADIO LOG",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700937 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
938 CommandOptions::WithTimeout(timeout / 1000).Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700939
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700940 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
Mark Salyzynecc07632015-07-30 14:57:09 -0700941
Colin Crossf45fa6b2012-03-26 12:38:26 -0700942 /* show the traces we collected in main(), if that was done */
943 if (dump_traces_path != NULL) {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700944 DumpFile("VM TRACES JUST NOW", dump_traces_path);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700945 }
946
947 /* only show ANR traces if they're less than 15 minutes old */
948 struct stat st;
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700949 std::string anrTracesPath = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
950 if (anrTracesPath.empty()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700951 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700952 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700953 int fd = TEMP_FAILURE_RETRY(
954 open(anrTracesPath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
955 if (fd < 0) {
956 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anrTracesPath.c_str(), strerror(errno));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700957 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700958 dump_file_from_fd("VM TRACES AT LAST ANR", anrTracesPath.c_str(), fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700959 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700960 }
961
962 /* slow traces for slow operations */
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700963 if (!anrTracesPath.empty()) {
964 int tail = anrTracesPath.size() - 1;
965 while (tail > 0 && anrTracesPath.at(tail) != '/') {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700966 tail--;
967 }
968 int i = 0;
969 while (1) {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700970 anrTracesPath =
971 anrTracesPath.substr(0, tail + 1) + android::base::StringPrintf("slow%02d.txt", i);
972 if (stat(anrTracesPath.c_str(), &st)) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700973 // No traces file at this index, done with the files.
974 break;
975 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700976 DumpFile("VM TRACES WHEN SLOW", anrTracesPath.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700977 i++;
978 }
979 }
980
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700981 int dumped = 0;
982 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
983 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800984 const char *name = tombstone_data[i].name;
985 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700986 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800987 if (zip_writer) {
988 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800989 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800990 }
991 } else {
992 dump_file_from_fd("TOMBSTONE", name, fd);
993 }
994 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700995 tombstone_data[i].fd = -1;
996 }
997 }
998 if (!dumped) {
999 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1000 }
1001
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001002 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1003 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1004 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1005 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1006 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001007
Todd Poynor2a83daa2013-11-22 15:44:22 -08001008 if (!stat(PSTORE_LAST_KMSG, &st)) {
1009 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001010 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzyn7d0a7622016-06-24 14:06:15 -07001011 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001012 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -08001013 } else {
1014 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001015 DumpFile("LAST KMSG", "/proc/last_kmsg");
Todd Poynor2a83daa2013-11-22 15:44:22 -08001016 }
1017
Mark Salyzyn2262c162014-12-16 09:09:26 -08001018 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001019 RunCommand("LAST LOGCAT",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001020 {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
Mark Salyzyn2262c162014-12-16 09:09:26 -08001021
Colin Crossf45fa6b2012-03-26 12:38:26 -07001022 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -08001023
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001024 RunCommand("NETWORK INTERFACES", {"ip", "link"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001025
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001026 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1027 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001028
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001029 RunCommand("IP RULES", {"ip", "rule", "show"});
1030 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001031
1032 dump_route_tables();
1033
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001034 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1035 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1036 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
1037 RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001038 CommandOptions::WithTimeout(20).Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001039
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001040#ifdef FWDUMP_bcmdhd
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001041 RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001042
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001043 RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, CommandOptions::AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001044
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001045 RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001046
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001047#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001048 DumpFile("INTERRUPTS (1)", "/proc/interrupts");
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001049
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001050 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001051 CommandOptions::WithTimeout(10).Build());
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001052
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001053#ifdef FWDUMP_bcmdhd
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001054 RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, CommandOptions::AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001055
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001056 RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, CommandOptions::AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001057
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001058 RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001059#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001060 DumpFile("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001061
1062 print_properties();
1063
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001064 RunCommand("VOLD DUMP", {"vdc", "dump"});
1065 RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001066
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001067 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001068
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001069 RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001070
1071 printf("------ BACKLIGHTS ------\n");
1072 printf("LCD brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001073 DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001074 printf("Button brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001075 DumpFile("", "/sys/class/leds/button-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001076 printf("Keyboard brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001077 DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001078 printf("ALS mode=");
Felipe Leme678727a2016-09-21 17:22:11 -07001079 DumpFile("", "/sys/class/leds/lcd-backlight/als");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001080 printf("LCD driver registers:\n");
Felipe Leme678727a2016-09-21 17:22:11 -07001081 DumpFile("", "/sys/class/leds/lcd-backlight/registers");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001082 printf("\n");
1083
1084 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001085 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1086 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1087 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1088 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1089 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001090
Colin Crossf45fa6b2012-03-26 12:38:26 -07001091 printf("========================================================\n");
1092 printf("== Board\n");
1093 printf("========================================================\n");
1094
Felipe Leme0bcc7ca2016-09-13 16:45:56 -07001095 {
1096 DurationReporter tmpDr("dumpstate_board()");
1097 dumpstate_board();
1098 printf("\n");
1099 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001100
1101 /* Migrate the ril_dumpstate to a dumpstate_board()? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001102 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1103 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001104 // su does not exist on user builds, so try running without it.
1105 // This way any implementations of vril-dump that do not require
1106 // root can run on user builds.
1107 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001108 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Leme6ad9c062016-09-28 11:58:36 -07001109 if (!IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001110 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001111 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001112 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001113 }
1114
1115 printf("========================================================\n");
1116 printf("== Android Framework Services\n");
1117 printf("========================================================\n");
1118
Felipe Leme5bcce572016-09-27 09:21:08 -07001119 RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
1120 10);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001121
1122 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001123 printf("== Checkins\n");
1124 printf("========================================================\n");
1125
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001126 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1127 RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
1128 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1129 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1130 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1131 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001132
1133 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001134 printf("== Running Application Activities\n");
1135 printf("========================================================\n");
1136
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001137 RunDumpsys("APP ACTIVITIES", {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001138
1139 printf("========================================================\n");
1140 printf("== Running Application Services\n");
1141 printf("========================================================\n");
1142
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001143 RunDumpsys("APP SERVICES", {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001144
1145 printf("========================================================\n");
1146 printf("== Running Application Providers\n");
1147 printf("========================================================\n");
1148
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001149 RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001150
1151 printf("========================================================\n");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001152 printf("== Final progress (pid %d): %d/%d (originally %d)\n", getpid(), ds.progress_,
1153 ds.weightTotal_, WEIGHT_TOTAL);
Felipe Leme608385d2016-02-01 10:35:38 -08001154 printf("========================================================\n");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001155 printf("== dumpstate: done (id %lu)\n", ds.id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001156 printf("========================================================\n");
1157}
1158
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001159static void ShowUsageAndExit(int exitCode = 1) {
1160 fprintf(stderr,
1161 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1162 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1163 " -h: display this help message\n"
1164 " -b: play sound file instead of vibrate, at beginning of job\n"
1165 " -e: play sound file instead of vibrate, at end of job\n"
1166 " -o: write to file (instead of stdout)\n"
1167 " -d: append date to filename (requires -o)\n"
1168 " -p: capture screenshot to filename.png (requires -o)\n"
1169 " -z: generate zipped file (requires -o)\n"
1170 " -s: write output to control socket (for init)\n"
1171 " -S: write file location to control socket (for init; requires -o and -z)"
1172 " -q: disable vibrate\n"
1173 " -B: send broadcast when finished (requires -o)\n"
1174 " -P: send broadcast when started and update system properties on "
1175 "progress (requires -o and -B)\n"
1176 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1177 "shouldn't be used with -P)\n"
1178 " -V: sets the bugreport format version (valid values: %s)\n",
1179 VERSION_DEFAULT.c_str());
1180 exit(exitCode);
1181}
1182
1183static void ExitOnInvalidArgs() {
1184 fprintf(stderr, "invalid combination of args\n");
1185 ShowUsageAndExit();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001186}
1187
Wei Liuf87959e2016-08-26 14:51:42 -07001188static void wake_lock_releaser() {
1189 if (release_wake_lock(WAKE_LOCK_NAME) < 0) {
1190 MYLOGE("Failed to release wake lock: %s \n", strerror(errno));
1191 } else {
1192 MYLOGD("Wake lock released.\n");
1193 }
1194}
1195
1196static void sig_handler(int signo) {
1197 wake_lock_releaser();
Andres Morales2e671bb2014-08-21 12:38:22 -07001198 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001199}
1200
Wei Liuf87959e2016-08-26 14:51:42 -07001201static void register_sig_handler() {
1202 struct sigaction sa;
1203 sigemptyset(&sa.sa_mask);
1204 sa.sa_flags = 0;
1205 sa.sa_handler = sig_handler;
1206 sigaction(SIGPIPE, &sa, NULL); // broken pipe
1207 sigaction(SIGSEGV, &sa, NULL); // segment fault
1208 sigaction(SIGINT, &sa, NULL); // ctrl-c
1209 sigaction(SIGTERM, &sa, NULL); // killed
1210 sigaction(SIGQUIT, &sa, NULL); // quit
1211}
1212
Felipe Leme1e9edc62015-12-21 16:02:13 -08001213/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1214 temporary file.
1215 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001216static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Lemee844a9d2016-09-21 15:01:39 -07001217 const std::string& log_path, time_t now) {
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001218 // Final timestamp
1219 char date[80];
1220 time_t the_real_now_please_stand_up = time(nullptr);
1221 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Lemee844a9d2016-09-21 15:01:39 -07001222 MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date,
1223 the_real_now_please_stand_up - now);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001224
Felipe Lemee82a27d2016-01-05 13:35:44 -08001225 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001226 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001227 return false;
1228 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001229 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001230 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001231 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001232 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001233
Felipe Leme0f3fb202016-06-10 17:10:53 -07001234 // Add log file (which contains stderr output) to zip...
1235 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
1236 if (!add_zip_entry("dumpstate_log.txt", log_path.c_str())) {
1237 MYLOGE("Failed to add dumpstate log to .zip file\n");
1238 return false;
1239 }
1240 // ... and re-opens it for further logging.
1241 redirect_to_existing_file(stderr, const_cast<char*>(log_path.c_str()));
1242 fprintf(stderr, "\n");
1243
Felipe Lemee82a27d2016-01-05 13:35:44 -08001244 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001245 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001246 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001247 return false;
1248 }
1249
Felipe Leme6ad9c062016-09-28 11:58:36 -07001250 if (IsUserBuild()) {
Felipe Lemec4eee562016-04-21 15:42:55 -07001251 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1252 if (remove(bugreport_path.c_str())) {
1253 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1254 }
1255 } else {
1256 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1257 }
1258
Felipe Leme1e9edc62015-12-21 16:02:13 -08001259 return true;
1260}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001261
Michal Karpinski4db754f2015-12-11 18:04:32 +00001262static std::string SHA256_file_hash(std::string filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001263 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1264 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001265 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001266 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001267 return NULL;
1268 }
1269
1270 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001271 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001272
1273 std::vector<uint8_t> buffer(65536);
1274 while (1) {
1275 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1276 if (bytes_read == 0) {
1277 break;
1278 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001279 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001280 return NULL;
1281 }
1282
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001283 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001284 }
1285
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001286 uint8_t hash[SHA256_DIGEST_LENGTH];
1287 SHA256_Final(hash, &ctx);
1288
1289 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1290 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001291 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001292 }
1293 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1294 return std::string(hash_buffer);
1295}
1296
Colin Crossf45fa6b2012-03-26 12:38:26 -07001297int main(int argc, char *argv[]) {
1298 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001299 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001300 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001301 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001302 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001303 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001304 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001305 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001306 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001307 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001308 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001309
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001310 now = time(nullptr);
Felipe Lemee82a27d2016-01-05 13:35:44 -08001311
Felipe Lemecbce55d2016-02-08 09:53:18 -08001312 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001313
Wei Liuf87959e2016-08-26 14:51:42 -07001314 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
1315 MYLOGE("Failed to acquire wake lock: %s \n", strerror(errno));
1316 } else {
1317 MYLOGD("Wake lock acquired.\n");
1318 atexit(wake_lock_releaser);
1319 register_sig_handler();
1320 }
1321
Felipe Lemee844a9d2016-09-21 15:01:39 -07001322 ds.dryRun_ = android::base::GetBoolProperty("dumpstate.dry_run", false);
1323 if (ds.dryRun_) {
Felipe Leme8268ed22016-08-02 18:18:25 -07001324 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
1325 }
1326
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001327 // TODO: use helper function to convert argv into a string
Felipe Leme30dbfa12016-09-02 12:43:26 -07001328 for (int i = 0; i < argc; i++) {
1329 args += argv[i];
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001330 if (i < argc - 1) {
1331 args += " ";
1332 }
Felipe Leme30dbfa12016-09-02 12:43:26 -07001333 }
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001334
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001335 extraOptions = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
1336 MYLOGI("Dumpstate args: %s (extra options: %s)\n", args.c_str(), extraOptions.c_str());
Felipe Leme30dbfa12016-09-02 12:43:26 -07001337
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001338 /* gets the sequential id */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001339 int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Felipe Lemee844a9d2016-09-21 15:01:39 -07001340 ds.id_ = ++lastId;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001341 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(lastId));
Felipe Lemee844a9d2016-09-21 15:01:39 -07001342 MYLOGI("dumpstate id: %lu\n", ds.id_);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001343
Colin Crossf45fa6b2012-03-26 12:38:26 -07001344 /* set as high priority, and protect from OOM killer */
1345 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001346
1347 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001348 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001349 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001350 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001351 } else {
1352 /* fallback to kernels <= 2.6.35 */
1353 oom_adj = fopen("/proc/self/oom_adj", "we");
1354 if (oom_adj) {
1355 fputs("-17", oom_adj);
1356 fclose(oom_adj);
1357 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001358 }
1359
Jeff Brown1dc94e32014-09-11 14:15:27 -07001360 /* parse arguments */
Colin Crossf45fa6b2012-03-26 12:38:26 -07001361 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001362 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001363 switch (c) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001364 // clang-format off
Felipe Leme71bbfc52015-11-23 14:14:51 -08001365 case 'd': do_add_date = 1; break;
1366 case 'z': do_zip_file = 1; break;
1367 case 'o': use_outfile = optarg; break;
1368 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001369 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001370 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001371 case 'q': do_vibrate = 0; break;
1372 case 'p': do_fb = 1; break;
Felipe Lemee844a9d2016-09-21 15:01:39 -07001373 case 'P': ds.updateProgress_ = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001374 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001375 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001376 case 'V': version = optarg; break;
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001377 case 'h':
1378 ShowUsageAndExit(0);
1379 break;
1380 default:
1381 fprintf(stderr, "Invalid option: %c\n", c);
1382 ShowUsageAndExit();
Felipe Lemee844a9d2016-09-21 15:01:39 -07001383 // clang-format on
Colin Crossf45fa6b2012-03-26 12:38:26 -07001384 }
1385 }
1386
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001387 if (!extraOptions.empty()) {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001388 // Framework uses a system property to override some command-line args.
1389 // Currently, it contains the type of the requested bugreport.
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001390 if (extraOptions == "bugreportplus") {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001391 MYLOGD("Running as bugreportplus: add -P, remove -p\n");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001392 ds.updateProgress_ = 1;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001393 do_fb = 0;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001394 } else if (extraOptions == "bugreportremote") {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001395 MYLOGD("Running as bugreportremote: add -q -R, remove -p\n");
1396 do_vibrate = 0;
1397 is_remote_mode = 1;
1398 do_fb = 0;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001399 } else if (extraOptions == "bugreportwear") {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001400 MYLOGD("Running as bugreportwear: add -P\n");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001401 ds.updateProgress_ = 1;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001402 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001403 MYLOGE("Unknown extra option: %s\n", extraOptions.c_str());
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001404 }
1405 // Reset the property
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001406 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001407 }
1408
Felipe Lemee844a9d2016-09-21 15:01:39 -07001409 if ((do_zip_file || do_add_date || ds.updateProgress_ || do_broadcast) && !use_outfile) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001410 ExitOnInvalidArgs();
Felipe Leme6e01fa62015-11-11 19:35:14 -08001411 }
1412
Felipe Leme2628e9e2016-04-12 16:36:51 -07001413 if (use_control_socket && !do_zip_file) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001414 ExitOnInvalidArgs();
Felipe Leme2628e9e2016-04-12 16:36:51 -07001415 }
1416
Felipe Lemee844a9d2016-09-21 15:01:39 -07001417 if (ds.updateProgress_ && !do_broadcast) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001418 ExitOnInvalidArgs();
Felipe Leme71bbfc52015-11-23 14:14:51 -08001419 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001420
Felipe Lemee844a9d2016-09-21 15:01:39 -07001421 if (is_remote_mode && (ds.updateProgress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001422 ExitOnInvalidArgs();
Michal Karpinski4db754f2015-12-11 18:04:32 +00001423 }
1424
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001425 if (version != VERSION_DEFAULT) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001426 ShowUsageAndExit();
Felipe Leme809d74e2016-02-02 12:57:00 -08001427 }
1428
Felipe Lemecbce55d2016-02-08 09:53:18 -08001429 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001430
Felipe Lemee844a9d2016-09-21 15:01:39 -07001431 do_early_screenshot = ds.updateProgress_;
Felipe Lemee338bf62015-12-07 14:03:50 -08001432
Christopher Ferrised9354f2014-10-01 17:35:01 -07001433 // If we are going to use a socket, do it as early as possible
1434 // to avoid timeouts from bugreport.
1435 if (use_socket) {
1436 redirect_to_socket(stdout, "dumpstate");
1437 }
1438
Felipe Leme2628e9e2016-04-12 16:36:51 -07001439 if (use_control_socket) {
1440 MYLOGD("Opening control socket\n");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001441 ds.controlSocketFd_ = open_socket("dumpstate");
1442 ds.updateProgress_ = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001443 }
1444
Felipe Lemecbce55d2016-02-08 09:53:18 -08001445 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001446 std::string tmp_path;
1447
Felipe Leme0f3fb202016-06-10 17:10:53 -07001448 /* full path of the file containing the dumpstate logs */
Felipe Lemecbce55d2016-02-08 09:53:18 -08001449 std::string log_path;
1450
Felipe Leme14e034a2016-03-30 18:51:03 -07001451 /* full path of the systrace file, when enabled */
1452 std::string systrace_path;
1453
Felipe Lemee338bf62015-12-07 14:03:50 -08001454 /* full path of the temporary file containing the screenshot (when requested) */
1455 std::string screenshot_path;
1456
Felipe Lemecbce55d2016-02-08 09:53:18 -08001457 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001458 std::string base_name;
1459
Felipe Leme71bbfc52015-11-23 14:14:51 -08001460 /* pointer to the actual path, be it zip or text */
1461 std::string path;
1462
Felipe Leme635ca312016-01-05 14:23:02 -08001463 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001464 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001465
Felipe Lemead5f6c42015-11-30 14:26:46 -08001466 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001467 bool is_redirecting = !use_socket && use_outfile;
1468
1469 if (is_redirecting) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001470 ds.bugreportDir_ = dirname(use_outfile);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001471 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001472 if (do_add_date) {
1473 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001474 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1475 suffix = date;
1476 } else {
1477 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001478 }
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001479 std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
1480 base_name = base_name + "-" + buildId;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001481 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001482 // TODO: if dumpstate was an object, the paths could be internal variables and then
1483 // we could have a function to calculate the derived values, such as:
1484 // screenshot_path = GetPath(".png");
Felipe Lemee844a9d2016-09-21 15:01:39 -07001485 screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001486 }
Felipe Lemee844a9d2016-09-21 15:01:39 -07001487 tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp";
1488 log_path =
1489 ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001490
Felipe Lemee844a9d2016-09-21 15:01:39 -07001491 MYLOGD(
1492 "Bugreport dir: %s\n"
1493 "Base name: %s\n"
1494 "Suffix: %s\n"
1495 "Log path: %s\n"
1496 "Temporary path: %s\n"
1497 "Screenshot path: %s\n",
1498 ds.bugreportDir_.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(),
1499 tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001500
Felipe Leme1e9edc62015-12-21 16:02:13 -08001501 if (do_zip_file) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001502 path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001503 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001504 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001505 zip_file.reset(fopen(path.c_str(), "wb"));
1506 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001507 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001508 do_zip_file = 0;
1509 } else {
1510 zip_writer.reset(new ZipWriter(zip_file.get()));
1511 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001512 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001513 }
1514
Felipe Lemee844a9d2016-09-21 15:01:39 -07001515 if (ds.updateProgress_) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001516 if (do_broadcast) {
1517 // clang-format off
1518 std::vector<std::string> am_args = {
1519 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1520 "--es", "android.intent.extra.NAME", suffix,
Felipe Lemee844a9d2016-09-21 15:01:39 -07001521 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001522 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1523 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1524 };
1525 // clang-format on
1526 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1527 }
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001528 if (use_control_socket) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001529 dprintf(ds.controlSocketFd_, "BEGIN:%s\n", path.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001530 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08001531 }
1532 }
1533
Nick Kralevichf3599b32016-01-25 15:05:16 -08001534 /* read /proc/cmdline before dropping root */
1535 FILE *cmdline = fopen("/proc/cmdline", "re");
1536 if (cmdline) {
1537 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1538 fclose(cmdline);
1539 }
1540
Jeff Brown1dc94e32014-09-11 14:15:27 -07001541 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001542 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001543 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001544 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001545 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001546 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001547 }
John Michelau1f794c42012-09-17 11:20:19 -05001548 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001549
Felipe Leme3634a1e2015-12-09 10:11:47 -08001550 if (do_fb && do_early_screenshot) {
1551 if (screenshot_path.empty()) {
1552 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001553 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001554 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001555 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001556 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001557 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001558 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001559 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001560 screenshot_path.c_str(), strerror(errno));
1561 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001562 }
1563 }
1564
Felipe Leme1e9edc62015-12-21 16:02:13 -08001565 if (do_zip_file) {
1566 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001567 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001568 }
1569 }
1570
Felipe Leme71bbfc52015-11-23 14:14:51 -08001571 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001572 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001573 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1574 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1575 log_path.c_str(), strerror(errno));
1576 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001577 /* TODO: rather than generating a text file now and zipping it later,
1578 it would be more efficient to redirect stdout to the zip entry
1579 directly, but the libziparchive doesn't support that option yet. */
1580 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001581 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1582 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1583 tmp_path.c_str(), strerror(errno));
1584 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001585 }
Felipe Leme608385d2016-02-01 10:35:38 -08001586 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1587 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001588 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001589 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001590
Felipe Leme71a74ac2016-03-17 15:43:25 -07001591 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001592 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1593 // the raw trace.
1594 if (!dump_anrd_trace()) {
1595 dump_systrace();
1596 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001597
Felipe Leme9c74aad2016-02-29 18:15:42 -08001598 // Invoking the following dumpsys calls before dump_traces() to try and
1599 // keep the system stats as close to its initial state as possible.
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001600 RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001601 CommandOptions::WithTimeout(90).DropRoot().Build());
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001602 RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001603 CommandOptions::WithTimeout(10).DropRoot().Build());
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001604
Felipe Lemee844a9d2016-09-21 15:01:39 -07001605 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1606 dump_raft();
1607
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001608 /* collect stack traces from Dalvik and native processes (needs root) */
1609 dump_traces_path = dump_traces();
1610
Felipe Lemec0808152016-06-17 17:37:13 -07001611 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001612 get_tombstone_fds(tombstone_data);
1613 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001614 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001615 add_dir(LOGPERSIST_DATA_DIR, false);
Felipe Leme6ad9c062016-09-28 11:58:36 -07001616 if (!IsUserBuild()) {
David Brazdild2991962016-06-03 14:40:44 +01001617 add_dir(PROFILE_DATA_DIR_CUR, true);
1618 add_dir(PROFILE_DATA_DIR_REF, true);
1619 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001620 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001621 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001622
Lorenzo Colittid3b809b2016-09-26 13:37:45 +09001623 // Run ss as root so we can see socket marks.
1624 run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
1625
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001626 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001627 return -1;
1628 }
1629
1630 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001631
Felipe Leme55b42a62015-11-10 17:39:08 -08001632 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001633 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001634 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001635 }
1636
Felipe Leme6e01fa62015-11-11 19:35:14 -08001637 /* rename or zip the (now complete) .tmp file to its final location */
1638 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001639
1640 /* check if user changed the suffix using system properties */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001641 std::string name = android::base::GetProperty(
1642 android::base::StringPrintf("dumpstate.%d.name", getpid()), "");
Felipe Lemead5f6c42015-11-30 14:26:46 -08001643 bool change_suffix= false;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001644 if (!name.empty()) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001645 /* must whitelist which characters are allowed, otherwise it could cross directories */
1646 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001647 if (std::regex_match(name.c_str(), valid_regex)) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001648 change_suffix = true;
1649 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001650 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001651 }
1652 }
1653 if (change_suffix) {
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001654 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), name.c_str());
1655 suffix = name;
Felipe Lemead5f6c42015-11-30 14:26:46 -08001656 if (!screenshot_path.empty()) {
1657 std::string new_screenshot_path =
Felipe Lemee844a9d2016-09-21 15:01:39 -07001658 ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
Felipe Lemead5f6c42015-11-30 14:26:46 -08001659 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001660 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001661 new_screenshot_path.c_str(), strerror(errno));
1662 } else {
1663 screenshot_path = new_screenshot_path;
1664 }
1665 }
1666 }
1667
Felipe Leme6e01fa62015-11-11 19:35:14 -08001668 bool do_text_file = true;
1669 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001670 std::string entry_name = base_name + "-" + suffix + ".txt";
1671 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
Felipe Leme0f3fb202016-06-10 17:10:53 -07001672 if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001673 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001674 do_text_file = true;
1675 } else {
1676 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001677 // Since zip file is already created, it needs to be renamed.
Felipe Lemee844a9d2016-09-21 15:01:39 -07001678 std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme91274352016-02-26 15:03:52 -08001679 if (path != new_path) {
1680 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1681 if (rename(path.c_str(), new_path.c_str())) {
1682 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1683 new_path.c_str(), strerror(errno));
1684 } else {
1685 path = new_path;
1686 }
1687 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001688 }
1689 }
1690 if (do_text_file) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001691 path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001692 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001693 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001694 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001695 path.clear();
1696 }
1697 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001698 if (use_control_socket) {
1699 if (do_text_file) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001700 dprintf(ds.controlSocketFd_,
1701 "FAIL:could not create zip file, check %s "
1702 "for more details\n",
1703 log_path.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001704 } else {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001705 dprintf(ds.controlSocketFd_, "OK:%s\n", path.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001706 }
1707 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001708 }
1709
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001710 /* vibrate a few but shortly times to let user know it's finished */
1711 if (vibrator) {
1712 for (int i = 0; i < 3; i++) {
1713 vibrate(vibrator.get(), 75);
1714 usleep((75 + 50) * 1000);
1715 }
1716 }
1717
Jeff Brown1dc94e32014-09-11 14:15:27 -07001718 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001719 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001720 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001721 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001722 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001723 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001724 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemee844a9d2016-09-21 15:01:39 -07001725 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001726 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemee844a9d2016-09-21 15:01:39 -07001727 "--ei", "android.intent.extra.MAX", std::to_string(ds.weightTotal_),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001728 "--es", "android.intent.extra.BUGREPORT", path,
1729 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001730 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001731 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001732 if (do_fb) {
1733 am_args.push_back("--es");
1734 am_args.push_back("android.intent.extra.SCREENSHOT");
1735 am_args.push_back(screenshot_path);
1736 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001737 if (is_remote_mode) {
1738 am_args.push_back("--es");
1739 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1740 am_args.push_back(SHA256_file_hash(path));
1741 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1742 } else {
1743 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1744 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001745 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001746 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001747 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001748 }
1749
Felipe Lemee844a9d2016-09-21 15:01:39 -07001750 MYLOGD("Final progress: %d/%d (originally %d)\n", ds.progress_, ds.weightTotal_, WEIGHT_TOTAL);
1751 MYLOGI("done (id %lu)\n", ds.id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001752
Felipe Leme107a05f2016-03-08 15:11:15 -08001753 if (is_redirecting) {
1754 fclose(stderr);
1755 }
1756
Felipe Lemee844a9d2016-09-21 15:01:39 -07001757 if (use_control_socket && ds.controlSocketFd_ != -1) {
1758 MYLOGD("Closing control socket\n");
1759 close(ds.controlSocketFd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001760 }
1761
Colin Crossf45fa6b2012-03-26 12:38:26 -07001762 return 0;
1763}