blob: d674a38f72c2982984541ede88d7e9ace7243f3a [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
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 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"
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 Lemedbfe0832016-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(), 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) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800671 ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
672 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800673 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800674 return false;
675 }
676
677 return add_zip_entry_from_fd(entry_name, fd.get());
678}
679
680/* adds a file to the existing zipped bugreport */
681static int _add_file_from_fd(const char *title, const char *path, int fd) {
682 return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
683}
684
Felipe Leme24b66ee2016-06-16 10:55:26 -0700685// TODO: move to util.cpp
Felipe Lemee82a27d2016-01-05 13:35:44 -0800686void add_dir(const char *dir, bool recursive) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800687 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800688 MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
Felipe Leme111b9d02016-02-03 09:28:24 -0800689 return;
690 }
Felipe Leme88c79332016-02-22 11:06:49 -0800691 MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
Felipe Leme608385d2016-02-01 10:35:38 -0800692 DurationReporter duration_reporter(dir, NULL);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800693 dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
694}
695
Felipe Leme809d74e2016-02-02 12:57:00 -0800696/* adds a text entry entry to the existing zip file. */
697static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
Felipe Leme111b9d02016-02-03 09:28:24 -0800698 if (!zip_writer) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800699 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 -0800700 return false;
701 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800702 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -0800703 int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
704 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800705 MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800706 ZipWriter::ErrorCodeString(err));
707 return false;
708 }
709
710 err = zip_writer->WriteBytes(content.c_str(), content.length());
711 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800712 MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme809d74e2016-02-02 12:57:00 -0800713 ZipWriter::ErrorCodeString(err));
714 return false;
715 }
716
717 err = zip_writer->FinishEntry();
718 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800719 MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800720 return false;
721 }
722
723 return true;
724}
725
Felipe Lemec0808152016-06-17 17:37:13 -0700726static void dump_iptables() {
727 run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
728 run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
729 run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
730 /* no ip6 nat */
731 run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
732 run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
733}
734
Srinath Sridharanfdf52d32016-02-01 15:50:22 -0800735static void dumpstate(const std::string& screenshot_path, const std::string& version) {
Felipe Leme770410d2016-01-26 17:07:14 -0800736 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800737 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700738
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700739 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700740 run_command("UPTIME", 10, "uptime", NULL);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700741 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800742 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700743 dump_file("MEMORY INFO", "/proc/meminfo");
Elliott Hughes52860032016-06-14 13:56:00 -0700744 run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
Elliott Hughes646e92f2016-06-13 17:35:07 -0700745 "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
Nick Kralevich2b1f88b2015-10-07 16:38:42 -0700746 run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700747 dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
748 dump_file("VMALLOC INFO", "/proc/vmallocinfo");
749 dump_file("SLAB INFO", "/proc/slabinfo");
750 dump_file("ZONEINFO", "/proc/zoneinfo");
751 dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
752 dump_file("BUDDYINFO", "/proc/buddyinfo");
Colin Cross2281af92012-10-28 22:41:06 -0700753 dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700754
Todd Poynor29e27a82012-05-22 17:54:59 -0700755 dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700756 dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
Mathias Agopian85aea742012-08-08 15:32:02 -0700757 dump_file("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700758
Elliott Hughes52860032016-06-14 13:56:00 -0700759 run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
Elliott Hughes32caf1d2016-05-04 14:03:54 -0700760 "-O", "pri,nice,rtprio,sched,pcy", NULL);
Nick Kralevichb82c9252015-11-27 17:56:13 -0800761 run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700762
Michal Karpinski4db754f2015-12-11 18:04:32 +0000763 run_command("PRINTENV", 10, "printenv", NULL);
Lorenzo Colittif7f26512016-03-11 10:58:55 +0900764 run_command("NETSTAT", 10, "netstat", "-n", NULL);
Felipe Lemee4eca582016-06-10 17:48:08 -0700765 struct stat s;
766 if (stat("/proc/modules", &s) != 0) {
767 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
768 } else {
769 run_command("LSMOD", 10, "lsmod", NULL);
770 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000771
Colin Crossf45fa6b2012-03-26 12:38:26 -0700772 do_dmesg();
773
774 run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700775 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
776 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800777 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700778
Felipe Leme6e01fa62015-11-11 19:35:14 -0800779 if (!screenshot_path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800780 MYLOGI("taking late screenshot\n");
Felipe Lemee338bf62015-12-07 14:03:50 -0800781 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -0800782 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Jeff Sharkey5a930032013-03-19 15:05:19 -0700783 }
784
Colin Crossf45fa6b2012-03-26 12:38:26 -0700785 // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700786 // calculate timeout
787 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
788 if (timeout < 20000) {
789 timeout = 20000;
790 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700791 run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
792 "-v", "printable",
793 "-d",
794 "*:v", NULL);
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800795 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700796 if (timeout < 20000) {
797 timeout = 20000;
798 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700799 run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
800 "-v", "threadtime",
801 "-v", "printable",
802 "-d",
803 "*:v", NULL);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700804 timeout = logcat_timeout("radio");
805 if (timeout < 20000) {
806 timeout = 20000;
807 }
Mark Salyzyn78316382015-10-09 14:02:07 -0700808 run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
809 "-v", "threadtime",
810 "-v", "printable",
811 "-d",
812 "*:v", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700813
Mark Salyzynecc07632015-07-30 14:57:09 -0700814 run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
815
Colin Crossf45fa6b2012-03-26 12:38:26 -0700816 /* show the traces we collected in main(), if that was done */
817 if (dump_traces_path != NULL) {
818 dump_file("VM TRACES JUST NOW", dump_traces_path);
819 }
820
821 /* only show ANR traces if they're less than 15 minutes old */
822 struct stat st;
823 char anr_traces_path[PATH_MAX];
824 property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
825 if (!anr_traces_path[0]) {
826 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700827 } else {
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800828 int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
829 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700830 if (fd < 0) {
831 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
832 } else {
833 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
834 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700835 }
836
837 /* slow traces for slow operations */
838 if (anr_traces_path[0] != 0) {
839 int tail = strlen(anr_traces_path)-1;
840 while (tail > 0 && anr_traces_path[tail] != '/') {
841 tail--;
842 }
843 int i = 0;
844 while (1) {
845 sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
846 if (stat(anr_traces_path, &st)) {
847 // No traces file at this index, done with the files.
848 break;
849 }
850 dump_file("VM TRACES WHEN SLOW", anr_traces_path);
851 i++;
852 }
853 }
854
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700855 int dumped = 0;
856 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
857 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800858 const char *name = tombstone_data[i].name;
859 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700860 dumped = 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800861 if (zip_writer) {
862 if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800863 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800864 }
865 } else {
866 dump_file_from_fd("TOMBSTONE", name, fd);
867 }
868 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700869 tombstone_data[i].fd = -1;
870 }
871 }
872 if (!dumped) {
873 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
874 }
875
Colin Crossf45fa6b2012-03-26 12:38:26 -0700876 dump_file("NETWORK DEV INFO", "/proc/net/dev");
877 dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
JP Abgrall012c2ea2012-05-16 20:49:29 -0700878 dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700879 dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
880 dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
881
Todd Poynor2a83daa2013-11-22 15:44:22 -0800882 if (!stat(PSTORE_LAST_KMSG, &st)) {
883 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
884 dump_file("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzyn7d0a7622016-06-24 14:06:15 -0700885 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
886 dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -0800887 } else {
888 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
889 dump_file("LAST KMSG", "/proc/last_kmsg");
890 }
891
Mark Salyzyn2262c162014-12-16 09:09:26 -0800892 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Mark Salyzyn78316382015-10-09 14:02:07 -0700893 run_command("LAST LOGCAT", 10, "logcat", "-L",
894 "-b", "all",
895 "-v", "threadtime",
896 "-v", "printable",
897 "-d",
898 "*:v", NULL);
Mark Salyzyn2262c162014-12-16 09:09:26 -0800899
Colin Crossf45fa6b2012-03-26 12:38:26 -0700900 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -0800901
902 run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900903
904 run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
905 run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
906
Colin Crossf45fa6b2012-03-26 12:38:26 -0700907 run_command("IP RULES", 10, "ip", "rule", "show", NULL);
908 run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -0700909
910 dump_route_tables();
911
Lorenzo Colittid4c3d382014-07-30 14:38:20 +0900912 run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
913 run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
Erik Klinef7f2b0f2016-05-27 11:29:19 +0900914 run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
Felipe Lemec0808152016-06-17 17:37:13 -0700915 run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700916
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800917#ifdef FWDUMP_bcmdhd
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900918 run_command("ND OFFLOAD TABLE", 5,
Erik Kline08165202016-05-30 11:55:44 +0900919 SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900920
921 run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900922 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900923
924 run_command("ND OFFLOAD STATUS (1)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900925 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900926
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800927#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800928 dump_file("INTERRUPTS (1)", "/proc/interrupts");
929
Felipe Lemedbfe0832016-06-30 14:27:04 -0700930 run_dumpsys("NETWORK DIAGNOSTICS", 10, {"connectivity", "--diag"});
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900931
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -0800932#ifdef FWDUMP_bcmdhd
Colin Crossf45fa6b2012-03-26 12:38:26 -0700933 run_command("DUMP WIFI STATUS", 20,
934 SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900935
936 run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
Erik Kline08165202016-05-30 11:55:44 +0900937 SU_PATH, "root", WLUTIL, "counters", NULL);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +0900938
939 run_command("ND OFFLOAD STATUS (2)", 5,
Erik Kline08165202016-05-30 11:55:44 +0900940 SU_PATH, "root", WLUTIL, "nd_status", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700941#endif
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -0800942 dump_file("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700943
944 print_properties();
945
946 run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
947 run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
948
Ken Sumrall8f75fa72013-02-08 17:35:58 -0800949 run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700950
Colin Crossf45fa6b2012-03-26 12:38:26 -0700951 run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
952
953 printf("------ BACKLIGHTS ------\n");
954 printf("LCD brightness=");
955 dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
956 printf("Button brightness=");
957 dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
958 printf("Keyboard brightness=");
959 dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
960 printf("ALS mode=");
961 dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
962 printf("LCD driver registers:\n");
963 dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
964 printf("\n");
965
966 /* Binder state is expensive to look at as it uses a lot of memory. */
967 dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
968 dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
969 dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
970 dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
971 dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
972
Colin Crossf45fa6b2012-03-26 12:38:26 -0700973 printf("========================================================\n");
974 printf("== Board\n");
975 printf("========================================================\n");
976
977 dumpstate_board();
978 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700979
980 /* Migrate the ril_dumpstate to a dumpstate_board()? */
981 char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
982 property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
983 if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
Felipe Lemec4eee562016-04-21 15:42:55 -0700984 if (is_user_build()) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700985 // su does not exist on user builds, so try running without it.
986 // This way any implementations of vril-dump that do not require
987 // root can run on user builds.
988 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
989 "vril-dump", NULL);
990 } else {
991 run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
992 SU_PATH, "root", "vril-dump", NULL);
993 }
994 }
995
996 printf("========================================================\n");
997 printf("== Android Framework Services\n");
998 printf("========================================================\n");
999
Felipe Lemedbfe0832016-06-30 14:27:04 -07001000 run_dumpsys("DUMPSYS", 60, {"--skip", "meminfo", "cpuinfo"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001001
1002 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001003 printf("== Checkins\n");
1004 printf("========================================================\n");
1005
Felipe Lemedbfe0832016-06-30 14:27:04 -07001006 run_dumpsys("CHECKIN BATTERYSTATS", 30, {"batterystats", "-c"});
1007 run_dumpsys("CHECKIN MEMINFO", 30, {"meminfo", "--checkin"});
1008 run_dumpsys("CHECKIN NETSTATS", 30, {"netstats", "--checkin"});
1009 run_dumpsys("CHECKIN PROCSTATS", 30, {"procstats", "-c"});
1010 run_dumpsys("CHECKIN USAGESTATS", 30, {"usagestats", "-c"});
1011 run_dumpsys("CHECKIN PACKAGE", 30, {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001012
1013 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001014 printf("== Running Application Activities\n");
1015 printf("========================================================\n");
1016
Felipe Lemedbfe0832016-06-30 14:27:04 -07001017 run_dumpsys("APP ACTIVITIES", 30, {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001018
1019 printf("========================================================\n");
1020 printf("== Running Application Services\n");
1021 printf("========================================================\n");
1022
Felipe Lemedbfe0832016-06-30 14:27:04 -07001023 run_dumpsys("APP SERVICES", 30, {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001024
1025 printf("========================================================\n");
1026 printf("== Running Application Providers\n");
1027 printf("========================================================\n");
1028
Felipe Lemedbfe0832016-06-30 14:27:04 -07001029 run_dumpsys("APP PROVIDERS", 30, {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001030
1031
1032 printf("========================================================\n");
Felipe Leme608385d2016-02-01 10:35:38 -08001033 printf("== Final progress (pid %d): %d/%d (originally %d)\n",
1034 getpid(), progress, weight_total, WEIGHT_TOTAL);
1035 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001036 printf("== dumpstate: done\n");
1037 printf("========================================================\n");
1038}
1039
1040static void usage() {
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001041 fprintf(stderr,
Felipe Leme2628e9e2016-04-12 16:36:51 -07001042 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
1043 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1044 " -h: display this help message\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001045 " -b: play sound file instead of vibrate, at beginning of job\n"
1046 " -e: play sound file instead of vibrate, at end of job\n"
1047 " -o: write to file (instead of stdout)\n"
1048 " -d: append date to filename (requires -o)\n"
1049 " -p: capture screenshot to filename.png (requires -o)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001050 " -z: generate zipped file (requires -o)\n"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001051 " -s: write output to control socket (for init)\n"
Felipe Leme2628e9e2016-04-12 16:36:51 -07001052 " -S: write file location to control socket (for init; requires -o and -z)"
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001053 " -q: disable vibrate\n"
1054 " -B: send broadcast when finished (requires -o)\n"
1055 " -P: send broadcast when started and update system properties on "
1056 "progress (requires -o and -B)\n"
1057 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1058 "shouldn't be used with -P)\n"
1059 " -V: sets the bugreport format version (valid values: %s)\n",
1060 VERSION_DEFAULT.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001061}
1062
John Michelau885f8882013-05-06 16:42:02 -05001063static void sigpipe_handler(int n) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001064 // don't complain to stderr or stdout
1065 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001066}
1067
Felipe Leme1e9edc62015-12-21 16:02:13 -08001068/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
1069 temporary file.
1070 */
Felipe Lemee82a27d2016-01-05 13:35:44 -08001071static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
Felipe Leme0f3fb202016-06-10 17:10:53 -07001072 const std::string& log_path, time_t now) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001073 if (!add_zip_entry(bugreport_name, bugreport_path)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001074 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001075 return false;
1076 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001077 if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001078 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001079 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001080 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001081
Felipe Leme0f3fb202016-06-10 17:10:53 -07001082 // Add log file (which contains stderr output) to zip...
1083 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
1084 if (!add_zip_entry("dumpstate_log.txt", log_path.c_str())) {
1085 MYLOGE("Failed to add dumpstate log to .zip file\n");
1086 return false;
1087 }
1088 // ... and re-opens it for further logging.
1089 redirect_to_existing_file(stderr, const_cast<char*>(log_path.c_str()));
1090 fprintf(stderr, "\n");
1091
Felipe Lemee82a27d2016-01-05 13:35:44 -08001092 int32_t err = zip_writer->Finish();
Felipe Leme1e9edc62015-12-21 16:02:13 -08001093 if (err) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001094 MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001095 return false;
1096 }
1097
Felipe Lemec4eee562016-04-21 15:42:55 -07001098 if (is_user_build()) {
1099 MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
1100 if (remove(bugreport_path.c_str())) {
1101 ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
1102 }
1103 } else {
1104 MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
1105 }
1106
Felipe Leme1e9edc62015-12-21 16:02:13 -08001107 return true;
1108}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001109
Michal Karpinski4db754f2015-12-11 18:04:32 +00001110static std::string SHA256_file_hash(std::string filepath) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001111 ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
1112 | O_NOFOLLOW)));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001113 if (fd.get() == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001114 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001115 return NULL;
1116 }
1117
1118 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001119 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001120
1121 std::vector<uint8_t> buffer(65536);
1122 while (1) {
1123 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1124 if (bytes_read == 0) {
1125 break;
1126 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001127 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001128 return NULL;
1129 }
1130
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001131 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001132 }
1133
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001134 uint8_t hash[SHA256_DIGEST_LENGTH];
1135 SHA256_Final(hash, &ctx);
1136
1137 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1138 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001139 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001140 }
1141 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1142 return std::string(hash_buffer);
1143}
1144
Colin Crossf45fa6b2012-03-26 12:38:26 -07001145int main(int argc, char *argv[]) {
John Michelau885f8882013-05-06 16:42:02 -05001146 struct sigaction sigact;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001147 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001148 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001149 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001150 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001151 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001152 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001153 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001154 int do_broadcast = 0;
Felipe Lemee338bf62015-12-07 14:03:50 -08001155 int do_early_screenshot = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001156 int is_remote_mode = 0;
Felipe Leme809d74e2016-02-02 12:57:00 -08001157 std::string version = VERSION_DEFAULT;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001158
Felipe Lemee82a27d2016-01-05 13:35:44 -08001159 now = time(NULL);
1160
Felipe Lemecbce55d2016-02-08 09:53:18 -08001161 MYLOGI("begin\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001162
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001163 /* gets the sequential id */
1164 char last_id[PROPERTY_VALUE_MAX];
1165 property_get("dumpstate.last_id", last_id, "0");
1166 id = strtoul(last_id, NULL, 10) + 1;
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001167 snprintf(last_id, sizeof(last_id), "%lu", id);
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001168 property_set("dumpstate.last_id", last_id);
1169 MYLOGI("dumpstate id: %lu\n", id);
1170
Jeff Brown1dc94e32014-09-11 14:15:27 -07001171 /* clear SIGPIPE handler */
John Michelau885f8882013-05-06 16:42:02 -05001172 memset(&sigact, 0, sizeof(sigact));
1173 sigact.sa_handler = sigpipe_handler;
1174 sigaction(SIGPIPE, &sigact, NULL);
JP Abgrall3e03d3f2012-05-11 14:14:09 -07001175
Colin Crossf45fa6b2012-03-26 12:38:26 -07001176 /* set as high priority, and protect from OOM killer */
1177 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001178
1179 FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001180 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001181 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001182 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001183 } else {
1184 /* fallback to kernels <= 2.6.35 */
1185 oom_adj = fopen("/proc/self/oom_adj", "we");
1186 if (oom_adj) {
1187 fputs("-17", oom_adj);
1188 fclose(oom_adj);
1189 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001190 }
1191
Jeff Brown1dc94e32014-09-11 14:15:27 -07001192 /* parse arguments */
Felipe Lemea34efb72016-03-11 09:33:32 -08001193 std::string args;
1194 format_args(argc, const_cast<const char **>(argv), &args);
1195 MYLOGD("Dumpstate command line: %s\n", args.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001196 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001197 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001198 switch (c) {
Felipe Leme71bbfc52015-11-23 14:14:51 -08001199 case 'd': do_add_date = 1; break;
1200 case 'z': do_zip_file = 1; break;
1201 case 'o': use_outfile = optarg; break;
1202 case 's': use_socket = 1; break;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001203 case 'S': use_control_socket = 1; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001204 case 'v': break; // compatibility no-op
Felipe Leme71bbfc52015-11-23 14:14:51 -08001205 case 'q': do_vibrate = 0; break;
1206 case 'p': do_fb = 1; break;
1207 case 'P': do_update_progress = 1; break;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001208 case 'R': is_remote_mode = 1; break;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001209 case 'B': do_broadcast = 1; break;
Felipe Leme809d74e2016-02-02 12:57:00 -08001210 case 'V': version = optarg; break;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001211 case '?': printf("\n");
1212 case 'h':
1213 usage();
1214 exit(1);
1215 }
1216 }
1217
Felipe Leme71bbfc52015-11-23 14:14:51 -08001218 if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001219 usage();
1220 exit(1);
1221 }
1222
Felipe Leme2628e9e2016-04-12 16:36:51 -07001223 if (use_control_socket && !do_zip_file) {
1224 usage();
1225 exit(1);
1226 }
1227
Felipe Leme71bbfc52015-11-23 14:14:51 -08001228 if (do_update_progress && !do_broadcast) {
1229 usage();
1230 exit(1);
1231 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001232
Michal Karpinski4db754f2015-12-11 18:04:32 +00001233 if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
1234 usage();
1235 exit(1);
1236 }
1237
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001238 if (version != VERSION_DEFAULT) {
1239 usage();
1240 exit(1);
Felipe Leme809d74e2016-02-02 12:57:00 -08001241 }
1242
Felipe Lemecbce55d2016-02-08 09:53:18 -08001243 MYLOGI("bugreport format version: %s\n", version.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001244
Felipe Lemee338bf62015-12-07 14:03:50 -08001245 do_early_screenshot = do_update_progress;
1246
Christopher Ferrised9354f2014-10-01 17:35:01 -07001247 // If we are going to use a socket, do it as early as possible
1248 // to avoid timeouts from bugreport.
1249 if (use_socket) {
1250 redirect_to_socket(stdout, "dumpstate");
1251 }
1252
Felipe Leme2628e9e2016-04-12 16:36:51 -07001253 if (use_control_socket) {
1254 MYLOGD("Opening control socket\n");
1255 control_socket_fd = open_socket("dumpstate");
1256 }
1257
Felipe Lemecbce55d2016-02-08 09:53:18 -08001258 /* full path of the temporary file containing the bugreport */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001259 std::string tmp_path;
1260
Felipe Leme0f3fb202016-06-10 17:10:53 -07001261 /* full path of the file containing the dumpstate logs */
Felipe Lemecbce55d2016-02-08 09:53:18 -08001262 std::string log_path;
1263
Felipe Leme14e034a2016-03-30 18:51:03 -07001264 /* full path of the systrace file, when enabled */
1265 std::string systrace_path;
1266
Felipe Lemee338bf62015-12-07 14:03:50 -08001267 /* full path of the temporary file containing the screenshot (when requested) */
1268 std::string screenshot_path;
1269
Felipe Lemecbce55d2016-02-08 09:53:18 -08001270 /* base name (without suffix or extensions) of the bugreport files */
Felipe Lemead5f6c42015-11-30 14:26:46 -08001271 std::string base_name;
1272
Felipe Leme71bbfc52015-11-23 14:14:51 -08001273 /* pointer to the actual path, be it zip or text */
1274 std::string path;
1275
Felipe Leme635ca312016-01-05 14:23:02 -08001276 /* pointer to the zipped file */
Felipe Leme1e9edc62015-12-21 16:02:13 -08001277 std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001278
Felipe Lemead5f6c42015-11-30 14:26:46 -08001279 /* redirect output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001280 bool is_redirecting = !use_socket && use_outfile;
1281
1282 if (is_redirecting) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001283 bugreport_dir = dirname(use_outfile);
1284 base_name = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001285 if (do_add_date) {
1286 char date[80];
Felipe Lemead5f6c42015-11-30 14:26:46 -08001287 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
1288 suffix = date;
1289 } else {
1290 suffix = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001291 }
Felipe Lemecc37b8e2016-04-11 13:45:18 -07001292 char build_id[PROPERTY_VALUE_MAX];
1293 property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
1294 base_name = base_name + "-" + build_id;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001295 if (do_fb) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001296 // TODO: if dumpstate was an object, the paths could be internal variables and then
1297 // we could have a function to calculate the derived values, such as:
1298 // screenshot_path = GetPath(".png");
1299 screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001300 }
Felipe Lemead5f6c42015-11-30 14:26:46 -08001301 tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
Felipe Lemecbce55d2016-02-08 09:53:18 -08001302 log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
1303 + std::to_string(getpid()) + ".txt";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001304
Felipe Lemecbce55d2016-02-08 09:53:18 -08001305 MYLOGD("Bugreport dir: %s\n"
1306 "Base name: %s\n"
1307 "Suffix: %s\n"
1308 "Log path: %s\n"
1309 "Temporary path: %s\n"
1310 "Screenshot path: %s\n",
1311 bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
1312 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001313
Felipe Leme1e9edc62015-12-21 16:02:13 -08001314 if (do_zip_file) {
Felipe Leme1e9edc62015-12-21 16:02:13 -08001315 path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
Felipe Leme26bd34c2016-03-15 13:40:33 -07001316 MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -08001317 create_parent_dirs(path.c_str());
Felipe Leme1e9edc62015-12-21 16:02:13 -08001318 zip_file.reset(fopen(path.c_str(), "wb"));
1319 if (!zip_file) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001320 MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001321 do_zip_file = 0;
1322 } else {
1323 zip_writer.reset(new ZipWriter(zip_file.get()));
1324 }
Felipe Leme809d74e2016-02-02 12:57:00 -08001325 add_text_zip_entry("version.txt", version);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001326 }
1327
Felipe Leme71bbfc52015-11-23 14:14:51 -08001328 if (do_update_progress) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001329 std::vector<std::string> am_args = {
Felipe Lemed5e724a2016-02-11 09:12:39 -08001330 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemead5f6c42015-11-30 14:26:46 -08001331 "--es", "android.intent.extra.NAME", suffix,
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001332 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001333 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
1334 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
1335 };
1336 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001337 }
1338 }
1339
Nick Kralevichf3599b32016-01-25 15:05:16 -08001340 /* read /proc/cmdline before dropping root */
1341 FILE *cmdline = fopen("/proc/cmdline", "re");
1342 if (cmdline) {
1343 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1344 fclose(cmdline);
1345 }
1346
Jeff Brown1dc94e32014-09-11 14:15:27 -07001347 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001348 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001349 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001350 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001351 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001352 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001353 }
John Michelau1f794c42012-09-17 11:20:19 -05001354 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001355
Felipe Leme3634a1e2015-12-09 10:11:47 -08001356 if (do_fb && do_early_screenshot) {
1357 if (screenshot_path.empty()) {
1358 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001359 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001360 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001361 MYLOGI("taking early screenshot\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001362 take_screenshot(screenshot_path);
Felipe Lemecbce55d2016-02-08 09:53:18 -08001363 MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
Felipe Leme3634a1e2015-12-09 10:11:47 -08001364 if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001365 MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
Felipe Leme3634a1e2015-12-09 10:11:47 -08001366 screenshot_path.c_str(), strerror(errno));
1367 }
Felipe Lemee338bf62015-12-07 14:03:50 -08001368 }
1369 }
1370
Felipe Leme1e9edc62015-12-21 16:02:13 -08001371 if (do_zip_file) {
1372 if (chown(path.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001373 MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001374 }
1375 }
1376
Felipe Leme71bbfc52015-11-23 14:14:51 -08001377 if (is_redirecting) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001378 redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001379 if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
1380 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1381 log_path.c_str(), strerror(errno));
1382 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001383 /* TODO: rather than generating a text file now and zipping it later,
1384 it would be more efficient to redirect stdout to the zip entry
1385 directly, but the libziparchive doesn't support that option yet. */
1386 redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001387 if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
1388 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
1389 tmp_path.c_str(), strerror(errno));
1390 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001391 }
Felipe Leme608385d2016-02-01 10:35:38 -08001392 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1393 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001394 // duration is logged into MYLOG instead.
Felipe Leme809d74e2016-02-02 12:57:00 -08001395 print_header(version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001396
Felipe Leme71a74ac2016-03-17 15:43:25 -07001397 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001398 dump_systrace();
Felipe Leme71a74ac2016-03-17 15:43:25 -07001399
Wei Liu341938b2016-04-27 16:18:17 -07001400 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
Felipe Lemeefd7e272016-05-18 09:27:16 -07001401 dump_raft();
Wei Liu341938b2016-04-27 16:18:17 -07001402
Felipe Leme9c74aad2016-02-29 18:15:42 -08001403 // Invoking the following dumpsys calls before dump_traces() to try and
1404 // keep the system stats as close to its initial state as possible.
Felipe Lemedbfe0832016-06-30 14:27:04 -07001405 run_dumpsys_as_shell("DUMPSYS MEMINFO", 90, {"meminfo", "-a"});
1406 run_dumpsys_as_shell("DUMPSYS CPUINFO", 10, {"cpuinfo", "-a"});
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001407
1408 /* collect stack traces from Dalvik and native processes (needs root) */
1409 dump_traces_path = dump_traces();
1410
Felipe Lemec0808152016-06-17 17:37:13 -07001411 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001412 get_tombstone_fds(tombstone_data);
1413 add_dir(RECOVERY_DIR, true);
Mark Salyzynd6ab0112016-03-25 12:56:39 -07001414 add_dir(RECOVERY_DATA_DIR, true);
Mark Salyzyn4d42dea2016-04-01 10:03:14 -07001415 add_dir(LOGPERSIST_DATA_DIR, false);
David Brazdild2991962016-06-03 14:40:44 +01001416 if (!is_user_build()) {
1417 add_dir(PROFILE_DATA_DIR_CUR, true);
1418 add_dir(PROFILE_DATA_DIR_REF, true);
1419 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001420 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001421 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001422
Felipe Lemecf6a8b42016-03-11 10:38:19 -08001423 if (!drop_root_user()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001424 return -1;
1425 }
1426
1427 dumpstate(do_early_screenshot ? "": screenshot_path, version);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001428
Felipe Leme55b42a62015-11-10 17:39:08 -08001429 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001430 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001431 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001432 }
1433
Felipe Leme6e01fa62015-11-11 19:35:14 -08001434 /* rename or zip the (now complete) .tmp file to its final location */
1435 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001436
1437 /* check if user changed the suffix using system properties */
1438 char key[PROPERTY_KEY_MAX];
1439 char value[PROPERTY_VALUE_MAX];
Nick Kralevichf0922cc2016-05-14 16:47:44 -07001440 snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001441 property_get(key, value, "");
1442 bool change_suffix= false;
1443 if (value[0]) {
1444 /* must whitelist which characters are allowed, otherwise it could cross directories */
1445 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
1446 if (std::regex_match(value, valid_regex)) {
1447 change_suffix = true;
1448 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001449 MYLOGE("invalid suffix provided by user: %s\n", value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001450 }
1451 }
1452 if (change_suffix) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001453 MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
Felipe Lemead5f6c42015-11-30 14:26:46 -08001454 suffix = value;
1455 if (!screenshot_path.empty()) {
1456 std::string new_screenshot_path =
1457 bugreport_dir + "/" + base_name + "-" + suffix + ".png";
1458 if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001459 MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
Felipe Lemead5f6c42015-11-30 14:26:46 -08001460 new_screenshot_path.c_str(), strerror(errno));
1461 } else {
1462 screenshot_path = new_screenshot_path;
1463 }
1464 }
1465 }
1466
Felipe Leme6e01fa62015-11-11 19:35:14 -08001467 bool do_text_file = true;
1468 if (do_zip_file) {
Felipe Leme88c79332016-02-22 11:06:49 -08001469 std::string entry_name = base_name + "-" + suffix + ".txt";
1470 MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
Felipe Leme0f3fb202016-06-10 17:10:53 -07001471 if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001472 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001473 do_text_file = true;
1474 } else {
1475 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001476 // Since zip file is already created, it needs to be renamed.
1477 std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
1478 if (path != new_path) {
1479 MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
1480 if (rename(path.c_str(), new_path.c_str())) {
1481 MYLOGE("rename(%s, %s): %s\n", path.c_str(),
1482 new_path.c_str(), strerror(errno));
1483 } else {
1484 path = new_path;
1485 }
1486 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001487 }
1488 }
1489 if (do_text_file) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001490 path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
Felipe Leme88c79332016-02-22 11:06:49 -08001491 MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001492 if (rename(tmp_path.c_str(), path.c_str())) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001493 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
Felipe Leme6e01fa62015-11-11 19:35:14 -08001494 path.clear();
1495 }
1496 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001497 if (use_control_socket) {
1498 if (do_text_file) {
1499 dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
1500 "for more details\n", log_path.c_str());
1501 } else {
1502 dprintf(control_socket_fd, "OK:%s\n", path.c_str());
1503 }
1504 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001505 }
1506
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001507 /* vibrate a few but shortly times to let user know it's finished */
1508 if (vibrator) {
1509 for (int i = 0; i < 3; i++) {
1510 vibrate(vibrator.get(), 75);
1511 usleep((75 + 50) * 1000);
1512 }
1513 }
1514
Jeff Brown1dc94e32014-09-11 14:15:27 -07001515 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001516 if (do_broadcast) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001517 if (!path.empty()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001518 MYLOGI("Final bugreport path: %s\n", path.c_str());
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001519 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001520 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001521 "--ei", "android.intent.extra.ID", std::to_string(id),
Felipe Leme71bbfc52015-11-23 14:14:51 -08001522 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
Felipe Lemeee2e4a02016-02-22 18:12:11 -08001523 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
Felipe Lemecbce55d2016-02-08 09:53:18 -08001524 "--es", "android.intent.extra.BUGREPORT", path,
1525 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001526 };
1527 if (do_fb) {
1528 am_args.push_back("--es");
1529 am_args.push_back("android.intent.extra.SCREENSHOT");
1530 am_args.push_back(screenshot_path);
1531 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001532 if (is_remote_mode) {
1533 am_args.push_back("--es");
1534 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
1535 am_args.push_back(SHA256_file_hash(path));
1536 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1537 } else {
1538 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1539 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001540 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001541 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001542 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001543 }
1544
Felipe Lemecbce55d2016-02-08 09:53:18 -08001545 MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
1546 MYLOGI("done\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001547
Felipe Leme107a05f2016-03-08 15:11:15 -08001548 if (is_redirecting) {
1549 fclose(stderr);
1550 }
1551
Felipe Leme2628e9e2016-04-12 16:36:51 -07001552 if (use_control_socket && control_socket_fd >= 0) {
1553 MYLOGD("Closing control socket\n");
1554 close(control_socket_fd);
1555 }
1556
Colin Crossf45fa6b2012-03-26 12:38:26 -07001557 return 0;
1558}