blob: 97dfd92e787f4947dbcfe75cbfa7a36a0feb0fcb [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
Elliott Hughes9dc117c2015-12-07 14:21:50 -080038#include <android-base/stringprintf.h>
Zhengyin Qian068ecc72016-08-10 16:48:14 -070039#include <android-base/file.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070040#include <cutils/properties.h>
Wei Liuf87959e2016-08-26 14:51:42 -070041#include <hardware_legacy/power.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070042
43#include "private/android_filesystem_config.h"
44
45#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070046#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070047
48#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080049#include "ScopedFd.h"
50#include "ziparchive/zip_writer.h"
51
Michal Karpinski4db754f2015-12-11 18:04:32 +000052#include "mincrypt/sha256.h"
53
Felipe Leme6e01fa62015-11-11 19:35:14 -080054using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070055
56/* read before root is shed */
57static char cmdline_buf[16384] = "(unknown)";
58static const char *dump_traces_path = NULL;
59
Felipe Lemeefd7e272016-05-18 09:27:16 -070060// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080061static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080062static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080063static time_t now;
64static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080065static std::set<std::string> mount_points;
66void add_mountinfo();
Felipe Leme02b7e002016-07-22 12:03:20 -070067int control_socket_fd = -1;
Felipe Lemeefd7e272016-05-18 09:27:16 -070068/* suffix of the bugreport files - it's typically the date (when invoked with -d),
69 * although it could be changed by the user using a system property */
70static std::string suffix;
Felipe Leme78f2c862015-12-21 09:55:22 -080071
Todd Poynor2a83daa2013-11-22 15:44:22 -080072#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzynced60782016-06-24 14:06:15 -070073#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080074
Wei Liu341938b2016-04-27 16:18:17 -070075#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080076#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070077#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070078#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010079#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
80#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070081#define TOMBSTONE_DIR "/data/tombstones"
82#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
83/* Can accomodate a tombstone number up to 9999. */
84#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
85#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090086#define WLUTIL "/vendor/xbin/wlutil"
Wei Liuf87959e2016-08-26 14:51:42 -070087#define WAKE_LOCK_NAME "dumpstate_wakelock"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070088
89typedef struct {
90 char name[TOMBSTONE_MAX_LEN];
91 int fd;
92} tombstone_data_t;
93
94static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
95
Felipe Leme71ca15e2016-05-19 16:18:17 -070096const std::string ZIP_ROOT_DIR = "FS";
97std::string bugreport_dir;
Felipe Lemee82a27d2016-01-05 13:35:44 -080098
Felipe Leme809d74e2016-02-02 12:57:00 -080099/*
100 * List of supported zip format versions.
101 *
102 * See bugreport-format.txt for more info.
103 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -0700104static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800105
Calvin On249beee2016-06-03 15:17:07 -0700106bool is_user_build() {
Felipe Lemec4eee562016-04-21 15:42:55 -0700107 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
108}
109
Felipe Lemee82a27d2016-01-05 13:35:44 -0800110/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
111 * otherwise gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700112static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800113 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700114 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
115 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800116 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
117 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700118 struct stat st;
119 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800120 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
121 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700122 } else {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800123 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700124 data[i].fd = -1;
125 }
126 }
127}
128
Felipe Leme635ca312016-01-05 14:23:02 -0800129// for_each_pid() callback to get mount info about a process.
130void do_mountinfo(int pid, const char *name) {
131 char path[PATH_MAX];
132
133 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
134 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700135 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800136 char linkname[PATH_MAX];
137 ssize_t r = readlink(path, linkname, PATH_MAX);
138 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800139 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800140 return;
141 }
142 linkname[r] = '\0';
143
144 if (mount_points.find(linkname) == mount_points.end()) {
145 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700146 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800147 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
148 mount_points.insert(linkname);
149 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800150 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800151 }
152 }
153}
154
155void add_mountinfo() {
156 if (!zip_writer) return;
157 const char *title = "MOUNT INFO";
158 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800159 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800160 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800161 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800162}
163
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700164static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
165{
166 DIR *d;
167 struct dirent *de;
168 char path[PATH_MAX];
169
170 d = opendir(driverpath);
171 if (d == NULL) {
172 return;
173 }
174
175 while ((de = readdir(d))) {
176 if (de->d_type != DT_LNK) {
177 continue;
178 }
179 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
180 dump_file(title, path);
181 }
182
183 closedir(d);
184}
185
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700186// return pid of a userspace process. If not found or error, return 0.
187static unsigned int pid_of_process(const char* ps_name) {
188 DIR *proc_dir;
189 struct dirent *ps;
190 unsigned int pid;
191 std::string cmdline;
192
193 if (!(proc_dir = opendir("/proc"))) {
194 MYLOGE("Can't open /proc\n");
195 return 0;
196 }
197
198 while ((ps = readdir(proc_dir))) {
199 if (!(pid = atoi(ps->d_name))) {
200 continue;
201 }
202 android::base::ReadFileToString("/proc/"
203 + std::string(ps->d_name) + "/cmdline", &cmdline);
204 if (cmdline.find(ps_name) == std::string::npos) {
205 continue;
206 } else {
207 closedir(proc_dir);
208 return pid;
209 }
210 }
211 closedir(proc_dir);
212 return 0;
213}
214
215// dump anrd's trace and add to the zip file.
216// 1. check if anrd is running on this device.
217// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
218// 3. wait until the trace generation completes and add to the zip file.
219static bool dump_anrd_trace() {
220 unsigned int pid;
221 char buf[50], path[PATH_MAX];
222 struct dirent *trace;
223 struct stat st;
224 DIR *trace_dir;
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700225 int retry = 5;
226 long max_ctime = 0, old_mtime;
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700227 long long cur_size = 0;
228 const char *trace_path = "/data/misc/anrd/";
229
230 if (!zip_writer) {
231 MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
232 return false;
233 }
234
235 // find anrd's pid if it is running.
236 pid = pid_of_process("/system/xbin/anrd");
237
238 if (pid > 0) {
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700239 if (stat(trace_path, &st) == 0) {
240 old_mtime = st.st_mtime;
241 } else {
242 MYLOGE("Failed to find: %s\n", trace_path);
243 return false;
244 }
245
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700246 // send SIGUSR1 to the anrd to generate a trace.
247 sprintf(buf, "%u", pid);
248 if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
249 MYLOGE("anrd signal timed out. Please manually collect trace\n");
250 return false;
251 }
252
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700253 while (retry-- > 0 && old_mtime == st.st_mtime) {
254 sleep(1);
255 stat(trace_path, &st);
256 }
257
258 if (retry < 0 && old_mtime == st.st_mtime) {
259 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
260 return false;
261 }
262
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700263 // identify the trace file by its creation time.
264 if (!(trace_dir = opendir(trace_path))) {
265 MYLOGE("Can't open trace file under %s\n", trace_path);
266 }
267 while ((trace = readdir(trace_dir))) {
268 if (strcmp(trace->d_name, ".") == 0
269 || strcmp(trace->d_name, "..") == 0) {
270 continue;
271 }
272 sprintf(path, "%s%s", trace_path, trace->d_name);
273 if (stat(path, &st) == 0) {
274 if (st.st_ctime > max_ctime) {
275 max_ctime = st.st_ctime;
276 sprintf(buf, "%s", trace->d_name);
277 }
278 }
279 }
280 closedir(trace_dir);
281
282 // Wait until the dump completes by checking the size of the trace.
283 if (max_ctime > 0) {
284 sprintf(path, "%s%s", trace_path, buf);
285 while(true) {
286 sleep(1);
287 if (stat(path, &st) == 0) {
288 if (st.st_size == cur_size) {
289 break;
290 } else if (st.st_size > cur_size) {
291 cur_size = st.st_size;
292 } else {
293 return false;
294 }
295 } else {
296 MYLOGE("Cant stat() %s anymore\n", path);
297 return false;
298 }
299 }
300 // Add to the zip file.
301 if (!add_zip_entry("anrd_trace.txt", path)) {
302 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
303 } else {
304 if (remove(path)) {
305 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
306 }
307 return true;
308 }
309 } else {
310 MYLOGE("Can't stats any trace file under %s\n", trace_path);
311 }
312 }
313 return false;
314}
315
Felipe Lemeefd7e272016-05-18 09:27:16 -0700316static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700317 if (!zip_writer) {
318 MYLOGD("Not dumping systrace because zip_writer is not set\n");
319 return;
320 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700321 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700322 if (systrace_path.empty()) {
323 MYLOGE("Not dumping systrace because path is empty\n");
324 return;
325 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700326 const char* path = "/sys/kernel/debug/tracing/tracing_on";
327 long int is_tracing;
328 if (read_file_as_long(path, &is_tracing)) {
329 return; // error already logged
330 }
331 if (is_tracing <= 0) {
332 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
333 return;
334 }
335
Felipe Leme14e034a2016-03-30 18:51:03 -0700336 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
337 systrace_path.c_str());
338 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
339 systrace_path.c_str(), NULL)) {
340 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
341 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
342 // we should call strace to stop itself, but there is no such option yet (just a
343 // --async_stop, which stops and dump
344 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
345 // MYLOGE("could not stop systrace ");
346 // }
347 }
348 if (!add_zip_entry("systrace.txt", systrace_path)) {
349 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700350 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700351 if (remove(systrace_path.c_str())) {
352 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
353 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700354 }
355}
356
Felipe Lemeefd7e272016-05-18 09:27:16 -0700357static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700358 if (is_user_build()) {
359 return;
360 }
361
Felipe Lemeefd7e272016-05-18 09:27:16 -0700362 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700363 if (raft_log_path.empty()) {
364 MYLOGD("raft_log_path is empty\n");
365 return;
366 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700367
368 struct stat s;
369 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
370 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
371 return;
372 }
373
Wei Liu341938b2016-04-27 16:18:17 -0700374 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700375 // Write compressed and encoded raft logs to stdout if not zip_writer.
376 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700377 return;
378 }
379
380 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
381 "-o", raft_log_path.c_str(), NULL);
382 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
383 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
384 } else {
385 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700386 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700387 }
388 }
389}
390
Mark Salyzyn326842f2015-04-30 09:49:41 -0700391static bool skip_not_stat(const char *path) {
392 static const char stat[] = "/stat";
393 size_t len = strlen(path);
394 if (path[len - 1] == '/') { /* Directory? */
395 return false;
396 }
397 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
398}
399
Felipe Lemee82a27d2016-01-05 13:35:44 -0800400static bool skip_none(const char *path) {
401 return false;
402}
403
Mark Salyzyn326842f2015-04-30 09:49:41 -0700404static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700405unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700406
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800407//
408// stat offsets
409// Name units description
410// ---- ----- -----------
411// read I/Os requests number of read I/Os processed
412#define __STAT_READ_IOS 0
413// read merges requests number of read I/Os merged with in-queue I/O
414#define __STAT_READ_MERGES 1
415// read sectors sectors number of sectors read
416#define __STAT_READ_SECTORS 2
417// read ticks milliseconds total wait time for read requests
418#define __STAT_READ_TICKS 3
419// write I/Os requests number of write I/Os processed
420#define __STAT_WRITE_IOS 4
421// write merges requests number of write I/Os merged with in-queue I/O
422#define __STAT_WRITE_MERGES 5
423// write sectors sectors number of sectors written
424#define __STAT_WRITE_SECTORS 6
425// write ticks milliseconds total wait time for write requests
426#define __STAT_WRITE_TICKS 7
427// in_flight requests number of I/Os currently in flight
428#define __STAT_IN_FLIGHT 8
429// io_ticks milliseconds total time this block device has been active
430#define __STAT_IO_TICKS 9
431// time_in_queue milliseconds total wait time for all requests
432#define __STAT_IN_QUEUE 10
433#define __STAT_NUMBER_FIELD 11
434//
435// read I/Os, write I/Os
436// =====================
437//
438// These values increment when an I/O request completes.
439//
440// read merges, write merges
441// =========================
442//
443// These values increment when an I/O request is merged with an
444// already-queued I/O request.
445//
446// read sectors, write sectors
447// ===========================
448//
449// These values count the number of sectors read from or written to this
450// block device. The "sectors" in question are the standard UNIX 512-byte
451// sectors, not any device- or filesystem-specific block size. The
452// counters are incremented when the I/O completes.
453#define SECTOR_SIZE 512
454//
455// read ticks, write ticks
456// =======================
457//
458// These values count the number of milliseconds that I/O requests have
459// waited on this block device. If there are multiple I/O requests waiting,
460// these values will increase at a rate greater than 1000/second; for
461// example, if 60 read requests wait for an average of 30 ms, the read_ticks
462// field will increase by 60*30 = 1800.
463//
464// in_flight
465// =========
466//
467// This value counts the number of I/O requests that have been issued to
468// the device driver but have not yet completed. It does not include I/O
469// requests that are in the queue but not yet issued to the device driver.
470//
471// io_ticks
472// ========
473//
474// This value counts the number of milliseconds during which the device has
475// had I/O requests queued.
476//
477// time_in_queue
478// =============
479//
480// This value counts the number of milliseconds that I/O requests have waited
481// on this block device. If there are multiple I/O requests waiting, this
482// value will increase as the product of the number of milliseconds times the
483// number of requests waiting (see "read ticks" above for an example).
484#define S_TO_MS 1000
485//
486
Mark Salyzyn326842f2015-04-30 09:49:41 -0700487static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800488 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700489 bool z;
490 char *cp, *buffer = NULL;
491 size_t i = 0;
492 FILE *fp = fdopen(fd, "rb");
493 getline(&buffer, &i, fp);
494 fclose(fp);
495 if (!buffer) {
496 return -errno;
497 }
498 i = strlen(buffer);
499 while ((i > 0) && (buffer[i - 1] == '\n')) {
500 buffer[--i] = '\0';
501 }
502 if (!*buffer) {
503 free(buffer);
504 return 0;
505 }
506 z = true;
507 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800508 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700509 if (fields[i] != 0) {
510 z = false;
511 }
512 }
513 if (z) { /* never accessed */
514 free(buffer);
515 return 0;
516 }
517
518 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
519 path += sizeof(mmcblk0) - 1;
520 }
521
522 printf("%s: %s\n", path, buffer);
523 free(buffer);
524
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800525 if (fields[__STAT_IO_TICKS]) {
526 unsigned long read_perf = 0;
527 unsigned long read_ios = 0;
528 if (fields[__STAT_READ_TICKS]) {
529 unsigned long long divisor = fields[__STAT_READ_TICKS]
530 * fields[__STAT_IO_TICKS];
531 read_perf = ((unsigned long long)SECTOR_SIZE
532 * fields[__STAT_READ_SECTORS]
533 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
534 / divisor;
535 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
536 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
537 / divisor;
538 }
539
540 unsigned long write_perf = 0;
541 unsigned long write_ios = 0;
542 if (fields[__STAT_WRITE_TICKS]) {
543 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
544 * fields[__STAT_IO_TICKS];
545 write_perf = ((unsigned long long)SECTOR_SIZE
546 * fields[__STAT_WRITE_SECTORS]
547 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
548 / divisor;
549 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
550 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
551 / divisor;
552 }
553
554 unsigned queue = (fields[__STAT_IN_QUEUE]
555 + (fields[__STAT_IO_TICKS] >> 1))
556 / fields[__STAT_IO_TICKS];
557
558 if (!write_perf && !write_ios) {
559 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
560 path, read_perf, read_ios, queue);
561 } else {
562 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
563 path, read_perf, read_ios, write_perf, write_ios, queue);
564 }
565
566 /* bugreport timeout factor adjustment */
567 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
568 worst_write_perf = write_perf;
569 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700570 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700571 return 0;
572}
573
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700574/* Copied policy from system/core/logd/LogBuffer.cpp */
575
576#define LOG_BUFFER_SIZE (256 * 1024)
577#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
578#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
579
580static bool valid_size(unsigned long value) {
581 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
582 return false;
583 }
584
585 long pages = sysconf(_SC_PHYS_PAGES);
586 if (pages < 1) {
587 return true;
588 }
589
590 long pagesize = sysconf(_SC_PAGESIZE);
591 if (pagesize <= 1) {
592 pagesize = PAGE_SIZE;
593 }
594
595 // maximum memory impact a somewhat arbitrary ~3%
596 pages = (pages + 31) / 32;
597 unsigned long maximum = pages * pagesize;
598
599 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
600 return true;
601 }
602
603 return value <= maximum;
604}
605
606static unsigned long property_get_size(const char *key) {
607 unsigned long value;
608 char *cp, property[PROPERTY_VALUE_MAX];
609
610 property_get(key, property, "");
611 value = strtoul(property, &cp, 10);
612
613 switch(*cp) {
614 case 'm':
615 case 'M':
616 value *= 1024;
617 /* FALLTHRU */
618 case 'k':
619 case 'K':
620 value *= 1024;
621 /* FALLTHRU */
622 case '\0':
623 break;
624
625 default:
626 value = 0;
627 }
628
629 if (!valid_size(value)) {
630 value = 0;
631 }
632
633 return value;
634}
635
636/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800637static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700638 static const char global_tuneable[] = "persist.logd.size"; // Settings App
639 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
640 char key[PROP_NAME_MAX];
641 unsigned long property_size, default_size;
642
643 default_size = property_get_size(global_tuneable);
644 if (!default_size) {
645 default_size = property_get_size(global_default);
646 }
647
648 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
649 property_size = property_get_size(key);
650
651 if (!property_size) {
652 snprintf(key, sizeof(key), "%s.%s", global_default, name);
653 property_size = property_get_size(key);
654 }
655
656 if (!property_size) {
657 property_size = default_size;
658 }
659
660 if (!property_size) {
661 property_size = LOG_BUFFER_SIZE;
662 }
663
664 /* Engineering margin is ten-fold our guess */
665 return 10 * (property_size + worst_write_perf) / worst_write_perf;
666}
667
668/* End copy from system/core/logd/LogBuffer.cpp */
669
Colin Crossf45fa6b2012-03-26 12:38:26 -0700670/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800671static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700672 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
673 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
674 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700675
676 property_get("ro.build.display.id", build, "(unknown)");
677 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
678 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700679 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700680 property_get("ro.bootloader", bootloader, "(unknown)");
681 property_get("gsm.operator.alpha", network, "(unknown)");
682 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
683
684 printf("========================================================\n");
685 printf("== dumpstate: %s\n", date);
686 printf("========================================================\n");
687
688 printf("\n");
689 printf("Build: %s\n", build);
690 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
691 printf("Bootloader: %s\n", bootloader);
692 printf("Radio: %s\n", radio);
693 printf("Network: %s\n", network);
694
695 printf("Kernel: ");
696 dump_file(NULL, "/proc/version");
697 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800698 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800699 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700700 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800701}
702
Felipe Leme24b66ee2016-06-16 10:55:26 -0700703// List of file extensions that can cause a zip file attachment to be rejected by some email
704// service providers.
705static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
706 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
707 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
708 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
709};
710
Felipe Leme71ca15e2016-05-19 16:18:17 -0700711bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800712 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800713 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
714 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800715 return false;
716 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700717 std::string valid_name = entry_name;
718
719 // Rename extension if necessary.
720 size_t idx = entry_name.rfind(".");
721 if (idx != std::string::npos) {
722 std::string extension = entry_name.substr(idx);
723 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
724 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
725 valid_name = entry_name + ".renamed";
726 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
727 }
728 }
729
Felipe Leme6fe9db62016-02-12 09:04:16 -0800730 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
731 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700732 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800733 ZipWriter::kCompress, get_mtime(fd, now));
734 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700735 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800736 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800737 return false;
738 }
739
Felipe Leme770410d2016-01-26 17:07:14 -0800740 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800741 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800742 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
743 if (bytes_read == 0) {
744 break;
745 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800746 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800747 return false;
748 }
749 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
750 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800751 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800752 return false;
753 }
754 }
755
756 err = zip_writer->FinishEntry();
757 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800758 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800759 return false;
760 }
761
762 return true;
763}
764
Felipe Leme71ca15e2016-05-19 16:18:17 -0700765bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800766 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
767 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800768 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800769 return false;
770 }
771
772 return add_zip_entry_from_fd(entry_name, fd.get());
773}
774
775/* adds a file to the existing zipped bugreport */
776static int _add_file_from_fd(const char *title, const char *path, int fd) {
777 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
778}
779
Felipe Leme24b66ee2016-06-16 10:55:26 -0700780// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800781void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800782 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800783 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800784 return;
785 }
Felipe Leme88c79332016-02-22 11:06:49 -0800786 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800787 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800788 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
789}
790
Felipe Leme809d74e2016-02-02 12:57:00 -0800791/* adds a text entry entry to the existing zip file. */
792static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800793 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800794 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 -0800795 return false;
796 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800797 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800798 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
799 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800800 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800801 ZipWriter::ErrorCodeString(err));
802 return false;
803 }
804
805 err = zip_writer->WriteBytes(content.c_str(), content.length());
806 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800807 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800808 ZipWriter::ErrorCodeString(err));
809 return false;
810 }
811
812 err = zip_writer->FinishEntry();
813 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800814 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800815 return false;
816 }
817
818 return true;
819}
820
Felipe Lemec0808152016-06-17 17:37:13 -0700821static void dump_iptables() {
822 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
823 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
824 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
825 /* no ip6 nat */
Calvin On329b9092016-08-12 16:33:12 -0700826 run_command("IPTABLE MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
827 run_command("IP6TABLE MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700828 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
829 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
830}
831
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800832static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800833 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800834 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700835
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700836 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700837 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700838 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800839 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700840 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughesb32c7e12015-11-13 11:32:48 -0800841 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700842 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700843 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
844 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
845 dump_file("SLAB INFO", "/proc/slabinfo");
846 dump_file("ZONEINFO", "/proc/zoneinfo");
847 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
848 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700849 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700850
Todd Poynor29e27a82012-05-22 17:54:59 -0700851 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700852 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700853 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700854
Elliott Hughesa3533a32015-10-30 16:17:49 -0700855 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800856 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700857
Michal Karpinski4db754f2015-12-11 18:04:32 +0000858 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900859 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Michal Karpinski4db754f2015-12-11 18:04:32 +0000860 run_command("LSMOD", 10, "lsmod", NULL);
861
Colin Crossf45fa6b2012-03-26 12:38:26 -0700862 do_dmesg();
863
864 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700865 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
866 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800867 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700868
Felipe Leme6e01fa62015-11-11 19:35:14 -0800869 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800870 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800871 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800872 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700873 }
874
Colin Crossf45fa6b2012-03-26 12:38:26 -0700875 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700876 // calculate timeout
877 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
878 if (timeout < 20000) {
879 timeout = 20000;
880 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700881 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
882 "-v", "printable",
883 "-d",
884 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800885 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700886 if (timeout < 20000) {
887 timeout = 20000;
888 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700889 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
890 "-v", "threadtime",
891 "-v", "printable",
892 "-d",
893 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700894 timeout = logcat_timeout("radio");
895 if (timeout < 20000) {
896 timeout = 20000;
897 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700898 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
899 "-v", "threadtime",
900 "-v", "printable",
901 "-d",
902 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700903
Mark Salyzynecc07632015-07-30 14:57:09 -0700904 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
905
Colin Crossf45fa6b2012-03-26 12:38:26 -0700906 /* show the traces we collected in main(), if that was done */
907 if (dump_traces_path != NULL) {
908 dump_file("VM TRACES JUST NOW", dump_traces_path);
909 }
910
911 /* only show ANR traces if they're less than 15 minutes old */
912 struct stat st;
913 char anr_traces_path[PATH_MAX];
914 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
915 if (!anr_traces_path[0]) {
916 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700917 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800918 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
919 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700920 if (fd < 0) {
921 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
922 } else {
923 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
924 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700925 }
926
927 /* slow traces for slow operations */
928 if (anr_traces_path[0] != 0) {
929 int tail = strlen(anr_traces_path)-1;
930 while (tail > 0 && anr_traces_path[tail] != '/') {
931 tail--;
932 }
933 int i = 0;
934 while (1) {
935 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
936 if (stat(anr_traces_path, &st)) {
937 // No traces file at this index, done with the files.
938 break;
939 }
940 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
941 i++;
942 }
943 }
944
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700945 int dumped = 0;
946 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
947 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800948 const char *name = tombstone_data[i].name;
949 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700950 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800951 if (zip_writer) {
952 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800953 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800954 }
955 } else {
956 dump_file_from_fd("TOMBSTONE", name, fd);
957 }
958 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700959 tombstone_data[i].fd = -1;
960 }
961 }
962 if (!dumped) {
963 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
964 }
965
Colin Crossf45fa6b2012-03-26 12:38:26 -0700966 dump_file("NETWORK DEV INFO", "/proc/net/dev");
967 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700968 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700969 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
970 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
971
Todd Poynor2a83daa2013-11-22 15:44:22 -0800972 if (!stat(PSTORE_LAST_KMSG, &st)) {
973 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
974 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzynced60782016-06-24 14:06:15 -0700975 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
976 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800977 } else {
978 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
979 dump_file("LAST KMSG", "/proc/last_kmsg");
980 }
981
Mark Salyzyn2262c162014-12-16 09:09:26 -0800982 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700983 run_command("LAST LOGCAT", 10, "logcat", "-L",
984 "-b", "all",
985 "-v", "threadtime",
986 "-v", "printable",
987 "-d",
988 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800989
Colin Crossf45fa6b2012-03-26 12:38:26 -0700990 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800991
992 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900993
994 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
995 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
996
Colin Crossf45fa6b2012-03-26 12:38:26 -0700997 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
998 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700999
1000 dump_route_tables();
1001
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001002 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1003 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +09001004 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -07001005 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001006
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001007#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001008 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +09001009 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001010
1011 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +09001012 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001013
1014 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +09001015 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001016
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001017#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001018 dump_file("INTERRUPTS (1)", "/proc/interrupts");
1019
Felipe Leme7cff4622016-06-08 09:51:29 -07001020 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001021
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001022#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -07001023 run_command("DUMP WIFI STATUS", 20,
1024 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001025
1026 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +09001027 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001028
1029 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +09001030 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001031#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001032 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001033
1034 print_properties();
1035
1036 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1037 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1038
Ken Sumrall8f75fa72013-02-08 17:35:58 -08001039 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001040
Colin Crossf45fa6b2012-03-26 12:38:26 -07001041 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1042
1043 printf("------ BACKLIGHTS ------\n");
1044 printf("LCD brightness=");
1045 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1046 printf("Button brightness=");
1047 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1048 printf("Keyboard brightness=");
1049 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1050 printf("ALS mode=");
1051 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1052 printf("LCD driver registers:\n");
1053 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1054 printf("\n");
1055
1056 /* Binder state is expensive to look at as it uses a lot of memory. */
1057 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1058 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1059 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1060 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1061 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1062
Colin Crossf45fa6b2012-03-26 12:38:26 -07001063 printf("========================================================\n");
1064 printf("== Board\n");
1065 printf("========================================================\n");
1066
1067 dumpstate_board();
1068 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001069
1070 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1071 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1072 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1073 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -07001074 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001075 // su does not exist on user builds, so try running without it.
1076 // This way any implementations of vril-dump that do not require
1077 // root can run on user builds.
1078 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1079 "vril-dump", NULL);
1080 } else {
1081 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1082 SU_PATH, "root", "vril-dump", NULL);
1083 }
1084 }
1085
1086 printf("========================================================\n");
1087 printf("== Android Framework Services\n");
1088 printf("========================================================\n");
1089
Wei Liu34222562016-05-19 13:59:01 -07001090 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001091
1092 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001093 printf("== Checkins\n");
1094 printf("========================================================\n");
1095
Felipe Leme7cff4622016-06-08 09:51:29 -07001096 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1097 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1098 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1099 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1100 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1101 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
Dianne Hackborn02bea972013-06-26 18:59:09 -07001102
1103 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001104 printf("== Running Application Activities\n");
1105 printf("========================================================\n");
1106
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001107 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001108
1109 printf("========================================================\n");
1110 printf("== Running Application Services\n");
1111 printf("========================================================\n");
1112
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001113 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001114
1115 printf("========================================================\n");
1116 printf("== Running Application Providers\n");
1117 printf("========================================================\n");
1118
Junda Liucfc33d42016-06-14 00:09:10 -07001119 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001120
1121
1122 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001123 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1124 getpid(), progress, weight_total, WEIGHT_TOTAL);
1125 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001126 printf("== dumpstate: done\n");
1127 printf("========================================================\n");
1128}
1129
1130static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001131 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001132 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1133 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1134 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001135 " -b: play sound file instead of vibrate, at beginning of job\n"
1136 " -e: play sound file instead of vibrate, at end of job\n"
1137 " -o: write to file (instead of stdout)\n"
1138 " -d: append date to filename (requires -o)\n"
1139 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001140 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001141 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001142 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001143 " -q: disable vibrate\n"
1144 " -B: send broadcast when finished (requires -o)\n"
1145 " -P: send broadcast when started and update system properties on "
1146 "progress (requires -o and -B)\n"
1147 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1148 "shouldn't be used with -P)\n"
1149 " -V: sets the bugreport format version (valid values: %s)\n",
1150 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001151}
1152
Wei Liuf87959e2016-08-26 14:51:42 -07001153static void wake_lock_releaser() {
1154 if (release_wake_lock(WAKE_LOCK_NAME) < 0) {
1155 MYLOGE("Failed to release wake lock: %s \n", strerror(errno));
1156 } else {
1157 MYLOGD("Wake lock released.\n");
1158 }
1159}
1160
1161static void sig_handler(int signo) {
1162 wake_lock_releaser();
Andres Morales2e671bb2014-08-21 12:38:22 -07001163 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001164}
1165
Wei Liuf87959e2016-08-26 14:51:42 -07001166static void register_sig_handler() {
1167 struct sigaction sa;
1168 sigemptyset(&sa.sa_mask);
1169 sa.sa_flags = 0;
1170 sa.sa_handler = sig_handler;
1171 sigaction(SIGPIPE, &sa, NULL); // broken pipe
1172 sigaction(SIGSEGV, &sa, NULL); // segment fault
1173 sigaction(SIGINT, &sa, NULL); // ctrl-c
1174 sigaction(SIGTERM, &sa, NULL); // killed
1175 sigaction(SIGQUIT, &sa, NULL); // quit
1176}
1177
Felipe Leme1e9edc62015-12-21 16:02:13 -08001178/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1179 temporary file.
1180 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001181static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme1e9edc62015-12-21 16:02:13 -08001182 time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001183 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001184 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001185 return false;
1186 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001187 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001188 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001189 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001190 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001191
Felipe Lemee82a27d2016-01-05 13:35:44 -08001192 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001193 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001194 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001195 return false;
1196 }
1197
Felipe Lemec4eee562016-04-21 15:42:55 -07001198 if (is_user_build()) {
1199 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1200 if (remove(bugreport_path.c_str())) {
1201 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1202 }
1203 } else {
1204 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1205 }
1206
Felipe Leme1e9edc62015-12-21 16:02:13 -08001207 return true;
1208}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001209
Michal Karpinski4db754f2015-12-11 18:04:32 +00001210static std::string SHA256_file_hash(std::string filepath) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001211 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1212 | O_NOFOLLOW)));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001213 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001214 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001215 return NULL;
1216 }
1217
1218 SHA256_CTX ctx;
1219 SHA256_init(&ctx);
1220
1221 std::vector<uint8_t> buffer(65536);
1222 while (1) {
1223 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1224 if (bytes_read == 0) {
1225 break;
1226 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001227 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001228 return NULL;
1229 }
1230
1231 SHA256_update(&ctx, buffer.data(), bytes_read);
1232 }
1233
1234 uint8_t hash[SHA256_DIGEST_SIZE];
1235 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1236 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001237 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1238 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001239 }
1240 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1241 return std::string(hash_buffer);
1242}
1243
Colin Crossf45fa6b2012-03-26 12:38:26 -07001244int main(int argc, char *argv[]) {
1245 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001246 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001247 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001248 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001249 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001250 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001251 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001252 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001253 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001254 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001255 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001256
Felipe Lemee82a27d2016-01-05 13:35:44 -08001257 now = time(NULL);
1258
Felipe Lemecbce55d2016-02-08 09:53:18 -08001259 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001260
Wei Liuf87959e2016-08-26 14:51:42 -07001261 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
1262 MYLOGE("Failed to acquire wake lock: %s \n", strerror(errno));
1263 } else {
1264 MYLOGD("Wake lock acquired.\n");
1265 atexit(wake_lock_releaser);
1266 register_sig_handler();
1267 }
1268
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001269 /* gets the sequential id */
1270 char last_id[PROPERTY_VALUE_MAX];
1271 property_get("dumpstate.last_id", last_id, "0");
1272 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001273 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001274 property_set("dumpstate.last_id", last_id);
1275 MYLOGI("dumpstate id: %lu\n", id);
1276
Colin Crossf45fa6b2012-03-26 12:38:26 -07001277 /* set as high priority, and protect from OOM killer */
1278 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001279
1280 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001281 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001282 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001283 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001284 } else {
1285 /* fallback to kernels <= 2.6.35 */
1286 oom_adj = fopen("/proc/self/oom_adj", "we");
1287 if (oom_adj) {
1288 fputs("-17", oom_adj);
1289 fclose(oom_adj);
1290 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001291 }
1292
Jeff Brown1dc94e32014-09-11 14:15:27 -07001293 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001294 std::string args;
1295 format_args(argc, const_cast<const char **>(argv), &args);
1296 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001297 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001298 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001299 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001300 case 'd': do_add_date = 1; break;
1301 case 'z': do_zip_file = 1; break;
1302 case 'o': use_outfile = optarg; break;
1303 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001304 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001305 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001306 case 'q': do_vibrate = 0; break;
1307 case 'p': do_fb = 1; break;
1308 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001309 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001310 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001311 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001312 case '?': printf("\n");
1313 case 'h':
1314 usage();
1315 exit(1);
1316 }
1317 }
1318
Felipe Leme71bbfc52015-11-23 14:14:51 -08001319 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001320 usage();
1321 exit(1);
1322 }
1323
Felipe Leme2628e9e2016-04-12 16:36:51 -07001324 if (use_control_socket && !do_zip_file) {
1325 usage();
1326 exit(1);
1327 }
1328
Felipe Leme71bbfc52015-11-23 14:14:51 -08001329 if (do_update_progress && !do_broadcast) {
1330 usage();
1331 exit(1);
1332 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001333
Michal Karpinski4db754f2015-12-11 18:04:32 +00001334 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1335 usage();
1336 exit(1);
1337 }
1338
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001339 if (version != VERSION_DEFAULT) {
1340 usage();
1341 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001342 }
1343
Felipe Lemecbce55d2016-02-08 09:53:18 -08001344 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001345
Felipe Lemee338bf62015-12-07 14:03:50 -08001346 do_early_screenshot = do_update_progress;
1347
Christopher Ferrised9354f2014-10-01 17:35:01 -07001348 // If we are going to use a socket, do it as early as possible
1349 // to avoid timeouts from bugreport.
1350 if (use_socket) {
1351 redirect_to_socket(stdout, "dumpstate");
1352 }
1353
Felipe Leme2628e9e2016-04-12 16:36:51 -07001354 if (use_control_socket) {
1355 MYLOGD("Opening control socket\n");
1356 control_socket_fd = open_socket("dumpstate");
Felipe Leme02b7e002016-07-22 12:03:20 -07001357 do_update_progress = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001358 }
1359
Felipe Lemecbce55d2016-02-08 09:53:18 -08001360 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001361 std::string tmp_path;
1362
Felipe Lemecbce55d2016-02-08 09:53:18 -08001363 /* full path of the file containing the dumpstate logs*/
1364 std::string log_path;
1365
Felipe Leme14e034a2016-03-30 18:51:03 -07001366 /* full path of the systrace file, when enabled */
1367 std::string systrace_path;
1368
Felipe Lemee338bf62015-12-07 14:03:50 -08001369 /* full path of the temporary file containing the screenshot (when requested) */
1370 std::string screenshot_path;
1371
Felipe Lemecbce55d2016-02-08 09:53:18 -08001372 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001373 std::string base_name;
1374
Felipe Leme71bbfc52015-11-23 14:14:51 -08001375 /* pointer to the actual path, be it zip or text */
1376 std::string path;
1377
Felipe Leme635ca312016-01-05 14:23:02 -08001378 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001379 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001380
Felipe Lemead5f6c42015-11-30 14:26:46 -08001381 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001382 bool is_redirecting = !use_socket && use_outfile;
1383
1384 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001385 bugreport_dir = dirname(use_outfile);
1386 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001387 if (do_add_date) {
1388 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001389 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1390 suffix = date;
1391 } else {
1392 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001393 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001394 char build_id[PROPERTY_VALUE_MAX];
1395 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1396 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001397 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001398 // TODO: if dumpstate was an object, the paths could be internal variables and then
1399 // we could have a function to calculate the derived values, such as:
1400 // screenshot_path = GetPath(".png");
1401 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001402 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001403 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001404 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1405 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001406
Felipe Lemecbce55d2016-02-08 09:53:18 -08001407 MYLOGD("Bugreport dir: %s\n"
1408 "Base name: %s\n"
1409 "Suffix: %s\n"
1410 "Log path: %s\n"
1411 "Temporary path: %s\n"
1412 "Screenshot path: %s\n",
1413 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1414 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001415
Felipe Leme1e9edc62015-12-21 16:02:13 -08001416 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001417 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001418 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001419 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001420 zip_file.reset(fopen(path.c_str(), "wb"));
1421 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001422 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001423 do_zip_file = 0;
1424 } else {
1425 zip_writer.reset(new ZipWriter(zip_file.get()));
1426 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001427 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001428 }
1429
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001430 if (do_update_progress) {
1431 if (do_broadcast) {
1432 // clang-format off
1433 std::vector<std::string> am_args = {
1434 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1435 "--es", "android.intent.extra.NAME", suffix,
1436 "--ei", "android.intent.extra.ID", std::to_string(id),
1437 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1438 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1439 };
1440 // clang-format on
1441 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1442 }
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001443 if (use_control_socket) {
1444 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1445 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08001446 }
1447 }
1448
Nick Kralevichf3599b32016-01-25 15:05:16 -08001449 /* read /proc/cmdline before dropping root */
1450 FILE *cmdline = fopen("/proc/cmdline", "re");
1451 if (cmdline) {
1452 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1453 fclose(cmdline);
1454 }
1455
Jeff Brown1dc94e32014-09-11 14:15:27 -07001456 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001457 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001458 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001459 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001460 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001461 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001462 }
John Michelau1f794c42012-09-17 11:20:19 -05001463 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001464
Felipe Leme3634a1e2015-12-09 10:11:47 -08001465 if (do_fb && do_early_screenshot) {
1466 if (screenshot_path.empty()) {
1467 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001468 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001469 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001470 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001471 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001472 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001473 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001474 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001475 screenshot_path.c_str(), strerror(errno));
1476 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001477 }
1478 }
1479
Felipe Leme1e9edc62015-12-21 16:02:13 -08001480 if (do_zip_file) {
1481 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001482 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001483 }
1484 }
1485
Felipe Leme71bbfc52015-11-23 14:14:51 -08001486 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001487 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001488 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1489 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1490 log_path.c_str(), strerror(errno));
1491 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001492 /* TODO: rather than generating a text file now and zipping it later,
1493 it would be more efficient to redirect stdout to the zip entry
1494 directly, but the libziparchive doesn't support that option yet. */
1495 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001496 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1497 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1498 tmp_path.c_str(), strerror(errno));
1499 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001500 }
Felipe Leme608385d2016-02-01 10:35:38 -08001501 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1502 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001503 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001504 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001505
Felipe Leme71a74ac2016-03-17 15:43:25 -07001506 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001507 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1508 // the raw trace.
1509 if (!dump_anrd_trace()) {
1510 dump_systrace();
1511 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001512
Wei Liu341938b2016-04-27 16:18:17 -07001513 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001514 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001515
Felipe Leme9c74aad2016-02-29 18:15:42 -08001516 // Invoking the following dumpsys calls before dump_traces() to try and
1517 // keep the system stats as close to its initial state as possible.
Thierry Strudel8b78b752016-03-22 10:25:44 -07001518 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
Felipe Leme7cff4622016-06-08 09:51:29 -07001519 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001520
1521 /* collect stack traces from Dalvik and native processes (needs root) */
1522 dump_traces_path = dump_traces();
1523
Felipe Lemec0808152016-06-17 17:37:13 -07001524 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001525 get_tombstone_fds(tombstone_data);
1526 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001527 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001528 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001529 if (!is_user_build()) {
1530 add_dir(PROFILE_DATA_DIR_CUR, true);
1531 add_dir(PROFILE_DATA_DIR_REF, true);
1532 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001533 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001534 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001535
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001536 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001537 return -1;
1538 }
1539
1540 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001541
Felipe Leme55b42a62015-11-10 17:39:08 -08001542 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001543 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001544 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001545 }
1546
Felipe Leme6e01fa62015-11-11 19:35:14 -08001547 /* rename or zip the (now complete) .tmp file to its final location */
1548 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001549
1550 /* check if user changed the suffix using system properties */
1551 char key[PROPERTY_KEY_MAX];
1552 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001553 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001554 property_get(key, value, "");
1555 bool change_suffix= false;
1556 if (value[0]) {
1557 /* must whitelist which characters are allowed, otherwise it could cross directories */
1558 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1559 if (std::regex_match(value, valid_regex)) {
1560 change_suffix = true;
1561 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001562 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001563 }
1564 }
1565 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001566 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001567 suffix = value;
1568 if (!screenshot_path.empty()) {
1569 std::string new_screenshot_path =
1570 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1571 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001572 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001573 new_screenshot_path.c_str(), strerror(errno));
1574 } else {
1575 screenshot_path = new_screenshot_path;
1576 }
1577 }
1578 }
1579
Felipe Leme6e01fa62015-11-11 19:35:14 -08001580 bool do_text_file = true;
1581 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001582 std::string entry_name = base_name + "-" + suffix + ".txt";
1583 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1584 if (!finish_zip_file(entry_name, tmp_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001585 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001586 do_text_file = true;
1587 } else {
1588 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001589 // Since zip file is already created, it needs to be renamed.
1590 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1591 if (path != new_path) {
1592 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1593 if (rename(path.c_str(), new_path.c_str())) {
1594 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1595 new_path.c_str(), strerror(errno));
1596 } else {
1597 path = new_path;
1598 }
1599 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001600 }
1601 }
1602 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001603 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001604 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001605 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001606 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001607 path.clear();
1608 }
1609 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001610 if (use_control_socket) {
1611 if (do_text_file) {
1612 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1613 "for more details\n", log_path.c_str());
1614 } else {
1615 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1616 }
1617 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001618 }
1619
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001620 /* vibrate a few but shortly times to let user know it's finished */
1621 if (vibrator) {
1622 for (int i = 0; i < 3; i++) {
1623 vibrate(vibrator.get(), 75);
1624 usleep((75 + 50) * 1000);
1625 }
1626 }
1627
Jeff Brown1dc94e32014-09-11 14:15:27 -07001628 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001629 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001630 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001631 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001632 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001633 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001634 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001635 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001636 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001637 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001638 "--es", "android.intent.extra.BUGREPORT", path,
1639 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001640 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001641 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001642 if (do_fb) {
1643 am_args.push_back("--es");
1644 am_args.push_back("android.intent.extra.SCREENSHOT");
1645 am_args.push_back(screenshot_path);
1646 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001647 if (is_remote_mode) {
1648 am_args.push_back("--es");
1649 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1650 am_args.push_back(SHA256_file_hash(path));
1651 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1652 } else {
1653 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1654 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001655 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001656 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001657 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001658 }
1659
Felipe Lemecbce55d2016-02-08 09:53:18 -08001660 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1661 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001662
Felipe Leme107a05f2016-03-08 15:11:15 -08001663 if (is_redirecting) {
1664 fclose(stderr);
1665 }
1666
Felipe Leme02b7e002016-07-22 12:03:20 -07001667 if (use_control_socket && control_socket_fd != -1) {
1668 MYLOGD("Closing control socket\n");
1669 close(control_socket_fd);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001670 }
1671
Colin Crossf45fa6b2012-03-26 12:38:26 -07001672 return 0;
1673}