blob: 17d44d27436c35968e838743a7d0715d1a486437 [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>
Zhengyin Qian068ecc72016-08-10 16:48:14 -070038#include <android-base/file.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 "ScopedFd.h"
48#include "ziparchive/zip_writer.h"
49
Michal Karpinski4db754f2015-12-11 18:04:32 +000050#include "mincrypt/sha256.h"
51
Felipe Leme6e01fa62015-11-11 19:35:14 -080052using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070053
54/* read before root is shed */
55static char cmdline_buf[16384] = "(unknown)";
56static const char *dump_traces_path = NULL;
57
Felipe Lemeefd7e272016-05-18 09:27:16 -070058// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080059static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080060static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080061static time_t now;
62static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080063static std::set<std::string> mount_points;
64void add_mountinfo();
Felipe Leme02b7e002016-07-22 12:03:20 -070065int control_socket_fd = -1;
Felipe Lemeefd7e272016-05-18 09:27:16 -070066/* suffix of the bugreport files - it's typically the date (when invoked with -d),
67 * although it could be changed by the user using a system property */
68static std::string suffix;
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 Salyzynced60782016-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 *
99 * See bugreport-format.txt for more info.
100 */
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 Lemee82a27d2016-01-05 13:35:44 -0800107/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
108 * otherwise gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700109static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800110 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700111 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
112 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800113 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
114 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700115 struct stat st;
116 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800117 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
118 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700119 } else {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800120 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700121 data[i].fd = -1;
122 }
123 }
124}
125
Felipe Leme635ca312016-01-05 14:23:02 -0800126// for_each_pid() callback to get mount info about a process.
127void do_mountinfo(int pid, const char *name) {
128 char path[PATH_MAX];
129
130 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
131 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700132 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800133 char linkname[PATH_MAX];
134 ssize_t r = readlink(path, linkname, PATH_MAX);
135 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800136 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800137 return;
138 }
139 linkname[r] = '\0';
140
141 if (mount_points.find(linkname) == mount_points.end()) {
142 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700143 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800144 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
145 mount_points.insert(linkname);
146 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800147 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800148 }
149 }
150}
151
152void add_mountinfo() {
153 if (!zip_writer) return;
154 const char *title = "MOUNT INFO";
155 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800156 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800157 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800158 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800159}
160
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700161static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
162{
163 DIR *d;
164 struct dirent *de;
165 char path[PATH_MAX];
166
167 d = opendir(driverpath);
168 if (d == NULL) {
169 return;
170 }
171
172 while ((de = readdir(d))) {
173 if (de->d_type != DT_LNK) {
174 continue;
175 }
176 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
177 dump_file(title, path);
178 }
179
180 closedir(d);
181}
182
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700183// return pid of a userspace process. If not found or error, return 0.
184static unsigned int pid_of_process(const char* ps_name) {
185 DIR *proc_dir;
186 struct dirent *ps;
187 unsigned int pid;
188 std::string cmdline;
189
190 if (!(proc_dir = opendir("/proc"))) {
191 MYLOGE("Can't open /proc\n");
192 return 0;
193 }
194
195 while ((ps = readdir(proc_dir))) {
196 if (!(pid = atoi(ps->d_name))) {
197 continue;
198 }
199 android::base::ReadFileToString("/proc/"
200 + std::string(ps->d_name) + "/cmdline", &cmdline);
201 if (cmdline.find(ps_name) == std::string::npos) {
202 continue;
203 } else {
204 closedir(proc_dir);
205 return pid;
206 }
207 }
208 closedir(proc_dir);
209 return 0;
210}
211
212// dump anrd's trace and add to the zip file.
213// 1. check if anrd is running on this device.
214// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
215// 3. wait until the trace generation completes and add to the zip file.
216static bool dump_anrd_trace() {
217 unsigned int pid;
218 char buf[50], path[PATH_MAX];
219 struct dirent *trace;
220 struct stat st;
221 DIR *trace_dir;
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700222 int retry = 5;
223 long max_ctime = 0, old_mtime;
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700224 long long cur_size = 0;
225 const char *trace_path = "/data/misc/anrd/";
226
227 if (!zip_writer) {
228 MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
229 return false;
230 }
231
232 // find anrd's pid if it is running.
233 pid = pid_of_process("/system/xbin/anrd");
234
235 if (pid > 0) {
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700236 if (stat(trace_path, &st) == 0) {
237 old_mtime = st.st_mtime;
238 } else {
239 MYLOGE("Failed to find: %s\n", trace_path);
240 return false;
241 }
242
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700243 // send SIGUSR1 to the anrd to generate a trace.
244 sprintf(buf, "%u", pid);
245 if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
246 MYLOGE("anrd signal timed out. Please manually collect trace\n");
247 return false;
248 }
249
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700250 while (retry-- > 0 && old_mtime == st.st_mtime) {
251 sleep(1);
252 stat(trace_path, &st);
253 }
254
255 if (retry < 0 && old_mtime == st.st_mtime) {
256 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
257 return false;
258 }
259
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700260 // identify the trace file by its creation time.
261 if (!(trace_dir = opendir(trace_path))) {
262 MYLOGE("Can't open trace file under %s\n", trace_path);
263 }
264 while ((trace = readdir(trace_dir))) {
265 if (strcmp(trace->d_name, ".") == 0
266 || strcmp(trace->d_name, "..") == 0) {
267 continue;
268 }
269 sprintf(path, "%s%s", trace_path, trace->d_name);
270 if (stat(path, &st) == 0) {
271 if (st.st_ctime > max_ctime) {
272 max_ctime = st.st_ctime;
273 sprintf(buf, "%s", trace->d_name);
274 }
275 }
276 }
277 closedir(trace_dir);
278
279 // Wait until the dump completes by checking the size of the trace.
280 if (max_ctime > 0) {
281 sprintf(path, "%s%s", trace_path, buf);
282 while(true) {
283 sleep(1);
284 if (stat(path, &st) == 0) {
285 if (st.st_size == cur_size) {
286 break;
287 } else if (st.st_size > cur_size) {
288 cur_size = st.st_size;
289 } else {
290 return false;
291 }
292 } else {
293 MYLOGE("Cant stat() %s anymore\n", path);
294 return false;
295 }
296 }
297 // Add to the zip file.
298 if (!add_zip_entry("anrd_trace.txt", path)) {
299 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
300 } else {
301 if (remove(path)) {
302 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
303 }
304 return true;
305 }
306 } else {
307 MYLOGE("Can't stats any trace file under %s\n", trace_path);
308 }
309 }
310 return false;
311}
312
Felipe Lemeefd7e272016-05-18 09:27:16 -0700313static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700314 if (!zip_writer) {
315 MYLOGD("Not dumping systrace because zip_writer is not set\n");
316 return;
317 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700318 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700319 if (systrace_path.empty()) {
320 MYLOGE("Not dumping systrace because path is empty\n");
321 return;
322 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700323 const char* path = "/sys/kernel/debug/tracing/tracing_on";
324 long int is_tracing;
325 if (read_file_as_long(path, &is_tracing)) {
326 return; // error already logged
327 }
328 if (is_tracing <= 0) {
329 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
330 return;
331 }
332
Felipe Leme14e034a2016-03-30 18:51:03 -0700333 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
334 systrace_path.c_str());
335 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
336 systrace_path.c_str(), NULL)) {
337 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
338 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
339 // we should call strace to stop itself, but there is no such option yet (just a
340 // --async_stop, which stops and dump
341 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
342 // MYLOGE("could not stop systrace ");
343 // }
344 }
345 if (!add_zip_entry("systrace.txt", systrace_path)) {
346 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700347 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700348 if (remove(systrace_path.c_str())) {
349 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
350 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700351 }
352}
353
Felipe Lemeefd7e272016-05-18 09:27:16 -0700354static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700355 if (is_user_build()) {
356 return;
357 }
358
Felipe Lemeefd7e272016-05-18 09:27:16 -0700359 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700360 if (raft_log_path.empty()) {
361 MYLOGD("raft_log_path is empty\n");
362 return;
363 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700364
365 struct stat s;
366 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
367 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
368 return;
369 }
370
Wei Liu341938b2016-04-27 16:18:17 -0700371 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700372 // Write compressed and encoded raft logs to stdout if not zip_writer.
373 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700374 return;
375 }
376
377 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
378 "-o", raft_log_path.c_str(), NULL);
379 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
380 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
381 } else {
382 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700383 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700384 }
385 }
386}
387
Mark Salyzyn326842f2015-04-30 09:49:41 -0700388static bool skip_not_stat(const char *path) {
389 static const char stat[] = "/stat";
390 size_t len = strlen(path);
391 if (path[len - 1] == '/') { /* Directory? */
392 return false;
393 }
394 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
395}
396
Felipe Lemee82a27d2016-01-05 13:35:44 -0800397static bool skip_none(const char *path) {
398 return false;
399}
400
Mark Salyzyn326842f2015-04-30 09:49:41 -0700401static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700402unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700403
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800404//
405// stat offsets
406// Name units description
407// ---- ----- -----------
408// read I/Os requests number of read I/Os processed
409#define __STAT_READ_IOS 0
410// read merges requests number of read I/Os merged with in-queue I/O
411#define __STAT_READ_MERGES 1
412// read sectors sectors number of sectors read
413#define __STAT_READ_SECTORS 2
414// read ticks milliseconds total wait time for read requests
415#define __STAT_READ_TICKS 3
416// write I/Os requests number of write I/Os processed
417#define __STAT_WRITE_IOS 4
418// write merges requests number of write I/Os merged with in-queue I/O
419#define __STAT_WRITE_MERGES 5
420// write sectors sectors number of sectors written
421#define __STAT_WRITE_SECTORS 6
422// write ticks milliseconds total wait time for write requests
423#define __STAT_WRITE_TICKS 7
424// in_flight requests number of I/Os currently in flight
425#define __STAT_IN_FLIGHT 8
426// io_ticks milliseconds total time this block device has been active
427#define __STAT_IO_TICKS 9
428// time_in_queue milliseconds total wait time for all requests
429#define __STAT_IN_QUEUE 10
430#define __STAT_NUMBER_FIELD 11
431//
432// read I/Os, write I/Os
433// =====================
434//
435// These values increment when an I/O request completes.
436//
437// read merges, write merges
438// =========================
439//
440// These values increment when an I/O request is merged with an
441// already-queued I/O request.
442//
443// read sectors, write sectors
444// ===========================
445//
446// These values count the number of sectors read from or written to this
447// block device. The "sectors" in question are the standard UNIX 512-byte
448// sectors, not any device- or filesystem-specific block size. The
449// counters are incremented when the I/O completes.
450#define SECTOR_SIZE 512
451//
452// read ticks, write ticks
453// =======================
454//
455// These values count the number of milliseconds that I/O requests have
456// waited on this block device. If there are multiple I/O requests waiting,
457// these values will increase at a rate greater than 1000/second; for
458// example, if 60 read requests wait for an average of 30 ms, the read_ticks
459// field will increase by 60*30 = 1800.
460//
461// in_flight
462// =========
463//
464// This value counts the number of I/O requests that have been issued to
465// the device driver but have not yet completed. It does not include I/O
466// requests that are in the queue but not yet issued to the device driver.
467//
468// io_ticks
469// ========
470//
471// This value counts the number of milliseconds during which the device has
472// had I/O requests queued.
473//
474// time_in_queue
475// =============
476//
477// This value counts the number of milliseconds that I/O requests have waited
478// on this block device. If there are multiple I/O requests waiting, this
479// value will increase as the product of the number of milliseconds times the
480// number of requests waiting (see "read ticks" above for an example).
481#define S_TO_MS 1000
482//
483
Mark Salyzyn326842f2015-04-30 09:49:41 -0700484static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800485 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700486 bool z;
487 char *cp, *buffer = NULL;
488 size_t i = 0;
489 FILE *fp = fdopen(fd, "rb");
490 getline(&buffer, &i, fp);
491 fclose(fp);
492 if (!buffer) {
493 return -errno;
494 }
495 i = strlen(buffer);
496 while ((i > 0) && (buffer[i - 1] == '\n')) {
497 buffer[--i] = '\0';
498 }
499 if (!*buffer) {
500 free(buffer);
501 return 0;
502 }
503 z = true;
504 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800505 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700506 if (fields[i] != 0) {
507 z = false;
508 }
509 }
510 if (z) { /* never accessed */
511 free(buffer);
512 return 0;
513 }
514
515 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
516 path += sizeof(mmcblk0) - 1;
517 }
518
519 printf("%s: %s\n", path, buffer);
520 free(buffer);
521
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800522 if (fields[__STAT_IO_TICKS]) {
523 unsigned long read_perf = 0;
524 unsigned long read_ios = 0;
525 if (fields[__STAT_READ_TICKS]) {
526 unsigned long long divisor = fields[__STAT_READ_TICKS]
527 * fields[__STAT_IO_TICKS];
528 read_perf = ((unsigned long long)SECTOR_SIZE
529 * fields[__STAT_READ_SECTORS]
530 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
531 / divisor;
532 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
533 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
534 / divisor;
535 }
536
537 unsigned long write_perf = 0;
538 unsigned long write_ios = 0;
539 if (fields[__STAT_WRITE_TICKS]) {
540 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
541 * fields[__STAT_IO_TICKS];
542 write_perf = ((unsigned long long)SECTOR_SIZE
543 * fields[__STAT_WRITE_SECTORS]
544 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
545 / divisor;
546 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
547 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
548 / divisor;
549 }
550
551 unsigned queue = (fields[__STAT_IN_QUEUE]
552 + (fields[__STAT_IO_TICKS] >> 1))
553 / fields[__STAT_IO_TICKS];
554
555 if (!write_perf && !write_ios) {
556 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
557 path, read_perf, read_ios, queue);
558 } else {
559 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
560 path, read_perf, read_ios, write_perf, write_ios, queue);
561 }
562
563 /* bugreport timeout factor adjustment */
564 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
565 worst_write_perf = write_perf;
566 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700567 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700568 return 0;
569}
570
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700571/* Copied policy from system/core/logd/LogBuffer.cpp */
572
573#define LOG_BUFFER_SIZE (256 * 1024)
574#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
575#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
576
577static bool valid_size(unsigned long value) {
578 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
579 return false;
580 }
581
582 long pages = sysconf(_SC_PHYS_PAGES);
583 if (pages < 1) {
584 return true;
585 }
586
587 long pagesize = sysconf(_SC_PAGESIZE);
588 if (pagesize <= 1) {
589 pagesize = PAGE_SIZE;
590 }
591
592 // maximum memory impact a somewhat arbitrary ~3%
593 pages = (pages + 31) / 32;
594 unsigned long maximum = pages * pagesize;
595
596 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
597 return true;
598 }
599
600 return value <= maximum;
601}
602
603static unsigned long property_get_size(const char *key) {
604 unsigned long value;
605 char *cp, property[PROPERTY_VALUE_MAX];
606
607 property_get(key, property, "");
608 value = strtoul(property, &cp, 10);
609
610 switch(*cp) {
611 case 'm':
612 case 'M':
613 value *= 1024;
614 /* FALLTHRU */
615 case 'k':
616 case 'K':
617 value *= 1024;
618 /* FALLTHRU */
619 case '\0':
620 break;
621
622 default:
623 value = 0;
624 }
625
626 if (!valid_size(value)) {
627 value = 0;
628 }
629
630 return value;
631}
632
633/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800634static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700635 static const char global_tuneable[] = "persist.logd.size"; // Settings App
636 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
637 char key[PROP_NAME_MAX];
638 unsigned long property_size, default_size;
639
640 default_size = property_get_size(global_tuneable);
641 if (!default_size) {
642 default_size = property_get_size(global_default);
643 }
644
645 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
646 property_size = property_get_size(key);
647
648 if (!property_size) {
649 snprintf(key, sizeof(key), "%s.%s", global_default, name);
650 property_size = property_get_size(key);
651 }
652
653 if (!property_size) {
654 property_size = default_size;
655 }
656
657 if (!property_size) {
658 property_size = LOG_BUFFER_SIZE;
659 }
660
661 /* Engineering margin is ten-fold our guess */
662 return 10 * (property_size + worst_write_perf) / worst_write_perf;
663}
664
665/* End copy from system/core/logd/LogBuffer.cpp */
666
Colin Crossf45fa6b2012-03-26 12:38:26 -0700667/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800668static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700669 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
670 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
671 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700672
673 property_get("ro.build.display.id", build, "(unknown)");
674 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
675 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700676 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700677 property_get("ro.bootloader", bootloader, "(unknown)");
678 property_get("gsm.operator.alpha", network, "(unknown)");
679 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
680
681 printf("========================================================\n");
682 printf("== dumpstate: %s\n", date);
683 printf("========================================================\n");
684
685 printf("\n");
686 printf("Build: %s\n", build);
687 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
688 printf("Bootloader: %s\n", bootloader);
689 printf("Radio: %s\n", radio);
690 printf("Network: %s\n", network);
691
692 printf("Kernel: ");
693 dump_file(NULL, "/proc/version");
694 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800695 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800696 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700697 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800698}
699
Felipe Leme24b66ee2016-06-16 10:55:26 -0700700// List of file extensions that can cause a zip file attachment to be rejected by some email
701// service providers.
702static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
703 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
704 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
705 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
706};
707
Felipe Leme71ca15e2016-05-19 16:18:17 -0700708bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800709 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800710 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
711 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800712 return false;
713 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700714 std::string valid_name = entry_name;
715
716 // Rename extension if necessary.
717 size_t idx = entry_name.rfind(".");
718 if (idx != std::string::npos) {
719 std::string extension = entry_name.substr(idx);
720 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
721 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
722 valid_name = entry_name + ".renamed";
723 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
724 }
725 }
726
Felipe Leme6fe9db62016-02-12 09:04:16 -0800727 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
728 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700729 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800730 ZipWriter::kCompress, get_mtime(fd, now));
731 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700732 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800733 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800734 return false;
735 }
736
Felipe Leme770410d2016-01-26 17:07:14 -0800737 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800738 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800739 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
740 if (bytes_read == 0) {
741 break;
742 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800743 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800744 return false;
745 }
746 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
747 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800748 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800749 return false;
750 }
751 }
752
753 err = zip_writer->FinishEntry();
754 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800755 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800756 return false;
757 }
758
759 return true;
760}
761
Felipe Leme71ca15e2016-05-19 16:18:17 -0700762bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800763 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
764 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800765 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800766 return false;
767 }
768
769 return add_zip_entry_from_fd(entry_name, fd.get());
770}
771
772/* adds a file to the existing zipped bugreport */
773static int _add_file_from_fd(const char *title, const char *path, int fd) {
774 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
775}
776
Felipe Leme24b66ee2016-06-16 10:55:26 -0700777// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800778void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800779 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800780 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800781 return;
782 }
Felipe Leme88c79332016-02-22 11:06:49 -0800783 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800784 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800785 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
786}
787
Felipe Leme809d74e2016-02-02 12:57:00 -0800788/* adds a text entry entry to the existing zip file. */
789static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800790 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800791 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 -0800792 return false;
793 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800794 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800795 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
796 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800797 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800798 ZipWriter::ErrorCodeString(err));
799 return false;
800 }
801
802 err = zip_writer->WriteBytes(content.c_str(), content.length());
803 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800804 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800805 ZipWriter::ErrorCodeString(err));
806 return false;
807 }
808
809 err = zip_writer->FinishEntry();
810 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800811 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800812 return false;
813 }
814
815 return true;
816}
817
Felipe Lemec0808152016-06-17 17:37:13 -0700818static void dump_iptables() {
819 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
820 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
821 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
822 /* no ip6 nat */
Calvin On329b9092016-08-12 16:33:12 -0700823 run_command("IPTABLE MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
824 run_command("IP6TABLE MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700825 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
826 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
827}
828
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800829static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800830 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800831 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700832
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700833 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700834 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700835 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800836 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700837 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughesb32c7e12015-11-13 11:32:48 -0800838 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700839 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700840 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
841 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
842 dump_file("SLAB INFO", "/proc/slabinfo");
843 dump_file("ZONEINFO", "/proc/zoneinfo");
844 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
845 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700846 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700847
Todd Poynor29e27a82012-05-22 17:54:59 -0700848 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700849 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700850 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700851
Elliott Hughesa3533a32015-10-30 16:17:49 -0700852 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800853 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700854
Michal Karpinski4db754f2015-12-11 18:04:32 +0000855 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900856 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Michal Karpinski4db754f2015-12-11 18:04:32 +0000857 run_command("LSMOD", 10, "lsmod", NULL);
858
Colin Crossf45fa6b2012-03-26 12:38:26 -0700859 do_dmesg();
860
861 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700862 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
863 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800864 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700865
Felipe Leme6e01fa62015-11-11 19:35:14 -0800866 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800867 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800868 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800869 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700870 }
871
Colin Crossf45fa6b2012-03-26 12:38:26 -0700872 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700873 // calculate timeout
874 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
875 if (timeout < 20000) {
876 timeout = 20000;
877 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700878 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
879 "-v", "printable",
880 "-d",
881 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800882 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700883 if (timeout < 20000) {
884 timeout = 20000;
885 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700886 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
887 "-v", "threadtime",
888 "-v", "printable",
889 "-d",
890 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700891 timeout = logcat_timeout("radio");
892 if (timeout < 20000) {
893 timeout = 20000;
894 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700895 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
896 "-v", "threadtime",
897 "-v", "printable",
898 "-d",
899 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700900
Mark Salyzynecc07632015-07-30 14:57:09 -0700901 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
902
Colin Crossf45fa6b2012-03-26 12:38:26 -0700903 /* show the traces we collected in main(), if that was done */
904 if (dump_traces_path != NULL) {
905 dump_file("VM TRACES JUST NOW", dump_traces_path);
906 }
907
908 /* only show ANR traces if they're less than 15 minutes old */
909 struct stat st;
910 char anr_traces_path[PATH_MAX];
911 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
912 if (!anr_traces_path[0]) {
913 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700914 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800915 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
916 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700917 if (fd < 0) {
918 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
919 } else {
920 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
921 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700922 }
923
924 /* slow traces for slow operations */
925 if (anr_traces_path[0] != 0) {
926 int tail = strlen(anr_traces_path)-1;
927 while (tail > 0 && anr_traces_path[tail] != '/') {
928 tail--;
929 }
930 int i = 0;
931 while (1) {
932 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
933 if (stat(anr_traces_path, &st)) {
934 // No traces file at this index, done with the files.
935 break;
936 }
937 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
938 i++;
939 }
940 }
941
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700942 int dumped = 0;
943 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
944 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800945 const char *name = tombstone_data[i].name;
946 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700947 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800948 if (zip_writer) {
949 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800950 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800951 }
952 } else {
953 dump_file_from_fd("TOMBSTONE", name, fd);
954 }
955 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700956 tombstone_data[i].fd = -1;
957 }
958 }
959 if (!dumped) {
960 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
961 }
962
Colin Crossf45fa6b2012-03-26 12:38:26 -0700963 dump_file("NETWORK DEV INFO", "/proc/net/dev");
964 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700965 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700966 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
967 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
968
Todd Poynor2a83daa2013-11-22 15:44:22 -0800969 if (!stat(PSTORE_LAST_KMSG, &st)) {
970 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
971 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzynced60782016-06-24 14:06:15 -0700972 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
973 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800974 } else {
975 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
976 dump_file("LAST KMSG", "/proc/last_kmsg");
977 }
978
Mark Salyzyn2262c162014-12-16 09:09:26 -0800979 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700980 run_command("LAST LOGCAT", 10, "logcat", "-L",
981 "-b", "all",
982 "-v", "threadtime",
983 "-v", "printable",
984 "-d",
985 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800986
Colin Crossf45fa6b2012-03-26 12:38:26 -0700987 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800988
989 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900990
991 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
992 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
993
Colin Crossf45fa6b2012-03-26 12:38:26 -0700994 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
995 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700996
997 dump_route_tables();
998
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900999 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
1000 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +09001001 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -07001002 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001003
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001004#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001005 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +09001006 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001007
1008 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +09001009 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001010
1011 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +09001012 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001013
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001014#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001015 dump_file("INTERRUPTS (1)", "/proc/interrupts");
1016
Felipe Leme7cff4622016-06-08 09:51:29 -07001017 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001018
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001019#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -07001020 run_command("DUMP WIFI STATUS", 20,
1021 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001022
1023 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +09001024 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001025
1026 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +09001027 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001028#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001029 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001030
1031 print_properties();
1032
1033 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1034 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1035
Ken Sumrall8f75fa72013-02-08 17:35:58 -08001036 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001037
Colin Crossf45fa6b2012-03-26 12:38:26 -07001038 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1039
1040 printf("------ BACKLIGHTS ------\n");
1041 printf("LCD brightness=");
1042 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1043 printf("Button brightness=");
1044 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1045 printf("Keyboard brightness=");
1046 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1047 printf("ALS mode=");
1048 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1049 printf("LCD driver registers:\n");
1050 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1051 printf("\n");
1052
1053 /* Binder state is expensive to look at as it uses a lot of memory. */
1054 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1055 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1056 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1057 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1058 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1059
Colin Crossf45fa6b2012-03-26 12:38:26 -07001060 printf("========================================================\n");
1061 printf("== Board\n");
1062 printf("========================================================\n");
1063
1064 dumpstate_board();
1065 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001066
1067 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1068 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1069 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1070 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -07001071 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001072 // su does not exist on user builds, so try running without it.
1073 // This way any implementations of vril-dump that do not require
1074 // root can run on user builds.
1075 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1076 "vril-dump", NULL);
1077 } else {
1078 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1079 SU_PATH, "root", "vril-dump", NULL);
1080 }
1081 }
1082
1083 printf("========================================================\n");
1084 printf("== Android Framework Services\n");
1085 printf("========================================================\n");
1086
Wei Liu34222562016-05-19 13:59:01 -07001087 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001088
1089 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001090 printf("== Checkins\n");
1091 printf("========================================================\n");
1092
Felipe Leme7cff4622016-06-08 09:51:29 -07001093 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1094 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1095 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1096 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1097 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1098 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
Dianne Hackborn02bea972013-06-26 18:59:09 -07001099
1100 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001101 printf("== Running Application Activities\n");
1102 printf("========================================================\n");
1103
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001104 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001105
1106 printf("========================================================\n");
1107 printf("== Running Application Services\n");
1108 printf("========================================================\n");
1109
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001110 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001111
1112 printf("========================================================\n");
1113 printf("== Running Application Providers\n");
1114 printf("========================================================\n");
1115
Junda Liucfc33d42016-06-14 00:09:10 -07001116 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001117
1118
1119 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001120 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1121 getpid(), progress, weight_total, WEIGHT_TOTAL);
1122 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001123 printf("== dumpstate: done\n");
1124 printf("========================================================\n");
1125}
1126
1127static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001128 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001129 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1130 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1131 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001132 " -b: play sound file instead of vibrate, at beginning of job\n"
1133 " -e: play sound file instead of vibrate, at end of job\n"
1134 " -o: write to file (instead of stdout)\n"
1135 " -d: append date to filename (requires -o)\n"
1136 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001137 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001138 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001139 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001140 " -q: disable vibrate\n"
1141 " -B: send broadcast when finished (requires -o)\n"
1142 " -P: send broadcast when started and update system properties on "
1143 "progress (requires -o and -B)\n"
1144 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1145 "shouldn't be used with -P)\n"
1146 " -V: sets the bugreport format version (valid values: %s)\n",
1147 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001148}
1149
John Michelau885f8882013-05-06 16:42:02 -05001150static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001151 // don't complain to stderr or stdout
1152 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001153}
1154
Felipe Leme1e9edc62015-12-21 16:02:13 -08001155/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1156 temporary file.
1157 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001158static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme1e9edc62015-12-21 16:02:13 -08001159 time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001160 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001161 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001162 return false;
1163 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001164 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001165 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001166 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001167 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001168
Felipe Lemee82a27d2016-01-05 13:35:44 -08001169 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001170 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001171 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001172 return false;
1173 }
1174
Felipe Lemec4eee562016-04-21 15:42:55 -07001175 if (is_user_build()) {
1176 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1177 if (remove(bugreport_path.c_str())) {
1178 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1179 }
1180 } else {
1181 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1182 }
1183
Felipe Leme1e9edc62015-12-21 16:02:13 -08001184 return true;
1185}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001186
Michal Karpinski4db754f2015-12-11 18:04:32 +00001187static std::string SHA256_file_hash(std::string filepath) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001188 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1189 | O_NOFOLLOW)));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001190 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001191 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001192 return NULL;
1193 }
1194
1195 SHA256_CTX ctx;
1196 SHA256_init(&ctx);
1197
1198 std::vector<uint8_t> buffer(65536);
1199 while (1) {
1200 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1201 if (bytes_read == 0) {
1202 break;
1203 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001204 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001205 return NULL;
1206 }
1207
1208 SHA256_update(&ctx, buffer.data(), bytes_read);
1209 }
1210
1211 uint8_t hash[SHA256_DIGEST_SIZE];
1212 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1213 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001214 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1215 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001216 }
1217 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1218 return std::string(hash_buffer);
1219}
1220
Colin Crossf45fa6b2012-03-26 12:38:26 -07001221int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001222 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001223 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001224 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001225 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001226 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001227 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001228 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001229 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001230 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001231 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001232 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001233 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001234
Felipe Lemee82a27d2016-01-05 13:35:44 -08001235 now = time(NULL);
1236
Felipe Lemecbce55d2016-02-08 09:53:18 -08001237 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001238
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001239 /* gets the sequential id */
1240 char last_id[PROPERTY_VALUE_MAX];
1241 property_get("dumpstate.last_id", last_id, "0");
1242 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001243 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001244 property_set("dumpstate.last_id", last_id);
1245 MYLOGI("dumpstate id: %lu\n", id);
1246
Jeff Brown1dc94e32014-09-11 14:15:27 -07001247 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001248 memset(&sigact, 0, sizeof(sigact));
1249 sigact.sa_handler = sigpipe_handler;
1250 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001251
Colin Crossf45fa6b2012-03-26 12:38:26 -07001252 /* set as high priority, and protect from OOM killer */
1253 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001254
1255 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001256 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001257 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001258 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001259 } else {
1260 /* fallback to kernels <= 2.6.35 */
1261 oom_adj = fopen("/proc/self/oom_adj", "we");
1262 if (oom_adj) {
1263 fputs("-17", oom_adj);
1264 fclose(oom_adj);
1265 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001266 }
1267
Jeff Brown1dc94e32014-09-11 14:15:27 -07001268 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001269 std::string args;
1270 format_args(argc, const_cast<const char **>(argv), &args);
1271 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001272 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001273 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001274 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001275 case 'd': do_add_date = 1; break;
1276 case 'z': do_zip_file = 1; break;
1277 case 'o': use_outfile = optarg; break;
1278 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001279 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001280 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001281 case 'q': do_vibrate = 0; break;
1282 case 'p': do_fb = 1; break;
1283 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001284 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001285 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001286 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001287 case '?': printf("\n");
1288 case 'h':
1289 usage();
1290 exit(1);
1291 }
1292 }
1293
Felipe Leme71bbfc52015-11-23 14:14:51 -08001294 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001295 usage();
1296 exit(1);
1297 }
1298
Felipe Leme2628e9e2016-04-12 16:36:51 -07001299 if (use_control_socket && !do_zip_file) {
1300 usage();
1301 exit(1);
1302 }
1303
Felipe Leme71bbfc52015-11-23 14:14:51 -08001304 if (do_update_progress && !do_broadcast) {
1305 usage();
1306 exit(1);
1307 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001308
Michal Karpinski4db754f2015-12-11 18:04:32 +00001309 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1310 usage();
1311 exit(1);
1312 }
1313
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001314 if (version != VERSION_DEFAULT) {
1315 usage();
1316 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001317 }
1318
Felipe Lemecbce55d2016-02-08 09:53:18 -08001319 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001320
Felipe Lemee338bf62015-12-07 14:03:50 -08001321 do_early_screenshot = do_update_progress;
1322
Christopher Ferrised9354f2014-10-01 17:35:01 -07001323 // If we are going to use a socket, do it as early as possible
1324 // to avoid timeouts from bugreport.
1325 if (use_socket) {
1326 redirect_to_socket(stdout, "dumpstate");
1327 }
1328
Felipe Leme2628e9e2016-04-12 16:36:51 -07001329 if (use_control_socket) {
1330 MYLOGD("Opening control socket\n");
1331 control_socket_fd = open_socket("dumpstate");
Felipe Leme02b7e002016-07-22 12:03:20 -07001332 do_update_progress = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001333 }
1334
Felipe Lemecbce55d2016-02-08 09:53:18 -08001335 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001336 std::string tmp_path;
1337
Felipe Lemecbce55d2016-02-08 09:53:18 -08001338 /* full path of the file containing the dumpstate logs*/
1339 std::string log_path;
1340
Felipe Leme14e034a2016-03-30 18:51:03 -07001341 /* full path of the systrace file, when enabled */
1342 std::string systrace_path;
1343
Felipe Lemee338bf62015-12-07 14:03:50 -08001344 /* full path of the temporary file containing the screenshot (when requested) */
1345 std::string screenshot_path;
1346
Felipe Lemecbce55d2016-02-08 09:53:18 -08001347 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001348 std::string base_name;
1349
Felipe Leme71bbfc52015-11-23 14:14:51 -08001350 /* pointer to the actual path, be it zip or text */
1351 std::string path;
1352
Felipe Leme635ca312016-01-05 14:23:02 -08001353 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001354 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001355
Felipe Lemead5f6c42015-11-30 14:26:46 -08001356 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001357 bool is_redirecting = !use_socket && use_outfile;
1358
1359 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001360 bugreport_dir = dirname(use_outfile);
1361 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001362 if (do_add_date) {
1363 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001364 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1365 suffix = date;
1366 } else {
1367 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001368 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001369 char build_id[PROPERTY_VALUE_MAX];
1370 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1371 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001372 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001373 // TODO: if dumpstate was an object, the paths could be internal variables and then
1374 // we could have a function to calculate the derived values, such as:
1375 // screenshot_path = GetPath(".png");
1376 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001377 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001378 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001379 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1380 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001381
Felipe Lemecbce55d2016-02-08 09:53:18 -08001382 MYLOGD("Bugreport dir: %s\n"
1383 "Base name: %s\n"
1384 "Suffix: %s\n"
1385 "Log path: %s\n"
1386 "Temporary path: %s\n"
1387 "Screenshot path: %s\n",
1388 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1389 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001390
Felipe Leme1e9edc62015-12-21 16:02:13 -08001391 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001392 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001393 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001394 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001395 zip_file.reset(fopen(path.c_str(), "wb"));
1396 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001397 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001398 do_zip_file = 0;
1399 } else {
1400 zip_writer.reset(new ZipWriter(zip_file.get()));
1401 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001402 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001403 }
1404
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001405 if (do_update_progress) {
1406 if (do_broadcast) {
1407 // clang-format off
1408 std::vector<std::string> am_args = {
1409 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1410 "--es", "android.intent.extra.NAME", suffix,
1411 "--ei", "android.intent.extra.ID", std::to_string(id),
1412 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1413 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1414 };
1415 // clang-format on
1416 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1417 }
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001418 if (use_control_socket) {
1419 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1420 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08001421 }
1422 }
1423
Nick Kralevichf3599b32016-01-25 15:05:16 -08001424 /* read /proc/cmdline before dropping root */
1425 FILE *cmdline = fopen("/proc/cmdline", "re");
1426 if (cmdline) {
1427 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1428 fclose(cmdline);
1429 }
1430
Jeff Brown1dc94e32014-09-11 14:15:27 -07001431 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001432 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001433 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001434 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001435 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001436 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001437 }
John Michelau1f794c42012-09-17 11:20:19 -05001438 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001439
Felipe Leme3634a1e2015-12-09 10:11:47 -08001440 if (do_fb && do_early_screenshot) {
1441 if (screenshot_path.empty()) {
1442 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001443 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001444 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001445 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001446 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001447 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001448 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001449 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001450 screenshot_path.c_str(), strerror(errno));
1451 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001452 }
1453 }
1454
Felipe Leme1e9edc62015-12-21 16:02:13 -08001455 if (do_zip_file) {
1456 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001457 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001458 }
1459 }
1460
Felipe Leme71bbfc52015-11-23 14:14:51 -08001461 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001462 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001463 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1464 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1465 log_path.c_str(), strerror(errno));
1466 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001467 /* TODO: rather than generating a text file now and zipping it later,
1468 it would be more efficient to redirect stdout to the zip entry
1469 directly, but the libziparchive doesn't support that option yet. */
1470 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001471 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1472 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1473 tmp_path.c_str(), strerror(errno));
1474 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001475 }
Felipe Leme608385d2016-02-01 10:35:38 -08001476 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1477 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001478 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001479 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001480
Felipe Leme71a74ac2016-03-17 15:43:25 -07001481 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001482 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1483 // the raw trace.
1484 if (!dump_anrd_trace()) {
1485 dump_systrace();
1486 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001487
Wei Liu341938b2016-04-27 16:18:17 -07001488 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001489 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001490
Felipe Leme9c74aad2016-02-29 18:15:42 -08001491 // Invoking the following dumpsys calls before dump_traces() to try and
1492 // keep the system stats as close to its initial state as possible.
Thierry Strudel8b78b752016-03-22 10:25:44 -07001493 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
Felipe Leme7cff4622016-06-08 09:51:29 -07001494 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001495
1496 /* collect stack traces from Dalvik and native processes (needs root) */
1497 dump_traces_path = dump_traces();
1498
Felipe Lemec0808152016-06-17 17:37:13 -07001499 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001500 get_tombstone_fds(tombstone_data);
1501 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001502 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001503 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001504 if (!is_user_build()) {
1505 add_dir(PROFILE_DATA_DIR_CUR, true);
1506 add_dir(PROFILE_DATA_DIR_REF, true);
1507 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001508 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001509 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001510
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001511 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001512 return -1;
1513 }
1514
1515 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001516
Felipe Leme55b42a62015-11-10 17:39:08 -08001517 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001518 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001519 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001520 }
1521
Felipe Leme6e01fa62015-11-11 19:35:14 -08001522 /* rename or zip the (now complete) .tmp file to its final location */
1523 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001524
1525 /* check if user changed the suffix using system properties */
1526 char key[PROPERTY_KEY_MAX];
1527 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001528 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001529 property_get(key, value, "");
1530 bool change_suffix= false;
1531 if (value[0]) {
1532 /* must whitelist which characters are allowed, otherwise it could cross directories */
1533 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1534 if (std::regex_match(value, valid_regex)) {
1535 change_suffix = true;
1536 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001537 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001538 }
1539 }
1540 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001541 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001542 suffix = value;
1543 if (!screenshot_path.empty()) {
1544 std::string new_screenshot_path =
1545 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1546 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001547 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001548 new_screenshot_path.c_str(), strerror(errno));
1549 } else {
1550 screenshot_path = new_screenshot_path;
1551 }
1552 }
1553 }
1554
Felipe Leme6e01fa62015-11-11 19:35:14 -08001555 bool do_text_file = true;
1556 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001557 std::string entry_name = base_name + "-" + suffix + ".txt";
1558 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1559 if (!finish_zip_file(entry_name, tmp_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001560 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001561 do_text_file = true;
1562 } else {
1563 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001564 // Since zip file is already created, it needs to be renamed.
1565 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1566 if (path != new_path) {
1567 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1568 if (rename(path.c_str(), new_path.c_str())) {
1569 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1570 new_path.c_str(), strerror(errno));
1571 } else {
1572 path = new_path;
1573 }
1574 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001575 }
1576 }
1577 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001578 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001579 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001580 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001581 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001582 path.clear();
1583 }
1584 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001585 if (use_control_socket) {
1586 if (do_text_file) {
1587 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1588 "for more details\n", log_path.c_str());
1589 } else {
1590 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1591 }
1592 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001593 }
1594
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001595 /* vibrate a few but shortly times to let user know it's finished */
1596 if (vibrator) {
1597 for (int i = 0; i < 3; i++) {
1598 vibrate(vibrator.get(), 75);
1599 usleep((75 + 50) * 1000);
1600 }
1601 }
1602
Jeff Brown1dc94e32014-09-11 14:15:27 -07001603 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001604 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001605 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001606 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001607 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001608 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001609 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001610 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001611 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001612 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001613 "--es", "android.intent.extra.BUGREPORT", path,
1614 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001615 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001616 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001617 if (do_fb) {
1618 am_args.push_back("--es");
1619 am_args.push_back("android.intent.extra.SCREENSHOT");
1620 am_args.push_back(screenshot_path);
1621 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001622 if (is_remote_mode) {
1623 am_args.push_back("--es");
1624 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1625 am_args.push_back(SHA256_file_hash(path));
1626 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1627 } else {
1628 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1629 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001630 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001631 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001632 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001633 }
1634
Felipe Lemecbce55d2016-02-08 09:53:18 -08001635 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1636 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001637
Felipe Leme107a05f2016-03-08 15:11:15 -08001638 if (is_redirecting) {
1639 fclose(stderr);
1640 }
1641
Felipe Leme02b7e002016-07-22 12:03:20 -07001642 if (use_control_socket && control_socket_fd != -1) {
1643 MYLOGD("Closing control socket\n");
1644 close(control_socket_fd);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001645 }
1646
Colin Crossf45fa6b2012-03-26 12:38:26 -07001647 return 0;
1648}