blob: 6d539c89d30f835e3b19b1e7386dfc1ea551a960 [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 */
Felipe Lemef0292972016-11-22 13:57:05 -080016
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070017#define LOG_TAG "dumpstate"
Colin Crossf45fa6b2012-03-26 12:38:26 -070018
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -070019#include <dirent.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <errno.h>
21#include <fcntl.h>
Felipe Lemead5f6c42015-11-30 14:26:46 -080022#include <libgen.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070023#include <limits.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080024#include <memory>
Felipe Lemead5f6c42015-11-30 14:26:46 -080025#include <regex>
Felipe Leme635ca312016-01-05 14:23:02 -080026#include <set>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070027#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <stdio.h>
29#include <stdlib.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080030#include <string>
Colin Crossf45fa6b2012-03-26 12:38:26 -070031#include <string.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070032#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <sys/resource.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/wait.h>
37#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070038
Felipe Leme96c2bbb2016-09-26 09:21:21 -070039#include <android-base/file.h>
40#include <android-base/properties.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080041#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070042#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070043#include <android-base/unique_fd.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080044#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
Steven Morelandcb7ef822016-11-29 13:20:37 -080045#include <android/hardware/vibrator/1.0/IVibrator.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080046#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070047#include <cutils/properties.h>
Felipe Leme75876a22016-10-27 16:31:27 -070048#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070049#include <private/android_filesystem_config.h>
50#include <private/android_logger.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070051
Felipe Lemef0292972016-11-22 13:57:05 -080052#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070053#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070054#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080055
Steven Morelandcb7ef822016-11-29 13:20:37 -080056using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
57using ::android::hardware::vibrator::V1_0::IVibrator;
58using VibratorStatus = ::android::hardware::vibrator::V1_0::Status;
59
Colin Crossf45fa6b2012-03-26 12:38:26 -070060/* read before root is shed */
61static char cmdline_buf[16384] = "(unknown)";
62static const char *dump_traces_path = NULL;
63
Felipe Leme1d486fe2016-10-14 18:06:47 -070064// TODO: variables and functions below should be part of dumpstate object
65
Felipe Leme635ca312016-01-05 14:23:02 -080066static std::set<std::string> mount_points;
67void add_mountinfo();
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 Lemee844a9d2016-09-21 15:01:39 -070092// TODO: temporary variables and functions used during C++ refactoring
93static Dumpstate& ds = Dumpstate::GetInstance();
Felipe Leme678727a2016-09-21 17:22:11 -070094static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
95 const CommandOptions& options = CommandOptions::DEFAULT) {
96 return ds.RunCommand(title, fullCommand, options);
97}
98static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -080099 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Felipe Leme678727a2016-09-21 17:22:11 -0700100 long dumpsysTimeout = 0) {
101 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
102}
103static int DumpFile(const std::string& title, const std::string& path) {
104 return ds.DumpFile(title, path);
105}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800106
Felipe Lemee844a9d2016-09-21 15:01:39 -0700107// Relative directory (inside the zip) for all files copied as-is into the bugreport.
108static const std::string ZIP_ROOT_DIR = "FS";
109
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700110static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700111static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700112static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700113
Felipe Lemef0292972016-11-22 13:57:05 -0800114static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
115
Felipe Leme3d305a12016-05-20 11:24:37 -0700116/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
117 * otherwise, gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700118static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700119 time_t thirty_minutes_ago = ds.now_ - 60 * 30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700120 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
121 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800122 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
123 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700124 struct stat st;
Felipe Leme3d305a12016-05-20 11:24:37 -0700125 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
Felipe Leme1d486fe2016-10-14 18:06:47 -0700126 (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
Felipe Leme3d305a12016-05-20 11:24:37 -0700127 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700128 } else {
Felipe Leme3d305a12016-05-20 11:24:37 -0700129 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700130 data[i].fd = -1;
131 }
132 }
133}
134
Felipe Leme635ca312016-01-05 14:23:02 -0800135// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700136void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800137 char path[PATH_MAX];
138
139 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
140 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700141 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800142 char linkname[PATH_MAX];
143 ssize_t r = readlink(path, linkname, PATH_MAX);
144 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800145 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800146 return;
147 }
148 linkname[r] = '\0';
149
150 if (mount_points.find(linkname) == mount_points.end()) {
151 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700152 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700153 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800154 mount_points.insert(linkname);
155 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800156 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800157 }
158 }
159}
160
161void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700162 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700163 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800164 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800165 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700166 for_each_pid(do_mountinfo, nullptr);
167 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800168}
169
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700170static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
171{
172 DIR *d;
173 struct dirent *de;
174 char path[PATH_MAX];
175
176 d = opendir(driverpath);
177 if (d == NULL) {
178 return;
179 }
180
181 while ((de = readdir(d))) {
182 if (de->d_type != DT_LNK) {
183 continue;
184 }
185 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700186 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700187 }
188
189 closedir(d);
190}
191
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700192// return pid of a userspace process. If not found or error, return 0.
193static unsigned int pid_of_process(const char* ps_name) {
194 DIR *proc_dir;
195 struct dirent *ps;
196 unsigned int pid;
197 std::string cmdline;
198
199 if (!(proc_dir = opendir("/proc"))) {
200 MYLOGE("Can't open /proc\n");
201 return 0;
202 }
203
204 while ((ps = readdir(proc_dir))) {
205 if (!(pid = atoi(ps->d_name))) {
206 continue;
207 }
208 android::base::ReadFileToString("/proc/"
209 + std::string(ps->d_name) + "/cmdline", &cmdline);
210 if (cmdline.find(ps_name) == std::string::npos) {
211 continue;
212 } else {
213 closedir(proc_dir);
214 return pid;
215 }
216 }
217 closedir(proc_dir);
218 return 0;
219}
220
221// dump anrd's trace and add to the zip file.
222// 1. check if anrd is running on this device.
223// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
224// 3. wait until the trace generation completes and add to the zip file.
225static bool dump_anrd_trace() {
226 unsigned int pid;
227 char buf[50], path[PATH_MAX];
228 struct dirent *trace;
229 struct stat st;
230 DIR *trace_dir;
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700231 int retry = 5;
232 long max_ctime = 0, old_mtime;
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700233 long long cur_size = 0;
234 const char *trace_path = "/data/misc/anrd/";
235
Felipe Leme1d486fe2016-10-14 18:06:47 -0700236 if (!ds.IsZipping()) {
237 MYLOGE("Not dumping anrd trace because it's not a zipped bugreport\n");
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700238 return false;
239 }
240
241 // find anrd's pid if it is running.
242 pid = pid_of_process("/system/xbin/anrd");
243
244 if (pid > 0) {
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700245 if (stat(trace_path, &st) == 0) {
246 old_mtime = st.st_mtime;
247 } else {
248 MYLOGE("Failed to find: %s\n", trace_path);
249 return false;
250 }
251
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700252 // send SIGUSR1 to the anrd to generate a trace.
253 sprintf(buf, "%u", pid);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700254 if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700255 CommandOptions::WithTimeout(1).Build())) {
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700256 MYLOGE("anrd signal timed out. Please manually collect trace\n");
257 return false;
258 }
259
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700260 while (retry-- > 0 && old_mtime == st.st_mtime) {
261 sleep(1);
262 stat(trace_path, &st);
263 }
264
265 if (retry < 0 && old_mtime == st.st_mtime) {
266 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
267 return false;
268 }
269
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700270 // identify the trace file by its creation time.
271 if (!(trace_dir = opendir(trace_path))) {
272 MYLOGE("Can't open trace file under %s\n", trace_path);
273 }
274 while ((trace = readdir(trace_dir))) {
275 if (strcmp(trace->d_name, ".") == 0
276 || strcmp(trace->d_name, "..") == 0) {
277 continue;
278 }
279 sprintf(path, "%s%s", trace_path, trace->d_name);
280 if (stat(path, &st) == 0) {
281 if (st.st_ctime > max_ctime) {
282 max_ctime = st.st_ctime;
283 sprintf(buf, "%s", trace->d_name);
284 }
285 }
286 }
287 closedir(trace_dir);
288
289 // Wait until the dump completes by checking the size of the trace.
290 if (max_ctime > 0) {
291 sprintf(path, "%s%s", trace_path, buf);
292 while(true) {
293 sleep(1);
294 if (stat(path, &st) == 0) {
295 if (st.st_size == cur_size) {
296 break;
297 } else if (st.st_size > cur_size) {
298 cur_size = st.st_size;
299 } else {
300 return false;
301 }
302 } else {
303 MYLOGE("Cant stat() %s anymore\n", path);
304 return false;
305 }
306 }
307 // Add to the zip file.
Felipe Leme1d486fe2016-10-14 18:06:47 -0700308 if (!ds.AddZipEntry("anrd_trace.txt", path)) {
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700309 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
310 } else {
311 if (remove(path)) {
312 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
313 }
314 return true;
315 }
316 } else {
317 MYLOGE("Can't stats any trace file under %s\n", trace_path);
318 }
319 }
320 return false;
321}
322
Felipe Lemeefd7e272016-05-18 09:27:16 -0700323static void dump_systrace() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700324 if (!ds.IsZipping()) {
325 MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
Felipe Leme71a74ac2016-03-17 15:43:25 -0700326 return;
327 }
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700328 std::string systrace_path = ds.GetPath("-systrace.txt");
Felipe Leme14e034a2016-03-30 18:51:03 -0700329 if (systrace_path.empty()) {
330 MYLOGE("Not dumping systrace because path is empty\n");
331 return;
332 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700333 const char* path = "/sys/kernel/debug/tracing/tracing_on";
334 long int is_tracing;
335 if (read_file_as_long(path, &is_tracing)) {
336 return; // error already logged
337 }
338 if (is_tracing <= 0) {
339 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
340 return;
341 }
342
Felipe Leme14e034a2016-03-30 18:51:03 -0700343 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
344 systrace_path.c_str());
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700345 if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700346 CommandOptions::WithTimeout(120).Build())) {
Felipe Leme14e034a2016-03-30 18:51:03 -0700347 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
Felipe Lemec7fe8fe2016-09-21 18:13:20 -0700348 // TODO: RunCommand tries to kill the process, but atrace doesn't die
Felipe Leme30dbfa12016-09-02 12:43:26 -0700349 // peacefully; ideally, we should call strace to stop itself, but there is no such option
350 // yet (just a --async_stop, which stops and dump
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700351 // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
Felipe Leme30dbfa12016-09-02 12:43:26 -0700352 // MYLOGE("could not stop systrace ");
353 // }
Felipe Leme14e034a2016-03-30 18:51:03 -0700354 }
Felipe Leme1d486fe2016-10-14 18:06:47 -0700355 if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
Felipe Leme14e034a2016-03-30 18:51:03 -0700356 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700357 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700358 if (remove(systrace_path.c_str())) {
359 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
360 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700361 }
362}
363
Felipe Lemeefd7e272016-05-18 09:27:16 -0700364static void dump_raft() {
Felipe Lemef0292972016-11-22 13:57:05 -0800365 if (PropertiesHelper::IsUserBuild()) {
Wei Liu341938b2016-04-27 16:18:17 -0700366 return;
367 }
368
Felipe Leme1d486fe2016-10-14 18:06:47 -0700369 std::string raft_path = ds.GetPath("-raft_log.txt");
370 if (raft_path.empty()) {
371 MYLOGD("raft_path is empty\n");
Wei Liu341938b2016-04-27 16:18:17 -0700372 return;
373 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700374
375 struct stat s;
376 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
377 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
378 return;
379 }
380
Felipe Leme30dbfa12016-09-02 12:43:26 -0700381 CommandOptions options = CommandOptions::WithTimeout(600).Build();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700382 if (!ds.IsZipping()) {
383 // Write compressed and encoded raft logs to stdout if it's not a zipped bugreport.
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700384 RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
Wei Liu341938b2016-04-27 16:18:17 -0700385 return;
386 }
387
Felipe Leme1d486fe2016-10-14 18:06:47 -0700388 RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_path}, options);
389 if (!ds.AddZipEntry("raft_log.txt", raft_path)) {
390 MYLOGE("Unable to add raft log %s to zip file\n", raft_path.c_str());
Wei Liu341938b2016-04-27 16:18:17 -0700391 } else {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700392 if (remove(raft_path.c_str())) {
393 MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700394 }
395 }
396}
397
Naveen Kalla058e1e82016-10-19 21:38:44 -0700398/**
399 * Finds the last modified file in the directory dir whose name starts with file_prefix.
400 *
401 * Function returns empty string when it does not find a file
402 */
403static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
404 const std::string& file_prefix) {
405 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
406 if (d == nullptr) {
407 MYLOGD("Error %d opening %s\n", errno, dir.c_str());
408 return "";
409 }
410
411 // Find the newest file matching the file_prefix in dir
412 struct dirent *de;
413 time_t last_modified_time = 0;
414 std::string last_modified_file = "";
415 struct stat s;
416
417 while ((de = readdir(d.get()))) {
418 std::string file = std::string(de->d_name);
419 if (!file_prefix.empty()) {
420 if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
421 }
422 file = dir + "/" + file;
423 int ret = stat(file.c_str(), &s);
424
425 if ((ret == 0) && (s.st_mtime > last_modified_time)) {
426 last_modified_file = file;
427 last_modified_time = s.st_mtime;
428 }
429 }
430
431 return last_modified_file;
432}
433
434static void DumpModemLogs() {
435 DurationReporter durationReporter("DUMP MODEM LOGS");
Felipe Lemef0292972016-11-22 13:57:05 -0800436 if (PropertiesHelper::IsUserBuild()) {
Naveen Kalla058e1e82016-10-19 21:38:44 -0700437 return;
438 }
439
440 if (!ds.IsZipping()) {
441 MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
442 return;
443 }
444
445 std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
446
447 if(file_prefix.empty()) {
448 MYLOGD("No modem log : file_prefix is empty\n");
449 return;
450 }
451
452 // TODO: use bugreport_dir_ directly when this function is moved to Dumpstate class
453 std::string bugreport_dir = dirname(ds.GetPath("").c_str());
454 MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
455 bugreport_dir.c_str(), file_prefix.c_str());
456
457 std::string modem_log_file = GetLastModifiedFileWithPrefix(bugreport_dir, file_prefix);
458
459 struct stat s;
460 if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
461 MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
462 return;
463 }
464
465 std::string filename = basename(modem_log_file.c_str());
466 if (!ds.AddZipEntry(filename, modem_log_file)) {
467 MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
468 } else {
469 MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
Naveen Kallab77df782016-11-18 17:32:23 -0800470 if (remove(modem_log_file.c_str())) {
471 MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
472 }
Naveen Kalla058e1e82016-10-19 21:38:44 -0700473 }
474}
475
Mark Salyzyn326842f2015-04-30 09:49:41 -0700476static bool skip_not_stat(const char *path) {
477 static const char stat[] = "/stat";
478 size_t len = strlen(path);
479 if (path[len - 1] == '/') { /* Directory? */
480 return false;
481 }
482 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
483}
484
Felipe Leme4c2d6632016-09-28 14:32:00 -0700485static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800486 return false;
487}
488
Mark Salyzyn326842f2015-04-30 09:49:41 -0700489static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700490unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700491
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800492//
493// stat offsets
494// Name units description
495// ---- ----- -----------
496// read I/Os requests number of read I/Os processed
497#define __STAT_READ_IOS 0
498// read merges requests number of read I/Os merged with in-queue I/O
499#define __STAT_READ_MERGES 1
500// read sectors sectors number of sectors read
501#define __STAT_READ_SECTORS 2
502// read ticks milliseconds total wait time for read requests
503#define __STAT_READ_TICKS 3
504// write I/Os requests number of write I/Os processed
505#define __STAT_WRITE_IOS 4
506// write merges requests number of write I/Os merged with in-queue I/O
507#define __STAT_WRITE_MERGES 5
508// write sectors sectors number of sectors written
509#define __STAT_WRITE_SECTORS 6
510// write ticks milliseconds total wait time for write requests
511#define __STAT_WRITE_TICKS 7
512// in_flight requests number of I/Os currently in flight
513#define __STAT_IN_FLIGHT 8
514// io_ticks milliseconds total time this block device has been active
515#define __STAT_IO_TICKS 9
516// time_in_queue milliseconds total wait time for all requests
517#define __STAT_IN_QUEUE 10
518#define __STAT_NUMBER_FIELD 11
519//
520// read I/Os, write I/Os
521// =====================
522//
523// These values increment when an I/O request completes.
524//
525// read merges, write merges
526// =========================
527//
528// These values increment when an I/O request is merged with an
529// already-queued I/O request.
530//
531// read sectors, write sectors
532// ===========================
533//
534// These values count the number of sectors read from or written to this
535// block device. The "sectors" in question are the standard UNIX 512-byte
536// sectors, not any device- or filesystem-specific block size. The
537// counters are incremented when the I/O completes.
538#define SECTOR_SIZE 512
539//
540// read ticks, write ticks
541// =======================
542//
543// These values count the number of milliseconds that I/O requests have
544// waited on this block device. If there are multiple I/O requests waiting,
545// these values will increase at a rate greater than 1000/second; for
546// example, if 60 read requests wait for an average of 30 ms, the read_ticks
547// field will increase by 60*30 = 1800.
548//
549// in_flight
550// =========
551//
552// This value counts the number of I/O requests that have been issued to
553// the device driver but have not yet completed. It does not include I/O
554// requests that are in the queue but not yet issued to the device driver.
555//
556// io_ticks
557// ========
558//
559// This value counts the number of milliseconds during which the device has
560// had I/O requests queued.
561//
562// time_in_queue
563// =============
564//
565// This value counts the number of milliseconds that I/O requests have waited
566// on this block device. If there are multiple I/O requests waiting, this
567// value will increase as the product of the number of milliseconds times the
568// number of requests waiting (see "read ticks" above for an example).
569#define S_TO_MS 1000
570//
571
Mark Salyzyn326842f2015-04-30 09:49:41 -0700572static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800573 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700574 bool z;
575 char *cp, *buffer = NULL;
576 size_t i = 0;
577 FILE *fp = fdopen(fd, "rb");
578 getline(&buffer, &i, fp);
579 fclose(fp);
580 if (!buffer) {
581 return -errno;
582 }
583 i = strlen(buffer);
584 while ((i > 0) && (buffer[i - 1] == '\n')) {
585 buffer[--i] = '\0';
586 }
587 if (!*buffer) {
588 free(buffer);
589 return 0;
590 }
591 z = true;
592 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800593 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700594 if (fields[i] != 0) {
595 z = false;
596 }
597 }
598 if (z) { /* never accessed */
599 free(buffer);
600 return 0;
601 }
602
603 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
604 path += sizeof(mmcblk0) - 1;
605 }
606
Felipe Lemed8b94e52016-12-08 10:21:44 -0800607 printf("%s: %s\n", path, buffer);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700608 free(buffer);
609
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800610 if (fields[__STAT_IO_TICKS]) {
611 unsigned long read_perf = 0;
612 unsigned long read_ios = 0;
613 if (fields[__STAT_READ_TICKS]) {
614 unsigned long long divisor = fields[__STAT_READ_TICKS]
615 * fields[__STAT_IO_TICKS];
616 read_perf = ((unsigned long long)SECTOR_SIZE
617 * fields[__STAT_READ_SECTORS]
618 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
619 / divisor;
620 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
621 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
622 / divisor;
623 }
624
625 unsigned long write_perf = 0;
626 unsigned long write_ios = 0;
627 if (fields[__STAT_WRITE_TICKS]) {
628 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
629 * fields[__STAT_IO_TICKS];
630 write_perf = ((unsigned long long)SECTOR_SIZE
631 * fields[__STAT_WRITE_SECTORS]
632 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
633 / divisor;
634 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
635 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
636 / divisor;
637 }
638
639 unsigned queue = (fields[__STAT_IN_QUEUE]
640 + (fields[__STAT_IO_TICKS] >> 1))
641 / fields[__STAT_IO_TICKS];
642
643 if (!write_perf && !write_ios) {
Felipe Lemed8b94e52016-12-08 10:21:44 -0800644 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800645 } else {
Felipe Lemed8b94e52016-12-08 10:21:44 -0800646 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
647 read_ios, write_perf, write_ios, queue);
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800648 }
649
650 /* bugreport timeout factor adjustment */
651 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
652 worst_write_perf = write_perf;
653 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700654 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700655 return 0;
656}
657
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700658/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800659static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -0700660 log_id_t id = android_name_to_log_id(name);
661 unsigned long property_size = __android_logger_get_buffer_size(id);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700662 /* Engineering margin is ten-fold our guess */
663 return 10 * (property_size + worst_write_perf) / worst_write_perf;
664}
665
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700666void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700667 std::string build, fingerprint, radio, bootloader, network;
668 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700669
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700670 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
671 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700672 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
673 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
674 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700675 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700676
Felipe Lemed8b94e52016-12-08 10:21:44 -0800677 printf("========================================================\n");
678 printf("== dumpstate: %s\n", date);
679 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700680
Felipe Lemed8b94e52016-12-08 10:21:44 -0800681 printf("\n");
682 printf("Build: %s\n", build.c_str());
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700683 // NOTE: fingerprint entry format is important for other tools.
Felipe Lemed8b94e52016-12-08 10:21:44 -0800684 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
685 printf("Bootloader: %s\n", bootloader.c_str());
686 printf("Radio: %s\n", radio.c_str());
687 printf("Network: %s\n", network.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700688
Felipe Lemed8b94e52016-12-08 10:21:44 -0800689 printf("Kernel: ");
Felipe Lemef0292972016-11-22 13:57:05 -0800690 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Felipe Lemed8b94e52016-12-08 10:21:44 -0800691 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
692 printf("Bugreport format version: %s\n", version_.c_str());
693 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
694 PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
695 printf("\n");
Felipe Leme78f2c862015-12-21 09:55:22 -0800696}
697
Felipe Leme24b66ee2016-06-16 10:55:26 -0700698// List of file extensions that can cause a zip file attachment to be rejected by some email
699// service providers.
700static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
701 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
702 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
703 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
704};
705
Felipe Leme1d486fe2016-10-14 18:06:47 -0700706bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
707 if (!IsZipping()) {
708 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
709 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800710 return false;
711 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700712 std::string valid_name = entry_name;
713
714 // Rename extension if necessary.
715 size_t idx = entry_name.rfind(".");
716 if (idx != std::string::npos) {
717 std::string extension = entry_name.substr(idx);
718 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
719 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
720 valid_name = entry_name + ".renamed";
721 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
722 }
723 }
724
Felipe Leme6fe9db62016-02-12 09:04:16 -0800725 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
726 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700727 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
728 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700729 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700730 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700731 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800732 return false;
733 }
734
Felipe Leme770410d2016-01-26 17:07:14 -0800735 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800736 while (1) {
Zach Riggle22200402016-08-18 01:01:24 -0400737 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800738 if (bytes_read == 0) {
739 break;
740 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800741 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800742 return false;
743 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700744 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800745 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700746 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800747 return false;
748 }
749 }
750
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700751 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700752 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700753 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800754 return false;
755 }
756
757 return true;
758}
759
Felipe Leme1d486fe2016-10-14 18:06:47 -0700760bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
761 android::base::unique_fd fd(
762 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700763 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800764 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800765 return false;
766 }
767
Felipe Leme1d486fe2016-10-14 18:06:47 -0700768 return AddZipEntryFromFd(entry_name, fd.get());
Felipe Lemee82a27d2016-01-05 13:35:44 -0800769}
770
771/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700772static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700773 return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800774}
775
Felipe Leme1d486fe2016-10-14 18:06:47 -0700776void Dumpstate::AddDir(const std::string& dir, bool recursive) {
777 if (!IsZipping()) {
778 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800779 return;
780 }
Felipe Leme678727a2016-09-21 17:22:11 -0700781 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800782 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700783 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800784}
785
Felipe Leme1d486fe2016-10-14 18:06:47 -0700786bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
787 if (!IsZipping()) {
788 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
789 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800790 return false;
791 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800792 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700793 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700794 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700795 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700796 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800797 return false;
798 }
799
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700800 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700801 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700802 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700803 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800804 return false;
805 }
806
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700807 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700808 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700809 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800810 return false;
811 }
812
813 return true;
814}
815
Felipe Leme6ec6ac42017-01-10 15:29:53 -0800816static void DoKmsg() {
817 struct stat st;
818 if (!stat(PSTORE_LAST_KMSG, &st)) {
819 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
820 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
821 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
822 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
823 } else {
824 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
825 DumpFile("LAST KMSG", "/proc/last_kmsg");
826 }
827}
828
829static void DoLogcat() {
830 unsigned long timeout;
831 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
832 // calculate timeout
833 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
834 if (timeout < 20000) {
835 timeout = 20000;
836 }
837 RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
838 CommandOptions::WithTimeout(timeout / 1000).Build());
839 timeout = logcat_timeout("events");
840 if (timeout < 20000) {
841 timeout = 20000;
842 }
843 RunCommand("EVENT LOG",
844 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
845 CommandOptions::WithTimeout(timeout / 1000).Build());
846 timeout = logcat_timeout("radio");
847 if (timeout < 20000) {
848 timeout = 20000;
849 }
850 RunCommand("RADIO LOG",
851 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
852 CommandOptions::WithTimeout(timeout / 1000).Build());
853
854 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
855
856 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
857 RunCommand("LAST LOGCAT",
858 {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
859}
860
861static void DumpIpTables() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700862 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
863 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900864 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700865 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900866 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
867 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
868 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
869 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700870}
871
Felipe Lemee184f662016-10-27 10:04:47 -0700872static void AddAnrTraceFiles() {
873 bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
874 std::string dump_traces_dir;
875
876 /* show the traces we collected in main(), if that was done */
877 if (dump_traces_path != nullptr) {
878 if (add_to_zip) {
879 dump_traces_dir = dirname(dump_traces_path);
880 MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
881 ds.AddDir(dump_traces_dir, true);
882 } else {
883 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
884 dump_traces_path);
885 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
886 }
887 }
888
889 std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
890 std::string anr_traces_dir = dirname(anr_traces_path.c_str());
891
892 // Make sure directory is not added twice.
893 // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
894 // generated by dump_traces() - and anr_traces_path - which is retrieved from a system
895 // property - but in reality they're the same path (although the former could be nullptr).
896 // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
897 // be revisited.
898 bool already_dumped = anr_traces_dir == dump_traces_dir;
899
900 MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
901 dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
902
903 if (anr_traces_path.empty()) {
Felipe Lemed8b94e52016-12-08 10:21:44 -0800904 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
Felipe Lemee184f662016-10-27 10:04:47 -0700905 } else {
906 int fd = TEMP_FAILURE_RETRY(
907 open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
908 if (fd < 0) {
Felipe Lemed8b94e52016-12-08 10:21:44 -0800909 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
910 strerror(errno));
Felipe Lemee184f662016-10-27 10:04:47 -0700911 } else {
912 if (add_to_zip) {
913 if (!already_dumped) {
914 MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
915 anr_traces_dir.c_str());
916 ds.AddDir(anr_traces_dir, true);
917 already_dumped = true;
918 }
919 } else {
920 MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
921 anr_traces_path.c_str());
922 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
923 }
924 }
925 }
926
927 if (add_to_zip && already_dumped) {
928 MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
929 return;
930 }
931
932 /* slow traces for slow operations */
933 struct stat st;
934 if (!anr_traces_path.empty()) {
935 int tail = anr_traces_path.size() - 1;
936 while (tail > 0 && anr_traces_path.at(tail) != '/') {
937 tail--;
938 }
939 int i = 0;
940 while (1) {
941 anr_traces_path = anr_traces_path.substr(0, tail + 1) +
942 android::base::StringPrintf("slow%02d.txt", i);
943 if (stat(anr_traces_path.c_str(), &st)) {
944 // No traces file at this index, done with the files.
945 break;
946 }
947 ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
948 i++;
949 }
950 }
951}
952
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700953static void dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -0700954 DurationReporter duration_reporter("DUMPSTATE");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700955
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700956 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700957 RunCommand("UPTIME", {"uptime"});
Mark Salyzyn326842f2015-04-30 09:49:41 -0700958 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800959 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700960 DumpFile("MEMORY INFO", "/proc/meminfo");
961 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700962 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Felipe Lemef0292972016-11-22 13:57:05 -0800963 RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700964 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
965 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
966 DumpFile("SLAB INFO", "/proc/slabinfo");
967 DumpFile("ZONEINFO", "/proc/zoneinfo");
968 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
969 DumpFile("BUDDYINFO", "/proc/buddyinfo");
970 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700971
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700972 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
973 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
974 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700975
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700976 RunCommand("PROCESSES AND THREADS",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700977 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
Felipe Lemef0292972016-11-22 13:57:05 -0800978 RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700979
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700980 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -0700981 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700982 struct stat s;
983 if (stat("/proc/modules", &s) != 0) {
984 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
985 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700986 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700987 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000988
Colin Crossf45fa6b2012-03-26 12:38:26 -0700989 do_dmesg();
990
Felipe Lemef0292972016-11-22 13:57:05 -0800991 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700992 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
993 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800994 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700995
Ajay Panickerd886ec42016-09-14 12:26:46 -0700996 /* Dump Bluetooth HCI logs */
Felipe Leme1d486fe2016-10-14 18:06:47 -0700997 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -0700998
Felipe Leme9a523ae2016-10-20 15:10:33 -0700999 if (!ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001000 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001001 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -07001002 }
1003
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001004 DoLogcat();
Mark Salyzynecc07632015-07-30 14:57:09 -07001005
Felipe Lemee184f662016-10-27 10:04:47 -07001006 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001007
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001008 int dumped = 0;
1009 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
1010 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -08001011 const char *name = tombstone_data[i].name;
1012 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001013 dumped = 1;
Felipe Leme1d486fe2016-10-14 18:06:47 -07001014 if (ds.IsZipping()) {
1015 if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001016 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -08001017 }
1018 } else {
1019 dump_file_from_fd("TOMBSTONE", name, fd);
1020 }
1021 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001022 tombstone_data[i].fd = -1;
1023 }
1024 }
1025 if (!dumped) {
Felipe Lemed8b94e52016-12-08 10:21:44 -08001026 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001027 }
1028
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001029 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1030 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1031 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1032 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1033 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001034
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001035 DoKmsg();
Mark Salyzyn2262c162014-12-16 09:09:26 -08001036
Colin Crossf45fa6b2012-03-26 12:38:26 -07001037 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -08001038
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001039 RunCommand("NETWORK INTERFACES", {"ip", "link"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001040
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001041 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1042 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001043
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001044 RunCommand("IP RULES", {"ip", "rule", "show"});
1045 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001046
1047 dump_route_tables();
1048
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001049 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1050 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1051 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
1052 RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001053 CommandOptions::WithTimeout(20).Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001054
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001055#ifdef FWDUMP_bcmdhd
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001056 RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001057
Felipe Lemef0292972016-11-22 13:57:05 -08001058 RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001059
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001060 RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001061
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001062#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001063 DumpFile("INTERRUPTS (1)", "/proc/interrupts");
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001064
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001065 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001066 CommandOptions::WithTimeout(10).Build());
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001067
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001068#ifdef FWDUMP_bcmdhd
Felipe Lemef0292972016-11-22 13:57:05 -08001069 RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001070
Felipe Lemef0292972016-11-22 13:57:05 -08001071 RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001072
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001073 RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001074#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001075 DumpFile("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001076
1077 print_properties();
1078
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001079 RunCommand("VOLD DUMP", {"vdc", "dump"});
1080 RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001081
ynwangf649a6e2016-07-17 21:56:00 -07001082 RunCommand("STORAGED TASKIOINFO", {"storaged", "-d"}, CommandOptions::WithTimeout(10).Build());
1083
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001084 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001085
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001086 RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001087
Felipe Lemed8b94e52016-12-08 10:21:44 -08001088 printf("------ BACKLIGHTS ------\n");
1089 printf("LCD brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001090 DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001091 printf("Button brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001092 DumpFile("", "/sys/class/leds/button-backlight/brightness");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001093 printf("Keyboard brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001094 DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001095 printf("ALS mode=");
Felipe Leme678727a2016-09-21 17:22:11 -07001096 DumpFile("", "/sys/class/leds/lcd-backlight/als");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001097 printf("LCD driver registers:\n");
Felipe Leme678727a2016-09-21 17:22:11 -07001098 DumpFile("", "/sys/class/leds/lcd-backlight/registers");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001099 printf("\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001100
1101 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001102 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1103 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1104 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1105 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1106 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001107
Felipe Leme6f674ae2016-11-18 17:10:33 -08001108 ds.DumpstateBoard();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001109
1110 /* Migrate the ril_dumpstate to a dumpstate_board()? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001111 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1112 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001113 // su does not exist on user builds, so try running without it.
1114 // This way any implementations of vril-dump that do not require
1115 // root can run on user builds.
1116 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001117 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001118 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001119 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001120 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001121 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001122 }
1123
Felipe Lemed8b94e52016-12-08 10:21:44 -08001124 printf("========================================================\n");
1125 printf("== Android Framework Services\n");
1126 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001127
Felipe Leme5bcce572016-09-27 09:21:08 -07001128 RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
1129 10);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001130
Felipe Lemed8b94e52016-12-08 10:21:44 -08001131 printf("========================================================\n");
1132 printf("== Checkins\n");
1133 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001134
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001135 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1136 RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
1137 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1138 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1139 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1140 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001141
Felipe Lemed8b94e52016-12-08 10:21:44 -08001142 printf("========================================================\n");
1143 printf("== Running Application Activities\n");
1144 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001145
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001146 RunDumpsys("APP ACTIVITIES", {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001147
Felipe Lemed8b94e52016-12-08 10:21:44 -08001148 printf("========================================================\n");
1149 printf("== Running Application Services\n");
1150 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001151
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001152 RunDumpsys("APP SERVICES", {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001153
Felipe Lemed8b94e52016-12-08 10:21:44 -08001154 printf("========================================================\n");
1155 printf("== Running Application Providers\n");
1156 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001157
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001158 RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001159
Naveen Kalla058e1e82016-10-19 21:38:44 -07001160 // DumpModemLogs adds the modem logs if available to the bugreport.
1161 // Do this at the end to allow for sufficient time for the modem logs to be
1162 // collected.
1163 DumpModemLogs();
1164
Felipe Lemed8b94e52016-12-08 10:21:44 -08001165 printf("========================================================\n");
1166 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1167 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
1168 printf("========================================================\n");
1169 printf("== dumpstate: done (id %d)\n", ds.id_);
1170 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001171}
1172
Felipe Leme6f674ae2016-11-18 17:10:33 -08001173void Dumpstate::DumpstateBoard() {
1174 DurationReporter duration_reporter("dumpstate_board()");
Felipe Lemed8b94e52016-12-08 10:21:44 -08001175 printf("========================================================\n");
1176 printf("== Board\n");
1177 printf("========================================================\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001178
Steven Morelandcb7ef822016-11-29 13:20:37 -08001179 ::android::sp<IDumpstateDevice> dumpstate_device(
1180 IDumpstateDevice::getService("DumpstateDevice"));
Felipe Leme6f674ae2016-11-18 17:10:33 -08001181 if (dumpstate_device == nullptr) {
1182 // TODO: temporary workaround until devices on master implement it
1183 MYLOGE("no IDumpstateDevice implementation; using legacy dumpstate_board()\n");
1184 dumpstate_board();
1185 return;
1186 }
1187
1188 if (!IsZipping()) {
1189 MYLOGE("Not dumping board info because it's not a zipped bugreport\n");
1190 return;
1191 }
1192
1193 std::string path = ds.GetPath("-dumpstate-board.txt");
1194 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
1195
1196 int fd =
1197 TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1198 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
1199 if (fd < 0) {
1200 MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
1201 return;
1202 }
1203
1204 native_handle_t* handle = native_handle_create(1, 0);
1205 if (handle == nullptr) {
1206 MYLOGE("Could not create native_handle\n");
1207 return;
1208 }
1209 handle->data[0] = fd;
1210
Felipe Lemef0292972016-11-22 13:57:05 -08001211 // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
Felipe Leme6f674ae2016-11-18 17:10:33 -08001212 dumpstate_device->dumpstateBoard(handle);
1213
1214 AddZipEntry("dumpstate-board.txt", path);
Felipe Lemed8b94e52016-12-08 10:21:44 -08001215 printf("*** See dumpstate-board.txt entry ***\n");
Felipe Leme6f674ae2016-11-18 17:10:33 -08001216
1217 native_handle_close(handle);
1218 native_handle_delete(handle);
1219
1220 if (remove(path.c_str()) != 0) {
1221 MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
1222 }
1223}
1224
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001225static void ShowUsageAndExit(int exitCode = 1) {
1226 fprintf(stderr,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001227 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001228 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1229 " -h: display this help message\n"
1230 " -b: play sound file instead of vibrate, at beginning of job\n"
1231 " -e: play sound file instead of vibrate, at end of job\n"
1232 " -o: write to file (instead of stdout)\n"
1233 " -d: append date to filename (requires -o)\n"
1234 " -p: capture screenshot to filename.png (requires -o)\n"
1235 " -z: generate zipped file (requires -o)\n"
1236 " -s: write output to control socket (for init)\n"
1237 " -S: write file location to control socket (for init; requires -o and -z)"
1238 " -q: disable vibrate\n"
1239 " -B: send broadcast when finished (requires -o)\n"
1240 " -P: send broadcast when started and update system properties on "
1241 "progress (requires -o and -B)\n"
1242 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1243 "shouldn't be used with -P)\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001244 " -v: prints the dumpstate header and exit\n");
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001245 exit(exitCode);
1246}
1247
1248static void ExitOnInvalidArgs() {
1249 fprintf(stderr, "invalid combination of args\n");
1250 ShowUsageAndExit();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001251}
1252
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08001253static void sig_handler(int) {
Andres Morales2e671bb2014-08-21 12:38:22 -07001254 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001255}
1256
Wei Liuf87959e2016-08-26 14:51:42 -07001257static void register_sig_handler() {
1258 struct sigaction sa;
1259 sigemptyset(&sa.sa_mask);
1260 sa.sa_flags = 0;
1261 sa.sa_handler = sig_handler;
1262 sigaction(SIGPIPE, &sa, NULL); // broken pipe
1263 sigaction(SIGSEGV, &sa, NULL); // segment fault
1264 sigaction(SIGINT, &sa, NULL); // ctrl-c
1265 sigaction(SIGTERM, &sa, NULL); // killed
1266 sigaction(SIGQUIT, &sa, NULL); // quit
1267}
1268
Felipe Leme1d486fe2016-10-14 18:06:47 -07001269bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001270 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001271 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001272 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001273 // Final timestamp
1274 char date[80];
1275 time_t the_real_now_please_stand_up = time(nullptr);
1276 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001277 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001278 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001279
Felipe Leme9a523ae2016-10-20 15:10:33 -07001280 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001281 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001282 return false;
1283 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001284 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001285 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001286 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001287 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001288
Felipe Leme0f3fb202016-06-10 17:10:53 -07001289 // Add log file (which contains stderr output) to zip...
1290 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001291 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001292 MYLOGE("Failed to add dumpstate log to .zip file\n");
1293 return false;
1294 }
1295 // ... and re-opens it for further logging.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001296 redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
Felipe Leme0f3fb202016-06-10 17:10:53 -07001297 fprintf(stderr, "\n");
1298
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001299 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001300 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001301 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001302 return false;
1303 }
1304
Felipe Leme1d486fe2016-10-14 18:06:47 -07001305 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1306 ds.zip_file.reset(nullptr);
1307
Felipe Lemee9d2c542016-11-15 11:48:26 -08001308 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
1309 if (remove(tmp_path_.c_str()) != 0) {
1310 MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
Felipe Lemec4eee562016-04-21 15:42:55 -07001311 }
1312
Felipe Leme1e9edc62015-12-21 16:02:13 -08001313 return true;
1314}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001315
Michal Karpinski4db754f2015-12-11 18:04:32 +00001316static std::string SHA256_file_hash(std::string filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001317 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1318 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001319 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001320 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001321 return NULL;
1322 }
1323
1324 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001325 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001326
1327 std::vector<uint8_t> buffer(65536);
1328 while (1) {
1329 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1330 if (bytes_read == 0) {
1331 break;
1332 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001333 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001334 return NULL;
1335 }
1336
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001337 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001338 }
1339
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001340 uint8_t hash[SHA256_DIGEST_LENGTH];
1341 SHA256_Final(hash, &ctx);
1342
1343 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1344 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001345 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001346 }
1347 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1348 return std::string(hash_buffer);
1349}
1350
Colin Crossf45fa6b2012-03-26 12:38:26 -07001351int main(int argc, char *argv[]) {
1352 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001353 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001354 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001355 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001356 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001357 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001358 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001359 int do_broadcast = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001360 int is_remote_mode = 0;
Felipe Lemed071c682016-10-20 16:48:00 -07001361 bool show_header_only = false;
Felipe Leme75876a22016-10-27 16:31:27 -07001362 bool do_start_service = false;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001363 bool telephony_only = false;
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001364
Colin Crossf45fa6b2012-03-26 12:38:26 -07001365 /* set as high priority, and protect from OOM killer */
1366 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001367
Felipe Lemed071c682016-10-20 16:48:00 -07001368 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001369 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001370 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001371 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001372 } else {
1373 /* fallback to kernels <= 2.6.35 */
1374 oom_adj = fopen("/proc/self/oom_adj", "we");
1375 if (oom_adj) {
1376 fputs("-17", oom_adj);
1377 fclose(oom_adj);
1378 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001379 }
1380
Jeff Brown1dc94e32014-09-11 14:15:27 -07001381 /* parse arguments */
Colin Crossf45fa6b2012-03-26 12:38:26 -07001382 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001383 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001384 switch (c) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001385 // clang-format off
Felipe Lemed071c682016-10-20 16:48:00 -07001386 case 'd': do_add_date = 1; break;
1387 case 'z': do_zip_file = 1; break;
1388 case 'o': use_outfile = optarg; break;
1389 case 's': use_socket = 1; break;
1390 case 'S': use_control_socket = 1; break;
1391 case 'v': show_header_only = true; break;
1392 case 'q': do_vibrate = 0; break;
1393 case 'p': do_fb = 1; break;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001394 case 'P': ds.update_progress_ = true; break;
Felipe Lemed071c682016-10-20 16:48:00 -07001395 case 'R': is_remote_mode = 1; break;
1396 case 'B': do_broadcast = 1; break;
1397 case 'V': break; // compatibility no-op
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001398 case 'h':
1399 ShowUsageAndExit(0);
1400 break;
1401 default:
1402 fprintf(stderr, "Invalid option: %c\n", c);
1403 ShowUsageAndExit();
Felipe Lemee844a9d2016-09-21 15:01:39 -07001404 // clang-format on
Colin Crossf45fa6b2012-03-26 12:38:26 -07001405 }
1406 }
1407
Felipe Lemed071c682016-10-20 16:48:00 -07001408 // TODO: use helper function to convert argv into a string
1409 for (int i = 0; i < argc; i++) {
1410 ds.args_ += argv[i];
1411 if (i < argc - 1) {
1412 ds.args_ += " ";
1413 }
1414 }
1415
1416 ds.extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001417 if (!ds.extra_options_.empty()) {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001418 // Framework uses a system property to override some command-line args.
1419 // Currently, it contains the type of the requested bugreport.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001420 if (ds.extra_options_ == "bugreportplus") {
Felipe Leme75876a22016-10-27 16:31:27 -07001421 // Currently, the dumpstate binder is only used by Shell to update progress.
1422 do_start_service = true;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001423 ds.update_progress_ = true;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001424 do_fb = 0;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001425 } else if (ds.extra_options_ == "bugreportremote") {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001426 do_vibrate = 0;
1427 is_remote_mode = 1;
1428 do_fb = 0;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001429 } else if (ds.extra_options_ == "bugreportwear") {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001430 ds.update_progress_ = true;
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001431 } else if (ds.extra_options_ == "bugreporttelephony") {
1432 telephony_only = true;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001433 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001434 MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001435 }
1436 // Reset the property
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001437 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001438 }
1439
Felipe Leme9a523ae2016-10-20 15:10:33 -07001440 if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001441 ExitOnInvalidArgs();
Felipe Leme6e01fa62015-11-11 19:35:14 -08001442 }
1443
Felipe Leme2628e9e2016-04-12 16:36:51 -07001444 if (use_control_socket && !do_zip_file) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001445 ExitOnInvalidArgs();
Felipe Leme2628e9e2016-04-12 16:36:51 -07001446 }
1447
Felipe Leme9a523ae2016-10-20 15:10:33 -07001448 if (ds.update_progress_ && !do_broadcast) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001449 ExitOnInvalidArgs();
Felipe Leme71bbfc52015-11-23 14:14:51 -08001450 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001451
Felipe Leme9a523ae2016-10-20 15:10:33 -07001452 if (is_remote_mode && (ds.update_progress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001453 ExitOnInvalidArgs();
Michal Karpinski4db754f2015-12-11 18:04:32 +00001454 }
1455
Felipe Lemed071c682016-10-20 16:48:00 -07001456 if (ds.version_ == VERSION_DEFAULT) {
1457 ds.version_ = VERSION_CURRENT;
Felipe Leme809d74e2016-02-02 12:57:00 -08001458 }
1459
Felipe Lemee184f662016-10-27 10:04:47 -07001460 if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
1461 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
1462 ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
1463 VERSION_SPLIT_ANR.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07001464 exit(1);
1465 }
1466
1467 if (show_header_only) {
1468 ds.PrintHeader();
1469 exit(0);
1470 }
1471
Felipe Leme7447d7c2016-11-03 18:12:22 -07001472 /* redirect output if needed */
1473 bool is_redirecting = !use_socket && use_outfile;
1474
1475 // TODO: temporarily set progress until it's part of the Dumpstate constructor
1476 std::string stats_path =
1477 is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
1478 : "";
1479 ds.progress_.reset(new Progress(stats_path));
1480
Felipe Lemed071c682016-10-20 16:48:00 -07001481 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07001482 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Felipe Lemed071c682016-10-20 16:48:00 -07001483 ds.id_ = ++last_id;
1484 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
1485
1486 MYLOGI("begin\n");
1487
Felipe Leme6ae5c4f2017-01-10 14:13:22 -08001488 register_sig_handler();
Felipe Lemed071c682016-10-20 16:48:00 -07001489
Felipe Leme75876a22016-10-27 16:31:27 -07001490 if (do_start_service) {
1491 MYLOGI("Starting 'dumpstate' service\n");
1492 android::status_t ret;
1493 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
1494 MYLOGE("Unable to start DumpstateService: %d\n", ret);
1495 }
1496 }
1497
Felipe Lemef0292972016-11-22 13:57:05 -08001498 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07001499 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
1500 }
1501
Felipe Leme7447d7c2016-11-03 18:12:22 -07001502 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
Felipe Lemed071c682016-10-20 16:48:00 -07001503 ds.extra_options_.c_str());
1504
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001505 MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001506
Felipe Leme9a523ae2016-10-20 15:10:33 -07001507 ds.do_early_screenshot_ = ds.update_progress_;
Felipe Lemee338bf62015-12-07 14:03:50 -08001508
Christopher Ferrised9354f2014-10-01 17:35:01 -07001509 // If we are going to use a socket, do it as early as possible
1510 // to avoid timeouts from bugreport.
1511 if (use_socket) {
1512 redirect_to_socket(stdout, "dumpstate");
1513 }
1514
Felipe Leme2628e9e2016-04-12 16:36:51 -07001515 if (use_control_socket) {
1516 MYLOGD("Opening control socket\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001517 ds.control_socket_fd_ = open_socket("dumpstate");
1518 ds.update_progress_ = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001519 }
1520
Felipe Leme71bbfc52015-11-23 14:14:51 -08001521 if (is_redirecting) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001522 ds.bugreport_dir_ = dirname(use_outfile);
1523 ds.base_name_ = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001524 if (do_add_date) {
1525 char date[80];
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001526 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001527 ds.name_ = date;
Felipe Lemead5f6c42015-11-30 14:26:46 -08001528 } else {
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001529 ds.name_ = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001530 }
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001531 std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001532
1533 if (telephony_only) {
1534 ds.base_name_ += "-telephony";
1535 }
1536
Felipe Leme9a523ae2016-10-20 15:10:33 -07001537 ds.base_name_ += "-" + buildId;
Felipe Leme71bbfc52015-11-23 14:14:51 -08001538 if (do_fb) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001539 ds.screenshot_path_ = ds.GetPath(".png");
Felipe Leme71bbfc52015-11-23 14:14:51 -08001540 }
Felipe Leme9a523ae2016-10-20 15:10:33 -07001541 ds.tmp_path_ = ds.GetPath(".tmp");
Felipe Leme75876a22016-10-27 16:31:27 -07001542 ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
Felipe Leme71bbfc52015-11-23 14:14:51 -08001543
Felipe Lemee844a9d2016-09-21 15:01:39 -07001544 MYLOGD(
1545 "Bugreport dir: %s\n"
1546 "Base name: %s\n"
1547 "Suffix: %s\n"
1548 "Log path: %s\n"
1549 "Temporary path: %s\n"
1550 "Screenshot path: %s\n",
Felipe Leme9a523ae2016-10-20 15:10:33 -07001551 ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(),
1552 ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
Felipe Leme71bbfc52015-11-23 14:14:51 -08001553
Felipe Leme1e9edc62015-12-21 16:02:13 -08001554 if (do_zip_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001555 ds.path_ = ds.GetPath(".zip");
1556 MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
1557 create_parent_dirs(ds.path_.c_str());
1558 ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
Felipe Leme1d486fe2016-10-14 18:06:47 -07001559 if (ds.zip_file == nullptr) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001560 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001561 do_zip_file = 0;
1562 } else {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001563 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001564 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001565 ds.AddTextZipEntry("version.txt", ds.version_);
Felipe Leme1e9edc62015-12-21 16:02:13 -08001566 }
1567
Felipe Leme9a523ae2016-10-20 15:10:33 -07001568 if (ds.update_progress_) {
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001569 if (do_broadcast) {
1570 // clang-format off
1571 std::vector<std::string> am_args = {
1572 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001573 "--es", "android.intent.extra.NAME", ds.name_,
Felipe Lemee844a9d2016-09-21 15:01:39 -07001574 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
Felipe Leme75876a22016-10-27 16:31:27 -07001575 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
Felipe Leme7447d7c2016-11-03 18:12:22 -07001576 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Felipe Lemedcd1f0d2016-08-04 12:48:50 -07001577 };
1578 // clang-format on
1579 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
1580 }
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001581 if (use_control_socket) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001582 dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001583 }
Felipe Leme71bbfc52015-11-23 14:14:51 -08001584 }
1585 }
1586
Nick Kralevichf3599b32016-01-25 15:05:16 -08001587 /* read /proc/cmdline before dropping root */
1588 FILE *cmdline = fopen("/proc/cmdline", "re");
1589 if (cmdline) {
1590 fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
1591 fclose(cmdline);
1592 }
1593
Steven Morelandcb7ef822016-11-29 13:20:37 -08001594 ::android::sp<IVibrator> vibrator = nullptr;
John Michelau1f794c42012-09-17 11:20:19 -05001595 if (do_vibrate) {
Steven Morelandcb7ef822016-11-29 13:20:37 -08001596 vibrator = IVibrator::getService("vibrator");
1597
1598 if (vibrator != nullptr) {
1599 // cancel previous vibration if any
1600 ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
1601 if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
1602 MYLOGE("Vibrator off failed.");
1603 } else {
1604 ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(150);
1605 if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
1606 MYLOGE("Vibrator on failed.");
1607 }
1608 }
Jeff Brown1dc94e32014-09-11 14:15:27 -07001609 }
John Michelau1f794c42012-09-17 11:20:19 -05001610 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001611
Felipe Leme9a523ae2016-10-20 15:10:33 -07001612 if (do_fb && ds.do_early_screenshot_) {
1613 if (ds.screenshot_path_.empty()) {
Felipe Leme3634a1e2015-12-09 10:11:47 -08001614 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001615 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001616 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001617 MYLOGI("taking early screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001618 ds.TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08001619 }
1620 }
1621
Felipe Leme1e9edc62015-12-21 16:02:13 -08001622 if (do_zip_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001623 if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
1624 MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001625 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001626 }
1627 }
1628
Felipe Leme71bbfc52015-11-23 14:14:51 -08001629 if (is_redirecting) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001630 redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
1631 if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
1632 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1633 ds.log_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001634 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001635 /* TODO: rather than generating a text file now and zipping it later,
1636 it would be more efficient to redirect stdout to the zip entry
1637 directly, but the libziparchive doesn't support that option yet. */
Felipe Leme9a523ae2016-10-20 15:10:33 -07001638 redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
1639 if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08001640 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Felipe Leme9a523ae2016-10-20 15:10:33 -07001641 ds.tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001642 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001643 }
Felipe Lemed8b94e52016-12-08 10:21:44 -08001644
1645 // Don't buffer stdout
1646 setvbuf(stdout, nullptr, _IONBF, 0);
1647
Felipe Leme608385d2016-02-01 10:35:38 -08001648 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1649 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001650 // duration is logged into MYLOG instead.
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001651 ds.PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001652
Felipe Leme6ec6ac42017-01-10 15:29:53 -08001653 if (telephony_only) {
1654 DumpIpTables();
1655 if (!DropRootUser()) {
1656 return -1;
1657 }
1658 do_dmesg();
1659 DoLogcat();
1660 DoKmsg();
1661 ds.DumpstateBoard();
1662 DumpModemLogs();
1663 } else {
1664 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
1665 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1666 // the raw trace.
1667 if (!dump_anrd_trace()) {
1668 dump_systrace();
1669 }
1670
1671 // Invoking the following dumpsys calls before dump_traces() to try and
1672 // keep the system stats as close to its initial state as possible.
1673 RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
1674 CommandOptions::WithTimeout(90).DropRoot().Build());
1675 RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
1676 CommandOptions::WithTimeout(10).DropRoot().Build());
1677
1678 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1679 dump_raft();
1680
1681 /* collect stack traces from Dalvik and native processes (needs root) */
1682 dump_traces_path = dump_traces();
1683
1684 /* Run some operations that require root. */
1685 get_tombstone_fds(tombstone_data);
1686 ds.AddDir(RECOVERY_DIR, true);
1687 ds.AddDir(RECOVERY_DATA_DIR, true);
1688 ds.AddDir(LOGPERSIST_DATA_DIR, false);
1689 if (!PropertiesHelper::IsUserBuild()) {
1690 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1691 ds.AddDir(PROFILE_DATA_DIR_REF, true);
1692 }
1693 add_mountinfo();
1694 DumpIpTables();
1695
1696 // Capture any IPSec policies in play. No keys are exposed here.
1697 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
1698 CommandOptions::WithTimeout(10).Build());
1699
1700 // Run ss as root so we can see socket marks.
1701 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
1702 CommandOptions::WithTimeout(10).Build());
1703
1704 if (!DropRootUser()) {
1705 return -1;
1706 }
1707
1708 dumpstate();
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001709 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001710
Felipe Leme55b42a62015-11-10 17:39:08 -08001711 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001712 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001713 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001714 }
1715
Felipe Leme6e01fa62015-11-11 19:35:14 -08001716 /* rename or zip the (now complete) .tmp file to its final location */
1717 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001718
1719 /* check if user changed the suffix using system properties */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001720 std::string name = android::base::GetProperty(
Felipe Leme75876a22016-10-27 16:31:27 -07001721 android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
Felipe Lemead5f6c42015-11-30 14:26:46 -08001722 bool change_suffix= false;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001723 if (!name.empty()) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001724 /* must whitelist which characters are allowed, otherwise it could cross directories */
1725 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001726 if (std::regex_match(name.c_str(), valid_regex)) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001727 change_suffix = true;
1728 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001729 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001730 }
1731 }
1732 if (change_suffix) {
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001733 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
1734 ds.name_ = name;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001735 if (!ds.screenshot_path_.empty()) {
1736 std::string new_screenshot_path = ds.GetPath(".png");
1737 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
1738 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
1739 new_screenshot_path.c_str(), strerror(errno));
Felipe Lemead5f6c42015-11-30 14:26:46 -08001740 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001741 ds.screenshot_path_ = new_screenshot_path;
Felipe Lemead5f6c42015-11-30 14:26:46 -08001742 }
1743 }
1744 }
1745
Felipe Leme6e01fa62015-11-11 19:35:14 -08001746 bool do_text_file = true;
1747 if (do_zip_file) {
Felipe Leme1d486fe2016-10-14 18:06:47 -07001748 if (!ds.FinishZipFile()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001749 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001750 do_text_file = true;
1751 } else {
1752 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001753 // Since zip file is already created, it needs to be renamed.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001754 std::string new_path = ds.GetPath(".zip");
1755 if (ds.path_ != new_path) {
1756 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
1757 if (rename(ds.path_.c_str(), new_path.c_str())) {
1758 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001759 strerror(errno));
Felipe Leme91274352016-02-26 15:03:52 -08001760 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001761 ds.path_ = new_path;
Felipe Leme91274352016-02-26 15:03:52 -08001762 }
1763 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001764 }
1765 }
1766 if (do_text_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001767 ds.path_ = ds.GetPath(".txt");
1768 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(),
1769 ds.tmp_path_.c_str());
1770 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
1771 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001772 strerror(errno));
Felipe Leme9a523ae2016-10-20 15:10:33 -07001773 ds.path_.clear();
Felipe Leme6e01fa62015-11-11 19:35:14 -08001774 }
1775 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001776 if (use_control_socket) {
1777 if (do_text_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001778 dprintf(ds.control_socket_fd_,
Felipe Lemee844a9d2016-09-21 15:01:39 -07001779 "FAIL:could not create zip file, check %s "
1780 "for more details\n",
Felipe Leme9a523ae2016-10-20 15:10:33 -07001781 ds.log_path_.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001782 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001783 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001784 }
1785 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001786 }
1787
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001788 /* vibrate a few but shortly times to let user know it's finished */
Steven Morelandcb7ef822016-11-29 13:20:37 -08001789 if (vibrator != nullptr) {
1790 // in case dumpstate magically completes before the above vibration
1791 ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
1792 if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
1793 MYLOGE("Vibrator off failed.");
1794 } else {
1795 for (int i = 0; i < 3; i++) {
1796 ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(75);
1797 if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
1798 MYLOGE("Vibrator on failed.");
1799 break;
1800 }
1801 usleep((75 + 50) * 1000);
1802 }
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001803 }
1804 }
1805
Jeff Brown1dc94e32014-09-11 14:15:27 -07001806 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001807 if (do_broadcast) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001808 if (!ds.path_.empty()) {
1809 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001810 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001811 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001812 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemee844a9d2016-09-21 15:01:39 -07001813 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
Felipe Leme75876a22016-10-27 16:31:27 -07001814 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
Felipe Leme7447d7c2016-11-03 18:12:22 -07001815 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001816 "--es", "android.intent.extra.BUGREPORT", ds.path_,
1817 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001818 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001819 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001820 if (do_fb) {
1821 am_args.push_back("--es");
1822 am_args.push_back("android.intent.extra.SCREENSHOT");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001823 am_args.push_back(ds.screenshot_path_);
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001824 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001825 if (is_remote_mode) {
1826 am_args.push_back("--es");
1827 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001828 am_args.push_back(SHA256_file_hash(ds.path_));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001829 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1830 } else {
1831 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1832 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001833 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001834 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001835 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001836 }
1837
Felipe Leme7447d7c2016-11-03 18:12:22 -07001838 MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
1839 ds.progress_->GetInitialMax());
1840 ds.progress_->Save();
1841 MYLOGI("done (id %d)\n", ds.id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001842
Felipe Leme107a05f2016-03-08 15:11:15 -08001843 if (is_redirecting) {
1844 fclose(stderr);
1845 }
1846
Felipe Leme9a523ae2016-10-20 15:10:33 -07001847 if (use_control_socket && ds.control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001848 MYLOGD("Closing control socket\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001849 close(ds.control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001850 }
1851
Colin Crossf45fa6b2012-03-26 12:38:26 -07001852 return 0;
1853}