blob: f950f4d6de21f2827149ad7324702620b89d8eac [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>
Colin Crossf45fa6b2012-03-26 12:38:26 -070038#include <cutils/properties.h>
39
40#include "private/android_filesystem_config.h"
41
42#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070043#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044
45#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080046#include "ScopedFd.h"
47#include "ziparchive/zip_writer.h"
48
Michal Karpinski4db754f2015-12-11 18:04:32 +000049#include "mincrypt/sha256.h"
50
Felipe Leme6e01fa62015-11-11 19:35:14 -080051using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070052
53/* read before root is shed */
54static char cmdline_buf[16384] = "(unknown)";
55static const char *dump_traces_path = NULL;
56
Felipe Lemeefd7e272016-05-18 09:27:16 -070057// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080058static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080059static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080060static time_t now;
61static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080062static std::set<std::string> mount_points;
63void add_mountinfo();
Felipe Leme2628e9e2016-04-12 16:36:51 -070064static int control_socket_fd;
Felipe Lemeefd7e272016-05-18 09:27:16 -070065/* suffix of the bugreport files - it's typically the date (when invoked with -d),
66 * although it could be changed by the user using a system property */
67static std::string suffix;
Felipe Leme78f2c862015-12-21 09:55:22 -080068
Todd Poynor2a83daa2013-11-22 15:44:22 -080069#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
70
Wei Liu341938b2016-04-27 16:18:17 -070071#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080072#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070073#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070074#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010075#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
76#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070077#define TOMBSTONE_DIR "/data/tombstones"
78#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
79/* Can accomodate a tombstone number up to 9999. */
80#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
81#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090082#define WLUTIL "/vendor/xbin/wlutil"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070083
84typedef struct {
85 char name[TOMBSTONE_MAX_LEN];
86 int fd;
87} tombstone_data_t;
88
89static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
90
Felipe Leme71ca15e2016-05-19 16:18:17 -070091const std::string ZIP_ROOT_DIR = "FS";
92std::string bugreport_dir;
Felipe Lemee82a27d2016-01-05 13:35:44 -080093
Felipe Leme809d74e2016-02-02 12:57:00 -080094/*
95 * List of supported zip format versions.
96 *
97 * See bugreport-format.txt for more info.
98 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -070099static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800100
Calvin On249beee2016-06-03 15:17:07 -0700101bool is_user_build() {
Felipe Lemec4eee562016-04-21 15:42:55 -0700102 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
103}
104
Felipe Lemee82a27d2016-01-05 13:35:44 -0800105/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
106 * otherwise gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700107static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800108 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700109 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
110 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800111 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
112 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700113 struct stat st;
114 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800115 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
116 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700117 } else {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800118 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700119 data[i].fd = -1;
120 }
121 }
122}
123
Felipe Leme635ca312016-01-05 14:23:02 -0800124// for_each_pid() callback to get mount info about a process.
125void do_mountinfo(int pid, const char *name) {
126 char path[PATH_MAX];
127
128 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
129 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700130 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800131 char linkname[PATH_MAX];
132 ssize_t r = readlink(path, linkname, PATH_MAX);
133 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800134 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800135 return;
136 }
137 linkname[r] = '\0';
138
139 if (mount_points.find(linkname) == mount_points.end()) {
140 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700141 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800142 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
143 mount_points.insert(linkname);
144 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800145 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800146 }
147 }
148}
149
150void add_mountinfo() {
151 if (!zip_writer) return;
152 const char *title = "MOUNT INFO";
153 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800154 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800155 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800156 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800157}
158
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700159static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
160{
161 DIR *d;
162 struct dirent *de;
163 char path[PATH_MAX];
164
165 d = opendir(driverpath);
166 if (d == NULL) {
167 return;
168 }
169
170 while ((de = readdir(d))) {
171 if (de->d_type != DT_LNK) {
172 continue;
173 }
174 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
175 dump_file(title, path);
176 }
177
178 closedir(d);
179}
180
Felipe Lemeefd7e272016-05-18 09:27:16 -0700181static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700182 if (!zip_writer) {
183 MYLOGD("Not dumping systrace because zip_writer is not set\n");
184 return;
185 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700186 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700187 if (systrace_path.empty()) {
188 MYLOGE("Not dumping systrace because path is empty\n");
189 return;
190 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700191 const char* path = "/sys/kernel/debug/tracing/tracing_on";
192 long int is_tracing;
193 if (read_file_as_long(path, &is_tracing)) {
194 return; // error already logged
195 }
196 if (is_tracing <= 0) {
197 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
198 return;
199 }
200
Felipe Leme14e034a2016-03-30 18:51:03 -0700201 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
202 systrace_path.c_str());
203 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
204 systrace_path.c_str(), NULL)) {
205 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
206 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
207 // we should call strace to stop itself, but there is no such option yet (just a
208 // --async_stop, which stops and dump
209 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
210 // MYLOGE("could not stop systrace ");
211 // }
212 }
213 if (!add_zip_entry("systrace.txt", systrace_path)) {
214 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700215 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700216 if (remove(systrace_path.c_str())) {
217 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
218 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700219 }
220}
221
Felipe Lemeefd7e272016-05-18 09:27:16 -0700222static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700223 if (is_user_build()) {
224 return;
225 }
226
Felipe Lemeefd7e272016-05-18 09:27:16 -0700227 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700228 if (raft_log_path.empty()) {
229 MYLOGD("raft_log_path is empty\n");
230 return;
231 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700232
233 struct stat s;
234 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
235 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
236 return;
237 }
238
Wei Liu341938b2016-04-27 16:18:17 -0700239 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700240 // Write compressed and encoded raft logs to stdout if not zip_writer.
241 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700242 return;
243 }
244
245 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
246 "-o", raft_log_path.c_str(), NULL);
247 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
248 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
249 } else {
250 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700251 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700252 }
253 }
254}
255
Mark Salyzyn326842f2015-04-30 09:49:41 -0700256static bool skip_not_stat(const char *path) {
257 static const char stat[] = "/stat";
258 size_t len = strlen(path);
259 if (path[len - 1] == '/') { /* Directory? */
260 return false;
261 }
262 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
263}
264
Felipe Lemee82a27d2016-01-05 13:35:44 -0800265static bool skip_none(const char *path) {
266 return false;
267}
268
Mark Salyzyn326842f2015-04-30 09:49:41 -0700269static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700270unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700271
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800272//
273// stat offsets
274// Name units description
275// ---- ----- -----------
276// read I/Os requests number of read I/Os processed
277#define __STAT_READ_IOS 0
278// read merges requests number of read I/Os merged with in-queue I/O
279#define __STAT_READ_MERGES 1
280// read sectors sectors number of sectors read
281#define __STAT_READ_SECTORS 2
282// read ticks milliseconds total wait time for read requests
283#define __STAT_READ_TICKS 3
284// write I/Os requests number of write I/Os processed
285#define __STAT_WRITE_IOS 4
286// write merges requests number of write I/Os merged with in-queue I/O
287#define __STAT_WRITE_MERGES 5
288// write sectors sectors number of sectors written
289#define __STAT_WRITE_SECTORS 6
290// write ticks milliseconds total wait time for write requests
291#define __STAT_WRITE_TICKS 7
292// in_flight requests number of I/Os currently in flight
293#define __STAT_IN_FLIGHT 8
294// io_ticks milliseconds total time this block device has been active
295#define __STAT_IO_TICKS 9
296// time_in_queue milliseconds total wait time for all requests
297#define __STAT_IN_QUEUE 10
298#define __STAT_NUMBER_FIELD 11
299//
300// read I/Os, write I/Os
301// =====================
302//
303// These values increment when an I/O request completes.
304//
305// read merges, write merges
306// =========================
307//
308// These values increment when an I/O request is merged with an
309// already-queued I/O request.
310//
311// read sectors, write sectors
312// ===========================
313//
314// These values count the number of sectors read from or written to this
315// block device. The "sectors" in question are the standard UNIX 512-byte
316// sectors, not any device- or filesystem-specific block size. The
317// counters are incremented when the I/O completes.
318#define SECTOR_SIZE 512
319//
320// read ticks, write ticks
321// =======================
322//
323// These values count the number of milliseconds that I/O requests have
324// waited on this block device. If there are multiple I/O requests waiting,
325// these values will increase at a rate greater than 1000/second; for
326// example, if 60 read requests wait for an average of 30 ms, the read_ticks
327// field will increase by 60*30 = 1800.
328//
329// in_flight
330// =========
331//
332// This value counts the number of I/O requests that have been issued to
333// the device driver but have not yet completed. It does not include I/O
334// requests that are in the queue but not yet issued to the device driver.
335//
336// io_ticks
337// ========
338//
339// This value counts the number of milliseconds during which the device has
340// had I/O requests queued.
341//
342// time_in_queue
343// =============
344//
345// This value counts the number of milliseconds that I/O requests have waited
346// on this block device. If there are multiple I/O requests waiting, this
347// value will increase as the product of the number of milliseconds times the
348// number of requests waiting (see "read ticks" above for an example).
349#define S_TO_MS 1000
350//
351
Mark Salyzyn326842f2015-04-30 09:49:41 -0700352static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800353 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700354 bool z;
355 char *cp, *buffer = NULL;
356 size_t i = 0;
357 FILE *fp = fdopen(fd, "rb");
358 getline(&buffer, &i, fp);
359 fclose(fp);
360 if (!buffer) {
361 return -errno;
362 }
363 i = strlen(buffer);
364 while ((i > 0) && (buffer[i - 1] == '\n')) {
365 buffer[--i] = '\0';
366 }
367 if (!*buffer) {
368 free(buffer);
369 return 0;
370 }
371 z = true;
372 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800373 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700374 if (fields[i] != 0) {
375 z = false;
376 }
377 }
378 if (z) { /* never accessed */
379 free(buffer);
380 return 0;
381 }
382
383 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
384 path += sizeof(mmcblk0) - 1;
385 }
386
387 printf("%s: %s\n", path, buffer);
388 free(buffer);
389
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800390 if (fields[__STAT_IO_TICKS]) {
391 unsigned long read_perf = 0;
392 unsigned long read_ios = 0;
393 if (fields[__STAT_READ_TICKS]) {
394 unsigned long long divisor = fields[__STAT_READ_TICKS]
395 * fields[__STAT_IO_TICKS];
396 read_perf = ((unsigned long long)SECTOR_SIZE
397 * fields[__STAT_READ_SECTORS]
398 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
399 / divisor;
400 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
401 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
402 / divisor;
403 }
404
405 unsigned long write_perf = 0;
406 unsigned long write_ios = 0;
407 if (fields[__STAT_WRITE_TICKS]) {
408 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
409 * fields[__STAT_IO_TICKS];
410 write_perf = ((unsigned long long)SECTOR_SIZE
411 * fields[__STAT_WRITE_SECTORS]
412 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
413 / divisor;
414 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
415 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
416 / divisor;
417 }
418
419 unsigned queue = (fields[__STAT_IN_QUEUE]
420 + (fields[__STAT_IO_TICKS] >> 1))
421 / fields[__STAT_IO_TICKS];
422
423 if (!write_perf && !write_ios) {
424 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
425 path, read_perf, read_ios, queue);
426 } else {
427 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
428 path, read_perf, read_ios, write_perf, write_ios, queue);
429 }
430
431 /* bugreport timeout factor adjustment */
432 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
433 worst_write_perf = write_perf;
434 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700435 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700436 return 0;
437}
438
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700439/* Copied policy from system/core/logd/LogBuffer.cpp */
440
441#define LOG_BUFFER_SIZE (256 * 1024)
442#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
443#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
444
445static bool valid_size(unsigned long value) {
446 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
447 return false;
448 }
449
450 long pages = sysconf(_SC_PHYS_PAGES);
451 if (pages < 1) {
452 return true;
453 }
454
455 long pagesize = sysconf(_SC_PAGESIZE);
456 if (pagesize <= 1) {
457 pagesize = PAGE_SIZE;
458 }
459
460 // maximum memory impact a somewhat arbitrary ~3%
461 pages = (pages + 31) / 32;
462 unsigned long maximum = pages * pagesize;
463
464 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
465 return true;
466 }
467
468 return value <= maximum;
469}
470
471static unsigned long property_get_size(const char *key) {
472 unsigned long value;
473 char *cp, property[PROPERTY_VALUE_MAX];
474
475 property_get(key, property, "");
476 value = strtoul(property, &cp, 10);
477
478 switch(*cp) {
479 case 'm':
480 case 'M':
481 value *= 1024;
482 /* FALLTHRU */
483 case 'k':
484 case 'K':
485 value *= 1024;
486 /* FALLTHRU */
487 case '\0':
488 break;
489
490 default:
491 value = 0;
492 }
493
494 if (!valid_size(value)) {
495 value = 0;
496 }
497
498 return value;
499}
500
501/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800502static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700503 static const char global_tuneable[] = "persist.logd.size"; // Settings App
504 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
505 char key[PROP_NAME_MAX];
506 unsigned long property_size, default_size;
507
508 default_size = property_get_size(global_tuneable);
509 if (!default_size) {
510 default_size = property_get_size(global_default);
511 }
512
513 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
514 property_size = property_get_size(key);
515
516 if (!property_size) {
517 snprintf(key, sizeof(key), "%s.%s", global_default, name);
518 property_size = property_get_size(key);
519 }
520
521 if (!property_size) {
522 property_size = default_size;
523 }
524
525 if (!property_size) {
526 property_size = LOG_BUFFER_SIZE;
527 }
528
529 /* Engineering margin is ten-fold our guess */
530 return 10 * (property_size + worst_write_perf) / worst_write_perf;
531}
532
533/* End copy from system/core/logd/LogBuffer.cpp */
534
Colin Crossf45fa6b2012-03-26 12:38:26 -0700535/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800536static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700537 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
538 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
539 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700540
541 property_get("ro.build.display.id", build, "(unknown)");
542 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
543 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700544 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700545 property_get("ro.bootloader", bootloader, "(unknown)");
546 property_get("gsm.operator.alpha", network, "(unknown)");
547 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
548
549 printf("========================================================\n");
550 printf("== dumpstate: %s\n", date);
551 printf("========================================================\n");
552
553 printf("\n");
554 printf("Build: %s\n", build);
555 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
556 printf("Bootloader: %s\n", bootloader);
557 printf("Radio: %s\n", radio);
558 printf("Network: %s\n", network);
559
560 printf("Kernel: ");
561 dump_file(NULL, "/proc/version");
562 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800563 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800564 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700565 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800566}
567
Felipe Leme24b66ee2016-06-16 10:55:26 -0700568// List of file extensions that can cause a zip file attachment to be rejected by some email
569// service providers.
570static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
571 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
572 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
573 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
574};
575
Felipe Leme71ca15e2016-05-19 16:18:17 -0700576bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800577 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800578 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
579 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800580 return false;
581 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700582 std::string valid_name = entry_name;
583
584 // Rename extension if necessary.
585 size_t idx = entry_name.rfind(".");
586 if (idx != std::string::npos) {
587 std::string extension = entry_name.substr(idx);
588 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
589 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
590 valid_name = entry_name + ".renamed";
591 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
592 }
593 }
594
Felipe Leme6fe9db62016-02-12 09:04:16 -0800595 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
596 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700597 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800598 ZipWriter::kCompress, get_mtime(fd, now));
599 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700600 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800601 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800602 return false;
603 }
604
Felipe Leme770410d2016-01-26 17:07:14 -0800605 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800606 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800607 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
608 if (bytes_read == 0) {
609 break;
610 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800611 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800612 return false;
613 }
614 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
615 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800616 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800617 return false;
618 }
619 }
620
621 err = zip_writer->FinishEntry();
622 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800623 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800624 return false;
625 }
626
627 return true;
628}
629
Felipe Leme71ca15e2016-05-19 16:18:17 -0700630bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800631 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
632 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800633 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800634 return false;
635 }
636
637 return add_zip_entry_from_fd(entry_name, fd.get());
638}
639
640/* adds a file to the existing zipped bugreport */
641static int _add_file_from_fd(const char *title, const char *path, int fd) {
642 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
643}
644
Felipe Leme24b66ee2016-06-16 10:55:26 -0700645// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800646void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800647 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800648 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800649 return;
650 }
Felipe Leme88c79332016-02-22 11:06:49 -0800651 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800652 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800653 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
654}
655
Felipe Leme809d74e2016-02-02 12:57:00 -0800656/* adds a text entry entry to the existing zip file. */
657static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800658 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800659 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 -0800660 return false;
661 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800662 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800663 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
664 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800665 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800666 ZipWriter::ErrorCodeString(err));
667 return false;
668 }
669
670 err = zip_writer->WriteBytes(content.c_str(), content.length());
671 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800672 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800673 ZipWriter::ErrorCodeString(err));
674 return false;
675 }
676
677 err = zip_writer->FinishEntry();
678 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800679 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800680 return false;
681 }
682
683 return true;
684}
685
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800686static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800687 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800688 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700689
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700690 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700691 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700692 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800693 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700694 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughesb32c7e12015-11-13 11:32:48 -0800695 run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700696 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700697 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
698 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
699 dump_file("SLAB INFO", "/proc/slabinfo");
700 dump_file("ZONEINFO", "/proc/zoneinfo");
701 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
702 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700703 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700704
Todd Poynor29e27a82012-05-22 17:54:59 -0700705 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700706 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700707 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700708
Elliott Hughesa3533a32015-10-30 16:17:49 -0700709 run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800710 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700711
Michal Karpinski4db754f2015-12-11 18:04:32 +0000712 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900713 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Michal Karpinski4db754f2015-12-11 18:04:32 +0000714 run_command("LSMOD", 10, "lsmod", NULL);
715
Colin Crossf45fa6b2012-03-26 12:38:26 -0700716 do_dmesg();
717
718 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700719 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
720 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800721 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700722
Felipe Leme6e01fa62015-11-11 19:35:14 -0800723 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800724 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800725 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800726 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700727 }
728
Colin Crossf45fa6b2012-03-26 12:38:26 -0700729 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700730 // calculate timeout
731 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
732 if (timeout < 20000) {
733 timeout = 20000;
734 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700735 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
736 "-v", "printable",
737 "-d",
738 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800739 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700740 if (timeout < 20000) {
741 timeout = 20000;
742 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700743 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
744 "-v", "threadtime",
745 "-v", "printable",
746 "-d",
747 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700748 timeout = logcat_timeout("radio");
749 if (timeout < 20000) {
750 timeout = 20000;
751 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700752 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
753 "-v", "threadtime",
754 "-v", "printable",
755 "-d",
756 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700757
Mark Salyzynecc07632015-07-30 14:57:09 -0700758 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
759
Colin Crossf45fa6b2012-03-26 12:38:26 -0700760 /* show the traces we collected in main(), if that was done */
761 if (dump_traces_path != NULL) {
762 dump_file("VM TRACES JUST NOW", dump_traces_path);
763 }
764
765 /* only show ANR traces if they're less than 15 minutes old */
766 struct stat st;
767 char anr_traces_path[PATH_MAX];
768 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
769 if (!anr_traces_path[0]) {
770 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700771 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800772 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
773 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700774 if (fd < 0) {
775 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
776 } else {
777 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
778 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700779 }
780
781 /* slow traces for slow operations */
782 if (anr_traces_path[0] != 0) {
783 int tail = strlen(anr_traces_path)-1;
784 while (tail > 0 && anr_traces_path[tail] != '/') {
785 tail--;
786 }
787 int i = 0;
788 while (1) {
789 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
790 if (stat(anr_traces_path, &st)) {
791 // No traces file at this index, done with the files.
792 break;
793 }
794 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
795 i++;
796 }
797 }
798
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700799 int dumped = 0;
800 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
801 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800802 const char *name = tombstone_data[i].name;
803 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700804 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800805 if (zip_writer) {
806 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800807 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800808 }
809 } else {
810 dump_file_from_fd("TOMBSTONE", name, fd);
811 }
812 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700813 tombstone_data[i].fd = -1;
814 }
815 }
816 if (!dumped) {
817 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
818 }
819
Colin Crossf45fa6b2012-03-26 12:38:26 -0700820 dump_file("NETWORK DEV INFO", "/proc/net/dev");
821 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700822 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700823 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
824 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
825
Todd Poynor2a83daa2013-11-22 15:44:22 -0800826 if (!stat(PSTORE_LAST_KMSG, &st)) {
827 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
828 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
829 } else {
830 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
831 dump_file("LAST KMSG", "/proc/last_kmsg");
832 }
833
Mark Salyzyn2262c162014-12-16 09:09:26 -0800834 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700835 run_command("LAST LOGCAT", 10, "logcat", "-L",
836 "-b", "all",
837 "-v", "threadtime",
838 "-v", "printable",
839 "-d",
840 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800841
Colin Crossf45fa6b2012-03-26 12:38:26 -0700842 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800843
844 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900845
846 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
847 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
848
Colin Crossf45fa6b2012-03-26 12:38:26 -0700849 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
850 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700851
852 dump_route_tables();
853
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900854 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
855 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +0900856 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900857
Colin Crossf45fa6b2012-03-26 12:38:26 -0700858 run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
859 run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
JP Abgrall012c2ea2012-05-16 20:49:29 -0700860 run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
861 /* no ip6 nat */
862 run_command("IPTABLE RAW", 10, SU_PATH, "root", "iptables", "-t", "raw", "-L", "-nvx", NULL);
863 run_command("IP6TABLE RAW", 10, SU_PATH, "root", "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700864
865 run_command("WIFI NETWORKS", 20,
Dmitry Shmidt1d6b97c2013-08-21 10:58:29 -0700866 SU_PATH, "root", "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700867
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800868#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900869 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +0900870 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900871
872 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900873 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900874
875 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900876 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900877
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800878#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800879 dump_file("INTERRUPTS (1)", "/proc/interrupts");
880
Felipe Leme7cff4622016-06-08 09:51:29 -0700881 run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900882
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800883#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -0700884 run_command("DUMP WIFI STATUS", 20,
885 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900886
887 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900888 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900889
890 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900891 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700892#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800893 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700894
895 print_properties();
896
897 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
898 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
899
Ken Sumrall8f75fa72013-02-08 17:35:58 -0800900 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700901
Colin Crossf45fa6b2012-03-26 12:38:26 -0700902 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
903
904 printf("------ BACKLIGHTS ------\n");
905 printf("LCD brightness=");
906 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
907 printf("Button brightness=");
908 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
909 printf("Keyboard brightness=");
910 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
911 printf("ALS mode=");
912 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
913 printf("LCD driver registers:\n");
914 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
915 printf("\n");
916
917 /* Binder state is expensive to look at as it uses a lot of memory. */
918 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
919 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
920 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
921 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
922 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
923
Colin Crossf45fa6b2012-03-26 12:38:26 -0700924 printf("========================================================\n");
925 printf("== Board\n");
926 printf("========================================================\n");
927
928 dumpstate_board();
929 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700930
931 /* Migrate the ril_dumpstate to a dumpstate_board()? */
932 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
933 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
934 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -0700935 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700936 // su does not exist on user builds, so try running without it.
937 // This way any implementations of vril-dump that do not require
938 // root can run on user builds.
939 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
940 "vril-dump", NULL);
941 } else {
942 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
943 SU_PATH, "root", "vril-dump", NULL);
944 }
945 }
946
947 printf("========================================================\n");
948 printf("== Android Framework Services\n");
949 printf("========================================================\n");
950
Wei Liu34222562016-05-19 13:59:01 -0700951 run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700952
953 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -0700954 printf("== Checkins\n");
955 printf("========================================================\n");
956
Felipe Leme7cff4622016-06-08 09:51:29 -0700957 run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
958 run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
959 run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
960 run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
961 run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
962 run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
Dianne Hackborn02bea972013-06-26 18:59:09 -0700963
964 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700965 printf("== Running Application Activities\n");
966 printf("========================================================\n");
967
Felipe Leme3f83dbe2016-06-10 16:56:33 -0700968 run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700969
970 printf("========================================================\n");
971 printf("== Running Application Services\n");
972 printf("========================================================\n");
973
Felipe Leme3f83dbe2016-06-10 16:56:33 -0700974 run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700975
976 printf("========================================================\n");
977 printf("== Running Application Providers\n");
978 printf("========================================================\n");
979
Junda Liucfc33d42016-06-14 00:09:10 -0700980 run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700981
982
983 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -0800984 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
985 getpid(), progress, weight_total, WEIGHT_TOTAL);
986 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700987 printf("== dumpstate: done\n");
988 printf("========================================================\n");
989}
990
991static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -0700992 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -0700993 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
994 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
995 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -0700996 " -b: play sound file instead of vibrate, at beginning of job\n"
997 " -e: play sound file instead of vibrate, at end of job\n"
998 " -o: write to file (instead of stdout)\n"
999 " -d: append date to filename (requires -o)\n"
1000 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001001 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001002 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001003 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001004 " -q: disable vibrate\n"
1005 " -B: send broadcast when finished (requires -o)\n"
1006 " -P: send broadcast when started and update system properties on "
1007 "progress (requires -o and -B)\n"
1008 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1009 "shouldn't be used with -P)\n"
1010 " -V: sets the bugreport format version (valid values: %s)\n",
1011 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001012}
1013
John Michelau885f8882013-05-06 16:42:02 -05001014static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001015 // don't complain to stderr or stdout
1016 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001017}
1018
Felipe Leme1e9edc62015-12-21 16:02:13 -08001019/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1020 temporary file.
1021 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001022static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme1e9edc62015-12-21 16:02:13 -08001023 time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001024 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001025 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001026 return false;
1027 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001028 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001029 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001030 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001031 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001032
Felipe Lemee82a27d2016-01-05 13:35:44 -08001033 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001034 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001035 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001036 return false;
1037 }
1038
Felipe Lemec4eee562016-04-21 15:42:55 -07001039 if (is_user_build()) {
1040 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1041 if (remove(bugreport_path.c_str())) {
1042 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1043 }
1044 } else {
1045 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1046 }
1047
Felipe Leme1e9edc62015-12-21 16:02:13 -08001048 return true;
1049}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001050
Michal Karpinski4db754f2015-12-11 18:04:32 +00001051static std::string SHA256_file_hash(std::string filepath) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001052 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1053 | O_NOFOLLOW)));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001054 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001055 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001056 return NULL;
1057 }
1058
1059 SHA256_CTX ctx;
1060 SHA256_init(&ctx);
1061
1062 std::vector<uint8_t> buffer(65536);
1063 while (1) {
1064 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1065 if (bytes_read == 0) {
1066 break;
1067 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001068 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001069 return NULL;
1070 }
1071
1072 SHA256_update(&ctx, buffer.data(), bytes_read);
1073 }
1074
1075 uint8_t hash[SHA256_DIGEST_SIZE];
1076 memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
1077 char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001078 for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
1079 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001080 }
1081 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1082 return std::string(hash_buffer);
1083}
1084
Colin Crossf45fa6b2012-03-26 12:38:26 -07001085int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001086 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001087 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001088 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001089 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001090 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001091 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001092 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001093 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001094 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001095 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001096 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001097 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001098
Felipe Lemee82a27d2016-01-05 13:35:44 -08001099 now = time(NULL);
1100
Felipe Lemecbce55d2016-02-08 09:53:18 -08001101 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001102
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001103 /* gets the sequential id */
1104 char last_id[PROPERTY_VALUE_MAX];
1105 property_get("dumpstate.last_id", last_id, "0");
1106 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001107 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001108 property_set("dumpstate.last_id", last_id);
1109 MYLOGI("dumpstate id: %lu\n", id);
1110
Jeff Brown1dc94e32014-09-11 14:15:27 -07001111 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001112 memset(&sigact, 0, sizeof(sigact));
1113 sigact.sa_handler = sigpipe_handler;
1114 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001115
Colin Crossf45fa6b2012-03-26 12:38:26 -07001116 /* set as high priority, and protect from OOM killer */
1117 setpriority(PRIO_PROCESS, 0, -20);
Nick Kralevichcd67e9f2015-03-19 11:30:59 -07001118 FILE *oom_adj = fopen("/proc/self/oom_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001119 if (oom_adj) {
1120 fputs("-17", oom_adj);
1121 fclose(oom_adj);
1122 }
1123
Jeff Brown1dc94e32014-09-11 14:15:27 -07001124 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001125 std::string args;
1126 format_args(argc, const_cast<const char **>(argv), &args);
1127 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001128 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001129 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001130 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001131 case 'd': do_add_date = 1; break;
1132 case 'z': do_zip_file = 1; break;
1133 case 'o': use_outfile = optarg; break;
1134 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001135 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001136 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001137 case 'q': do_vibrate = 0; break;
1138 case 'p': do_fb = 1; break;
1139 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001140 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001141 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001142 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001143 case '?': printf("\n");
1144 case 'h':
1145 usage();
1146 exit(1);
1147 }
1148 }
1149
Felipe Leme71bbfc52015-11-23 14:14:51 -08001150 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001151 usage();
1152 exit(1);
1153 }
1154
Felipe Leme2628e9e2016-04-12 16:36:51 -07001155 if (use_control_socket && !do_zip_file) {
1156 usage();
1157 exit(1);
1158 }
1159
Felipe Leme71bbfc52015-11-23 14:14:51 -08001160 if (do_update_progress && !do_broadcast) {
1161 usage();
1162 exit(1);
1163 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001164
Michal Karpinski4db754f2015-12-11 18:04:32 +00001165 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1166 usage();
1167 exit(1);
1168 }
1169
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001170 if (version != VERSION_DEFAULT) {
1171 usage();
1172 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001173 }
1174
Felipe Lemecbce55d2016-02-08 09:53:18 -08001175 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001176
Felipe Lemee338bf62015-12-07 14:03:50 -08001177 do_early_screenshot = do_update_progress;
1178
Christopher Ferrised9354f2014-10-01 17:35:01 -07001179 // If we are going to use a socket, do it as early as possible
1180 // to avoid timeouts from bugreport.
1181 if (use_socket) {
1182 redirect_to_socket(stdout, "dumpstate");
1183 }
1184
Felipe Leme2628e9e2016-04-12 16:36:51 -07001185 if (use_control_socket) {
1186 MYLOGD("Opening control socket\n");
1187 control_socket_fd = open_socket("dumpstate");
1188 }
1189
Felipe Lemecbce55d2016-02-08 09:53:18 -08001190 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001191 std::string tmp_path;
1192
Felipe Lemecbce55d2016-02-08 09:53:18 -08001193 /* full path of the file containing the dumpstate logs*/
1194 std::string log_path;
1195
Felipe Leme14e034a2016-03-30 18:51:03 -07001196 /* full path of the systrace file, when enabled */
1197 std::string systrace_path;
1198
Felipe Lemee338bf62015-12-07 14:03:50 -08001199 /* full path of the temporary file containing the screenshot (when requested) */
1200 std::string screenshot_path;
1201
Felipe Lemecbce55d2016-02-08 09:53:18 -08001202 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001203 std::string base_name;
1204
Felipe Leme71bbfc52015-11-23 14:14:51 -08001205 /* pointer to the actual path, be it zip or text */
1206 std::string path;
1207
Felipe Leme635ca312016-01-05 14:23:02 -08001208 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001209 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001210
Felipe Lemead5f6c42015-11-30 14:26:46 -08001211 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001212 bool is_redirecting = !use_socket && use_outfile;
1213
1214 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001215 bugreport_dir = dirname(use_outfile);
1216 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001217 if (do_add_date) {
1218 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001219 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1220 suffix = date;
1221 } else {
1222 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001223 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001224 char build_id[PROPERTY_VALUE_MAX];
1225 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1226 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001227 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001228 // TODO: if dumpstate was an object, the paths could be internal variables and then
1229 // we could have a function to calculate the derived values, such as:
1230 // screenshot_path = GetPath(".png");
1231 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001232 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001233 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001234 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1235 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001236
Felipe Lemecbce55d2016-02-08 09:53:18 -08001237 MYLOGD("Bugreport dir: %s\n"
1238 "Base name: %s\n"
1239 "Suffix: %s\n"
1240 "Log path: %s\n"
1241 "Temporary path: %s\n"
1242 "Screenshot path: %s\n",
1243 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1244 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001245
Felipe Leme1e9edc62015-12-21 16:02:13 -08001246 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001247 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001248 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001249 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001250 zip_file.reset(fopen(path.c_str(), "wb"));
1251 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001252 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001253 do_zip_file = 0;
1254 } else {
1255 zip_writer.reset(new ZipWriter(zip_file.get()));
1256 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001257 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001258 }
1259
Felipe Leme71bbfc52015-11-23 14:14:51 -08001260 if (do_update_progress) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001261 std::vector<std::string> am_args = {
Felipe Lemed5e724a2016-02-11 09:12:39 -08001262 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemead5f6c42015-11-30 14:26:46 -08001263 "--es", "android.intent.extra.NAME", suffix,
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001264 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001265 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1266 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1267 };
1268 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001269 }
1270 }
1271
Nick Kralevichf3599b32016-01-25 15:05:16 -08001272 /* read /proc/cmdline before dropping root */
1273 FILE *cmdline = fopen("/proc/cmdline", "re");
1274 if (cmdline) {
1275 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1276 fclose(cmdline);
1277 }
1278
Jeff Brown1dc94e32014-09-11 14:15:27 -07001279 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001280 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001281 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001282 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001283 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001284 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001285 }
John Michelau1f794c42012-09-17 11:20:19 -05001286 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001287
Felipe Leme3634a1e2015-12-09 10:11:47 -08001288 if (do_fb && do_early_screenshot) {
1289 if (screenshot_path.empty()) {
1290 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001291 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001292 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001293 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001294 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001295 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001296 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001297 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001298 screenshot_path.c_str(), strerror(errno));
1299 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001300 }
1301 }
1302
Felipe Leme1e9edc62015-12-21 16:02:13 -08001303 if (do_zip_file) {
1304 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001305 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001306 }
1307 }
1308
Felipe Leme71bbfc52015-11-23 14:14:51 -08001309 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001310 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001311 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1312 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1313 log_path.c_str(), strerror(errno));
1314 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001315 /* TODO: rather than generating a text file now and zipping it later,
1316 it would be more efficient to redirect stdout to the zip entry
1317 directly, but the libziparchive doesn't support that option yet. */
1318 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001319 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1320 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1321 tmp_path.c_str(), strerror(errno));
1322 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001323 }
Felipe Leme608385d2016-02-01 10:35:38 -08001324 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1325 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001326 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001327 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001328
Felipe Leme71a74ac2016-03-17 15:43:25 -07001329 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001330 dump_systrace();
Felipe Leme71a74ac2016-03-17 15:43:25 -07001331
Wei Liu341938b2016-04-27 16:18:17 -07001332 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001333 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001334
Felipe Leme9c74aad2016-02-29 18:15:42 -08001335 // Invoking the following dumpsys calls before dump_traces() to try and
1336 // keep the system stats as close to its initial state as possible.
Thierry Strudel8b78b752016-03-22 10:25:44 -07001337 run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
Felipe Leme7cff4622016-06-08 09:51:29 -07001338 run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001339
1340 /* collect stack traces from Dalvik and native processes (needs root) */
1341 dump_traces_path = dump_traces();
1342
1343 /* Get the tombstone fds, recovery files, and mount info here while we are running as root. */
1344 get_tombstone_fds(tombstone_data);
1345 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001346 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001347 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001348 if (!is_user_build()) {
1349 add_dir(PROFILE_DATA_DIR_CUR, true);
1350 add_dir(PROFILE_DATA_DIR_REF, true);
1351 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001352 add_mountinfo();
1353
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001354 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001355 return -1;
1356 }
1357
1358 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001359
Felipe Leme55b42a62015-11-10 17:39:08 -08001360 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001361 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001362 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001363 }
1364
Felipe Leme6e01fa62015-11-11 19:35:14 -08001365 /* rename or zip the (now complete) .tmp file to its final location */
1366 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001367
1368 /* check if user changed the suffix using system properties */
1369 char key[PROPERTY_KEY_MAX];
1370 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001371 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001372 property_get(key, value, "");
1373 bool change_suffix= false;
1374 if (value[0]) {
1375 /* must whitelist which characters are allowed, otherwise it could cross directories */
1376 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1377 if (std::regex_match(value, valid_regex)) {
1378 change_suffix = true;
1379 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001380 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001381 }
1382 }
1383 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001384 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001385 suffix = value;
1386 if (!screenshot_path.empty()) {
1387 std::string new_screenshot_path =
1388 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1389 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001390 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001391 new_screenshot_path.c_str(), strerror(errno));
1392 } else {
1393 screenshot_path = new_screenshot_path;
1394 }
1395 }
1396 }
1397
Felipe Leme6e01fa62015-11-11 19:35:14 -08001398 bool do_text_file = true;
1399 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001400 std::string entry_name = base_name + "-" + suffix + ".txt";
1401 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
1402 if (!finish_zip_file(entry_name, tmp_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001403 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001404 do_text_file = true;
1405 } else {
1406 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001407 // Since zip file is already created, it needs to be renamed.
1408 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1409 if (path != new_path) {
1410 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1411 if (rename(path.c_str(), new_path.c_str())) {
1412 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1413 new_path.c_str(), strerror(errno));
1414 } else {
1415 path = new_path;
1416 }
1417 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001418 }
1419 }
1420 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001421 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001422 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001423 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001424 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001425 path.clear();
1426 }
1427 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001428 if (use_control_socket) {
1429 if (do_text_file) {
1430 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1431 "for more details\n", log_path.c_str());
1432 } else {
1433 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1434 }
1435 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001436 }
1437
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001438 /* vibrate a few but shortly times to let user know it's finished */
1439 if (vibrator) {
1440 for (int i = 0; i < 3; i++) {
1441 vibrate(vibrator.get(), 75);
1442 usleep((75 + 50) * 1000);
1443 }
1444 }
1445
Jeff Brown1dc94e32014-09-11 14:15:27 -07001446 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001447 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001448 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001449 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001450 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001451 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001452 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001453 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001454 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001455 "--es", "android.intent.extra.BUGREPORT", path,
1456 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001457 };
1458 if (do_fb) {
1459 am_args.push_back("--es");
1460 am_args.push_back("android.intent.extra.SCREENSHOT");
1461 am_args.push_back(screenshot_path);
1462 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001463 if (is_remote_mode) {
1464 am_args.push_back("--es");
1465 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1466 am_args.push_back(SHA256_file_hash(path));
1467 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1468 } else {
1469 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1470 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001471 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001472 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001473 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001474 }
1475
Felipe Lemecbce55d2016-02-08 09:53:18 -08001476 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1477 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001478
Felipe Leme107a05f2016-03-08 15:11:15 -08001479 if (is_redirecting) {
1480 fclose(stderr);
1481 }
1482
Felipe Leme2628e9e2016-04-12 16:36:51 -07001483 if (use_control_socket && control_socket_fd >= 0) {
1484 MYLOGD("Closing control socket\n");
1485 close(control_socket_fd);
1486 }
1487
Colin Crossf45fa6b2012-03-26 12:38:26 -07001488 return 0;
1489}