blob: ca00539af3d0a4a494b530d353451801f64451b0 [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>
Wei Liud7803db2016-08-18 11:01:05 -070040#include <hardware_legacy/power.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070041
42#include "private/android_filesystem_config.h"
43
44#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070045#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070046
47#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080048#include "ScopedFd.h"
49#include "ziparchive/zip_writer.h"
50
Michal Karpinski4db754f2015-12-11 18:04:32 +000051#include "mincrypt/sha256.h"
52
Felipe Leme6e01fa62015-11-11 19:35:14 -080053using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070054
55/* read before root is shed */
56static char cmdline_buf[16384] = "(unknown)";
57static const char *dump_traces_path = NULL;
58
Felipe Lemeefd7e272016-05-18 09:27:16 -070059// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080060static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080061static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080062static time_t now;
63static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080064static std::set<std::string> mount_points;
65void add_mountinfo();
Felipe Leme02b7e002016-07-22 12:03:20 -070066int control_socket_fd = -1;
Felipe Lemeefd7e272016-05-18 09:27:16 -070067/* suffix of the bugreport files - it's typically the date (when invoked with -d),
68 * although it could be changed by the user using a system property */
69static std::string suffix;
Felipe Leme78f2c862015-12-21 09:55:22 -080070
Todd Poynor2a83daa2013-11-22 15:44:22 -080071#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzynced60782016-06-24 14:06:15 -070072#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080073
Wei Liu341938b2016-04-27 16:18:17 -070074#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080075#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070076#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070077#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010078#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
79#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070080#define TOMBSTONE_DIR "/data/tombstones"
81#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
82/* Can accomodate a tombstone number up to 9999. */
83#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
84#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090085#define WLUTIL "/vendor/xbin/wlutil"
Wei Liud7803db2016-08-18 11:01:05 -070086#define WAKE_LOCK_NAME "dumpstate_wakelock"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070087
88typedef struct {
89 char name[TOMBSTONE_MAX_LEN];
90 int fd;
91} tombstone_data_t;
92
93static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
94
Felipe Leme71ca15e2016-05-19 16:18:17 -070095const std::string ZIP_ROOT_DIR = "FS";
96std::string bugreport_dir;
Felipe Lemee82a27d2016-01-05 13:35:44 -080097
Felipe Leme809d74e2016-02-02 12:57:00 -080098/*
99 * List of supported zip format versions.
100 *
101 * See bugreport-format.txt for more info.
102 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -0700103static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800104
Calvin On249beee2016-06-03 15:17:07 -0700105bool is_user_build() {
Felipe Lemec4eee562016-04-21 15:42:55 -0700106 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
107}
108
Felipe Lemee82a27d2016-01-05 13:35:44 -0800109/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
110 * otherwise gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700111static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800112 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700113 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
114 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800115 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
116 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700117 struct stat st;
118 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800119 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
120 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700121 } else {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800122 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700123 data[i].fd = -1;
124 }
125 }
126}
127
Felipe Leme635ca312016-01-05 14:23:02 -0800128// for_each_pid() callback to get mount info about a process.
129void do_mountinfo(int pid, const char *name) {
130 char path[PATH_MAX];
131
132 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
133 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700134 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800135 char linkname[PATH_MAX];
136 ssize_t r = readlink(path, linkname, PATH_MAX);
137 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800138 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800139 return;
140 }
141 linkname[r] = '\0';
142
143 if (mount_points.find(linkname) == mount_points.end()) {
144 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700145 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800146 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
147 mount_points.insert(linkname);
148 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800149 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800150 }
151 }
152}
153
154void add_mountinfo() {
155 if (!zip_writer) return;
156 const char *title = "MOUNT INFO";
157 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800158 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800159 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800160 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800161}
162
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700163static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
164{
165 DIR *d;
166 struct dirent *de;
167 char path[PATH_MAX];
168
169 d = opendir(driverpath);
170 if (d == NULL) {
171 return;
172 }
173
174 while ((de = readdir(d))) {
175 if (de->d_type != DT_LNK) {
176 continue;
177 }
178 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
179 dump_file(title, path);
180 }
181
182 closedir(d);
183}
184
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700185// return pid of a userspace process. If not found or error, return 0.
186static unsigned int pid_of_process(const char* ps_name) {
187 DIR *proc_dir;
188 struct dirent *ps;
189 unsigned int pid;
190 std::string cmdline;
191
192 if (!(proc_dir = opendir("/proc"))) {
193 MYLOGE("Can't open /proc\n");
194 return 0;
195 }
196
197 while ((ps = readdir(proc_dir))) {
198 if (!(pid = atoi(ps->d_name))) {
199 continue;
200 }
201 android::base::ReadFileToString("/proc/"
202 + std::string(ps->d_name) + "/cmdline", &cmdline);
203 if (cmdline.find(ps_name) == std::string::npos) {
204 continue;
205 } else {
206 closedir(proc_dir);
207 return pid;
208 }
209 }
210 closedir(proc_dir);
211 return 0;
212}
213
214// dump anrd's trace and add to the zip file.
215// 1. check if anrd is running on this device.
216// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
217// 3. wait until the trace generation completes and add to the zip file.
218static bool dump_anrd_trace() {
219 unsigned int pid;
220 char buf[50], path[PATH_MAX];
221 struct dirent *trace;
222 struct stat st;
223 DIR *trace_dir;
224 long max_ctime = 0;
225 long long cur_size = 0;
226 const char *trace_path = "/data/misc/anrd/";
227
228 if (!zip_writer) {
229 MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
230 return false;
231 }
232
233 // find anrd's pid if it is running.
234 pid = pid_of_process("/system/xbin/anrd");
235
236 if (pid > 0) {
237 // send SIGUSR1 to the anrd to generate a trace.
238 sprintf(buf, "%u", pid);
239 if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
240 MYLOGE("anrd signal timed out. Please manually collect trace\n");
241 return false;
242 }
243
244 // identify the trace file by its creation time.
245 if (!(trace_dir = opendir(trace_path))) {
246 MYLOGE("Can't open trace file under %s\n", trace_path);
247 }
248 while ((trace = readdir(trace_dir))) {
249 if (strcmp(trace->d_name, ".") == 0
250 || strcmp(trace->d_name, "..") == 0) {
251 continue;
252 }
253 sprintf(path, "%s%s", trace_path, trace->d_name);
254 if (stat(path, &st) == 0) {
255 if (st.st_ctime > max_ctime) {
256 max_ctime = st.st_ctime;
257 sprintf(buf, "%s", trace->d_name);
258 }
259 }
260 }
261 closedir(trace_dir);
262
263 // Wait until the dump completes by checking the size of the trace.
264 if (max_ctime > 0) {
265 sprintf(path, "%s%s", trace_path, buf);
266 while(true) {
267 sleep(1);
268 if (stat(path, &st) == 0) {
269 if (st.st_size == cur_size) {
270 break;
271 } else if (st.st_size > cur_size) {
272 cur_size = st.st_size;
273 } else {
274 return false;
275 }
276 } else {
277 MYLOGE("Cant stat() %s anymore\n", path);
278 return false;
279 }
280 }
281 // Add to the zip file.
282 if (!add_zip_entry("anrd_trace.txt", path)) {
283 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
284 } else {
285 if (remove(path)) {
286 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
287 }
288 return true;
289 }
290 } else {
291 MYLOGE("Can't stats any trace file under %s\n", trace_path);
292 }
293 }
294 return false;
295}
296
Felipe Lemeefd7e272016-05-18 09:27:16 -0700297static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700298 if (!zip_writer) {
299 MYLOGD("Not dumping systrace because zip_writer is not set\n");
300 return;
301 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700302 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700303 if (systrace_path.empty()) {
304 MYLOGE("Not dumping systrace because path is empty\n");
305 return;
306 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700307 const char* path = "/sys/kernel/debug/tracing/tracing_on";
308 long int is_tracing;
309 if (read_file_as_long(path, &is_tracing)) {
310 return; // error already logged
311 }
312 if (is_tracing <= 0) {
313 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
314 return;
315 }
316
Felipe Leme14e034a2016-03-30 18:51:03 -0700317 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
318 systrace_path.c_str());
319 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
320 systrace_path.c_str(), NULL)) {
321 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
322 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
323 // we should call strace to stop itself, but there is no such option yet (just a
324 // --async_stop, which stops and dump
325 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
326 // MYLOGE("could not stop systrace ");
327 // }
328 }
329 if (!add_zip_entry("systrace.txt", systrace_path)) {
330 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700331 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700332 if (remove(systrace_path.c_str())) {
333 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
334 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700335 }
336}
337
Felipe Lemeefd7e272016-05-18 09:27:16 -0700338static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700339 if (is_user_build()) {
340 return;
341 }
342
Felipe Lemeefd7e272016-05-18 09:27:16 -0700343 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700344 if (raft_log_path.empty()) {
345 MYLOGD("raft_log_path is empty\n");
346 return;
347 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700348
349 struct stat s;
350 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
351 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
352 return;
353 }
354
Wei Liu341938b2016-04-27 16:18:17 -0700355 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700356 // Write compressed and encoded raft logs to stdout if not zip_writer.
357 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700358 return;
359 }
360
361 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
362 "-o", raft_log_path.c_str(), NULL);
363 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
364 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
365 } else {
366 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700367 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700368 }
369 }
370}
371
Mark Salyzyn326842f2015-04-30 09:49:41 -0700372static bool skip_not_stat(const char *path) {
373 static const char stat[] = "/stat";
374 size_t len = strlen(path);
375 if (path[len - 1] == '/') { /* Directory? */
376 return false;
377 }
378 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
379}
380
Felipe Lemee82a27d2016-01-05 13:35:44 -0800381static bool skip_none(const char *path) {
382 return false;
383}
384
Mark Salyzyn326842f2015-04-30 09:49:41 -0700385static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700386unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700387
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800388//
389// stat offsets
390// Name units description
391// ---- ----- -----------
392// read I/Os requests number of read I/Os processed
393#define __STAT_READ_IOS 0
394// read merges requests number of read I/Os merged with in-queue I/O
395#define __STAT_READ_MERGES 1
396// read sectors sectors number of sectors read
397#define __STAT_READ_SECTORS 2
398// read ticks milliseconds total wait time for read requests
399#define __STAT_READ_TICKS 3
400// write I/Os requests number of write I/Os processed
401#define __STAT_WRITE_IOS 4
402// write merges requests number of write I/Os merged with in-queue I/O
403#define __STAT_WRITE_MERGES 5
404// write sectors sectors number of sectors written
405#define __STAT_WRITE_SECTORS 6
406// write ticks milliseconds total wait time for write requests
407#define __STAT_WRITE_TICKS 7
408// in_flight requests number of I/Os currently in flight
409#define __STAT_IN_FLIGHT 8
410// io_ticks milliseconds total time this block device has been active
411#define __STAT_IO_TICKS 9
412// time_in_queue milliseconds total wait time for all requests
413#define __STAT_IN_QUEUE 10
414#define __STAT_NUMBER_FIELD 11
415//
416// read I/Os, write I/Os
417// =====================
418//
419// These values increment when an I/O request completes.
420//
421// read merges, write merges
422// =========================
423//
424// These values increment when an I/O request is merged with an
425// already-queued I/O request.
426//
427// read sectors, write sectors
428// ===========================
429//
430// These values count the number of sectors read from or written to this
431// block device. The "sectors" in question are the standard UNIX 512-byte
432// sectors, not any device- or filesystem-specific block size. The
433// counters are incremented when the I/O completes.
434#define SECTOR_SIZE 512
435//
436// read ticks, write ticks
437// =======================
438//
439// These values count the number of milliseconds that I/O requests have
440// waited on this block device. If there are multiple I/O requests waiting,
441// these values will increase at a rate greater than 1000/second; for
442// example, if 60 read requests wait for an average of 30 ms, the read_ticks
443// field will increase by 60*30 = 1800.
444//
445// in_flight
446// =========
447//
448// This value counts the number of I/O requests that have been issued to
449// the device driver but have not yet completed. It does not include I/O
450// requests that are in the queue but not yet issued to the device driver.
451//
452// io_ticks
453// ========
454//
455// This value counts the number of milliseconds during which the device has
456// had I/O requests queued.
457//
458// time_in_queue
459// =============
460//
461// This value counts the number of milliseconds that I/O requests have waited
462// on this block device. If there are multiple I/O requests waiting, this
463// value will increase as the product of the number of milliseconds times the
464// number of requests waiting (see "read ticks" above for an example).
465#define S_TO_MS 1000
466//
467
Mark Salyzyn326842f2015-04-30 09:49:41 -0700468static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800469 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700470 bool z;
471 char *cp, *buffer = NULL;
472 size_t i = 0;
473 FILE *fp = fdopen(fd, "rb");
474 getline(&buffer, &i, fp);
475 fclose(fp);
476 if (!buffer) {
477 return -errno;
478 }
479 i = strlen(buffer);
480 while ((i > 0) && (buffer[i - 1] == '\n')) {
481 buffer[--i] = '\0';
482 }
483 if (!*buffer) {
484 free(buffer);
485 return 0;
486 }
487 z = true;
488 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800489 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700490 if (fields[i] != 0) {
491 z = false;
492 }
493 }
494 if (z) { /* never accessed */
495 free(buffer);
496 return 0;
497 }
498
499 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
500 path += sizeof(mmcblk0) - 1;
501 }
502
503 printf("%s: %s\n", path, buffer);
504 free(buffer);
505
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800506 if (fields[__STAT_IO_TICKS]) {
507 unsigned long read_perf = 0;
508 unsigned long read_ios = 0;
509 if (fields[__STAT_READ_TICKS]) {
510 unsigned long long divisor = fields[__STAT_READ_TICKS]
511 * fields[__STAT_IO_TICKS];
512 read_perf = ((unsigned long long)SECTOR_SIZE
513 * fields[__STAT_READ_SECTORS]
514 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
515 / divisor;
516 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
517 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
518 / divisor;
519 }
520
521 unsigned long write_perf = 0;
522 unsigned long write_ios = 0;
523 if (fields[__STAT_WRITE_TICKS]) {
524 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
525 * fields[__STAT_IO_TICKS];
526 write_perf = ((unsigned long long)SECTOR_SIZE
527 * fields[__STAT_WRITE_SECTORS]
528 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
529 / divisor;
530 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
531 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
532 / divisor;
533 }
534
535 unsigned queue = (fields[__STAT_IN_QUEUE]
536 + (fields[__STAT_IO_TICKS] >> 1))
537 / fields[__STAT_IO_TICKS];
538
539 if (!write_perf && !write_ios) {
540 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
541 path, read_perf, read_ios, queue);
542 } else {
543 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
544 path, read_perf, read_ios, write_perf, write_ios, queue);
545 }
546
547 /* bugreport timeout factor adjustment */
548 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
549 worst_write_perf = write_perf;
550 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700551 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700552 return 0;
553}
554
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700555/* Copied policy from system/core/logd/LogBuffer.cpp */
556
557#define LOG_BUFFER_SIZE (256 * 1024)
558#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
559#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
560
561static bool valid_size(unsigned long value) {
562 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
563 return false;
564 }
565
566 long pages = sysconf(_SC_PHYS_PAGES);
567 if (pages < 1) {
568 return true;
569 }
570
571 long pagesize = sysconf(_SC_PAGESIZE);
572 if (pagesize <= 1) {
573 pagesize = PAGE_SIZE;
574 }
575
576 // maximum memory impact a somewhat arbitrary ~3%
577 pages = (pages + 31) / 32;
578 unsigned long maximum = pages * pagesize;
579
580 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
581 return true;
582 }
583
584 return value <= maximum;
585}
586
587static unsigned long property_get_size(const char *key) {
588 unsigned long value;
589 char *cp, property[PROPERTY_VALUE_MAX];
590
591 property_get(key, property, "");
592 value = strtoul(property, &cp, 10);
593
594 switch(*cp) {
595 case 'm':
596 case 'M':
597 value *= 1024;
598 /* FALLTHRU */
599 case 'k':
600 case 'K':
601 value *= 1024;
602 /* FALLTHRU */
603 case '\0':
604 break;
605
606 default:
607 value = 0;
608 }
609
610 if (!valid_size(value)) {
611 value = 0;
612 }
613
614 return value;
615}
616
617/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800618static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700619 static const char global_tuneable[] = "persist.logd.size"; // Settings App
620 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
621 char key[PROP_NAME_MAX];
622 unsigned long property_size, default_size;
623
624 default_size = property_get_size(global_tuneable);
625 if (!default_size) {
626 default_size = property_get_size(global_default);
627 }
628
629 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
630 property_size = property_get_size(key);
631
632 if (!property_size) {
633 snprintf(key, sizeof(key), "%s.%s", global_default, name);
634 property_size = property_get_size(key);
635 }
636
637 if (!property_size) {
638 property_size = default_size;
639 }
640
641 if (!property_size) {
642 property_size = LOG_BUFFER_SIZE;
643 }
644
645 /* Engineering margin is ten-fold our guess */
646 return 10 * (property_size + worst_write_perf) / worst_write_perf;
647}
648
649/* End copy from system/core/logd/LogBuffer.cpp */
650
Colin Crossf45fa6b2012-03-26 12:38:26 -0700651/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800652static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700653 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
654 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
655 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700656
657 property_get("ro.build.display.id", build, "(unknown)");
658 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
659 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700660 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700661 property_get("ro.bootloader", bootloader, "(unknown)");
662 property_get("gsm.operator.alpha", network, "(unknown)");
663 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
664
665 printf("========================================================\n");
666 printf("== dumpstate: %s\n", date);
667 printf("========================================================\n");
668
669 printf("\n");
670 printf("Build: %s\n", build);
671 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
672 printf("Bootloader: %s\n", bootloader);
673 printf("Radio: %s\n", radio);
674 printf("Network: %s\n", network);
675
676 printf("Kernel: ");
677 dump_file(NULL, "/proc/version");
678 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800679 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800680 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700681 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800682}
683
Felipe Leme24b66ee2016-06-16 10:55:26 -0700684// List of file extensions that can cause a zip file attachment to be rejected by some email
685// service providers.
686static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
687 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
688 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
689 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
690};
691
Felipe Leme71ca15e2016-05-19 16:18:17 -0700692bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800693 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800694 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
695 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800696 return false;
697 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700698 std::string valid_name = entry_name;
699
700 // Rename extension if necessary.
701 size_t idx = entry_name.rfind(".");
702 if (idx != std::string::npos) {
703 std::string extension = entry_name.substr(idx);
704 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
705 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
706 valid_name = entry_name + ".renamed";
707 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
708 }
709 }
710
Felipe Leme6fe9db62016-02-12 09:04:16 -0800711 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
712 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700713 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800714 ZipWriter::kCompress, get_mtime(fd, now));
715 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700716 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800717 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800718 return false;
719 }
720
Felipe Leme770410d2016-01-26 17:07:14 -0800721 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800722 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800723 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
724 if (bytes_read == 0) {
725 break;
726 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800727 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800728 return false;
729 }
730 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
731 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800732 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800733 return false;
734 }
735 }
736
737 err = zip_writer->FinishEntry();
738 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800739 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800740 return false;
741 }
742
743 return true;
744}
745
Felipe Leme71ca15e2016-05-19 16:18:17 -0700746bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800747 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
748 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800749 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800750 return false;
751 }
752
753 return add_zip_entry_from_fd(entry_name, fd.get());
754}
755
756/* adds a file to the existing zipped bugreport */
757static int _add_file_from_fd(const char *title, const char *path, int fd) {
758 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
759}
760
Felipe Leme24b66ee2016-06-16 10:55:26 -0700761// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800762void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800763 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800764 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800765 return;
766 }
Felipe Leme88c79332016-02-22 11:06:49 -0800767 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800768 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800769 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
770}
771
Felipe Leme809d74e2016-02-02 12:57:00 -0800772/* adds a text entry entry to the existing zip file. */
773static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800774 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800775 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 -0800776 return false;
777 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800778 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800779 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
780 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800781 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800782 ZipWriter::ErrorCodeString(err));
783 return false;
784 }
785
786 err = zip_writer->WriteBytes(content.c_str(), content.length());
787 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800788 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800789 ZipWriter::ErrorCodeString(err));
790 return false;
791 }
792
793 err = zip_writer->FinishEntry();
794 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800795 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800796 return false;
797 }
798
799 return true;
800}
801
Felipe Lemec0808152016-06-17 17:37:13 -0700802static void dump_iptables() {
803 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
804 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
805 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
806 /* no ip6 nat */
807 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
808 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
809}
810
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800811static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800812 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800813 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700814
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700815 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700816 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700817 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800818 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700819 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughesb32c7e12015-11-13 11:32:48 -0800820 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700821 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700822 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
823 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
824 dump_file("SLAB INFO", "/proc/slabinfo");
825 dump_file("ZONEINFO", "/proc/zoneinfo");
826 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
827 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700828 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700829
Todd Poynor29e27a82012-05-22 17:54:59 -0700830 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700831 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700832 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700833
Elliott Hughesa3533a32015-10-30 16:17:49 -0700834 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800835 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700836
Michal Karpinski4db754f2015-12-11 18:04:32 +0000837 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900838 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Michal Karpinski4db754f2015-12-11 18:04:32 +0000839 run_command("LSMOD", 10, "lsmod", NULL);
840
Colin Crossf45fa6b2012-03-26 12:38:26 -0700841 do_dmesg();
842
843 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700844 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
845 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800846 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700847
Felipe Leme6e01fa62015-11-11 19:35:14 -0800848 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800849 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800850 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800851 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700852 }
853
Colin Crossf45fa6b2012-03-26 12:38:26 -0700854 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700855 // calculate timeout
856 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
857 if (timeout < 20000) {
858 timeout = 20000;
859 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700860 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
861 "-v", "printable",
862 "-d",
863 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800864 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700865 if (timeout < 20000) {
866 timeout = 20000;
867 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700868 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
869 "-v", "threadtime",
870 "-v", "printable",
871 "-d",
872 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700873 timeout = logcat_timeout("radio");
874 if (timeout < 20000) {
875 timeout = 20000;
876 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700877 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
878 "-v", "threadtime",
879 "-v", "printable",
880 "-d",
881 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700882
Mark Salyzynecc07632015-07-30 14:57:09 -0700883 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
884
Colin Crossf45fa6b2012-03-26 12:38:26 -0700885 /* show the traces we collected in main(), if that was done */
886 if (dump_traces_path != NULL) {
887 dump_file("VM TRACES JUST NOW", dump_traces_path);
888 }
889
890 /* only show ANR traces if they're less than 15 minutes old */
891 struct stat st;
892 char anr_traces_path[PATH_MAX];
893 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
894 if (!anr_traces_path[0]) {
895 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700896 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800897 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
898 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700899 if (fd < 0) {
900 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
901 } else {
902 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
903 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700904 }
905
906 /* slow traces for slow operations */
907 if (anr_traces_path[0] != 0) {
908 int tail = strlen(anr_traces_path)-1;
909 while (tail > 0 && anr_traces_path[tail] != '/') {
910 tail--;
911 }
912 int i = 0;
913 while (1) {
914 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
915 if (stat(anr_traces_path, &st)) {
916 // No traces file at this index, done with the files.
917 break;
918 }
919 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
920 i++;
921 }
922 }
923
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700924 int dumped = 0;
925 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
926 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800927 const char *name = tombstone_data[i].name;
928 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700929 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800930 if (zip_writer) {
931 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800932 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800933 }
934 } else {
935 dump_file_from_fd("TOMBSTONE", name, fd);
936 }
937 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700938 tombstone_data[i].fd = -1;
939 }
940 }
941 if (!dumped) {
942 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
943 }
944
Colin Crossf45fa6b2012-03-26 12:38:26 -0700945 dump_file("NETWORK DEV INFO", "/proc/net/dev");
946 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700947 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700948 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
949 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
950
Todd Poynor2a83daa2013-11-22 15:44:22 -0800951 if (!stat(PSTORE_LAST_KMSG, &st)) {
952 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
953 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzynced60782016-06-24 14:06:15 -0700954 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
955 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800956 } else {
957 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
958 dump_file("LAST KMSG", "/proc/last_kmsg");
959 }
960
Mark Salyzyn2262c162014-12-16 09:09:26 -0800961 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700962 run_command("LAST LOGCAT", 10, "logcat", "-L",
963 "-b", "all",
964 "-v", "threadtime",
965 "-v", "printable",
966 "-d",
967 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800968
Colin Crossf45fa6b2012-03-26 12:38:26 -0700969 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800970
971 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900972
973 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
974 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
975
Colin Crossf45fa6b2012-03-26 12:38:26 -0700976 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
977 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700978
979 dump_route_tables();
980
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900981 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
982 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +0900983 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700984 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700985
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800986#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900987 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +0900988 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900989
990 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900991 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900992
993 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900994 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900995
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800996#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800997 dump_file("INTERRUPTS (1)", "/proc/interrupts");
998
Felipe Leme7cff4622016-06-08 09:51:29 -0700999 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001000
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001001#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -07001002 run_command("DUMP WIFI STATUS", 20,
1003 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001004
1005 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +09001006 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001007
1008 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +09001009 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001010#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001011 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001012
1013 print_properties();
1014
1015 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
1016 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
1017
Ken Sumrall8f75fa72013-02-08 17:35:58 -08001018 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001019
Colin Crossf45fa6b2012-03-26 12:38:26 -07001020 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
1021
1022 printf("------ BACKLIGHTS ------\n");
1023 printf("LCD brightness=");
1024 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
1025 printf("Button brightness=");
1026 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
1027 printf("Keyboard brightness=");
1028 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
1029 printf("ALS mode=");
1030 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
1031 printf("LCD driver registers:\n");
1032 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
1033 printf("\n");
1034
1035 /* Binder state is expensive to look at as it uses a lot of memory. */
1036 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1037 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1038 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1039 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
1040 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
1041
Colin Crossf45fa6b2012-03-26 12:38:26 -07001042 printf("========================================================\n");
1043 printf("== Board\n");
1044 printf("========================================================\n");
1045
1046 dumpstate_board();
1047 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001048
1049 /* Migrate the ril_dumpstate to a dumpstate_board()? */
1050 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
1051 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
1052 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -07001053 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001054 // su does not exist on user builds, so try running without it.
1055 // This way any implementations of vril-dump that do not require
1056 // root can run on user builds.
1057 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1058 "vril-dump", NULL);
1059 } else {
1060 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
1061 SU_PATH, "root", "vril-dump", NULL);
1062 }
1063 }
1064
1065 printf("========================================================\n");
1066 printf("== Android Framework Services\n");
1067 printf("========================================================\n");
1068
Wei Liu34222562016-05-19 13:59:01 -07001069 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001070
1071 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001072 printf("== Checkins\n");
1073 printf("========================================================\n");
1074
Felipe Leme7cff4622016-06-08 09:51:29 -07001075 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
1076 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
1077 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
1078 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
1079 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
1080 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
Dianne Hackborn02bea972013-06-26 18:59:09 -07001081
1082 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001083 printf("== Running Application Activities\n");
1084 printf("========================================================\n");
1085
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001086 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001087
1088 printf("========================================================\n");
1089 printf("== Running Application Services\n");
1090 printf("========================================================\n");
1091
Felipe Leme3f83dbe2016-06-10 16:56:33 -07001092 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001093
1094 printf("========================================================\n");
1095 printf("== Running Application Providers\n");
1096 printf("========================================================\n");
1097
Junda Liucfc33d42016-06-14 00:09:10 -07001098 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001099
1100
1101 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001102 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1103 getpid(), progress, weight_total, WEIGHT_TOTAL);
1104 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001105 printf("== dumpstate: done\n");
1106 printf("========================================================\n");
1107}
1108
1109static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001110 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001111 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1112 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1113 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001114 " -b: play sound file instead of vibrate, at beginning of job\n"
1115 " -e: play sound file instead of vibrate, at end of job\n"
1116 " -o: write to file (instead of stdout)\n"
1117 " -d: append date to filename (requires -o)\n"
1118 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001119 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001120 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001121 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001122 " -q: disable vibrate\n"
1123 " -B: send broadcast when finished (requires -o)\n"
1124 " -P: send broadcast when started and update system properties on "
1125 "progress (requires -o and -B)\n"
1126 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1127 "shouldn't be used with -P)\n"
1128 " -V: sets the bugreport format version (valid values: %s)\n",
1129 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001130}
1131
John Michelau885f8882013-05-06 16:42:02 -05001132static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001133 // don't complain to stderr or stdout
1134 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001135}
1136
Felipe Leme1e9edc62015-12-21 16:02:13 -08001137/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1138 temporary file.
1139 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001140static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme1e9edc62015-12-21 16:02:13 -08001141 time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001142 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001143 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001144 return false;
1145 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001146 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001147 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001148 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001149 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001150
Felipe Lemee82a27d2016-01-05 13:35:44 -08001151 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001152 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001153 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001154 return false;
1155 }
1156
Felipe Lemec4eee562016-04-21 15:42:55 -07001157 if (is_user_build()) {
1158 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1159 if (remove(bugreport_path.c_str())) {
1160 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1161 }
1162 } else {
1163 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1164 }
1165
Felipe Leme1e9edc62015-12-21 16:02:13 -08001166 return true;
1167}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001168
Michal Karpinski4db754f2015-12-11 18:04:32 +00001169static std::string SHA256_file_hash(std::string filepath) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001170 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1171 | O_NOFOLLOW)));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001172 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001173 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001174 return NULL;
1175 }
1176
1177 SHA256_CTX ctx;
1178 SHA256_init(&ctx);
1179
1180 std::vector<uint8_t> buffer(65536);
1181 while (1) {
1182 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1183 if (bytes_read == 0) {
1184 break;
1185 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001186 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001187 return NULL;
1188 }
1189
1190 SHA256_update(&ctx, buffer.data(), bytes_read);
1191 }
1192
1193 uint8_t hash[SHA256_DIGEST_SIZE];
1194 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1195 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001196 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1197 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001198 }
1199 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1200 return std::string(hash_buffer);
1201}
1202
Wei Liud7803db2016-08-18 11:01:05 -07001203static void wake_lock_releaser() {
1204 release_wake_lock(WAKE_LOCK_NAME);
1205}
1206
Colin Crossf45fa6b2012-03-26 12:38:26 -07001207int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001208 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001209 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001210 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001211 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001212 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001213 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001214 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001215 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001216 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001217 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001218 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001219 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001220
Felipe Lemee82a27d2016-01-05 13:35:44 -08001221 now = time(NULL);
1222
Felipe Lemecbce55d2016-02-08 09:53:18 -08001223 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001224
Wei Liud7803db2016-08-18 11:01:05 -07001225 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
1226 atexit(wake_lock_releaser);
1227
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001228 /* gets the sequential id */
1229 char last_id[PROPERTY_VALUE_MAX];
1230 property_get("dumpstate.last_id", last_id, "0");
1231 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001232 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001233 property_set("dumpstate.last_id", last_id);
1234 MYLOGI("dumpstate id: %lu\n", id);
1235
Jeff Brown1dc94e32014-09-11 14:15:27 -07001236 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001237 memset(&sigact, 0, sizeof(sigact));
1238 sigact.sa_handler = sigpipe_handler;
1239 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001240
Colin Crossf45fa6b2012-03-26 12:38:26 -07001241 /* set as high priority, and protect from OOM killer */
1242 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001243
1244 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001245 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001246 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001247 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001248 } else {
1249 /* fallback to kernels <= 2.6.35 */
1250 oom_adj = fopen("/proc/self/oom_adj", "we");
1251 if (oom_adj) {
1252 fputs("-17", oom_adj);
1253 fclose(oom_adj);
1254 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001255 }
1256
Jeff Brown1dc94e32014-09-11 14:15:27 -07001257 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001258 std::string args;
1259 format_args(argc, const_cast<const char **>(argv), &args);
1260 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001261 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001262 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001263 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001264 case 'd': do_add_date = 1; break;
1265 case 'z': do_zip_file = 1; break;
1266 case 'o': use_outfile = optarg; break;
1267 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001268 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001269 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001270 case 'q': do_vibrate = 0; break;
1271 case 'p': do_fb = 1; break;
1272 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001273 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001274 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001275 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001276 case '?': printf("\n");
1277 case 'h':
1278 usage();
1279 exit(1);
1280 }
1281 }
1282
Felipe Leme71bbfc52015-11-23 14:14:51 -08001283 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001284 usage();
1285 exit(1);
1286 }
1287
Felipe Leme2628e9e2016-04-12 16:36:51 -07001288 if (use_control_socket && !do_zip_file) {
1289 usage();
1290 exit(1);
1291 }
1292
Felipe Leme71bbfc52015-11-23 14:14:51 -08001293 if (do_update_progress && !do_broadcast) {
1294 usage();
1295 exit(1);
1296 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001297
Michal Karpinski4db754f2015-12-11 18:04:32 +00001298 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1299 usage();
1300 exit(1);
1301 }
1302
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001303 if (version != VERSION_DEFAULT) {
1304 usage();
1305 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001306 }
1307
Felipe Lemecbce55d2016-02-08 09:53:18 -08001308 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001309
Felipe Lemee338bf62015-12-07 14:03:50 -08001310 do_early_screenshot = do_update_progress;
1311
Christopher Ferrised9354f2014-10-01 17:35:01 -07001312 // If we are going to use a socket, do it as early as possible
1313 // to avoid timeouts from bugreport.
1314 if (use_socket) {
1315 redirect_to_socket(stdout, "dumpstate");
1316 }
1317
Felipe Leme2628e9e2016-04-12 16:36:51 -07001318 if (use_control_socket) {
1319 MYLOGD("Opening control socket\n");
1320 control_socket_fd = open_socket("dumpstate");
Felipe Leme02b7e002016-07-22 12:03:20 -07001321 do_update_progress = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001322 }
1323
Felipe Lemecbce55d2016-02-08 09:53:18 -08001324 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001325 std::string tmp_path;
1326
Felipe Lemecbce55d2016-02-08 09:53:18 -08001327 /* full path of the file containing the dumpstate logs*/
1328 std::string log_path;
1329
Felipe Leme14e034a2016-03-30 18:51:03 -07001330 /* full path of the systrace file, when enabled */
1331 std::string systrace_path;
1332
Felipe Lemee338bf62015-12-07 14:03:50 -08001333 /* full path of the temporary file containing the screenshot (when requested) */
1334 std::string screenshot_path;
1335
Felipe Lemecbce55d2016-02-08 09:53:18 -08001336 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001337 std::string base_name;
1338
Felipe Leme71bbfc52015-11-23 14:14:51 -08001339 /* pointer to the actual path, be it zip or text */
1340 std::string path;
1341
Felipe Leme635ca312016-01-05 14:23:02 -08001342 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001343 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001344
Felipe Lemead5f6c42015-11-30 14:26:46 -08001345 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001346 bool is_redirecting = !use_socket && use_outfile;
1347
1348 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001349 bugreport_dir = dirname(use_outfile);
1350 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001351 if (do_add_date) {
1352 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001353 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1354 suffix = date;
1355 } else {
1356 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001357 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001358 char build_id[PROPERTY_VALUE_MAX];
1359 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1360 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001361 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001362 // TODO: if dumpstate was an object, the paths could be internal variables and then
1363 // we could have a function to calculate the derived values, such as:
1364 // screenshot_path = GetPath(".png");
1365 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001366 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001367 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001368 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1369 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001370
Felipe Lemecbce55d2016-02-08 09:53:18 -08001371 MYLOGD("Bugreport dir: %s\n"
1372 "Base name: %s\n"
1373 "Suffix: %s\n"
1374 "Log path: %s\n"
1375 "Temporary path: %s\n"
1376 "Screenshot path: %s\n",
1377 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1378 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001379
Felipe Leme1e9edc62015-12-21 16:02:13 -08001380 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001381 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001382 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001383 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001384 zip_file.reset(fopen(path.c_str(), "wb"));
1385 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001386 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001387 do_zip_file = 0;
1388 } else {
1389 zip_writer.reset(new ZipWriter(zip_file.get()));
1390 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001391 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001392 }
1393
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001394 if (do_update_progress) {
1395 if (do_broadcast) {
1396 // clang-format off
1397 std::vector<std::string> am_args = {
1398 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
1399 "--es", "android.intent.extra.NAME", suffix,
1400 "--ei", "android.intent.extra.ID", std::to_string(id),
1401 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1402 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1403 };
1404 // clang-format on
1405 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1406 }
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001407 if (use_control_socket) {
1408 dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
1409 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08001410 }
1411 }
1412
Nick Kralevichf3599b32016-01-25 15:05:16 -08001413 /* read /proc/cmdline before dropping root */
1414 FILE *cmdline = fopen("/proc/cmdline", "re");
1415 if (cmdline) {
1416 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1417 fclose(cmdline);
1418 }
1419
Jeff Brown1dc94e32014-09-11 14:15:27 -07001420 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001421 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001422 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001423 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001424 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001425 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001426 }
John Michelau1f794c42012-09-17 11:20:19 -05001427 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001428
Felipe Leme3634a1e2015-12-09 10:11:47 -08001429 if (do_fb && do_early_screenshot) {
1430 if (screenshot_path.empty()) {
1431 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001432 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001433 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001434 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001435 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001436 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001437 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001438 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001439 screenshot_path.c_str(), strerror(errno));
1440 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001441 }
1442 }
1443
Felipe Leme1e9edc62015-12-21 16:02:13 -08001444 if (do_zip_file) {
1445 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001446 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001447 }
1448 }
1449
Felipe Leme71bbfc52015-11-23 14:14:51 -08001450 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001451 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001452 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1453 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1454 log_path.c_str(), strerror(errno));
1455 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001456 /* TODO: rather than generating a text file now and zipping it later,
1457 it would be more efficient to redirect stdout to the zip entry
1458 directly, but the libziparchive doesn't support that option yet. */
1459 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001460 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1461 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1462 tmp_path.c_str(), strerror(errno));
1463 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001464 }
Felipe Leme608385d2016-02-01 10:35:38 -08001465 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1466 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001467 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001468 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001469
Felipe Leme71a74ac2016-03-17 15:43:25 -07001470 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001471 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1472 // the raw trace.
1473 if (!dump_anrd_trace()) {
1474 dump_systrace();
1475 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001476
Wei Liu341938b2016-04-27 16:18:17 -07001477 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001478 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001479
Felipe Leme9c74aad2016-02-29 18:15:42 -08001480 // Invoking the following dumpsys calls before dump_traces() to try and
1481 // keep the system stats as close to its initial state as possible.
Thierry Strudel8b78b752016-03-22 10:25:44 -07001482 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
Felipe Leme7cff4622016-06-08 09:51:29 -07001483 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001484
1485 /* collect stack traces from Dalvik and native processes (needs root) */
1486 dump_traces_path = dump_traces();
1487
Felipe Lemec0808152016-06-17 17:37:13 -07001488 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001489 get_tombstone_fds(tombstone_data);
1490 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001491 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001492 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001493 if (!is_user_build()) {
1494 add_dir(PROFILE_DATA_DIR_CUR, true);
1495 add_dir(PROFILE_DATA_DIR_REF, true);
1496 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001497 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001498 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001499
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001500 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001501 return -1;
1502 }
1503
1504 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001505
Felipe Leme55b42a62015-11-10 17:39:08 -08001506 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001507 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001508 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001509 }
1510
Felipe Leme6e01fa62015-11-11 19:35:14 -08001511 /* rename or zip the (now complete) .tmp file to its final location */
1512 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001513
1514 /* check if user changed the suffix using system properties */
1515 char key[PROPERTY_KEY_MAX];
1516 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001517 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001518 property_get(key, value, "");
1519 bool change_suffix= false;
1520 if (value[0]) {
1521 /* must whitelist which characters are allowed, otherwise it could cross directories */
1522 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1523 if (std::regex_match(value, valid_regex)) {
1524 change_suffix = true;
1525 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001526 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001527 }
1528 }
1529 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001530 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001531 suffix = value;
1532 if (!screenshot_path.empty()) {
1533 std::string new_screenshot_path =
1534 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1535 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001536 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001537 new_screenshot_path.c_str(), strerror(errno));
1538 } else {
1539 screenshot_path = new_screenshot_path;
1540 }
1541 }
1542 }
1543
Felipe Leme6e01fa62015-11-11 19:35:14 -08001544 bool do_text_file = true;
1545 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001546 std::string entry_name = base_name + "-" + suffix + ".txt";
1547 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1548 if (!finish_zip_file(entry_name, tmp_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001549 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001550 do_text_file = true;
1551 } else {
1552 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001553 // Since zip file is already created, it needs to be renamed.
1554 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1555 if (path != new_path) {
1556 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1557 if (rename(path.c_str(), new_path.c_str())) {
1558 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1559 new_path.c_str(), strerror(errno));
1560 } else {
1561 path = new_path;
1562 }
1563 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001564 }
1565 }
1566 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001567 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001568 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001569 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001570 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001571 path.clear();
1572 }
1573 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001574 if (use_control_socket) {
1575 if (do_text_file) {
1576 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1577 "for more details\n", log_path.c_str());
1578 } else {
1579 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1580 }
1581 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001582 }
1583
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001584 /* vibrate a few but shortly times to let user know it's finished */
1585 if (vibrator) {
1586 for (int i = 0; i < 3; i++) {
1587 vibrate(vibrator.get(), 75);
1588 usleep((75 + 50) * 1000);
1589 }
1590 }
1591
Jeff Brown1dc94e32014-09-11 14:15:27 -07001592 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001593 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001594 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001595 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001596 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001597 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001598 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001599 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001600 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001601 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001602 "--es", "android.intent.extra.BUGREPORT", path,
1603 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001604 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001605 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001606 if (do_fb) {
1607 am_args.push_back("--es");
1608 am_args.push_back("android.intent.extra.SCREENSHOT");
1609 am_args.push_back(screenshot_path);
1610 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001611 if (is_remote_mode) {
1612 am_args.push_back("--es");
1613 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1614 am_args.push_back(SHA256_file_hash(path));
1615 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1616 } else {
1617 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1618 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001619 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001620 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001621 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001622 }
1623
Felipe Lemecbce55d2016-02-08 09:53:18 -08001624 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1625 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001626
Felipe Leme107a05f2016-03-08 15:11:15 -08001627 if (is_redirecting) {
1628 fclose(stderr);
1629 }
1630
Felipe Leme02b7e002016-07-22 12:03:20 -07001631 if (use_control_socket && control_socket_fd != -1) {
1632 MYLOGD("Closing control socket\n");
1633 close(control_socket_fd);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001634 }
1635
Colin Crossf45fa6b2012-03-26 12:38:26 -07001636 return 0;
1637}