blob: 52c6e56b62f967089352bc6a36fa5ef76ced5c8c [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>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070025#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070026#include <stdio.h>
27#include <stdlib.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080028#include <string>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <string.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070030#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070031#include <sys/resource.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/wait.h>
35#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070036
Elliott Hughes9dc117c2015-12-07 14:21:50 -080037#include <android-base/stringprintf.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070038#include <android-base/unique_fd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070039#include <cutils/properties.h>
40
41#include "private/android_filesystem_config.h"
42
43#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070044#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070045
46#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080047#include "ziparchive/zip_writer.h"
48
Elliott Hughesc4dc1412016-04-12 16:28:31 -070049#include <openssl/sha.h>
Michal Karpinski4db754f2015-12-11 18:04:32 +000050
Felipe Leme6e01fa62015-11-11 19:35:14 -080051using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070052
53/* read before root is shed */
54static char cmdline_buf[16384] = "(unknown)";
55static const char *dump_traces_path = NULL;
56
Felipe Lemeefd7e272016-05-18 09:27:16 -070057// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080058static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080059static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080060static time_t now;
61static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080062static std::set<std::string> mount_points;
63void add_mountinfo();
Felipe Leme02b7e002016-07-22 12:03:20 -070064int control_socket_fd = -1;
Felipe Lemeefd7e272016-05-18 09:27:16 -070065/* suffix of the bugreport files - it's typically the date (when invoked with -d),
66 * although it could be changed by the user using a system property */
67static std::string suffix;
Felipe Leme8268ed22016-08-02 18:18:25 -070068static bool dry_run = false;
Felipe Leme78f2c862015-12-21 09:55:22 -080069
Todd Poynor2a83daa2013-11-22 15:44:22 -080070#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -070071#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080072
Wei Liu341938b2016-04-27 16:18:17 -070073#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080074#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070075#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070076#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010077#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
78#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070079#define TOMBSTONE_DIR "/data/tombstones"
80#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
81/* Can accomodate a tombstone number up to 9999. */
82#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
83#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090084#define WLUTIL "/vendor/xbin/wlutil"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070085
86typedef struct {
87 char name[TOMBSTONE_MAX_LEN];
88 int fd;
89} tombstone_data_t;
90
91static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
92
Felipe Leme71ca15e2016-05-19 16:18:17 -070093const std::string ZIP_ROOT_DIR = "FS";
94std::string bugreport_dir;
Felipe Lemee82a27d2016-01-05 13:35:44 -080095
Felipe Leme809d74e2016-02-02 12:57:00 -080096/*
97 * List of supported zip format versions.
98 *
Felipe Leme8268ed22016-08-02 18:18:25 -070099 * See bugreport-format.md for more info.
Felipe Leme809d74e2016-02-02 12:57:00 -0800100 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -0700101static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800102
Calvin On249beee2016-06-03 15:17:07 -0700103bool is_user_build() {
Felipe Lemec4eee562016-04-21 15:42:55 -0700104 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
105}
106
Felipe Leme8268ed22016-08-02 18:18:25 -0700107bool is_dry_run() {
108 return dry_run;
109}
110
Felipe Leme3d305a12016-05-20 11:24:37 -0700111/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
112 * otherwise, gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700113static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800114 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700115 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
116 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800117 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
118 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700119 struct stat st;
Felipe Leme3d305a12016-05-20 11:24:37 -0700120 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800121 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
Felipe Leme3d305a12016-05-20 11:24:37 -0700122 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700123 } else {
Felipe Leme3d305a12016-05-20 11:24:37 -0700124 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700125 data[i].fd = -1;
126 }
127 }
128}
129
Felipe Leme635ca312016-01-05 14:23:02 -0800130// for_each_pid() callback to get mount info about a process.
131void do_mountinfo(int pid, const char *name) {
132 char path[PATH_MAX];
133
134 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
135 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700136 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800137 char linkname[PATH_MAX];
138 ssize_t r = readlink(path, linkname, PATH_MAX);
139 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800140 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800141 return;
142 }
143 linkname[r] = '\0';
144
145 if (mount_points.find(linkname) == mount_points.end()) {
146 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700147 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800148 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
149 mount_points.insert(linkname);
150 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800151 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800152 }
153 }
154}
155
156void add_mountinfo() {
157 if (!zip_writer) return;
158 const char *title = "MOUNT INFO";
159 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800160 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800161 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800162 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800163}
164
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700165static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
166{
167 DIR *d;
168 struct dirent *de;
169 char path[PATH_MAX];
170
171 d = opendir(driverpath);
172 if (d == NULL) {
173 return;
174 }
175
176 while ((de = readdir(d))) {
177 if (de->d_type != DT_LNK) {
178 continue;
179 }
180 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
181 dump_file(title, path);
182 }
183
184 closedir(d);
185}
186
Felipe Lemeefd7e272016-05-18 09:27:16 -0700187static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700188 if (!zip_writer) {
189 MYLOGD("Not dumping systrace because zip_writer is not set\n");
190 return;
191 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700192 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700193 if (systrace_path.empty()) {
194 MYLOGE("Not dumping systrace because path is empty\n");
195 return;
196 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700197 const char* path = "/sys/kernel/debug/tracing/tracing_on";
198 long int is_tracing;
199 if (read_file_as_long(path, &is_tracing)) {
200 return; // error already logged
201 }
202 if (is_tracing <= 0) {
203 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
204 return;
205 }
206
Felipe Leme14e034a2016-03-30 18:51:03 -0700207 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
208 systrace_path.c_str());
209 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
210 systrace_path.c_str(), NULL)) {
211 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
212 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
213 // we should call strace to stop itself, but there is no such option yet (just a
214 // --async_stop, which stops and dump
215 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
216 // MYLOGE("could not stop systrace ");
217 // }
218 }
219 if (!add_zip_entry("systrace.txt", systrace_path)) {
220 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700221 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700222 if (remove(systrace_path.c_str())) {
223 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
224 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700225 }
226}
227
Felipe Lemeefd7e272016-05-18 09:27:16 -0700228static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700229 if (is_user_build()) {
230 return;
231 }
232
Felipe Lemeefd7e272016-05-18 09:27:16 -0700233 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700234 if (raft_log_path.empty()) {
235 MYLOGD("raft_log_path is empty\n");
236 return;
237 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700238
239 struct stat s;
240 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
241 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
242 return;
243 }
244
Wei Liu341938b2016-04-27 16:18:17 -0700245 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700246 // Write compressed and encoded raft logs to stdout if not zip_writer.
247 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700248 return;
249 }
250
251 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
252 "-o", raft_log_path.c_str(), NULL);
253 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
254 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
255 } else {
256 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700257 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700258 }
259 }
260}
261
Mark Salyzyn326842f2015-04-30 09:49:41 -0700262static bool skip_not_stat(const char *path) {
263 static const char stat[] = "/stat";
264 size_t len = strlen(path);
265 if (path[len - 1] == '/') { /* Directory? */
266 return false;
267 }
268 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
269}
270
Felipe Lemee82a27d2016-01-05 13:35:44 -0800271static bool skip_none(const char *path) {
272 return false;
273}
274
Felipe Lemedc42bda2016-06-30 14:27:04 -0700275static void _run_dumpsys(const std::string& title, RootMode root_mode, int timeout_seconds,
276 const std::vector<std::string>& args) {
277 DurationReporter duration_reporter(title.c_str());
278
279 std::string timeout_string = std::to_string(timeout_seconds);
280
281 const char *dumpsys_args[ARG_MAX] = { "/system/bin/dumpsys", "-t", timeout_string.c_str()};
282
283 int index = 3; // 'dumpsys' '-t' 'TIMEOUT'
284 for (const std::string& arg : args) {
285 if (index > ARG_MAX - 2) {
286 MYLOGE("Too many arguments for '%s': %d\n", title.c_str(), (int) args.size());
287 return;
288 }
289 dumpsys_args[index++] = arg.c_str();
290 }
291 // Always terminate with nullptr.
292 dumpsys_args[index] = nullptr;
293
294 std::string args_string;
295 format_args(index, dumpsys_args, &args_string);
296 printf("------ %s (%s) ------\n", title.c_str(), args_string.c_str());
297 fflush(stdout);
298
299 ON_DRY_RUN({ update_progress(timeout_seconds); return; });
300
301 run_command_always(title.c_str(), root_mode, NORMAL_STDOUT, timeout_seconds, dumpsys_args);
302}
303
304static void run_dumpsys(const std::string& title, int timeout_seconds,
305 const std::vector<std::string>& args) {
306 _run_dumpsys(title, DONT_DROP_ROOT, timeout_seconds, args);
307}
308
309static void run_dumpsys_as_shell(const std::string& title, int timeout_seconds,
310 const std::vector<std::string>& args) {
311 _run_dumpsys(title, DROP_ROOT, timeout_seconds, args);
312}
313
Mark Salyzyn326842f2015-04-30 09:49:41 -0700314static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700315unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700316
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800317//
318// stat offsets
319// Name units description
320// ---- ----- -----------
321// read I/Os requests number of read I/Os processed
322#define __STAT_READ_IOS 0
323// read merges requests number of read I/Os merged with in-queue I/O
324#define __STAT_READ_MERGES 1
325// read sectors sectors number of sectors read
326#define __STAT_READ_SECTORS 2
327// read ticks milliseconds total wait time for read requests
328#define __STAT_READ_TICKS 3
329// write I/Os requests number of write I/Os processed
330#define __STAT_WRITE_IOS 4
331// write merges requests number of write I/Os merged with in-queue I/O
332#define __STAT_WRITE_MERGES 5
333// write sectors sectors number of sectors written
334#define __STAT_WRITE_SECTORS 6
335// write ticks milliseconds total wait time for write requests
336#define __STAT_WRITE_TICKS 7
337// in_flight requests number of I/Os currently in flight
338#define __STAT_IN_FLIGHT 8
339// io_ticks milliseconds total time this block device has been active
340#define __STAT_IO_TICKS 9
341// time_in_queue milliseconds total wait time for all requests
342#define __STAT_IN_QUEUE 10
343#define __STAT_NUMBER_FIELD 11
344//
345// read I/Os, write I/Os
346// =====================
347//
348// These values increment when an I/O request completes.
349//
350// read merges, write merges
351// =========================
352//
353// These values increment when an I/O request is merged with an
354// already-queued I/O request.
355//
356// read sectors, write sectors
357// ===========================
358//
359// These values count the number of sectors read from or written to this
360// block device. The "sectors" in question are the standard UNIX 512-byte
361// sectors, not any device- or filesystem-specific block size. The
362// counters are incremented when the I/O completes.
363#define SECTOR_SIZE 512
364//
365// read ticks, write ticks
366// =======================
367//
368// These values count the number of milliseconds that I/O requests have
369// waited on this block device. If there are multiple I/O requests waiting,
370// these values will increase at a rate greater than 1000/second; for
371// example, if 60 read requests wait for an average of 30 ms, the read_ticks
372// field will increase by 60*30 = 1800.
373//
374// in_flight
375// =========
376//
377// This value counts the number of I/O requests that have been issued to
378// the device driver but have not yet completed. It does not include I/O
379// requests that are in the queue but not yet issued to the device driver.
380//
381// io_ticks
382// ========
383//
384// This value counts the number of milliseconds during which the device has
385// had I/O requests queued.
386//
387// time_in_queue
388// =============
389//
390// This value counts the number of milliseconds that I/O requests have waited
391// on this block device. If there are multiple I/O requests waiting, this
392// value will increase as the product of the number of milliseconds times the
393// number of requests waiting (see "read ticks" above for an example).
394#define S_TO_MS 1000
395//
396
Mark Salyzyn326842f2015-04-30 09:49:41 -0700397static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800398 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700399 bool z;
400 char *cp, *buffer = NULL;
401 size_t i = 0;
402 FILE *fp = fdopen(fd, "rb");
403 getline(&buffer, &i, fp);
404 fclose(fp);
405 if (!buffer) {
406 return -errno;
407 }
408 i = strlen(buffer);
409 while ((i > 0) && (buffer[i - 1] == '\n')) {
410 buffer[--i] = '\0';
411 }
412 if (!*buffer) {
413 free(buffer);
414 return 0;
415 }
416 z = true;
417 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800418 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700419 if (fields[i] != 0) {
420 z = false;
421 }
422 }
423 if (z) { /* never accessed */
424 free(buffer);
425 return 0;
426 }
427
428 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
429 path += sizeof(mmcblk0) - 1;
430 }
431
432 printf("%s: %s\n", path, buffer);
433 free(buffer);
434
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800435 if (fields[__STAT_IO_TICKS]) {
436 unsigned long read_perf = 0;
437 unsigned long read_ios = 0;
438 if (fields[__STAT_READ_TICKS]) {
439 unsigned long long divisor = fields[__STAT_READ_TICKS]
440 * fields[__STAT_IO_TICKS];
441 read_perf = ((unsigned long long)SECTOR_SIZE
442 * fields[__STAT_READ_SECTORS]
443 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
444 / divisor;
445 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
446 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
447 / divisor;
448 }
449
450 unsigned long write_perf = 0;
451 unsigned long write_ios = 0;
452 if (fields[__STAT_WRITE_TICKS]) {
453 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
454 * fields[__STAT_IO_TICKS];
455 write_perf = ((unsigned long long)SECTOR_SIZE
456 * fields[__STAT_WRITE_SECTORS]
457 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
458 / divisor;
459 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
460 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
461 / divisor;
462 }
463
464 unsigned queue = (fields[__STAT_IN_QUEUE]
465 + (fields[__STAT_IO_TICKS] >> 1))
466 / fields[__STAT_IO_TICKS];
467
468 if (!write_perf && !write_ios) {
469 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
470 path, read_perf, read_ios, queue);
471 } else {
472 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
473 path, read_perf, read_ios, write_perf, write_ios, queue);
474 }
475
476 /* bugreport timeout factor adjustment */
477 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
478 worst_write_perf = write_perf;
479 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700480 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700481 return 0;
482}
483
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700484/* Copied policy from system/core/logd/LogBuffer.cpp */
485
486#define LOG_BUFFER_SIZE (256 * 1024)
487#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
488#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
489
490static bool valid_size(unsigned long value) {
491 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
492 return false;
493 }
494
495 long pages = sysconf(_SC_PHYS_PAGES);
496 if (pages < 1) {
497 return true;
498 }
499
500 long pagesize = sysconf(_SC_PAGESIZE);
501 if (pagesize <= 1) {
502 pagesize = PAGE_SIZE;
503 }
504
505 // maximum memory impact a somewhat arbitrary ~3%
506 pages = (pages + 31) / 32;
507 unsigned long maximum = pages * pagesize;
508
509 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
510 return true;
511 }
512
513 return value <= maximum;
514}
515
516static unsigned long property_get_size(const char *key) {
517 unsigned long value;
518 char *cp, property[PROPERTY_VALUE_MAX];
519
520 property_get(key, property, "");
521 value = strtoul(property, &cp, 10);
522
523 switch(*cp) {
524 case 'm':
525 case 'M':
526 value *= 1024;
527 /* FALLTHRU */
528 case 'k':
529 case 'K':
530 value *= 1024;
531 /* FALLTHRU */
532 case '\0':
533 break;
534
535 default:
536 value = 0;
537 }
538
539 if (!valid_size(value)) {
540 value = 0;
541 }
542
543 return value;
544}
545
546/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800547static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700548 static const char global_tuneable[] = "persist.logd.size"; // Settings App
549 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
550 char key[PROP_NAME_MAX];
551 unsigned long property_size, default_size;
552
553 default_size = property_get_size(global_tuneable);
554 if (!default_size) {
555 default_size = property_get_size(global_default);
556 }
557
558 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
559 property_size = property_get_size(key);
560
561 if (!property_size) {
562 snprintf(key, sizeof(key), "%s.%s", global_default, name);
563 property_size = property_get_size(key);
564 }
565
566 if (!property_size) {
567 property_size = default_size;
568 }
569
570 if (!property_size) {
571 property_size = LOG_BUFFER_SIZE;
572 }
573
574 /* Engineering margin is ten-fold our guess */
575 return 10 * (property_size + worst_write_perf) / worst_write_perf;
576}
577
578/* End copy from system/core/logd/LogBuffer.cpp */
579
Colin Crossf45fa6b2012-03-26 12:38:26 -0700580/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800581static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700582 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
583 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
584 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700585
586 property_get("ro.build.display.id", build, "(unknown)");
587 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
588 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700589 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700590 property_get("ro.bootloader", bootloader, "(unknown)");
591 property_get("gsm.operator.alpha", network, "(unknown)");
592 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
593
594 printf("========================================================\n");
595 printf("== dumpstate: %s\n", date);
596 printf("========================================================\n");
597
598 printf("\n");
599 printf("Build: %s\n", build);
600 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
601 printf("Bootloader: %s\n", bootloader);
602 printf("Radio: %s\n", radio);
603 printf("Network: %s\n", network);
604
605 printf("Kernel: ");
606 dump_file(NULL, "/proc/version");
607 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800608 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800609 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700610 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800611}
612
Felipe Leme24b66ee2016-06-16 10:55:26 -0700613// List of file extensions that can cause a zip file attachment to be rejected by some email
614// service providers.
615static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
616 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
617 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
618 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
619};
620
Felipe Leme71ca15e2016-05-19 16:18:17 -0700621bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800622 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800623 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
624 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800625 return false;
626 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700627 std::string valid_name = entry_name;
628
629 // Rename extension if necessary.
630 size_t idx = entry_name.rfind(".");
631 if (idx != std::string::npos) {
632 std::string extension = entry_name.substr(idx);
633 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
634 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
635 valid_name = entry_name + ".renamed";
636 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
637 }
638 }
639
Felipe Leme6fe9db62016-02-12 09:04:16 -0800640 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
641 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700642 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800643 ZipWriter::kCompress, get_mtime(fd, now));
644 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700645 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800646 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800647 return false;
648 }
649
Felipe Leme770410d2016-01-26 17:07:14 -0800650 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800651 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800652 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
653 if (bytes_read == 0) {
654 break;
655 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800656 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800657 return false;
658 }
659 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
660 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800661 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800662 return false;
663 }
664 }
665
666 err = zip_writer->FinishEntry();
667 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800668 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800669 return false;
670 }
671
672 return true;
673}
674
Felipe Leme71ca15e2016-05-19 16:18:17 -0700675bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -0700676 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK
677 | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700678 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800679 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800680 return false;
681 }
682
683 return add_zip_entry_from_fd(entry_name, fd.get());
684}
685
686/* adds a file to the existing zipped bugreport */
687static int _add_file_from_fd(const char *title, const char *path, int fd) {
688 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
689}
690
Felipe Leme24b66ee2016-06-16 10:55:26 -0700691// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800692void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800693 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800694 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800695 return;
696 }
Felipe Leme88c79332016-02-22 11:06:49 -0800697 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800698 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800699 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
700}
701
Felipe Leme809d74e2016-02-02 12:57:00 -0800702/* adds a text entry entry to the existing zip file. */
703static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800704 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800705 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 -0800706 return false;
707 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800708 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800709 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
710 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800711 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800712 ZipWriter::ErrorCodeString(err));
713 return false;
714 }
715
716 err = zip_writer->WriteBytes(content.c_str(), content.length());
717 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800718 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800719 ZipWriter::ErrorCodeString(err));
720 return false;
721 }
722
723 err = zip_writer->FinishEntry();
724 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800725 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800726 return false;
727 }
728
729 return true;
730}
731
Felipe Lemec0808152016-06-17 17:37:13 -0700732static void dump_iptables() {
733 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
734 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
735 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
736 /* no ip6 nat */
737 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
738 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
739}
740
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800741static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800742 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800743 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700744
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700745 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700746 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700747 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800748 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700749 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughes52860032016-06-14 13:56:00 -0700750 run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
Elliott Hughes646e92f2016-06-13 17:35:07 -0700751 "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700752 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700753 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
754 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
755 dump_file("SLAB INFO", "/proc/slabinfo");
756 dump_file("ZONEINFO", "/proc/zoneinfo");
757 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
758 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700759 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700760
Todd Poynor29e27a82012-05-22 17:54:59 -0700761 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700762 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700763 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700764
Elliott Hughes52860032016-06-14 13:56:00 -0700765 run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
Elliott Hughes32caf1d2016-05-04 14:03:54 -0700766 "-O", "pri,nice,rtprio,sched,pcy", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800767 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700768
Michal Karpinski4db754f2015-12-11 18:04:32 +0000769 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900770 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Felipe Lemee4eca582016-06-10 17:48:08 -0700771 struct stat s;
772 if (stat("/proc/modules", &s) != 0) {
773 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
774 } else {
775 run_command("LSMOD", 10, "lsmod", NULL);
776 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000777
Colin Crossf45fa6b2012-03-26 12:38:26 -0700778 do_dmesg();
779
780 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700781 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
782 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800783 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700784
Felipe Leme6e01fa62015-11-11 19:35:14 -0800785 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800786 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800787 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800788 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700789 }
790
Colin Crossf45fa6b2012-03-26 12:38:26 -0700791 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700792 // calculate timeout
793 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
794 if (timeout < 20000) {
795 timeout = 20000;
796 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700797 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
798 "-v", "printable",
799 "-d",
800 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800801 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700802 if (timeout < 20000) {
803 timeout = 20000;
804 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700805 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
806 "-v", "threadtime",
807 "-v", "printable",
808 "-d",
809 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700810 timeout = logcat_timeout("radio");
811 if (timeout < 20000) {
812 timeout = 20000;
813 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700814 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
815 "-v", "threadtime",
816 "-v", "printable",
817 "-d",
818 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700819
Mark Salyzynecc07632015-07-30 14:57:09 -0700820 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
821
Colin Crossf45fa6b2012-03-26 12:38:26 -0700822 /* show the traces we collected in main(), if that was done */
823 if (dump_traces_path != NULL) {
824 dump_file("VM TRACES JUST NOW", dump_traces_path);
825 }
826
827 /* only show ANR traces if they're less than 15 minutes old */
828 struct stat st;
829 char anr_traces_path[PATH_MAX];
830 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
831 if (!anr_traces_path[0]) {
832 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700833 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800834 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
835 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700836 if (fd < 0) {
837 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
838 } else {
839 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
840 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700841 }
842
843 /* slow traces for slow operations */
844 if (anr_traces_path[0] != 0) {
845 int tail = strlen(anr_traces_path)-1;
846 while (tail > 0 && anr_traces_path[tail] != '/') {
847 tail--;
848 }
849 int i = 0;
850 while (1) {
851 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
852 if (stat(anr_traces_path, &st)) {
853 // No traces file at this index, done with the files.
854 break;
855 }
856 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
857 i++;
858 }
859 }
860
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700861 int dumped = 0;
862 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
863 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800864 const char *name = tombstone_data[i].name;
865 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700866 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800867 if (zip_writer) {
868 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800869 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800870 }
871 } else {
872 dump_file_from_fd("TOMBSTONE", name, fd);
873 }
874 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700875 tombstone_data[i].fd = -1;
876 }
877 }
878 if (!dumped) {
879 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
880 }
881
Colin Crossf45fa6b2012-03-26 12:38:26 -0700882 dump_file("NETWORK DEV INFO", "/proc/net/dev");
883 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700884 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700885 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
886 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
887
Todd Poynor2a83daa2013-11-22 15:44:22 -0800888 if (!stat(PSTORE_LAST_KMSG, &st)) {
889 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
890 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700891 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
892 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800893 } else {
894 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
895 dump_file("LAST KMSG", "/proc/last_kmsg");
896 }
897
Mark Salyzyn2262c162014-12-16 09:09:26 -0800898 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700899 run_command("LAST LOGCAT", 10, "logcat", "-L",
900 "-b", "all",
901 "-v", "threadtime",
902 "-v", "printable",
903 "-d",
904 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800905
Colin Crossf45fa6b2012-03-26 12:38:26 -0700906 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800907
908 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900909
910 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
911 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
912
Colin Crossf45fa6b2012-03-26 12:38:26 -0700913 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
914 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700915
916 dump_route_tables();
917
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900918 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
919 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +0900920 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700921 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700922
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800923#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900924 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +0900925 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900926
927 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900928 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900929
930 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900931 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900932
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800933#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800934 dump_file("INTERRUPTS (1)", "/proc/interrupts");
935
Felipe Lemedc42bda2016-06-30 14:27:04 -0700936 run_dumpsys("NETWORK DIAGNOSTICS", 10, {"connectivity", "--diag"});
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900937
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800938#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -0700939 run_command("DUMP WIFI STATUS", 20,
940 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900941
942 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900943 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900944
945 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900946 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700947#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800948 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700949
950 print_properties();
951
952 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
953 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
954
Ken Sumrall8f75fa72013-02-08 17:35:58 -0800955 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700956
Colin Crossf45fa6b2012-03-26 12:38:26 -0700957 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
958
959 printf("------ BACKLIGHTS ------\n");
960 printf("LCD brightness=");
961 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
962 printf("Button brightness=");
963 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
964 printf("Keyboard brightness=");
965 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
966 printf("ALS mode=");
967 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
968 printf("LCD driver registers:\n");
969 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
970 printf("\n");
971
972 /* Binder state is expensive to look at as it uses a lot of memory. */
973 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
974 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
975 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
976 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
977 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
978
Colin Crossf45fa6b2012-03-26 12:38:26 -0700979 printf("========================================================\n");
980 printf("== Board\n");
981 printf("========================================================\n");
982
983 dumpstate_board();
984 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700985
986 /* Migrate the ril_dumpstate to a dumpstate_board()? */
987 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
988 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
989 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -0700990 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700991 // su does not exist on user builds, so try running without it.
992 // This way any implementations of vril-dump that do not require
993 // root can run on user builds.
994 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
995 "vril-dump", NULL);
996 } else {
997 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
998 SU_PATH, "root", "vril-dump", NULL);
999 }
1000 }
1001
1002 printf("========================================================\n");
1003 printf("== Android Framework Services\n");
1004 printf("========================================================\n");
1005
Felipe Lemedc42bda2016-06-30 14:27:04 -07001006 run_dumpsys("DUMPSYS", 60, {"--skip", "meminfo", "cpuinfo"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001007
1008 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001009 printf("== Checkins\n");
1010 printf("========================================================\n");
1011
Felipe Lemedc42bda2016-06-30 14:27:04 -07001012 run_dumpsys("CHECKIN BATTERYSTATS", 30, {"batterystats", "-c"});
1013 run_dumpsys("CHECKIN MEMINFO", 30, {"meminfo", "--checkin"});
1014 run_dumpsys("CHECKIN NETSTATS", 30, {"netstats", "--checkin"});
1015 run_dumpsys("CHECKIN PROCSTATS", 30, {"procstats", "-c"});
1016 run_dumpsys("CHECKIN USAGESTATS", 30, {"usagestats", "-c"});
1017 run_dumpsys("CHECKIN PACKAGE", 30, {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001018
1019 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001020 printf("== Running Application Activities\n");
1021 printf("========================================================\n");
1022
Felipe Lemedc42bda2016-06-30 14:27:04 -07001023 run_dumpsys("APP ACTIVITIES", 30, {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001024
1025 printf("========================================================\n");
1026 printf("== Running Application Services\n");
1027 printf("========================================================\n");
1028
Felipe Lemedc42bda2016-06-30 14:27:04 -07001029 run_dumpsys("APP SERVICES", 30, {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001030
1031 printf("========================================================\n");
1032 printf("== Running Application Providers\n");
1033 printf("========================================================\n");
1034
Felipe Lemedc42bda2016-06-30 14:27:04 -07001035 run_dumpsys("APP PROVIDERS", 30, {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001036
1037
1038 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001039 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1040 getpid(), progress, weight_total, WEIGHT_TOTAL);
1041 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001042 printf("== dumpstate: done\n");
1043 printf("========================================================\n");
1044}
1045
1046static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001047 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001048 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1049 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1050 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001051 " -b: play sound file instead of vibrate, at beginning of job\n"
1052 " -e: play sound file instead of vibrate, at end of job\n"
1053 " -o: write to file (instead of stdout)\n"
1054 " -d: append date to filename (requires -o)\n"
1055 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001056 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001057 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001058 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001059 " -q: disable vibrate\n"
1060 " -B: send broadcast when finished (requires -o)\n"
1061 " -P: send broadcast when started and update system properties on "
1062 "progress (requires -o and -B)\n"
1063 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1064 "shouldn't be used with -P)\n"
1065 " -V: sets the bugreport format version (valid values: %s)\n",
1066 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001067}
1068
John Michelau885f8882013-05-06 16:42:02 -05001069static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001070 // don't complain to stderr or stdout
1071 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001072}
1073
Felipe Leme1e9edc62015-12-21 16:02:13 -08001074/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1075 temporary file.
1076 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001077static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme0f3fb202016-06-10 17:10:53 -07001078 const std::string& log_path, time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001079 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001080 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001081 return false;
1082 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001083 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001084 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001085 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001086 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001087
Felipe Leme0f3fb202016-06-10 17:10:53 -07001088 // Add log file (which contains stderr output) to zip...
1089 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
1090 if (!add_zip_entry("dumpstate_log.txt", log_path.c_str())) {
1091 MYLOGE("Failed to add dumpstate log to .zip file\n");
1092 return false;
1093 }
1094 // ... and re-opens it for further logging.
1095 redirect_to_existing_file(stderr, const_cast<char*>(log_path.c_str()));
1096 fprintf(stderr, "\n");
1097
Felipe Lemee82a27d2016-01-05 13:35:44 -08001098 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001099 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001100 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001101 return false;
1102 }
1103
Felipe Lemec4eee562016-04-21 15:42:55 -07001104 if (is_user_build()) {
1105 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1106 if (remove(bugreport_path.c_str())) {
1107 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1108 }
1109 } else {
1110 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1111 }
1112
Felipe Leme1e9edc62015-12-21 16:02:13 -08001113 return true;
1114}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001115
Michal Karpinski4db754f2015-12-11 18:04:32 +00001116static std::string SHA256_file_hash(std::string filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001117 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1118 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001119 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001120 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001121 return NULL;
1122 }
1123
1124 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001125 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001126
1127 std::vector<uint8_t> buffer(65536);
1128 while (1) {
1129 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1130 if (bytes_read == 0) {
1131 break;
1132 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001133 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001134 return NULL;
1135 }
1136
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001137 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001138 }
1139
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001140 uint8_t hash[SHA256_DIGEST_LENGTH];
1141 SHA256_Final(hash, &ctx);
1142
1143 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1144 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001145 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001146 }
1147 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1148 return std::string(hash_buffer);
1149}
1150
Colin Crossf45fa6b2012-03-26 12:38:26 -07001151int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001152 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001153 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001154 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001155 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001156 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001157 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001158 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001159 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001160 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001161 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001162 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001163 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001164
Felipe Lemee82a27d2016-01-05 13:35:44 -08001165 now = time(NULL);
1166
Felipe Lemecbce55d2016-02-08 09:53:18 -08001167 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001168
Felipe Leme8268ed22016-08-02 18:18:25 -07001169 dry_run = property_get_bool("dumpstate.dry_run", 0) != 0;
1170 if (is_dry_run()) {
1171 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
1172 }
1173
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001174 /* gets the sequential id */
1175 char last_id[PROPERTY_VALUE_MAX];
1176 property_get("dumpstate.last_id", last_id, "0");
1177 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001178 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001179 property_set("dumpstate.last_id", last_id);
1180 MYLOGI("dumpstate id: %lu\n", id);
1181
Jeff Brown1dc94e32014-09-11 14:15:27 -07001182 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001183 memset(&sigact, 0, sizeof(sigact));
1184 sigact.sa_handler = sigpipe_handler;
1185 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001186
Colin Crossf45fa6b2012-03-26 12:38:26 -07001187 /* set as high priority, and protect from OOM killer */
1188 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001189
1190 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001191 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001192 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001193 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001194 } else {
1195 /* fallback to kernels <= 2.6.35 */
1196 oom_adj = fopen("/proc/self/oom_adj", "we");
1197 if (oom_adj) {
1198 fputs("-17", oom_adj);
1199 fclose(oom_adj);
1200 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001201 }
1202
Jeff Brown1dc94e32014-09-11 14:15:27 -07001203 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001204 std::string args;
1205 format_args(argc, const_cast<const char **>(argv), &args);
1206 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001207 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001208 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001209 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001210 case 'd': do_add_date = 1; break;
1211 case 'z': do_zip_file = 1; break;
1212 case 'o': use_outfile = optarg; break;
1213 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001214 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001215 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001216 case 'q': do_vibrate = 0; break;
1217 case 'p': do_fb = 1; break;
1218 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001219 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001220 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001221 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001222 case '?': printf("\n");
1223 case 'h':
1224 usage();
1225 exit(1);
1226 }
1227 }
1228
Felipe Leme71bbfc52015-11-23 14:14:51 -08001229 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001230 usage();
1231 exit(1);
1232 }
1233
Felipe Leme2628e9e2016-04-12 16:36:51 -07001234 if (use_control_socket && !do_zip_file) {
1235 usage();
1236 exit(1);
1237 }
1238
Felipe Leme71bbfc52015-11-23 14:14:51 -08001239 if (do_update_progress && !do_broadcast) {
1240 usage();
1241 exit(1);
1242 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001243
Michal Karpinski4db754f2015-12-11 18:04:32 +00001244 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1245 usage();
1246 exit(1);
1247 }
1248
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001249 if (version != VERSION_DEFAULT) {
1250 usage();
1251 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001252 }
1253
Felipe Lemecbce55d2016-02-08 09:53:18 -08001254 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001255
Felipe Lemee338bf62015-12-07 14:03:50 -08001256 do_early_screenshot = do_update_progress;
1257
Christopher Ferrised9354f2014-10-01 17:35:01 -07001258 // If we are going to use a socket, do it as early as possible
1259 // to avoid timeouts from bugreport.
1260 if (use_socket) {
1261 redirect_to_socket(stdout, "dumpstate");
1262 }
1263
Felipe Leme2628e9e2016-04-12 16:36:51 -07001264 if (use_control_socket) {
1265 MYLOGD("Opening control socket\n");
1266 control_socket_fd = open_socket("dumpstate");
Felipe Leme02b7e002016-07-22 12:03:20 -07001267 do_update_progress = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001268 }
1269
Felipe Lemecbce55d2016-02-08 09:53:18 -08001270 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001271 std::string tmp_path;
1272
Felipe Leme0f3fb202016-06-10 17:10:53 -07001273 /* full path of the file containing the dumpstate logs */
Felipe Lemecbce55d2016-02-08 09:53:18 -08001274 std::string log_path;
1275
Felipe Leme14e034a2016-03-30 18:51:03 -07001276 /* full path of the systrace file, when enabled */
1277 std::string systrace_path;
1278
Felipe Lemee338bf62015-12-07 14:03:50 -08001279 /* full path of the temporary file containing the screenshot (when requested) */
1280 std::string screenshot_path;
1281
Felipe Lemecbce55d2016-02-08 09:53:18 -08001282 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001283 std::string base_name;
1284
Felipe Leme71bbfc52015-11-23 14:14:51 -08001285 /* pointer to the actual path, be it zip or text */
1286 std::string path;
1287
Felipe Leme635ca312016-01-05 14:23:02 -08001288 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001289 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001290
Felipe Lemead5f6c42015-11-30 14:26:46 -08001291 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001292 bool is_redirecting = !use_socket && use_outfile;
1293
1294 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001295 bugreport_dir = dirname(use_outfile);
1296 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001297 if (do_add_date) {
1298 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001299 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1300 suffix = date;
1301 } else {
1302 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001303 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001304 char build_id[PROPERTY_VALUE_MAX];
1305 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1306 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001307 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001308 // TODO: if dumpstate was an object, the paths could be internal variables and then
1309 // we could have a function to calculate the derived values, such as:
1310 // screenshot_path = GetPath(".png");
1311 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001312 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001313 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001314 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1315 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001316
Felipe Lemecbce55d2016-02-08 09:53:18 -08001317 MYLOGD("Bugreport dir: %s\n"
1318 "Base name: %s\n"
1319 "Suffix: %s\n"
1320 "Log path: %s\n"
1321 "Temporary path: %s\n"
1322 "Screenshot path: %s\n",
1323 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1324 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001325
Felipe Leme1e9edc62015-12-21 16:02:13 -08001326 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001327 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001328 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001329 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001330 zip_file.reset(fopen(path.c_str(), "wb"));
1331 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001332 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001333 do_zip_file = 0;
1334 } else {
1335 zip_writer.reset(new ZipWriter(zip_file.get()));
1336 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001337 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001338 }
1339
Felipe Leme02b7e002016-07-22 12:03:20 -07001340 if (do_update_progress && do_broadcast) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001341 std::vector<std::string> am_args = {
Felipe Lemed5e724a2016-02-11 09:12:39 -08001342 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemead5f6c42015-11-30 14:26:46 -08001343 "--es", "android.intent.extra.NAME", suffix,
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001344 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001345 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1346 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1347 };
1348 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001349 }
1350 }
1351
Nick Kralevichf3599b32016-01-25 15:05:16 -08001352 /* read /proc/cmdline before dropping root */
1353 FILE *cmdline = fopen("/proc/cmdline", "re");
1354 if (cmdline) {
1355 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1356 fclose(cmdline);
1357 }
1358
Jeff Brown1dc94e32014-09-11 14:15:27 -07001359 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001360 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001361 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001362 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001363 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001364 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001365 }
John Michelau1f794c42012-09-17 11:20:19 -05001366 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001367
Felipe Leme3634a1e2015-12-09 10:11:47 -08001368 if (do_fb && do_early_screenshot) {
1369 if (screenshot_path.empty()) {
1370 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001371 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001372 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001373 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001374 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001375 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001376 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001377 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001378 screenshot_path.c_str(), strerror(errno));
1379 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001380 }
1381 }
1382
Felipe Leme1e9edc62015-12-21 16:02:13 -08001383 if (do_zip_file) {
1384 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001385 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001386 }
1387 }
1388
Felipe Leme71bbfc52015-11-23 14:14:51 -08001389 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001390 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001391 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1392 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1393 log_path.c_str(), strerror(errno));
1394 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001395 /* TODO: rather than generating a text file now and zipping it later,
1396 it would be more efficient to redirect stdout to the zip entry
1397 directly, but the libziparchive doesn't support that option yet. */
1398 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001399 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1400 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1401 tmp_path.c_str(), strerror(errno));
1402 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001403 }
Felipe Leme608385d2016-02-01 10:35:38 -08001404 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1405 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001406 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001407 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001408
Felipe Leme71a74ac2016-03-17 15:43:25 -07001409 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001410 dump_systrace();
Felipe Leme71a74ac2016-03-17 15:43:25 -07001411
Wei Liu341938b2016-04-27 16:18:17 -07001412 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001413 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001414
Felipe Leme9c74aad2016-02-29 18:15:42 -08001415 // Invoking the following dumpsys calls before dump_traces() to try and
1416 // keep the system stats as close to its initial state as possible.
Felipe Lemedc42bda2016-06-30 14:27:04 -07001417 run_dumpsys_as_shell("DUMPSYS MEMINFO", 90, {"meminfo", "-a"});
1418 run_dumpsys_as_shell("DUMPSYS CPUINFO", 10, {"cpuinfo", "-a"});
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001419
1420 /* collect stack traces from Dalvik and native processes (needs root) */
1421 dump_traces_path = dump_traces();
1422
Felipe Lemec0808152016-06-17 17:37:13 -07001423 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001424 get_tombstone_fds(tombstone_data);
1425 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001426 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001427 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001428 if (!is_user_build()) {
1429 add_dir(PROFILE_DATA_DIR_CUR, true);
1430 add_dir(PROFILE_DATA_DIR_REF, true);
1431 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001432 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001433 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001434
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001435 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001436 return -1;
1437 }
1438
1439 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001440
Felipe Leme55b42a62015-11-10 17:39:08 -08001441 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001442 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001443 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001444 }
1445
Felipe Leme6e01fa62015-11-11 19:35:14 -08001446 /* rename or zip the (now complete) .tmp file to its final location */
1447 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001448
1449 /* check if user changed the suffix using system properties */
1450 char key[PROPERTY_KEY_MAX];
1451 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001452 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001453 property_get(key, value, "");
1454 bool change_suffix= false;
1455 if (value[0]) {
1456 /* must whitelist which characters are allowed, otherwise it could cross directories */
1457 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1458 if (std::regex_match(value, valid_regex)) {
1459 change_suffix = true;
1460 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001461 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001462 }
1463 }
1464 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001465 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001466 suffix = value;
1467 if (!screenshot_path.empty()) {
1468 std::string new_screenshot_path =
1469 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1470 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001471 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001472 new_screenshot_path.c_str(), strerror(errno));
1473 } else {
1474 screenshot_path = new_screenshot_path;
1475 }
1476 }
1477 }
1478
Felipe Leme6e01fa62015-11-11 19:35:14 -08001479 bool do_text_file = true;
1480 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001481 std::string entry_name = base_name + "-" + suffix + ".txt";
1482 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
Felipe Leme0f3fb202016-06-10 17:10:53 -07001483 if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001484 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001485 do_text_file = true;
1486 } else {
1487 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001488 // Since zip file is already created, it needs to be renamed.
1489 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1490 if (path != new_path) {
1491 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1492 if (rename(path.c_str(), new_path.c_str())) {
1493 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1494 new_path.c_str(), strerror(errno));
1495 } else {
1496 path = new_path;
1497 }
1498 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001499 }
1500 }
1501 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001502 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001503 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001504 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001505 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001506 path.clear();
1507 }
1508 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001509 if (use_control_socket) {
1510 if (do_text_file) {
1511 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1512 "for more details\n", log_path.c_str());
1513 } else {
1514 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1515 }
1516 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001517 }
1518
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001519 /* vibrate a few but shortly times to let user know it's finished */
1520 if (vibrator) {
1521 for (int i = 0; i < 3; i++) {
1522 vibrate(vibrator.get(), 75);
1523 usleep((75 + 50) * 1000);
1524 }
1525 }
1526
Jeff Brown1dc94e32014-09-11 14:15:27 -07001527 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001528 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001529 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001530 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001531 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001532 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001533 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001534 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001535 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001536 "--es", "android.intent.extra.BUGREPORT", path,
1537 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001538 };
1539 if (do_fb) {
1540 am_args.push_back("--es");
1541 am_args.push_back("android.intent.extra.SCREENSHOT");
1542 am_args.push_back(screenshot_path);
1543 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001544 if (is_remote_mode) {
1545 am_args.push_back("--es");
1546 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1547 am_args.push_back(SHA256_file_hash(path));
1548 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1549 } else {
1550 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1551 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001552 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001553 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001554 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001555 }
1556
Felipe Lemecbce55d2016-02-08 09:53:18 -08001557 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1558 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001559
Felipe Leme107a05f2016-03-08 15:11:15 -08001560 if (is_redirecting) {
1561 fclose(stderr);
1562 }
1563
Felipe Leme02b7e002016-07-22 12:03:20 -07001564 if (use_control_socket && control_socket_fd != -1) {
1565 MYLOGD("Closing control socket\n");
1566 close(control_socket_fd);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001567 }
1568
Colin Crossf45fa6b2012-03-26 12:38:26 -07001569 return 0;
1570}