blob: 8a4ebf32493c3f6514a40394584f218936ca34cf [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070017#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070018#include <errno.h>
19#include <fcntl.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080020#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070021#include <limits.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080022#include <memory>
Felipe Lemead5f6c42015-11-30 14:26:46 -080023#include <regex>
Felipe Leme635ca312016-01-05 14:23:02 -080024#include <set>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070025#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070026#include <stdio.h>
27#include <stdlib.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080028#include <string>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <string.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070030#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070031#include <sys/resource.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/wait.h>
35#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070036
Elliott Hughes9dc117c2015-12-07 14:21:50 -080037#include <android-base/stringprintf.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070038#include <android-base/unique_fd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070039#include <cutils/properties.h>
40
41#include "private/android_filesystem_config.h"
42
43#define LOG_TAG "dumpstate"
Alex Ray656a6b92013-07-23 13:44:34 -070044#include <cutils/log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070045
46#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080047#include "ziparchive/zip_writer.h"
48
Elliott Hughesc4dc1412016-04-12 16:28:31 -070049#include <openssl/sha.h>
Michal Karpinski4db754f2015-12-11 18:04:32 +000050
Felipe Leme6e01fa62015-11-11 19:35:14 -080051using android::base::StringPrintf;
Colin Crossf45fa6b2012-03-26 12:38:26 -070052
53/* read before root is shed */
54static char cmdline_buf[16384] = "(unknown)";
55static const char *dump_traces_path = NULL;
56
Felipe Lemeefd7e272016-05-18 09:27:16 -070057// TODO: variables below should be part of dumpstate object
Felipe Leme8fecfdd2016-02-09 10:40:07 -080058static unsigned long id;
Felipe Leme78f2c862015-12-21 09:55:22 -080059static char build_type[PROPERTY_VALUE_MAX];
Felipe Lemee82a27d2016-01-05 13:35:44 -080060static time_t now;
61static std::unique_ptr<ZipWriter> zip_writer;
Felipe Leme635ca312016-01-05 14:23:02 -080062static std::set<std::string> mount_points;
63void add_mountinfo();
Felipe Leme02b7e002016-07-22 12:03:20 -070064int control_socket_fd = -1;
Felipe Lemeefd7e272016-05-18 09:27:16 -070065/* suffix of the bugreport files - it's typically the date (when invoked with -d),
66 * although it could be changed by the user using a system property */
67static std::string suffix;
Felipe Leme78f2c862015-12-21 09:55:22 -080068
Todd Poynor2a83daa2013-11-22 15:44:22 -080069#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -070070#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080071
Wei Liu341938b2016-04-27 16:18:17 -070072#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080073#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070074#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070075#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010076#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
77#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070078#define TOMBSTONE_DIR "/data/tombstones"
79#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
80/* Can accomodate a tombstone number up to 9999. */
81#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
82#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090083#define WLUTIL "/vendor/xbin/wlutil"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070084
85typedef struct {
86 char name[TOMBSTONE_MAX_LEN];
87 int fd;
88} tombstone_data_t;
89
90static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
91
Felipe Leme71ca15e2016-05-19 16:18:17 -070092const std::string ZIP_ROOT_DIR = "FS";
93std::string bugreport_dir;
Felipe Lemee82a27d2016-01-05 13:35:44 -080094
Felipe Leme809d74e2016-02-02 12:57:00 -080095/*
96 * List of supported zip format versions.
97 *
98 * See bugreport-format.txt for more info.
99 */
Felipe Lemeca9c12e2016-05-19 16:30:15 -0700100static std::string VERSION_DEFAULT = "1.0";
Felipe Leme809d74e2016-02-02 12:57:00 -0800101
Calvin On249beee2016-06-03 15:17:07 -0700102bool is_user_build() {
Felipe Lemec4eee562016-04-21 15:42:55 -0700103 return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
104}
105
Felipe Leme3d305a12016-05-20 11:24:37 -0700106/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
107 * otherwise, gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700108static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800109 time_t thirty_minutes_ago = now - 60*30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700110 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
111 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800112 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
113 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700114 struct stat st;
Felipe Leme3d305a12016-05-20 11:24:37 -0700115 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
Felipe Lemee82a27d2016-01-05 13:35:44 -0800116 (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
Felipe Leme3d305a12016-05-20 11:24:37 -0700117 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700118 } else {
Felipe Leme3d305a12016-05-20 11:24:37 -0700119 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700120 data[i].fd = -1;
121 }
122 }
123}
124
Felipe Leme635ca312016-01-05 14:23:02 -0800125// for_each_pid() callback to get mount info about a process.
126void do_mountinfo(int pid, const char *name) {
127 char path[PATH_MAX];
128
129 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
130 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700131 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800132 char linkname[PATH_MAX];
133 ssize_t r = readlink(path, linkname, PATH_MAX);
134 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800135 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800136 return;
137 }
138 linkname[r] = '\0';
139
140 if (mount_points.find(linkname) == mount_points.end()) {
141 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700142 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800143 if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
144 mount_points.insert(linkname);
145 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800146 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800147 }
148 }
149}
150
151void add_mountinfo() {
152 if (!zip_writer) return;
153 const char *title = "MOUNT INFO";
154 mount_points.clear();
Felipe Leme608385d2016-02-01 10:35:38 -0800155 DurationReporter duration_reporter(title, NULL);
Felipe Leme635ca312016-01-05 14:23:02 -0800156 for_each_pid(do_mountinfo, NULL);
Felipe Leme1b0225a2016-02-09 16:35:14 -0800157 MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800158}
159
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700160static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
161{
162 DIR *d;
163 struct dirent *de;
164 char path[PATH_MAX];
165
166 d = opendir(driverpath);
167 if (d == NULL) {
168 return;
169 }
170
171 while ((de = readdir(d))) {
172 if (de->d_type != DT_LNK) {
173 continue;
174 }
175 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
176 dump_file(title, path);
177 }
178
179 closedir(d);
180}
181
Felipe Lemeefd7e272016-05-18 09:27:16 -0700182static void dump_systrace() {
Felipe Leme71a74ac2016-03-17 15:43:25 -0700183 if (!zip_writer) {
184 MYLOGD("Not dumping systrace because zip_writer is not set\n");
185 return;
186 }
Felipe Lemeefd7e272016-05-18 09:27:16 -0700187 std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
Felipe Leme14e034a2016-03-30 18:51:03 -0700188 if (systrace_path.empty()) {
189 MYLOGE("Not dumping systrace because path is empty\n");
190 return;
191 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700192 const char* path = "/sys/kernel/debug/tracing/tracing_on";
193 long int is_tracing;
194 if (read_file_as_long(path, &is_tracing)) {
195 return; // error already logged
196 }
197 if (is_tracing <= 0) {
198 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
199 return;
200 }
201
Felipe Leme14e034a2016-03-30 18:51:03 -0700202 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
203 systrace_path.c_str());
204 if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
205 systrace_path.c_str(), NULL)) {
206 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
207 // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
208 // we should call strace to stop itself, but there is no such option yet (just a
209 // --async_stop, which stops and dump
210 // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
211 // MYLOGE("could not stop systrace ");
212 // }
213 }
214 if (!add_zip_entry("systrace.txt", systrace_path)) {
215 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700216 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700217 if (remove(systrace_path.c_str())) {
218 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
219 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700220 }
221}
222
Felipe Lemeefd7e272016-05-18 09:27:16 -0700223static void dump_raft() {
Wei Liu341938b2016-04-27 16:18:17 -0700224 if (is_user_build()) {
225 return;
226 }
227
Felipe Lemeefd7e272016-05-18 09:27:16 -0700228 std::string raft_log_path = bugreport_dir + "/raft_log.txt";
Wei Liu341938b2016-04-27 16:18:17 -0700229 if (raft_log_path.empty()) {
230 MYLOGD("raft_log_path is empty\n");
231 return;
232 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700233
234 struct stat s;
235 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
236 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
237 return;
238 }
239
Wei Liu341938b2016-04-27 16:18:17 -0700240 if (!zip_writer) {
Wei Liu310525a2016-05-25 11:28:57 -0700241 // Write compressed and encoded raft logs to stdout if not zip_writer.
242 run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
Wei Liu341938b2016-04-27 16:18:17 -0700243 return;
244 }
245
246 run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
247 "-o", raft_log_path.c_str(), NULL);
248 if (!add_zip_entry("raft_log.txt", raft_log_path)) {
249 MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
250 } else {
251 if (remove(raft_log_path.c_str())) {
Felipe Lemeefd7e272016-05-18 09:27:16 -0700252 MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700253 }
254 }
255}
256
Mark Salyzyn326842f2015-04-30 09:49:41 -0700257static bool skip_not_stat(const char *path) {
258 static const char stat[] = "/stat";
259 size_t len = strlen(path);
260 if (path[len - 1] == '/') { /* Directory? */
261 return false;
262 }
263 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
264}
265
Felipe Lemee82a27d2016-01-05 13:35:44 -0800266static bool skip_none(const char *path) {
267 return false;
268}
269
Felipe Lemedc42bda2016-06-30 14:27:04 -0700270static void _run_dumpsys(const std::string& title, RootMode root_mode, int timeout_seconds,
271 const std::vector<std::string>& args) {
272 DurationReporter duration_reporter(title.c_str());
273
274 std::string timeout_string = std::to_string(timeout_seconds);
275
276 const char *dumpsys_args[ARG_MAX] = { "/system/bin/dumpsys", "-t", timeout_string.c_str()};
277
278 int index = 3; // 'dumpsys' '-t' 'TIMEOUT'
279 for (const std::string& arg : args) {
280 if (index > ARG_MAX - 2) {
281 MYLOGE("Too many arguments for '%s': %d\n", title.c_str(), (int) args.size());
282 return;
283 }
284 dumpsys_args[index++] = arg.c_str();
285 }
286 // Always terminate with nullptr.
287 dumpsys_args[index] = nullptr;
288
289 std::string args_string;
290 format_args(index, dumpsys_args, &args_string);
291 printf("------ %s (%s) ------\n", title.c_str(), args_string.c_str());
292 fflush(stdout);
293
294 ON_DRY_RUN({ update_progress(timeout_seconds); return; });
295
296 run_command_always(title.c_str(), root_mode, NORMAL_STDOUT, timeout_seconds, dumpsys_args);
297}
298
299static void run_dumpsys(const std::string& title, int timeout_seconds,
300 const std::vector<std::string>& args) {
301 _run_dumpsys(title, DONT_DROP_ROOT, timeout_seconds, args);
302}
303
304static void run_dumpsys_as_shell(const std::string& title, int timeout_seconds,
305 const std::vector<std::string>& args) {
306 _run_dumpsys(title, DROP_ROOT, timeout_seconds, args);
307}
308
Mark Salyzyn326842f2015-04-30 09:49:41 -0700309static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700310unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700311
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800312//
313// stat offsets
314// Name units description
315// ---- ----- -----------
316// read I/Os requests number of read I/Os processed
317#define __STAT_READ_IOS 0
318// read merges requests number of read I/Os merged with in-queue I/O
319#define __STAT_READ_MERGES 1
320// read sectors sectors number of sectors read
321#define __STAT_READ_SECTORS 2
322// read ticks milliseconds total wait time for read requests
323#define __STAT_READ_TICKS 3
324// write I/Os requests number of write I/Os processed
325#define __STAT_WRITE_IOS 4
326// write merges requests number of write I/Os merged with in-queue I/O
327#define __STAT_WRITE_MERGES 5
328// write sectors sectors number of sectors written
329#define __STAT_WRITE_SECTORS 6
330// write ticks milliseconds total wait time for write requests
331#define __STAT_WRITE_TICKS 7
332// in_flight requests number of I/Os currently in flight
333#define __STAT_IN_FLIGHT 8
334// io_ticks milliseconds total time this block device has been active
335#define __STAT_IO_TICKS 9
336// time_in_queue milliseconds total wait time for all requests
337#define __STAT_IN_QUEUE 10
338#define __STAT_NUMBER_FIELD 11
339//
340// read I/Os, write I/Os
341// =====================
342//
343// These values increment when an I/O request completes.
344//
345// read merges, write merges
346// =========================
347//
348// These values increment when an I/O request is merged with an
349// already-queued I/O request.
350//
351// read sectors, write sectors
352// ===========================
353//
354// These values count the number of sectors read from or written to this
355// block device. The "sectors" in question are the standard UNIX 512-byte
356// sectors, not any device- or filesystem-specific block size. The
357// counters are incremented when the I/O completes.
358#define SECTOR_SIZE 512
359//
360// read ticks, write ticks
361// =======================
362//
363// These values count the number of milliseconds that I/O requests have
364// waited on this block device. If there are multiple I/O requests waiting,
365// these values will increase at a rate greater than 1000/second; for
366// example, if 60 read requests wait for an average of 30 ms, the read_ticks
367// field will increase by 60*30 = 1800.
368//
369// in_flight
370// =========
371//
372// This value counts the number of I/O requests that have been issued to
373// the device driver but have not yet completed. It does not include I/O
374// requests that are in the queue but not yet issued to the device driver.
375//
376// io_ticks
377// ========
378//
379// This value counts the number of milliseconds during which the device has
380// had I/O requests queued.
381//
382// time_in_queue
383// =============
384//
385// This value counts the number of milliseconds that I/O requests have waited
386// on this block device. If there are multiple I/O requests waiting, this
387// value will increase as the product of the number of milliseconds times the
388// number of requests waiting (see "read ticks" above for an example).
389#define S_TO_MS 1000
390//
391
Mark Salyzyn326842f2015-04-30 09:49:41 -0700392static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800393 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700394 bool z;
395 char *cp, *buffer = NULL;
396 size_t i = 0;
397 FILE *fp = fdopen(fd, "rb");
398 getline(&buffer, &i, fp);
399 fclose(fp);
400 if (!buffer) {
401 return -errno;
402 }
403 i = strlen(buffer);
404 while ((i > 0) && (buffer[i - 1] == '\n')) {
405 buffer[--i] = '\0';
406 }
407 if (!*buffer) {
408 free(buffer);
409 return 0;
410 }
411 z = true;
412 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800413 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700414 if (fields[i] != 0) {
415 z = false;
416 }
417 }
418 if (z) { /* never accessed */
419 free(buffer);
420 return 0;
421 }
422
423 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
424 path += sizeof(mmcblk0) - 1;
425 }
426
427 printf("%s: %s\n", path, buffer);
428 free(buffer);
429
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800430 if (fields[__STAT_IO_TICKS]) {
431 unsigned long read_perf = 0;
432 unsigned long read_ios = 0;
433 if (fields[__STAT_READ_TICKS]) {
434 unsigned long long divisor = fields[__STAT_READ_TICKS]
435 * fields[__STAT_IO_TICKS];
436 read_perf = ((unsigned long long)SECTOR_SIZE
437 * fields[__STAT_READ_SECTORS]
438 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
439 / divisor;
440 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
441 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
442 / divisor;
443 }
444
445 unsigned long write_perf = 0;
446 unsigned long write_ios = 0;
447 if (fields[__STAT_WRITE_TICKS]) {
448 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
449 * fields[__STAT_IO_TICKS];
450 write_perf = ((unsigned long long)SECTOR_SIZE
451 * fields[__STAT_WRITE_SECTORS]
452 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
453 / divisor;
454 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
455 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
456 / divisor;
457 }
458
459 unsigned queue = (fields[__STAT_IN_QUEUE]
460 + (fields[__STAT_IO_TICKS] >> 1))
461 / fields[__STAT_IO_TICKS];
462
463 if (!write_perf && !write_ios) {
464 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
465 path, read_perf, read_ios, queue);
466 } else {
467 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
468 path, read_perf, read_ios, write_perf, write_ios, queue);
469 }
470
471 /* bugreport timeout factor adjustment */
472 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
473 worst_write_perf = write_perf;
474 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700475 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700476 return 0;
477}
478
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700479/* Copied policy from system/core/logd/LogBuffer.cpp */
480
481#define LOG_BUFFER_SIZE (256 * 1024)
482#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
483#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
484
485static bool valid_size(unsigned long value) {
486 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
487 return false;
488 }
489
490 long pages = sysconf(_SC_PHYS_PAGES);
491 if (pages < 1) {
492 return true;
493 }
494
495 long pagesize = sysconf(_SC_PAGESIZE);
496 if (pagesize <= 1) {
497 pagesize = PAGE_SIZE;
498 }
499
500 // maximum memory impact a somewhat arbitrary ~3%
501 pages = (pages + 31) / 32;
502 unsigned long maximum = pages * pagesize;
503
504 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
505 return true;
506 }
507
508 return value <= maximum;
509}
510
511static unsigned long property_get_size(const char *key) {
512 unsigned long value;
513 char *cp, property[PROPERTY_VALUE_MAX];
514
515 property_get(key, property, "");
516 value = strtoul(property, &cp, 10);
517
518 switch(*cp) {
519 case 'm':
520 case 'M':
521 value *= 1024;
522 /* FALLTHRU */
523 case 'k':
524 case 'K':
525 value *= 1024;
526 /* FALLTHRU */
527 case '\0':
528 break;
529
530 default:
531 value = 0;
532 }
533
534 if (!valid_size(value)) {
535 value = 0;
536 }
537
538 return value;
539}
540
541/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800542static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700543 static const char global_tuneable[] = "persist.logd.size"; // Settings App
544 static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
545 char key[PROP_NAME_MAX];
546 unsigned long property_size, default_size;
547
548 default_size = property_get_size(global_tuneable);
549 if (!default_size) {
550 default_size = property_get_size(global_default);
551 }
552
553 snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
554 property_size = property_get_size(key);
555
556 if (!property_size) {
557 snprintf(key, sizeof(key), "%s.%s", global_default, name);
558 property_size = property_get_size(key);
559 }
560
561 if (!property_size) {
562 property_size = default_size;
563 }
564
565 if (!property_size) {
566 property_size = LOG_BUFFER_SIZE;
567 }
568
569 /* Engineering margin is ten-fold our guess */
570 return 10 * (property_size + worst_write_perf) / worst_write_perf;
571}
572
573/* End copy from system/core/logd/LogBuffer.cpp */
574
Colin Crossf45fa6b2012-03-26 12:38:26 -0700575/* dumps the current system state to stdout */
Felipe Leme809d74e2016-02-02 12:57:00 -0800576static void print_header(std::string version) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700577 char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
578 char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
579 char network[PROPERTY_VALUE_MAX], date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700580
581 property_get("ro.build.display.id", build, "(unknown)");
582 property_get("ro.build.fingerprint", fingerprint, "(unknown)");
583 property_get("ro.build.type", build_type, "(unknown)");
Junda Liu58ad9292016-06-12 11:51:54 -0700584 property_get("gsm.version.baseband", radio, "(unknown)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700585 property_get("ro.bootloader", bootloader, "(unknown)");
586 property_get("gsm.operator.alpha", network, "(unknown)");
587 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
588
589 printf("========================================================\n");
590 printf("== dumpstate: %s\n", date);
591 printf("========================================================\n");
592
593 printf("\n");
594 printf("Build: %s\n", build);
595 printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
596 printf("Bootloader: %s\n", bootloader);
597 printf("Radio: %s\n", radio);
598 printf("Network: %s\n", network);
599
600 printf("Kernel: ");
601 dump_file(NULL, "/proc/version");
602 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Leme809d74e2016-02-02 12:57:00 -0800603 printf("Bugreport format version: %s\n", version.c_str());
Felipe Leme8fecfdd2016-02-09 10:40:07 -0800604 printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700605 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800606}
607
Felipe Leme24b66ee2016-06-16 10:55:26 -0700608// List of file extensions that can cause a zip file attachment to be rejected by some email
609// service providers.
610static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
611 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
612 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
613 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
614};
615
Felipe Leme71ca15e2016-05-19 16:18:17 -0700616bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800617 if (!zip_writer) {
Felipe Leme88c79332016-02-22 11:06:49 -0800618 MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
619 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800620 return false;
621 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700622 std::string valid_name = entry_name;
623
624 // Rename extension if necessary.
625 size_t idx = entry_name.rfind(".");
626 if (idx != std::string::npos) {
627 std::string extension = entry_name.substr(idx);
628 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
629 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
630 valid_name = entry_name + ".renamed";
631 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
632 }
633 }
634
Felipe Leme6fe9db62016-02-12 09:04:16 -0800635 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
636 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Leme24b66ee2016-06-16 10:55:26 -0700637 int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
Felipe Lemee82a27d2016-01-05 13:35:44 -0800638 ZipWriter::kCompress, get_mtime(fd, now));
639 if (err) {
Felipe Leme24b66ee2016-06-16 10:55:26 -0700640 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800641 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800642 return false;
643 }
644
Felipe Leme770410d2016-01-26 17:07:14 -0800645 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800646 while (1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800647 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
648 if (bytes_read == 0) {
649 break;
650 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800651 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800652 return false;
653 }
654 err = zip_writer->WriteBytes(buffer.data(), bytes_read);
655 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800656 MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800657 return false;
658 }
659 }
660
661 err = zip_writer->FinishEntry();
662 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800663 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800664 return false;
665 }
666
667 return true;
668}
669
Felipe Leme71ca15e2016-05-19 16:18:17 -0700670bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -0700671 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK
672 | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700673 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800674 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800675 return false;
676 }
677
678 return add_zip_entry_from_fd(entry_name, fd.get());
679}
680
681/* adds a file to the existing zipped bugreport */
682static int _add_file_from_fd(const char *title, const char *path, int fd) {
683 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
684}
685
Felipe Leme24b66ee2016-06-16 10:55:26 -0700686// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800687void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800688 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800689 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800690 return;
691 }
Felipe Leme88c79332016-02-22 11:06:49 -0800692 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800693 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800694 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
695}
696
Felipe Leme809d74e2016-02-02 12:57:00 -0800697/* adds a text entry entry to the existing zip file. */
698static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800699 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800700 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 -0800701 return false;
702 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800703 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800704 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
705 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800706 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800707 ZipWriter::ErrorCodeString(err));
708 return false;
709 }
710
711 err = zip_writer->WriteBytes(content.c_str(), content.length());
712 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800713 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800714 ZipWriter::ErrorCodeString(err));
715 return false;
716 }
717
718 err = zip_writer->FinishEntry();
719 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800720 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800721 return false;
722 }
723
724 return true;
725}
726
Felipe Lemec0808152016-06-17 17:37:13 -0700727static void dump_iptables() {
728 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
729 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
730 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
731 /* no ip6 nat */
732 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
733 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
734}
735
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800736static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800737 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800738 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700739
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700740 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700741 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700742 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800743 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700744 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughes52860032016-06-14 13:56:00 -0700745 run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
Elliott Hughes646e92f2016-06-13 17:35:07 -0700746 "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700747 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700748 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
749 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
750 dump_file("SLAB INFO", "/proc/slabinfo");
751 dump_file("ZONEINFO", "/proc/zoneinfo");
752 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
753 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700754 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700755
Todd Poynor29e27a82012-05-22 17:54:59 -0700756 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700757 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700758 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700759
Elliott Hughes52860032016-06-14 13:56:00 -0700760 run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
Elliott Hughes32caf1d2016-05-04 14:03:54 -0700761 "-O", "pri,nice,rtprio,sched,pcy", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800762 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700763
Michal Karpinski4db754f2015-12-11 18:04:32 +0000764 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900765 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Felipe Lemee4eca582016-06-10 17:48:08 -0700766 struct stat s;
767 if (stat("/proc/modules", &s) != 0) {
768 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
769 } else {
770 run_command("LSMOD", 10, "lsmod", NULL);
771 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000772
Colin Crossf45fa6b2012-03-26 12:38:26 -0700773 do_dmesg();
774
775 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700776 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
777 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800778 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700779
Felipe Leme6e01fa62015-11-11 19:35:14 -0800780 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800781 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800782 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800783 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700784 }
785
Colin Crossf45fa6b2012-03-26 12:38:26 -0700786 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700787 // calculate timeout
788 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
789 if (timeout < 20000) {
790 timeout = 20000;
791 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700792 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
793 "-v", "printable",
794 "-d",
795 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800796 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700797 if (timeout < 20000) {
798 timeout = 20000;
799 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700800 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
801 "-v", "threadtime",
802 "-v", "printable",
803 "-d",
804 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700805 timeout = logcat_timeout("radio");
806 if (timeout < 20000) {
807 timeout = 20000;
808 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700809 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
810 "-v", "threadtime",
811 "-v", "printable",
812 "-d",
813 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700814
Mark Salyzynecc07632015-07-30 14:57:09 -0700815 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
816
Colin Crossf45fa6b2012-03-26 12:38:26 -0700817 /* show the traces we collected in main(), if that was done */
818 if (dump_traces_path != NULL) {
819 dump_file("VM TRACES JUST NOW", dump_traces_path);
820 }
821
822 /* only show ANR traces if they're less than 15 minutes old */
823 struct stat st;
824 char anr_traces_path[PATH_MAX];
825 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
826 if (!anr_traces_path[0]) {
827 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700828 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800829 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
830 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700831 if (fd < 0) {
832 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
833 } else {
834 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
835 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700836 }
837
838 /* slow traces for slow operations */
839 if (anr_traces_path[0] != 0) {
840 int tail = strlen(anr_traces_path)-1;
841 while (tail > 0 && anr_traces_path[tail] != '/') {
842 tail--;
843 }
844 int i = 0;
845 while (1) {
846 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
847 if (stat(anr_traces_path, &st)) {
848 // No traces file at this index, done with the files.
849 break;
850 }
851 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
852 i++;
853 }
854 }
855
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700856 int dumped = 0;
857 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
858 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800859 const char *name = tombstone_data[i].name;
860 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700861 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800862 if (zip_writer) {
863 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800864 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800865 }
866 } else {
867 dump_file_from_fd("TOMBSTONE", name, fd);
868 }
869 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700870 tombstone_data[i].fd = -1;
871 }
872 }
873 if (!dumped) {
874 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
875 }
876
Colin Crossf45fa6b2012-03-26 12:38:26 -0700877 dump_file("NETWORK DEV INFO", "/proc/net/dev");
878 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700879 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700880 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
881 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
882
Todd Poynor2a83daa2013-11-22 15:44:22 -0800883 if (!stat(PSTORE_LAST_KMSG, &st)) {
884 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
885 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700886 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
887 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800888 } else {
889 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
890 dump_file("LAST KMSG", "/proc/last_kmsg");
891 }
892
Mark Salyzyn2262c162014-12-16 09:09:26 -0800893 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700894 run_command("LAST LOGCAT", 10, "logcat", "-L",
895 "-b", "all",
896 "-v", "threadtime",
897 "-v", "printable",
898 "-d",
899 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800900
Colin Crossf45fa6b2012-03-26 12:38:26 -0700901 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800902
903 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900904
905 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
906 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
907
Colin Crossf45fa6b2012-03-26 12:38:26 -0700908 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
909 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700910
911 dump_route_tables();
912
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900913 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
914 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +0900915 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700916 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700917
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800918#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900919 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +0900920 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900921
922 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900923 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900924
925 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900926 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900927
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800928#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800929 dump_file("INTERRUPTS (1)", "/proc/interrupts");
930
Felipe Lemedc42bda2016-06-30 14:27:04 -0700931 run_dumpsys("NETWORK DIAGNOSTICS", 10, {"connectivity", "--diag"});
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900932
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800933#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -0700934 run_command("DUMP WIFI STATUS", 20,
935 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900936
937 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900938 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900939
940 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900941 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700942#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800943 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700944
945 print_properties();
946
947 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
948 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
949
Ken Sumrall8f75fa72013-02-08 17:35:58 -0800950 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700951
Colin Crossf45fa6b2012-03-26 12:38:26 -0700952 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
953
954 printf("------ BACKLIGHTS ------\n");
955 printf("LCD brightness=");
956 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
957 printf("Button brightness=");
958 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
959 printf("Keyboard brightness=");
960 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
961 printf("ALS mode=");
962 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
963 printf("LCD driver registers:\n");
964 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
965 printf("\n");
966
967 /* Binder state is expensive to look at as it uses a lot of memory. */
968 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
969 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
970 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
971 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
972 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
973
Colin Crossf45fa6b2012-03-26 12:38:26 -0700974 printf("========================================================\n");
975 printf("== Board\n");
976 printf("========================================================\n");
977
978 dumpstate_board();
979 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700980
981 /* Migrate the ril_dumpstate to a dumpstate_board()? */
982 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
983 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
984 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -0700985 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700986 // su does not exist on user builds, so try running without it.
987 // This way any implementations of vril-dump that do not require
988 // root can run on user builds.
989 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
990 "vril-dump", NULL);
991 } else {
992 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
993 SU_PATH, "root", "vril-dump", NULL);
994 }
995 }
996
997 printf("========================================================\n");
998 printf("== Android Framework Services\n");
999 printf("========================================================\n");
1000
Felipe Lemedc42bda2016-06-30 14:27:04 -07001001 run_dumpsys("DUMPSYS", 60, {"--skip", "meminfo", "cpuinfo"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001002
1003 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001004 printf("== Checkins\n");
1005 printf("========================================================\n");
1006
Felipe Lemedc42bda2016-06-30 14:27:04 -07001007 run_dumpsys("CHECKIN BATTERYSTATS", 30, {"batterystats", "-c"});
1008 run_dumpsys("CHECKIN MEMINFO", 30, {"meminfo", "--checkin"});
1009 run_dumpsys("CHECKIN NETSTATS", 30, {"netstats", "--checkin"});
1010 run_dumpsys("CHECKIN PROCSTATS", 30, {"procstats", "-c"});
1011 run_dumpsys("CHECKIN USAGESTATS", 30, {"usagestats", "-c"});
1012 run_dumpsys("CHECKIN PACKAGE", 30, {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001013
1014 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001015 printf("== Running Application Activities\n");
1016 printf("========================================================\n");
1017
Felipe Lemedc42bda2016-06-30 14:27:04 -07001018 run_dumpsys("APP ACTIVITIES", 30, {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001019
1020 printf("========================================================\n");
1021 printf("== Running Application Services\n");
1022 printf("========================================================\n");
1023
Felipe Lemedc42bda2016-06-30 14:27:04 -07001024 run_dumpsys("APP SERVICES", 30, {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001025
1026 printf("========================================================\n");
1027 printf("== Running Application Providers\n");
1028 printf("========================================================\n");
1029
Felipe Lemedc42bda2016-06-30 14:27:04 -07001030 run_dumpsys("APP PROVIDERS", 30, {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001031
1032
1033 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001034 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1035 getpid(), progress, weight_total, WEIGHT_TOTAL);
1036 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001037 printf("== dumpstate: done\n");
1038 printf("========================================================\n");
1039}
1040
1041static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001042 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001043 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1044 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1045 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001046 " -b: play sound file instead of vibrate, at beginning of job\n"
1047 " -e: play sound file instead of vibrate, at end of job\n"
1048 " -o: write to file (instead of stdout)\n"
1049 " -d: append date to filename (requires -o)\n"
1050 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001051 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001052 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001053 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001054 " -q: disable vibrate\n"
1055 " -B: send broadcast when finished (requires -o)\n"
1056 " -P: send broadcast when started and update system properties on "
1057 "progress (requires -o and -B)\n"
1058 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1059 "shouldn't be used with -P)\n"
1060 " -V: sets the bugreport format version (valid values: %s)\n",
1061 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001062}
1063
John Michelau885f8882013-05-06 16:42:02 -05001064static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001065 // don't complain to stderr or stdout
1066 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001067}
1068
Felipe Leme1e9edc62015-12-21 16:02:13 -08001069/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1070 temporary file.
1071 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001072static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme0f3fb202016-06-10 17:10:53 -07001073 const std::string& log_path, time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001074 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001075 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001076 return false;
1077 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001078 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001079 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001080 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001081 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001082
Felipe Leme0f3fb202016-06-10 17:10:53 -07001083 // Add log file (which contains stderr output) to zip...
1084 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
1085 if (!add_zip_entry("dumpstate_log.txt", log_path.c_str())) {
1086 MYLOGE("Failed to add dumpstate log to .zip file\n");
1087 return false;
1088 }
1089 // ... and re-opens it for further logging.
1090 redirect_to_existing_file(stderr, const_cast<char*>(log_path.c_str()));
1091 fprintf(stderr, "\n");
1092
Felipe Lemee82a27d2016-01-05 13:35:44 -08001093 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001094 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001095 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001096 return false;
1097 }
1098
Felipe Lemec4eee562016-04-21 15:42:55 -07001099 if (is_user_build()) {
1100 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1101 if (remove(bugreport_path.c_str())) {
1102 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1103 }
1104 } else {
1105 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1106 }
1107
Felipe Leme1e9edc62015-12-21 16:02:13 -08001108 return true;
1109}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001110
Michal Karpinski4db754f2015-12-11 18:04:32 +00001111static std::string SHA256_file_hash(std::string filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001112 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1113 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001114 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001115 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001116 return NULL;
1117 }
1118
1119 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001120 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001121
1122 std::vector<uint8_t> buffer(65536);
1123 while (1) {
1124 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1125 if (bytes_read == 0) {
1126 break;
1127 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001128 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001129 return NULL;
1130 }
1131
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001132 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001133 }
1134
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001135 uint8_t hash[SHA256_DIGEST_LENGTH];
1136 SHA256_Final(hash, &ctx);
1137
1138 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1139 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001140 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001141 }
1142 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1143 return std::string(hash_buffer);
1144}
1145
Colin Crossf45fa6b2012-03-26 12:38:26 -07001146int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001147 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001148 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001149 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001150 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001151 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001152 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001153 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001154 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001155 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001156 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001157 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001158 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001159
Felipe Lemee82a27d2016-01-05 13:35:44 -08001160 now = time(NULL);
1161
Felipe Lemecbce55d2016-02-08 09:53:18 -08001162 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001163
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001164 /* gets the sequential id */
1165 char last_id[PROPERTY_VALUE_MAX];
1166 property_get("dumpstate.last_id", last_id, "0");
1167 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001168 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001169 property_set("dumpstate.last_id", last_id);
1170 MYLOGI("dumpstate id: %lu\n", id);
1171
Jeff Brown1dc94e32014-09-11 14:15:27 -07001172 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001173 memset(&sigact, 0, sizeof(sigact));
1174 sigact.sa_handler = sigpipe_handler;
1175 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001176
Colin Crossf45fa6b2012-03-26 12:38:26 -07001177 /* set as high priority, and protect from OOM killer */
1178 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001179
1180 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001181 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001182 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001183 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001184 } else {
1185 /* fallback to kernels <= 2.6.35 */
1186 oom_adj = fopen("/proc/self/oom_adj", "we");
1187 if (oom_adj) {
1188 fputs("-17", oom_adj);
1189 fclose(oom_adj);
1190 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001191 }
1192
Jeff Brown1dc94e32014-09-11 14:15:27 -07001193 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001194 std::string args;
1195 format_args(argc, const_cast<const char **>(argv), &args);
1196 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001197 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001198 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001199 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001200 case 'd': do_add_date = 1; break;
1201 case 'z': do_zip_file = 1; break;
1202 case 'o': use_outfile = optarg; break;
1203 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001204 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001205 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001206 case 'q': do_vibrate = 0; break;
1207 case 'p': do_fb = 1; break;
1208 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001209 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001210 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001211 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001212 case '?': printf("\n");
1213 case 'h':
1214 usage();
1215 exit(1);
1216 }
1217 }
1218
Felipe Leme71bbfc52015-11-23 14:14:51 -08001219 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001220 usage();
1221 exit(1);
1222 }
1223
Felipe Leme2628e9e2016-04-12 16:36:51 -07001224 if (use_control_socket && !do_zip_file) {
1225 usage();
1226 exit(1);
1227 }
1228
Felipe Leme71bbfc52015-11-23 14:14:51 -08001229 if (do_update_progress && !do_broadcast) {
1230 usage();
1231 exit(1);
1232 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001233
Michal Karpinski4db754f2015-12-11 18:04:32 +00001234 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1235 usage();
1236 exit(1);
1237 }
1238
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001239 if (version != VERSION_DEFAULT) {
1240 usage();
1241 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001242 }
1243
Felipe Lemecbce55d2016-02-08 09:53:18 -08001244 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001245
Felipe Lemee338bf62015-12-07 14:03:50 -08001246 do_early_screenshot = do_update_progress;
1247
Christopher Ferrised9354f2014-10-01 17:35:01 -07001248 // If we are going to use a socket, do it as early as possible
1249 // to avoid timeouts from bugreport.
1250 if (use_socket) {
1251 redirect_to_socket(stdout, "dumpstate");
1252 }
1253
Felipe Leme2628e9e2016-04-12 16:36:51 -07001254 if (use_control_socket) {
1255 MYLOGD("Opening control socket\n");
1256 control_socket_fd = open_socket("dumpstate");
Felipe Leme02b7e002016-07-22 12:03:20 -07001257 do_update_progress = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001258 }
1259
Felipe Lemecbce55d2016-02-08 09:53:18 -08001260 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001261 std::string tmp_path;
1262
Felipe Leme0f3fb202016-06-10 17:10:53 -07001263 /* full path of the file containing the dumpstate logs */
Felipe Lemecbce55d2016-02-08 09:53:18 -08001264 std::string log_path;
1265
Felipe Leme14e034a2016-03-30 18:51:03 -07001266 /* full path of the systrace file, when enabled */
1267 std::string systrace_path;
1268
Felipe Lemee338bf62015-12-07 14:03:50 -08001269 /* full path of the temporary file containing the screenshot (when requested) */
1270 std::string screenshot_path;
1271
Felipe Lemecbce55d2016-02-08 09:53:18 -08001272 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001273 std::string base_name;
1274
Felipe Leme71bbfc52015-11-23 14:14:51 -08001275 /* pointer to the actual path, be it zip or text */
1276 std::string path;
1277
Felipe Leme635ca312016-01-05 14:23:02 -08001278 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001279 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001280
Felipe Lemead5f6c42015-11-30 14:26:46 -08001281 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001282 bool is_redirecting = !use_socket && use_outfile;
1283
1284 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001285 bugreport_dir = dirname(use_outfile);
1286 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001287 if (do_add_date) {
1288 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001289 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1290 suffix = date;
1291 } else {
1292 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001293 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001294 char build_id[PROPERTY_VALUE_MAX];
1295 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1296 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001297 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001298 // TODO: if dumpstate was an object, the paths could be internal variables and then
1299 // we could have a function to calculate the derived values, such as:
1300 // screenshot_path = GetPath(".png");
1301 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001302 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001303 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001304 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1305 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001306
Felipe Lemecbce55d2016-02-08 09:53:18 -08001307 MYLOGD("Bugreport dir: %s\n"
1308 "Base name: %s\n"
1309 "Suffix: %s\n"
1310 "Log path: %s\n"
1311 "Temporary path: %s\n"
1312 "Screenshot path: %s\n",
1313 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1314 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001315
Felipe Leme1e9edc62015-12-21 16:02:13 -08001316 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001317 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001318 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001319 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001320 zip_file.reset(fopen(path.c_str(), "wb"));
1321 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001322 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001323 do_zip_file = 0;
1324 } else {
1325 zip_writer.reset(new ZipWriter(zip_file.get()));
1326 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001327 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001328 }
1329
Felipe Leme02b7e002016-07-22 12:03:20 -07001330 if (do_update_progress && do_broadcast) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001331 std::vector<std::string> am_args = {
Felipe Lemed5e724a2016-02-11 09:12:39 -08001332 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemead5f6c42015-11-30 14:26:46 -08001333 "--es", "android.intent.extra.NAME", suffix,
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001334 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001335 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1336 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1337 };
1338 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001339 }
1340 }
1341
Nick Kralevichf3599b32016-01-25 15:05:16 -08001342 /* read /proc/cmdline before dropping root */
1343 FILE *cmdline = fopen("/proc/cmdline", "re");
1344 if (cmdline) {
1345 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1346 fclose(cmdline);
1347 }
1348
Jeff Brown1dc94e32014-09-11 14:15:27 -07001349 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001350 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001351 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001352 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001353 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001354 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001355 }
John Michelau1f794c42012-09-17 11:20:19 -05001356 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001357
Felipe Leme3634a1e2015-12-09 10:11:47 -08001358 if (do_fb && do_early_screenshot) {
1359 if (screenshot_path.empty()) {
1360 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001361 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001362 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001363 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001364 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001365 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001366 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001367 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001368 screenshot_path.c_str(), strerror(errno));
1369 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001370 }
1371 }
1372
Felipe Leme1e9edc62015-12-21 16:02:13 -08001373 if (do_zip_file) {
1374 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001375 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001376 }
1377 }
1378
Felipe Leme71bbfc52015-11-23 14:14:51 -08001379 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001380 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001381 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1382 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1383 log_path.c_str(), strerror(errno));
1384 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001385 /* TODO: rather than generating a text file now and zipping it later,
1386 it would be more efficient to redirect stdout to the zip entry
1387 directly, but the libziparchive doesn't support that option yet. */
1388 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001389 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1390 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1391 tmp_path.c_str(), strerror(errno));
1392 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001393 }
Felipe Leme608385d2016-02-01 10:35:38 -08001394 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1395 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001396 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001397 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001398
Felipe Leme71a74ac2016-03-17 15:43:25 -07001399 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001400 dump_systrace();
Felipe Leme71a74ac2016-03-17 15:43:25 -07001401
Wei Liu341938b2016-04-27 16:18:17 -07001402 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001403 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001404
Felipe Leme9c74aad2016-02-29 18:15:42 -08001405 // Invoking the following dumpsys calls before dump_traces() to try and
1406 // keep the system stats as close to its initial state as possible.
Felipe Lemedc42bda2016-06-30 14:27:04 -07001407 run_dumpsys_as_shell("DUMPSYS MEMINFO", 90, {"meminfo", "-a"});
1408 run_dumpsys_as_shell("DUMPSYS CPUINFO", 10, {"cpuinfo", "-a"});
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001409
1410 /* collect stack traces from Dalvik and native processes (needs root) */
1411 dump_traces_path = dump_traces();
1412
Felipe Lemec0808152016-06-17 17:37:13 -07001413 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001414 get_tombstone_fds(tombstone_data);
1415 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001416 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001417 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001418 if (!is_user_build()) {
1419 add_dir(PROFILE_DATA_DIR_CUR, true);
1420 add_dir(PROFILE_DATA_DIR_REF, true);
1421 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001422 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001423 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001424
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001425 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001426 return -1;
1427 }
1428
1429 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001430
Felipe Leme55b42a62015-11-10 17:39:08 -08001431 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001432 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001433 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001434 }
1435
Felipe Leme6e01fa62015-11-11 19:35:14 -08001436 /* rename or zip the (now complete) .tmp file to its final location */
1437 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001438
1439 /* check if user changed the suffix using system properties */
1440 char key[PROPERTY_KEY_MAX];
1441 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001442 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001443 property_get(key, value, "");
1444 bool change_suffix= false;
1445 if (value[0]) {
1446 /* must whitelist which characters are allowed, otherwise it could cross directories */
1447 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1448 if (std::regex_match(value, valid_regex)) {
1449 change_suffix = true;
1450 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001451 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001452 }
1453 }
1454 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001455 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001456 suffix = value;
1457 if (!screenshot_path.empty()) {
1458 std::string new_screenshot_path =
1459 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1460 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001461 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001462 new_screenshot_path.c_str(), strerror(errno));
1463 } else {
1464 screenshot_path = new_screenshot_path;
1465 }
1466 }
1467 }
1468
Felipe Leme6e01fa62015-11-11 19:35:14 -08001469 bool do_text_file = true;
1470 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001471 std::string entry_name = base_name + "-" + suffix + ".txt";
1472 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
Felipe Leme0f3fb202016-06-10 17:10:53 -07001473 if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001474 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001475 do_text_file = true;
1476 } else {
1477 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001478 // Since zip file is already created, it needs to be renamed.
1479 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1480 if (path != new_path) {
1481 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1482 if (rename(path.c_str(), new_path.c_str())) {
1483 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1484 new_path.c_str(), strerror(errno));
1485 } else {
1486 path = new_path;
1487 }
1488 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001489 }
1490 }
1491 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001492 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001493 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001494 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001495 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001496 path.clear();
1497 }
1498 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001499 if (use_control_socket) {
1500 if (do_text_file) {
1501 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1502 "for more details\n", log_path.c_str());
1503 } else {
1504 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1505 }
1506 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001507 }
1508
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001509 /* vibrate a few but shortly times to let user know it's finished */
1510 if (vibrator) {
1511 for (int i = 0; i < 3; i++) {
1512 vibrate(vibrator.get(), 75);
1513 usleep((75 + 50) * 1000);
1514 }
1515 }
1516
Jeff Brown1dc94e32014-09-11 14:15:27 -07001517 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001518 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001519 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001520 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001521 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001522 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001523 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001524 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001525 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001526 "--es", "android.intent.extra.BUGREPORT", path,
1527 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001528 };
1529 if (do_fb) {
1530 am_args.push_back("--es");
1531 am_args.push_back("android.intent.extra.SCREENSHOT");
1532 am_args.push_back(screenshot_path);
1533 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001534 if (is_remote_mode) {
1535 am_args.push_back("--es");
1536 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1537 am_args.push_back(SHA256_file_hash(path));
1538 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1539 } else {
1540 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1541 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001542 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001543 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001544 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001545 }
1546
Felipe Lemecbce55d2016-02-08 09:53:18 -08001547 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1548 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001549
Felipe Leme107a05f2016-03-08 15:11:15 -08001550 if (is_redirecting) {
1551 fclose(stderr);
1552 }
1553
Felipe Leme02b7e002016-07-22 12:03:20 -07001554 if (use_control_socket && control_socket_fd != -1) {
1555 MYLOGD("Closing control socket\n");
1556 close(control_socket_fd);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001557 }
1558
Colin Crossf45fa6b2012-03-26 12:38:26 -07001559 return 0;
1560}