blob: 30b5d9a497b0b9a50181962aa7a685ec3c0f66a6 [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>
Wei Liuf87959e2016-08-26 14:51:42 -070027#include <signal.h>
Mark Salyzyn8f37aa52015-06-12 12:28:24 -070028#include <stdbool.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <stdio.h>
30#include <stdlib.h>
Felipe Leme6e01fa62015-11-11 19:35:14 -080031#include <string>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032#include <string.h>
Christopher Ferris7dc7f322014-07-22 16:08:19 -070033#include <sys/prctl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070034#include <sys/resource.h>
35#include <sys/stat.h>
36#include <sys/time.h>
37#include <sys/wait.h>
38#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070039
Felipe Leme96c2bbb2016-09-26 09:21:21 -070040#include <android-base/file.h>
41#include <android-base/properties.h>
Elliott Hughes9dc117c2015-12-07 14:21:50 -080042#include <android-base/stringprintf.h>
Naveen Kalla058e1e82016-10-19 21:38:44 -070043#include <android-base/strings.h>
Andreas Gampeaff68432016-07-18 18:01:27 -070044#include <android-base/unique_fd.h>
Felipe Leme6f674ae2016-11-18 17:10:33 -080045#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
46#include <cutils/native_handle.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070047#include <cutils/properties.h>
Wei Liuf87959e2016-08-26 14:51:42 -070048#include <hardware_legacy/power.h>
Felipe Leme75876a22016-10-27 16:31:27 -070049#include <openssl/sha.h>
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -070050#include <private/android_filesystem_config.h>
51#include <private/android_logger.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070052
Felipe Lemef0292972016-11-22 13:57:05 -080053#include "DumpstateInternal.h"
Felipe Leme75876a22016-10-27 16:31:27 -070054#include "DumpstateService.h"
Colin Crossf45fa6b2012-03-26 12:38:26 -070055#include "dumpstate.h"
Felipe Leme6e01fa62015-11-11 19:35:14 -080056
Colin Crossf45fa6b2012-03-26 12:38:26 -070057/* read before root is shed */
58static char cmdline_buf[16384] = "(unknown)";
59static const char *dump_traces_path = NULL;
60
Felipe Leme1d486fe2016-10-14 18:06:47 -070061// TODO: variables and functions below should be part of dumpstate object
62
Felipe Leme635ca312016-01-05 14:23:02 -080063static std::set<std::string> mount_points;
64void add_mountinfo();
Felipe Leme78f2c862015-12-21 09:55:22 -080065
Todd Poynor2a83daa2013-11-22 15:44:22 -080066#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
Mark Salyzyn7d0a7622016-06-24 14:06:15 -070067#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
Todd Poynor2a83daa2013-11-22 15:44:22 -080068
Wei Liu341938b2016-04-27 16:18:17 -070069#define RAFT_DIR "/data/misc/raft"
Felipe Lemee82a27d2016-01-05 13:35:44 -080070#define RECOVERY_DIR "/cache/recovery"
Mark Salyzynd6ab0112016-03-25 12:56:39 -070071#define RECOVERY_DATA_DIR "/data/misc/recovery"
Mark Salyzyn4d42dea2016-04-01 10:03:14 -070072#define LOGPERSIST_DATA_DIR "/data/misc/logd"
David Brazdild2991962016-06-03 14:40:44 +010073#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
74#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070075#define TOMBSTONE_DIR "/data/tombstones"
76#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
77/* Can accomodate a tombstone number up to 9999. */
78#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
79#define NUM_TOMBSTONES 10
Erik Kline08165202016-05-30 11:55:44 +090080#define WLUTIL "/vendor/xbin/wlutil"
Wei Liuf87959e2016-08-26 14:51:42 -070081#define WAKE_LOCK_NAME "dumpstate_wakelock"
Christopher Ferris7dc7f322014-07-22 16:08:19 -070082
83typedef struct {
84 char name[TOMBSTONE_MAX_LEN];
85 int fd;
86} tombstone_data_t;
87
88static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
89
Felipe Lemee844a9d2016-09-21 15:01:39 -070090// TODO: temporary variables and functions used during C++ refactoring
91static Dumpstate& ds = Dumpstate::GetInstance();
Felipe Leme678727a2016-09-21 17:22:11 -070092static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
93 const CommandOptions& options = CommandOptions::DEFAULT) {
94 return ds.RunCommand(title, fullCommand, options);
95}
96static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
Felipe Lemebda15a02016-11-16 17:48:25 -080097 const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
Felipe Leme678727a2016-09-21 17:22:11 -070098 long dumpsysTimeout = 0) {
99 return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
100}
101static int DumpFile(const std::string& title, const std::string& path) {
102 return ds.DumpFile(title, path);
103}
Felipe Lemee82a27d2016-01-05 13:35:44 -0800104
Felipe Lemee844a9d2016-09-21 15:01:39 -0700105// Relative directory (inside the zip) for all files copied as-is into the bugreport.
106static const std::string ZIP_ROOT_DIR = "FS";
107
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700108static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700109static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
Felipe Lemed071c682016-10-20 16:48:00 -0700110static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
Felipe Leme9ce6aa42016-09-21 10:02:25 -0700111
Felipe Lemef0292972016-11-22 13:57:05 -0800112static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
113
Felipe Leme3d305a12016-05-20 11:24:37 -0700114/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
115 * otherwise, gets just those modified in the last half an hour. */
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700116static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700117 time_t thirty_minutes_ago = ds.now_ - 60 * 30;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700118 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
119 snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
Christopher Ferris54bcc5f2015-02-10 12:15:01 -0800120 int fd = TEMP_FAILURE_RETRY(open(data[i].name,
121 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700122 struct stat st;
Felipe Leme3d305a12016-05-20 11:24:37 -0700123 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
Felipe Leme1d486fe2016-10-14 18:06:47 -0700124 (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
Felipe Leme3d305a12016-05-20 11:24:37 -0700125 data[i].fd = fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700126 } else {
Felipe Leme3d305a12016-05-20 11:24:37 -0700127 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700128 data[i].fd = -1;
129 }
130 }
131}
132
Felipe Leme635ca312016-01-05 14:23:02 -0800133// for_each_pid() callback to get mount info about a process.
Felipe Leme4c2d6632016-09-28 14:32:00 -0700134void do_mountinfo(int pid, const char* name __attribute__((unused))) {
Felipe Leme635ca312016-01-05 14:23:02 -0800135 char path[PATH_MAX];
136
137 // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
138 // are added.
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700139 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
Felipe Leme635ca312016-01-05 14:23:02 -0800140 char linkname[PATH_MAX];
141 ssize_t r = readlink(path, linkname, PATH_MAX);
142 if (r == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800143 MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno));
Felipe Leme635ca312016-01-05 14:23:02 -0800144 return;
145 }
146 linkname[r] = '\0';
147
148 if (mount_points.find(linkname) == mount_points.end()) {
149 // First time this mount point was found: add it
Nick Kralevichf0922cc2016-05-14 16:47:44 -0700150 snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700151 if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
Felipe Leme635ca312016-01-05 14:23:02 -0800152 mount_points.insert(linkname);
153 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800154 MYLOGE("Unable to add mountinfo %s to zip file\n", path);
Felipe Leme635ca312016-01-05 14:23:02 -0800155 }
156 }
157}
158
159void add_mountinfo() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700160 if (!ds.IsZipping()) return;
Felipe Leme678727a2016-09-21 17:22:11 -0700161 std::string title = "MOUNT INFO";
Felipe Leme635ca312016-01-05 14:23:02 -0800162 mount_points.clear();
Felipe Leme46b85da2016-11-21 17:40:45 -0800163 DurationReporter duration_reporter(title, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700164 for_each_pid(do_mountinfo, nullptr);
165 MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
Felipe Leme635ca312016-01-05 14:23:02 -0800166}
167
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700168static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
169{
170 DIR *d;
171 struct dirent *de;
172 char path[PATH_MAX];
173
174 d = opendir(driverpath);
175 if (d == NULL) {
176 return;
177 }
178
179 while ((de = readdir(d))) {
180 if (de->d_type != DT_LNK) {
181 continue;
182 }
183 snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700184 DumpFile(title, path);
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700185 }
186
187 closedir(d);
188}
189
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700190// return pid of a userspace process. If not found or error, return 0.
191static unsigned int pid_of_process(const char* ps_name) {
192 DIR *proc_dir;
193 struct dirent *ps;
194 unsigned int pid;
195 std::string cmdline;
196
197 if (!(proc_dir = opendir("/proc"))) {
198 MYLOGE("Can't open /proc\n");
199 return 0;
200 }
201
202 while ((ps = readdir(proc_dir))) {
203 if (!(pid = atoi(ps->d_name))) {
204 continue;
205 }
206 android::base::ReadFileToString("/proc/"
207 + std::string(ps->d_name) + "/cmdline", &cmdline);
208 if (cmdline.find(ps_name) == std::string::npos) {
209 continue;
210 } else {
211 closedir(proc_dir);
212 return pid;
213 }
214 }
215 closedir(proc_dir);
216 return 0;
217}
218
219// dump anrd's trace and add to the zip file.
220// 1. check if anrd is running on this device.
221// 2. send a SIGUSR1 to its pid which will dump anrd's trace.
222// 3. wait until the trace generation completes and add to the zip file.
223static bool dump_anrd_trace() {
224 unsigned int pid;
225 char buf[50], path[PATH_MAX];
226 struct dirent *trace;
227 struct stat st;
228 DIR *trace_dir;
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700229 int retry = 5;
230 long max_ctime = 0, old_mtime;
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700231 long long cur_size = 0;
232 const char *trace_path = "/data/misc/anrd/";
233
Felipe Leme1d486fe2016-10-14 18:06:47 -0700234 if (!ds.IsZipping()) {
235 MYLOGE("Not dumping anrd trace because it's not a zipped bugreport\n");
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700236 return false;
237 }
238
239 // find anrd's pid if it is running.
240 pid = pid_of_process("/system/xbin/anrd");
241
242 if (pid > 0) {
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700243 if (stat(trace_path, &st) == 0) {
244 old_mtime = st.st_mtime;
245 } else {
246 MYLOGE("Failed to find: %s\n", trace_path);
247 return false;
248 }
249
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700250 // send SIGUSR1 to the anrd to generate a trace.
251 sprintf(buf, "%u", pid);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700252 if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700253 CommandOptions::WithTimeout(1).Build())) {
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700254 MYLOGE("anrd signal timed out. Please manually collect trace\n");
255 return false;
256 }
257
Zhengyin Qianafc38fe2016-09-08 16:50:09 -0700258 while (retry-- > 0 && old_mtime == st.st_mtime) {
259 sleep(1);
260 stat(trace_path, &st);
261 }
262
263 if (retry < 0 && old_mtime == st.st_mtime) {
264 MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path);
265 return false;
266 }
267
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700268 // identify the trace file by its creation time.
269 if (!(trace_dir = opendir(trace_path))) {
270 MYLOGE("Can't open trace file under %s\n", trace_path);
271 }
272 while ((trace = readdir(trace_dir))) {
273 if (strcmp(trace->d_name, ".") == 0
274 || strcmp(trace->d_name, "..") == 0) {
275 continue;
276 }
277 sprintf(path, "%s%s", trace_path, trace->d_name);
278 if (stat(path, &st) == 0) {
279 if (st.st_ctime > max_ctime) {
280 max_ctime = st.st_ctime;
281 sprintf(buf, "%s", trace->d_name);
282 }
283 }
284 }
285 closedir(trace_dir);
286
287 // Wait until the dump completes by checking the size of the trace.
288 if (max_ctime > 0) {
289 sprintf(path, "%s%s", trace_path, buf);
290 while(true) {
291 sleep(1);
292 if (stat(path, &st) == 0) {
293 if (st.st_size == cur_size) {
294 break;
295 } else if (st.st_size > cur_size) {
296 cur_size = st.st_size;
297 } else {
298 return false;
299 }
300 } else {
301 MYLOGE("Cant stat() %s anymore\n", path);
302 return false;
303 }
304 }
305 // Add to the zip file.
Felipe Leme1d486fe2016-10-14 18:06:47 -0700306 if (!ds.AddZipEntry("anrd_trace.txt", path)) {
Zhengyin Qian068ecc72016-08-10 16:48:14 -0700307 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
308 } else {
309 if (remove(path)) {
310 MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
311 }
312 return true;
313 }
314 } else {
315 MYLOGE("Can't stats any trace file under %s\n", trace_path);
316 }
317 }
318 return false;
319}
320
Felipe Lemeefd7e272016-05-18 09:27:16 -0700321static void dump_systrace() {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700322 if (!ds.IsZipping()) {
323 MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
Felipe Leme71a74ac2016-03-17 15:43:25 -0700324 return;
325 }
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700326 std::string systrace_path = ds.GetPath("-systrace.txt");
Felipe Leme14e034a2016-03-30 18:51:03 -0700327 if (systrace_path.empty()) {
328 MYLOGE("Not dumping systrace because path is empty\n");
329 return;
330 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700331 const char* path = "/sys/kernel/debug/tracing/tracing_on";
332 long int is_tracing;
333 if (read_file_as_long(path, &is_tracing)) {
334 return; // error already logged
335 }
336 if (is_tracing <= 0) {
337 MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
338 return;
339 }
340
Felipe Leme14e034a2016-03-30 18:51:03 -0700341 MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
342 systrace_path.c_str());
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700343 if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700344 CommandOptions::WithTimeout(120).Build())) {
Felipe Leme14e034a2016-03-30 18:51:03 -0700345 MYLOGE("systrace timed out, its zip entry will be incomplete\n");
Felipe Lemec7fe8fe2016-09-21 18:13:20 -0700346 // TODO: RunCommand tries to kill the process, but atrace doesn't die
Felipe Leme30dbfa12016-09-02 12:43:26 -0700347 // peacefully; ideally, we should call strace to stop itself, but there is no such option
348 // yet (just a --async_stop, which stops and dump
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700349 // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
Felipe Leme30dbfa12016-09-02 12:43:26 -0700350 // MYLOGE("could not stop systrace ");
351 // }
Felipe Leme14e034a2016-03-30 18:51:03 -0700352 }
Felipe Leme1d486fe2016-10-14 18:06:47 -0700353 if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
Felipe Leme14e034a2016-03-30 18:51:03 -0700354 MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
Felipe Leme71a74ac2016-03-17 15:43:25 -0700355 } else {
Felipe Leme14e034a2016-03-30 18:51:03 -0700356 if (remove(systrace_path.c_str())) {
357 MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
358 }
Felipe Leme71a74ac2016-03-17 15:43:25 -0700359 }
360}
361
Felipe Lemeefd7e272016-05-18 09:27:16 -0700362static void dump_raft() {
Felipe Lemef0292972016-11-22 13:57:05 -0800363 if (PropertiesHelper::IsUserBuild()) {
Wei Liu341938b2016-04-27 16:18:17 -0700364 return;
365 }
366
Felipe Leme1d486fe2016-10-14 18:06:47 -0700367 std::string raft_path = ds.GetPath("-raft_log.txt");
368 if (raft_path.empty()) {
369 MYLOGD("raft_path is empty\n");
Wei Liu341938b2016-04-27 16:18:17 -0700370 return;
371 }
Wei Liuf0e78d42016-05-25 14:21:02 -0700372
373 struct stat s;
374 if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
375 MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
376 return;
377 }
378
Felipe Leme30dbfa12016-09-02 12:43:26 -0700379 CommandOptions options = CommandOptions::WithTimeout(600).Build();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700380 if (!ds.IsZipping()) {
381 // Write compressed and encoded raft logs to stdout if it's not a zipped bugreport.
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700382 RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
Wei Liu341938b2016-04-27 16:18:17 -0700383 return;
384 }
385
Felipe Leme1d486fe2016-10-14 18:06:47 -0700386 RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_path}, options);
387 if (!ds.AddZipEntry("raft_log.txt", raft_path)) {
388 MYLOGE("Unable to add raft log %s to zip file\n", raft_path.c_str());
Wei Liu341938b2016-04-27 16:18:17 -0700389 } else {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700390 if (remove(raft_path.c_str())) {
391 MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
Wei Liu341938b2016-04-27 16:18:17 -0700392 }
393 }
394}
395
Naveen Kalla058e1e82016-10-19 21:38:44 -0700396/**
397 * Finds the last modified file in the directory dir whose name starts with file_prefix.
398 *
399 * Function returns empty string when it does not find a file
400 */
401static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
402 const std::string& file_prefix) {
403 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
404 if (d == nullptr) {
405 MYLOGD("Error %d opening %s\n", errno, dir.c_str());
406 return "";
407 }
408
409 // Find the newest file matching the file_prefix in dir
410 struct dirent *de;
411 time_t last_modified_time = 0;
412 std::string last_modified_file = "";
413 struct stat s;
414
415 while ((de = readdir(d.get()))) {
416 std::string file = std::string(de->d_name);
417 if (!file_prefix.empty()) {
418 if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
419 }
420 file = dir + "/" + file;
421 int ret = stat(file.c_str(), &s);
422
423 if ((ret == 0) && (s.st_mtime > last_modified_time)) {
424 last_modified_file = file;
425 last_modified_time = s.st_mtime;
426 }
427 }
428
429 return last_modified_file;
430}
431
432static void DumpModemLogs() {
433 DurationReporter durationReporter("DUMP MODEM LOGS");
Felipe Lemef0292972016-11-22 13:57:05 -0800434 if (PropertiesHelper::IsUserBuild()) {
Naveen Kalla058e1e82016-10-19 21:38:44 -0700435 return;
436 }
437
438 if (!ds.IsZipping()) {
439 MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
440 return;
441 }
442
443 std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
444
445 if(file_prefix.empty()) {
446 MYLOGD("No modem log : file_prefix is empty\n");
447 return;
448 }
449
450 // TODO: use bugreport_dir_ directly when this function is moved to Dumpstate class
451 std::string bugreport_dir = dirname(ds.GetPath("").c_str());
452 MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
453 bugreport_dir.c_str(), file_prefix.c_str());
454
455 std::string modem_log_file = GetLastModifiedFileWithPrefix(bugreport_dir, file_prefix);
456
457 struct stat s;
458 if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
459 MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
460 return;
461 }
462
463 std::string filename = basename(modem_log_file.c_str());
464 if (!ds.AddZipEntry(filename, modem_log_file)) {
465 MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
466 } else {
467 MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
Naveen Kallab77df782016-11-18 17:32:23 -0800468 if (remove(modem_log_file.c_str())) {
469 MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
470 }
Naveen Kalla058e1e82016-10-19 21:38:44 -0700471 }
472}
473
Mark Salyzyn326842f2015-04-30 09:49:41 -0700474static bool skip_not_stat(const char *path) {
475 static const char stat[] = "/stat";
476 size_t len = strlen(path);
477 if (path[len - 1] == '/') { /* Directory? */
478 return false;
479 }
480 return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
481}
482
Felipe Leme4c2d6632016-09-28 14:32:00 -0700483static bool skip_none(const char* path __attribute__((unused))) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800484 return false;
485}
486
Mark Salyzyn326842f2015-04-30 09:49:41 -0700487static const char mmcblk0[] = "/sys/block/mmcblk0/";
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700488unsigned long worst_write_perf = 20000; /* in KB/s */
Mark Salyzyn326842f2015-04-30 09:49:41 -0700489
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800490//
491// stat offsets
492// Name units description
493// ---- ----- -----------
494// read I/Os requests number of read I/Os processed
495#define __STAT_READ_IOS 0
496// read merges requests number of read I/Os merged with in-queue I/O
497#define __STAT_READ_MERGES 1
498// read sectors sectors number of sectors read
499#define __STAT_READ_SECTORS 2
500// read ticks milliseconds total wait time for read requests
501#define __STAT_READ_TICKS 3
502// write I/Os requests number of write I/Os processed
503#define __STAT_WRITE_IOS 4
504// write merges requests number of write I/Os merged with in-queue I/O
505#define __STAT_WRITE_MERGES 5
506// write sectors sectors number of sectors written
507#define __STAT_WRITE_SECTORS 6
508// write ticks milliseconds total wait time for write requests
509#define __STAT_WRITE_TICKS 7
510// in_flight requests number of I/Os currently in flight
511#define __STAT_IN_FLIGHT 8
512// io_ticks milliseconds total time this block device has been active
513#define __STAT_IO_TICKS 9
514// time_in_queue milliseconds total wait time for all requests
515#define __STAT_IN_QUEUE 10
516#define __STAT_NUMBER_FIELD 11
517//
518// read I/Os, write I/Os
519// =====================
520//
521// These values increment when an I/O request completes.
522//
523// read merges, write merges
524// =========================
525//
526// These values increment when an I/O request is merged with an
527// already-queued I/O request.
528//
529// read sectors, write sectors
530// ===========================
531//
532// These values count the number of sectors read from or written to this
533// block device. The "sectors" in question are the standard UNIX 512-byte
534// sectors, not any device- or filesystem-specific block size. The
535// counters are incremented when the I/O completes.
536#define SECTOR_SIZE 512
537//
538// read ticks, write ticks
539// =======================
540//
541// These values count the number of milliseconds that I/O requests have
542// waited on this block device. If there are multiple I/O requests waiting,
543// these values will increase at a rate greater than 1000/second; for
544// example, if 60 read requests wait for an average of 30 ms, the read_ticks
545// field will increase by 60*30 = 1800.
546//
547// in_flight
548// =========
549//
550// This value counts the number of I/O requests that have been issued to
551// the device driver but have not yet completed. It does not include I/O
552// requests that are in the queue but not yet issued to the device driver.
553//
554// io_ticks
555// ========
556//
557// This value counts the number of milliseconds during which the device has
558// had I/O requests queued.
559//
560// time_in_queue
561// =============
562//
563// This value counts the number of milliseconds that I/O requests have waited
564// on this block device. If there are multiple I/O requests waiting, this
565// value will increase as the product of the number of milliseconds times the
566// number of requests waiting (see "read ticks" above for an example).
567#define S_TO_MS 1000
568//
569
Mark Salyzyn326842f2015-04-30 09:49:41 -0700570static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800571 unsigned long long fields[__STAT_NUMBER_FIELD];
Mark Salyzyn326842f2015-04-30 09:49:41 -0700572 bool z;
573 char *cp, *buffer = NULL;
574 size_t i = 0;
575 FILE *fp = fdopen(fd, "rb");
576 getline(&buffer, &i, fp);
577 fclose(fp);
578 if (!buffer) {
579 return -errno;
580 }
581 i = strlen(buffer);
582 while ((i > 0) && (buffer[i - 1] == '\n')) {
583 buffer[--i] = '\0';
584 }
585 if (!*buffer) {
586 free(buffer);
587 return 0;
588 }
589 z = true;
590 for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800591 fields[i] = strtoull(cp, &cp, 10);
Mark Salyzyn326842f2015-04-30 09:49:41 -0700592 if (fields[i] != 0) {
593 z = false;
594 }
595 }
596 if (z) { /* never accessed */
597 free(buffer);
598 return 0;
599 }
600
601 if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
602 path += sizeof(mmcblk0) - 1;
603 }
604
605 printf("%s: %s\n", path, buffer);
606 free(buffer);
607
Mark Salyzyn01d6c392016-02-04 09:20:44 -0800608 if (fields[__STAT_IO_TICKS]) {
609 unsigned long read_perf = 0;
610 unsigned long read_ios = 0;
611 if (fields[__STAT_READ_TICKS]) {
612 unsigned long long divisor = fields[__STAT_READ_TICKS]
613 * fields[__STAT_IO_TICKS];
614 read_perf = ((unsigned long long)SECTOR_SIZE
615 * fields[__STAT_READ_SECTORS]
616 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
617 / divisor;
618 read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS]
619 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
620 / divisor;
621 }
622
623 unsigned long write_perf = 0;
624 unsigned long write_ios = 0;
625 if (fields[__STAT_WRITE_TICKS]) {
626 unsigned long long divisor = fields[__STAT_WRITE_TICKS]
627 * fields[__STAT_IO_TICKS];
628 write_perf = ((unsigned long long)SECTOR_SIZE
629 * fields[__STAT_WRITE_SECTORS]
630 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
631 / divisor;
632 write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS]
633 * fields[__STAT_IN_QUEUE] + (divisor >> 1))
634 / divisor;
635 }
636
637 unsigned queue = (fields[__STAT_IN_QUEUE]
638 + (fields[__STAT_IO_TICKS] >> 1))
639 / fields[__STAT_IO_TICKS];
640
641 if (!write_perf && !write_ios) {
642 printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
643 path, read_perf, read_ios, queue);
644 } else {
645 printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
646 path, read_perf, read_ios, write_perf, write_ios, queue);
647 }
648
649 /* bugreport timeout factor adjustment */
650 if ((write_perf > 1) && (write_perf < worst_write_perf)) {
651 worst_write_perf = write_perf;
652 }
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700653 }
Mark Salyzyn326842f2015-04-30 09:49:41 -0700654 return 0;
655}
656
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700657/* timeout in ms */
Felipe Leme8620bb42015-11-10 11:04:45 -0800658static unsigned long logcat_timeout(const char *name) {
Mark Salyzyn6c3d90f2016-09-27 14:55:27 -0700659 log_id_t id = android_name_to_log_id(name);
660 unsigned long property_size = __android_logger_get_buffer_size(id);
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700661 /* Engineering margin is ten-fold our guess */
662 return 10 * (property_size + worst_write_perf) / worst_write_perf;
663}
664
Felipe Leme2b9b06c2016-10-14 09:13:06 -0700665void Dumpstate::PrintHeader() const {
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700666 std::string build, fingerprint, radio, bootloader, network;
667 char date[80];
Colin Crossf45fa6b2012-03-26 12:38:26 -0700668
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700669 build = android::base::GetProperty("ro.build.display.id", "(unknown)");
670 fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700671 radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
672 bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
673 network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700674 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700675
676 printf("========================================================\n");
677 printf("== dumpstate: %s\n", date);
678 printf("========================================================\n");
679
680 printf("\n");
Felipe Leme96c2bbb2016-09-26 09:21:21 -0700681 printf("Build: %s\n", build.c_str());
682 // NOTE: fingerprint entry format is important for other tools.
683 printf("Build fingerprint: '%s'\n", fingerprint.c_str());
684 printf("Bootloader: %s\n", bootloader.c_str());
685 printf("Radio: %s\n", radio.c_str());
686 printf("Network: %s\n", network.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700687
688 printf("Kernel: ");
Felipe Lemebda15a02016-11-16 17:48:25 -0800689 fflush(stdout);
Felipe Lemef0292972016-11-22 13:57:05 -0800690 DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700691 printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700692 printf("Bugreport format version: %s\n", version_.c_str());
Felipe Leme7447d7c2016-11-03 18:12:22 -0700693 printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
Felipe Lemef0292972016-11-22 13:57:05 -0800694 PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700695 printf("\n");
Felipe Leme46b85da2016-11-21 17:40:45 -0800696 fflush(stdout);
Felipe Leme78f2c862015-12-21 09:55:22 -0800697}
698
Felipe Leme24b66ee2016-06-16 10:55:26 -0700699// List of file extensions that can cause a zip file attachment to be rejected by some email
700// service providers.
701static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
702 ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
703 ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
704 ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
705};
706
Felipe Leme1d486fe2016-10-14 18:06:47 -0700707bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
708 if (!IsZipping()) {
709 MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
710 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800711 return false;
712 }
Felipe Leme24b66ee2016-06-16 10:55:26 -0700713 std::string valid_name = entry_name;
714
715 // Rename extension if necessary.
716 size_t idx = entry_name.rfind(".");
717 if (idx != std::string::npos) {
718 std::string extension = entry_name.substr(idx);
719 std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
720 if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
721 valid_name = entry_name + ".renamed";
722 MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
723 }
724 }
725
Felipe Leme6fe9db62016-02-12 09:04:16 -0800726 // Logging statement below is useful to time how long each entry takes, but it's too verbose.
727 // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700728 int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
729 get_mtime(fd, ds.now_));
Felipe Leme1d486fe2016-10-14 18:06:47 -0700730 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700731 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700732 ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800733 return false;
734 }
735
Felipe Leme770410d2016-01-26 17:07:14 -0800736 std::vector<uint8_t> buffer(65536);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800737 while (1) {
Zach Riggle22200402016-08-18 01:01:24 -0400738 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800739 if (bytes_read == 0) {
740 break;
741 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800742 MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800743 return false;
744 }
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700745 err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800746 if (err) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700747 MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800748 return false;
749 }
750 }
751
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700752 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700753 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700754 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800755 return false;
756 }
757
758 return true;
759}
760
Felipe Leme1d486fe2016-10-14 18:06:47 -0700761bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
762 android::base::unique_fd fd(
763 TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
Andreas Gampeaff68432016-07-18 18:01:27 -0700764 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800765 MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
Felipe Lemee82a27d2016-01-05 13:35:44 -0800766 return false;
767 }
768
Felipe Leme1d486fe2016-10-14 18:06:47 -0700769 return AddZipEntryFromFd(entry_name, fd.get());
Felipe Lemee82a27d2016-01-05 13:35:44 -0800770}
771
772/* adds a file to the existing zipped bugreport */
Felipe Leme4c2d6632016-09-28 14:32:00 -0700773static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
Felipe Leme1d486fe2016-10-14 18:06:47 -0700774 return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
Felipe Lemee82a27d2016-01-05 13:35:44 -0800775}
776
Felipe Leme1d486fe2016-10-14 18:06:47 -0700777void Dumpstate::AddDir(const std::string& dir, bool recursive) {
778 if (!IsZipping()) {
779 MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800780 return;
781 }
Felipe Leme678727a2016-09-21 17:22:11 -0700782 MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
Felipe Leme46b85da2016-11-21 17:40:45 -0800783 DurationReporter duration_reporter(dir, true);
Felipe Leme678727a2016-09-21 17:22:11 -0700784 dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800785}
786
Felipe Leme1d486fe2016-10-14 18:06:47 -0700787bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
788 if (!IsZipping()) {
789 MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
790 entry_name.c_str());
Felipe Leme111b9d02016-02-03 09:28:24 -0800791 return false;
792 }
Felipe Lemecbce55d2016-02-08 09:53:18 -0800793 MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700794 int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
Felipe Leme1d486fe2016-10-14 18:06:47 -0700795 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700796 MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700797 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800798 return false;
799 }
800
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700801 err = zip_writer_->WriteBytes(content.c_str(), content.length());
Felipe Leme1d486fe2016-10-14 18:06:47 -0700802 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700803 MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -0700804 ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800805 return false;
806 }
807
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700808 err = zip_writer_->FinishEntry();
Felipe Leme1d486fe2016-10-14 18:06:47 -0700809 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -0700810 MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme809d74e2016-02-02 12:57:00 -0800811 return false;
812 }
813
814 return true;
815}
816
Felipe Lemec0808152016-06-17 17:37:13 -0700817static void dump_iptables() {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700818 RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
819 RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
Erik Kline32af8c22016-09-28 17:26:26 +0900820 RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700821 /* no ip6 nat */
Erik Kline32af8c22016-09-28 17:26:26 +0900822 RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
823 RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
824 RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
825 RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
Felipe Lemec0808152016-06-17 17:37:13 -0700826}
827
Felipe Lemee184f662016-10-27 10:04:47 -0700828static void AddAnrTraceFiles() {
829 bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
830 std::string dump_traces_dir;
831
832 /* show the traces we collected in main(), if that was done */
833 if (dump_traces_path != nullptr) {
834 if (add_to_zip) {
835 dump_traces_dir = dirname(dump_traces_path);
836 MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
837 ds.AddDir(dump_traces_dir, true);
838 } else {
839 MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
840 dump_traces_path);
841 ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
842 }
843 }
844
845 std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
846 std::string anr_traces_dir = dirname(anr_traces_path.c_str());
847
848 // Make sure directory is not added twice.
849 // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
850 // generated by dump_traces() - and anr_traces_path - which is retrieved from a system
851 // property - but in reality they're the same path (although the former could be nullptr).
852 // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
853 // be revisited.
854 bool already_dumped = anr_traces_dir == dump_traces_dir;
855
856 MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
857 dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
858
859 if (anr_traces_path.empty()) {
860 printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
861 } else {
862 int fd = TEMP_FAILURE_RETRY(
863 open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
864 if (fd < 0) {
865 printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
866 strerror(errno));
867 } else {
868 if (add_to_zip) {
869 if (!already_dumped) {
870 MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
871 anr_traces_dir.c_str());
872 ds.AddDir(anr_traces_dir, true);
873 already_dumped = true;
874 }
875 } else {
876 MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
877 anr_traces_path.c_str());
878 dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
879 }
880 }
881 }
882
883 if (add_to_zip && already_dumped) {
884 MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
885 return;
886 }
887
888 /* slow traces for slow operations */
889 struct stat st;
890 if (!anr_traces_path.empty()) {
891 int tail = anr_traces_path.size() - 1;
892 while (tail > 0 && anr_traces_path.at(tail) != '/') {
893 tail--;
894 }
895 int i = 0;
896 while (1) {
897 anr_traces_path = anr_traces_path.substr(0, tail + 1) +
898 android::base::StringPrintf("slow%02d.txt", i);
899 if (stat(anr_traces_path.c_str(), &st)) {
900 // No traces file at this index, done with the files.
901 break;
902 }
903 ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
904 i++;
905 }
906 }
907}
908
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700909static void dumpstate() {
Felipe Leme9a523ae2016-10-20 15:10:33 -0700910 DurationReporter duration_reporter("DUMPSTATE");
Felipe Leme78f2c862015-12-21 09:55:22 -0800911 unsigned long timeout;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700912
Arve Hjønnevåg2db0f5f2014-10-15 18:08:37 -0700913 dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700914 RunCommand("UPTIME", {"uptime"});
Mark Salyzyn326842f2015-04-30 09:49:41 -0700915 dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
Mark Salyzyn8c8130e2015-12-09 11:21:28 -0800916 dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700917 DumpFile("MEMORY INFO", "/proc/meminfo");
918 RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700919 "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
Felipe Lemef0292972016-11-22 13:57:05 -0800920 RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20);
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700921 DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
922 DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
923 DumpFile("SLAB INFO", "/proc/slabinfo");
924 DumpFile("ZONEINFO", "/proc/zoneinfo");
925 DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
926 DumpFile("BUDDYINFO", "/proc/buddyinfo");
927 DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700928
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700929 DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
930 DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
931 DumpFile("KERNEL SYNC", "/d/sync");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700932
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700933 RunCommand("PROCESSES AND THREADS",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700934 {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
Felipe Lemef0292972016-11-22 13:57:05 -0800935 RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700936
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700937 RunCommand("PRINTENV", {"printenv"});
Elliott Hughes21b7c8d2016-10-28 08:53:02 -0700938 RunCommand("NETSTAT", {"netstat", "-nW"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700939 struct stat s;
940 if (stat("/proc/modules", &s) != 0) {
941 MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
942 } else {
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700943 RunCommand("LSMOD", {"lsmod"});
Felipe Lemee4eca582016-06-10 17:48:08 -0700944 }
Michal Karpinski4db754f2015-12-11 18:04:32 +0000945
Colin Crossf45fa6b2012-03-26 12:38:26 -0700946 do_dmesg();
947
Felipe Lemef0292972016-11-22 13:57:05 -0800948 RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
Jeff Brown1dc94e32014-09-11 14:15:27 -0700949 for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
950 for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
Mark Salyzyna297c322016-02-05 15:33:17 -0800951 for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
Colin Crossf45fa6b2012-03-26 12:38:26 -0700952
Ajay Panickerd886ec42016-09-14 12:26:46 -0700953 /* Dump Bluetooth HCI logs */
Felipe Leme1d486fe2016-10-14 18:06:47 -0700954 ds.AddDir("/data/misc/bluetooth/logs", true);
Ajay Panickerd886ec42016-09-14 12:26:46 -0700955
Felipe Leme9a523ae2016-10-20 15:10:33 -0700956 if (!ds.do_early_screenshot_) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800957 MYLOGI("taking late screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -0700958 ds.TakeScreenshot();
Jeff Sharkey5a930032013-03-19 15:05:19 -0700959 }
960
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700961 // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700962 // calculate timeout
963 timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
964 if (timeout < 20000) {
965 timeout = 20000;
966 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700967 RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
Felipe Leme30dbfa12016-09-02 12:43:26 -0700968 CommandOptions::WithTimeout(timeout / 1000).Build());
Mark Salyzyn43afe5d2016-01-26 07:24:08 -0800969 timeout = logcat_timeout("events");
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700970 if (timeout < 20000) {
971 timeout = 20000;
972 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700973 RunCommand("EVENT LOG",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700974 {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
975 CommandOptions::WithTimeout(timeout / 1000).Build());
Mark Salyzyn8f37aa52015-06-12 12:28:24 -0700976 timeout = logcat_timeout("radio");
977 if (timeout < 20000) {
978 timeout = 20000;
979 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700980 RunCommand("RADIO LOG",
Felipe Leme30dbfa12016-09-02 12:43:26 -0700981 {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
982 CommandOptions::WithTimeout(timeout / 1000).Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -0700983
Felipe Lemeb0f669d2016-09-26 18:26:11 -0700984 RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
Mark Salyzynecc07632015-07-30 14:57:09 -0700985
Felipe Lemee184f662016-10-27 10:04:47 -0700986 AddAnrTraceFiles();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700987
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700988 int dumped = 0;
989 for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
990 if (tombstone_data[i].fd != -1) {
Felipe Lemee82a27d2016-01-05 13:35:44 -0800991 const char *name = tombstone_data[i].name;
992 int fd = tombstone_data[i].fd;
Christopher Ferris7dc7f322014-07-22 16:08:19 -0700993 dumped = 1;
Felipe Leme1d486fe2016-10-14 18:06:47 -0700994 if (ds.IsZipping()) {
995 if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -0800996 MYLOGE("Unable to add tombstone %s to zip file\n", name);
Felipe Lemee82a27d2016-01-05 13:35:44 -0800997 }
998 } else {
999 dump_file_from_fd("TOMBSTONE", name, fd);
1000 }
1001 close(fd);
Christopher Ferris7dc7f322014-07-22 16:08:19 -07001002 tombstone_data[i].fd = -1;
1003 }
1004 }
1005 if (!dumped) {
1006 printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
1007 }
1008
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001009 DumpFile("NETWORK DEV INFO", "/proc/net/dev");
1010 DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
1011 DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
1012 DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
1013 DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001014
Felipe Lemee184f662016-10-27 10:04:47 -07001015 struct stat st;
Todd Poynor2a83daa2013-11-22 15:44:22 -08001016 if (!stat(PSTORE_LAST_KMSG, &st)) {
1017 /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001018 DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
Mark Salyzyn7d0a7622016-06-24 14:06:15 -07001019 } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001020 DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
Todd Poynor2a83daa2013-11-22 15:44:22 -08001021 } else {
1022 /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001023 DumpFile("LAST KMSG", "/proc/last_kmsg");
Todd Poynor2a83daa2013-11-22 15:44:22 -08001024 }
1025
Mark Salyzyn2262c162014-12-16 09:09:26 -08001026 /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001027 RunCommand("LAST LOGCAT",
Felipe Leme30dbfa12016-09-02 12:43:26 -07001028 {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
Mark Salyzyn2262c162014-12-16 09:09:26 -08001029
Colin Crossf45fa6b2012-03-26 12:38:26 -07001030 /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
Elliott Hughesa59828a2015-01-27 20:48:52 -08001031
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001032 RunCommand("NETWORK INTERFACES", {"ip", "link"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001033
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001034 RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
1035 RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
Lorenzo Colittid4c3d382014-07-30 14:38:20 +09001036
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001037 RunCommand("IP RULES", {"ip", "rule", "show"});
1038 RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
Sreeram Ramachandran2b3bba32014-07-08 15:40:55 -07001039
1040 dump_route_tables();
1041
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001042 RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
1043 RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
1044 RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
1045 RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001046 CommandOptions::WithTimeout(20).Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001047
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001048#ifdef FWDUMP_bcmdhd
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001049 RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001050
Felipe Lemef0292972016-11-22 13:57:05 -08001051 RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001052
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001053 RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001054
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001055#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001056 DumpFile("INTERRUPTS (1)", "/proc/interrupts");
Dmitry Shmidt0b2c9262012-11-07 11:09:46 -08001057
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001058 RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001059 CommandOptions::WithTimeout(10).Build());
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001060
Dmitry Shmidtc11f56e2012-11-07 10:42:05 -08001061#ifdef FWDUMP_bcmdhd
Felipe Lemef0292972016-11-22 13:57:05 -08001062 RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001063
Felipe Lemef0292972016-11-22 13:57:05 -08001064 RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
Lorenzo Colitti6afc38c2015-09-09 22:59:25 +09001065
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001066 RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001067#endif
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001068 DumpFile("INTERRUPTS (2)", "/proc/interrupts");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001069
1070 print_properties();
1071
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001072 RunCommand("VOLD DUMP", {"vdc", "dump"});
1073 RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001074
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001075 RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001076
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001077 RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001078
1079 printf("------ BACKLIGHTS ------\n");
1080 printf("LCD brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001081 DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001082 printf("Button brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001083 DumpFile("", "/sys/class/leds/button-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001084 printf("Keyboard brightness=");
Felipe Leme678727a2016-09-21 17:22:11 -07001085 DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001086 printf("ALS mode=");
Felipe Leme678727a2016-09-21 17:22:11 -07001087 DumpFile("", "/sys/class/leds/lcd-backlight/als");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001088 printf("LCD driver registers:\n");
Felipe Leme678727a2016-09-21 17:22:11 -07001089 DumpFile("", "/sys/class/leds/lcd-backlight/registers");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001090 printf("\n");
1091
1092 /* Binder state is expensive to look at as it uses a lot of memory. */
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001093 DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
1094 DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
1095 DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
1096 DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
1097 DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001098
Felipe Leme6f674ae2016-11-18 17:10:33 -08001099 ds.DumpstateBoard();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001100
1101 /* Migrate the ril_dumpstate to a dumpstate_board()? */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001102 int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
1103 if (rilDumpstateTimeout > 0) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001104 // su does not exist on user builds, so try running without it.
1105 // This way any implementations of vril-dump that do not require
1106 // root can run on user builds.
1107 CommandOptions::CommandOptionsBuilder options =
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001108 CommandOptions::WithTimeout(rilDumpstateTimeout);
Felipe Lemef0292972016-11-22 13:57:05 -08001109 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme30dbfa12016-09-02 12:43:26 -07001110 options.AsRoot();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001111 }
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001112 RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
Colin Crossf45fa6b2012-03-26 12:38:26 -07001113 }
1114
1115 printf("========================================================\n");
1116 printf("== Android Framework Services\n");
1117 printf("========================================================\n");
1118
Felipe Leme5bcce572016-09-27 09:21:08 -07001119 RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
1120 10);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001121
1122 printf("========================================================\n");
Dianne Hackborn02bea972013-06-26 18:59:09 -07001123 printf("== Checkins\n");
1124 printf("========================================================\n");
1125
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001126 RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
1127 RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
1128 RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
1129 RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
1130 RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
1131 RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
Dianne Hackborn02bea972013-06-26 18:59:09 -07001132
1133 printf("========================================================\n");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001134 printf("== Running Application Activities\n");
1135 printf("========================================================\n");
1136
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001137 RunDumpsys("APP ACTIVITIES", {"activity", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001138
1139 printf("========================================================\n");
1140 printf("== Running Application Services\n");
1141 printf("========================================================\n");
1142
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001143 RunDumpsys("APP SERVICES", {"activity", "service", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001144
1145 printf("========================================================\n");
1146 printf("== Running Application Providers\n");
1147 printf("========================================================\n");
1148
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001149 RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
Colin Crossf45fa6b2012-03-26 12:38:26 -07001150
Naveen Kalla058e1e82016-10-19 21:38:44 -07001151 // DumpModemLogs adds the modem logs if available to the bugreport.
1152 // Do this at the end to allow for sufficient time for the modem logs to be
1153 // collected.
1154 DumpModemLogs();
1155
Colin Crossf45fa6b2012-03-26 12:38:26 -07001156 printf("========================================================\n");
Felipe Leme7447d7c2016-11-03 18:12:22 -07001157 printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
1158 ds.progress_->GetMax(), ds.progress_->GetInitialMax());
Felipe Leme608385d2016-02-01 10:35:38 -08001159 printf("========================================================\n");
Felipe Leme7447d7c2016-11-03 18:12:22 -07001160 printf("== dumpstate: done (id %d)\n", ds.id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001161 printf("========================================================\n");
1162}
1163
Felipe Leme6f674ae2016-11-18 17:10:33 -08001164void Dumpstate::DumpstateBoard() {
1165 DurationReporter duration_reporter("dumpstate_board()");
1166 printf("========================================================\n");
1167 printf("== Board\n");
1168 printf("========================================================\n");
1169 fflush(stdout);
1170
1171 android::sp<android::hardware::dumpstate::V1_0::IDumpstateDevice> dumpstate_device(
1172 android::hardware::dumpstate::V1_0::IDumpstateDevice::getService("DumpstateDevice"));
1173 if (dumpstate_device == nullptr) {
1174 // TODO: temporary workaround until devices on master implement it
1175 MYLOGE("no IDumpstateDevice implementation; using legacy dumpstate_board()\n");
1176 dumpstate_board();
1177 return;
1178 }
1179
1180 if (!IsZipping()) {
1181 MYLOGE("Not dumping board info because it's not a zipped bugreport\n");
1182 return;
1183 }
1184
1185 std::string path = ds.GetPath("-dumpstate-board.txt");
1186 MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
1187
1188 int fd =
1189 TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1190 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
1191 if (fd < 0) {
1192 MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
1193 return;
1194 }
1195
1196 native_handle_t* handle = native_handle_create(1, 0);
1197 if (handle == nullptr) {
1198 MYLOGE("Could not create native_handle\n");
1199 return;
1200 }
1201 handle->data[0] = fd;
1202
Felipe Lemef0292972016-11-22 13:57:05 -08001203 // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
Felipe Leme6f674ae2016-11-18 17:10:33 -08001204 dumpstate_device->dumpstateBoard(handle);
1205
1206 AddZipEntry("dumpstate-board.txt", path);
Felipe Leme46b85da2016-11-21 17:40:45 -08001207 printf("*** See dumpstate-board.txt entry ***\n");
1208 fflush(stdout);
Felipe Leme6f674ae2016-11-18 17:10:33 -08001209
1210 native_handle_close(handle);
1211 native_handle_delete(handle);
1212
1213 if (remove(path.c_str()) != 0) {
1214 MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
1215 }
1216}
1217
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001218static void ShowUsageAndExit(int exitCode = 1) {
1219 fprintf(stderr,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001220 "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001221 "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
1222 " -h: display this help message\n"
1223 " -b: play sound file instead of vibrate, at beginning of job\n"
1224 " -e: play sound file instead of vibrate, at end of job\n"
1225 " -o: write to file (instead of stdout)\n"
1226 " -d: append date to filename (requires -o)\n"
1227 " -p: capture screenshot to filename.png (requires -o)\n"
1228 " -z: generate zipped file (requires -o)\n"
1229 " -s: write output to control socket (for init)\n"
1230 " -S: write file location to control socket (for init; requires -o and -z)"
1231 " -q: disable vibrate\n"
1232 " -B: send broadcast when finished (requires -o)\n"
1233 " -P: send broadcast when started and update system properties on "
1234 "progress (requires -o and -B)\n"
1235 " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
1236 "shouldn't be used with -P)\n"
Felipe Lemed071c682016-10-20 16:48:00 -07001237 " -v: prints the dumpstate header and exit\n");
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001238 exit(exitCode);
1239}
1240
1241static void ExitOnInvalidArgs() {
1242 fprintf(stderr, "invalid combination of args\n");
1243 ShowUsageAndExit();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001244}
1245
Wei Liuf87959e2016-08-26 14:51:42 -07001246static void wake_lock_releaser() {
1247 if (release_wake_lock(WAKE_LOCK_NAME) < 0) {
1248 MYLOGE("Failed to release wake lock: %s \n", strerror(errno));
1249 } else {
1250 MYLOGD("Wake lock released.\n");
1251 }
1252}
1253
Felipe Leme4c2d6632016-09-28 14:32:00 -07001254static void sig_handler(int signo __attribute__((unused))) {
Wei Liuf87959e2016-08-26 14:51:42 -07001255 wake_lock_releaser();
Andres Morales2e671bb2014-08-21 12:38:22 -07001256 _exit(EXIT_FAILURE);
John Michelau885f8882013-05-06 16:42:02 -05001257}
1258
Wei Liuf87959e2016-08-26 14:51:42 -07001259static void register_sig_handler() {
1260 struct sigaction sa;
1261 sigemptyset(&sa.sa_mask);
1262 sa.sa_flags = 0;
1263 sa.sa_handler = sig_handler;
1264 sigaction(SIGPIPE, &sa, NULL); // broken pipe
1265 sigaction(SIGSEGV, &sa, NULL); // segment fault
1266 sigaction(SIGINT, &sa, NULL); // ctrl-c
1267 sigaction(SIGTERM, &sa, NULL); // killed
1268 sigaction(SIGQUIT, &sa, NULL); // quit
1269}
1270
Felipe Leme1d486fe2016-10-14 18:06:47 -07001271bool Dumpstate::FinishZipFile() {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001272 std::string entry_name = base_name_ + "-" + name_ + ".txt";
Felipe Leme1d486fe2016-10-14 18:06:47 -07001273 MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001274 tmp_path_.c_str());
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001275 // Final timestamp
1276 char date[80];
1277 time_t the_real_now_please_stand_up = time(nullptr);
1278 strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
Felipe Leme7447d7c2016-11-03 18:12:22 -07001279 MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001280 the_real_now_please_stand_up - ds.now_);
Felipe Leme5b9d3bf2016-08-16 17:20:21 -07001281
Felipe Leme9a523ae2016-10-20 15:10:33 -07001282 if (!ds.AddZipEntry(entry_name, tmp_path_)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001283 MYLOGE("Failed to add text entry to .zip file\n");
Felipe Leme1e9edc62015-12-21 16:02:13 -08001284 return false;
1285 }
Felipe Leme1d486fe2016-10-14 18:06:47 -07001286 if (!AddTextZipEntry("main_entry.txt", entry_name)) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001287 MYLOGE("Failed to add main_entry.txt to .zip file\n");
Felipe Leme111b9d02016-02-03 09:28:24 -08001288 return false;
Felipe Leme809d74e2016-02-02 12:57:00 -08001289 }
Felipe Leme1e9edc62015-12-21 16:02:13 -08001290
Felipe Leme0f3fb202016-06-10 17:10:53 -07001291 // Add log file (which contains stderr output) to zip...
1292 fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001293 if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
Felipe Leme0f3fb202016-06-10 17:10:53 -07001294 MYLOGE("Failed to add dumpstate log to .zip file\n");
1295 return false;
1296 }
1297 // ... and re-opens it for further logging.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001298 redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
Felipe Leme0f3fb202016-06-10 17:10:53 -07001299 fprintf(stderr, "\n");
1300
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001301 int32_t err = zip_writer_->Finish();
Felipe Leme1d486fe2016-10-14 18:06:47 -07001302 if (err != 0) {
Felipe Lemec6bc8bc2016-10-27 15:58:27 -07001303 MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001304 return false;
1305 }
1306
Felipe Leme1d486fe2016-10-14 18:06:47 -07001307 // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
1308 ds.zip_file.reset(nullptr);
1309
Felipe Lemee9d2c542016-11-15 11:48:26 -08001310 MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
1311 if (remove(tmp_path_.c_str()) != 0) {
1312 MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
Felipe Lemec4eee562016-04-21 15:42:55 -07001313 }
1314
Felipe Leme1e9edc62015-12-21 16:02:13 -08001315 return true;
1316}
Felipe Leme6e01fa62015-11-11 19:35:14 -08001317
Michal Karpinski4db754f2015-12-11 18:04:32 +00001318static std::string SHA256_file_hash(std::string filepath) {
Andreas Gampe27cd7b22016-07-18 18:24:05 -07001319 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
1320 | O_CLOEXEC | O_NOFOLLOW)));
Andreas Gampeaff68432016-07-18 18:01:27 -07001321 if (fd == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001322 MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001323 return NULL;
1324 }
1325
1326 SHA256_CTX ctx;
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001327 SHA256_Init(&ctx);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001328
1329 std::vector<uint8_t> buffer(65536);
1330 while (1) {
1331 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
1332 if (bytes_read == 0) {
1333 break;
1334 } else if (bytes_read == -1) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001335 MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001336 return NULL;
1337 }
1338
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001339 SHA256_Update(&ctx, buffer.data(), bytes_read);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001340 }
1341
Elliott Hughesc4dc1412016-04-12 16:28:31 -07001342 uint8_t hash[SHA256_DIGEST_LENGTH];
1343 SHA256_Final(hash, &ctx);
1344
1345 char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
1346 for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
Michal Karpinskicbbdf732016-01-07 20:45:02 +00001347 sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
Michal Karpinski4db754f2015-12-11 18:04:32 +00001348 }
1349 hash_buffer[sizeof(hash_buffer) - 1] = 0;
1350 return std::string(hash_buffer);
1351}
1352
Colin Crossf45fa6b2012-03-26 12:38:26 -07001353int main(int argc, char *argv[]) {
1354 int do_add_date = 0;
Felipe Leme6e01fa62015-11-11 19:35:14 -08001355 int do_zip_file = 0;
John Michelau1f794c42012-09-17 11:20:19 -05001356 int do_vibrate = 1;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001357 char* use_outfile = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001358 int use_socket = 0;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001359 int use_control_socket = 0;
Colin Crossf45fa6b2012-03-26 12:38:26 -07001360 int do_fb = 0;
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001361 int do_broadcast = 0;
Michal Karpinski4db754f2015-12-11 18:04:32 +00001362 int is_remote_mode = 0;
Felipe Lemed071c682016-10-20 16:48:00 -07001363 bool show_header_only = false;
Felipe Leme75876a22016-10-27 16:31:27 -07001364 bool do_start_service = false;
Felipe Leme8fecfdd2016-02-09 10:40:07 -08001365
Colin Crossf45fa6b2012-03-26 12:38:26 -07001366 /* set as high priority, and protect from OOM killer */
1367 setpriority(PRIO_PROCESS, 0, -20);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001368
Felipe Lemed071c682016-10-20 16:48:00 -07001369 FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
Colin Crossf45fa6b2012-03-26 12:38:26 -07001370 if (oom_adj) {
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001371 fputs("-1000", oom_adj);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001372 fclose(oom_adj);
Wei Wang9c1f9bb2016-06-28 14:32:35 -07001373 } else {
1374 /* fallback to kernels <= 2.6.35 */
1375 oom_adj = fopen("/proc/self/oom_adj", "we");
1376 if (oom_adj) {
1377 fputs("-17", oom_adj);
1378 fclose(oom_adj);
1379 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001380 }
1381
Jeff Brown1dc94e32014-09-11 14:15:27 -07001382 /* parse arguments */
Colin Crossf45fa6b2012-03-26 12:38:26 -07001383 int c;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001384 while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001385 switch (c) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001386 // clang-format off
Felipe Lemed071c682016-10-20 16:48:00 -07001387 case 'd': do_add_date = 1; break;
1388 case 'z': do_zip_file = 1; break;
1389 case 'o': use_outfile = optarg; break;
1390 case 's': use_socket = 1; break;
1391 case 'S': use_control_socket = 1; break;
1392 case 'v': show_header_only = true; break;
1393 case 'q': do_vibrate = 0; break;
1394 case 'p': do_fb = 1; break;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001395 case 'P': ds.update_progress_ = true; break;
Felipe Lemed071c682016-10-20 16:48:00 -07001396 case 'R': is_remote_mode = 1; break;
1397 case 'B': do_broadcast = 1; break;
1398 case 'V': break; // compatibility no-op
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001399 case 'h':
1400 ShowUsageAndExit(0);
1401 break;
1402 default:
1403 fprintf(stderr, "Invalid option: %c\n", c);
1404 ShowUsageAndExit();
Felipe Lemee844a9d2016-09-21 15:01:39 -07001405 // clang-format on
Colin Crossf45fa6b2012-03-26 12:38:26 -07001406 }
1407 }
1408
Felipe Lemed071c682016-10-20 16:48:00 -07001409 // TODO: use helper function to convert argv into a string
1410 for (int i = 0; i < argc; i++) {
1411 ds.args_ += argv[i];
1412 if (i < argc - 1) {
1413 ds.args_ += " ";
1414 }
1415 }
1416
1417 ds.extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001418 if (!ds.extra_options_.empty()) {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001419 // Framework uses a system property to override some command-line args.
1420 // Currently, it contains the type of the requested bugreport.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001421 if (ds.extra_options_ == "bugreportplus") {
Felipe Leme75876a22016-10-27 16:31:27 -07001422 // Currently, the dumpstate binder is only used by Shell to update progress.
1423 do_start_service = true;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001424 ds.update_progress_ = true;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001425 do_fb = 0;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001426 } else if (ds.extra_options_ == "bugreportremote") {
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001427 do_vibrate = 0;
1428 is_remote_mode = 1;
1429 do_fb = 0;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001430 } else if (ds.extra_options_ == "bugreportwear") {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001431 ds.update_progress_ = true;
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001432 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001433 MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001434 }
1435 // Reset the property
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001436 android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
Felipe Leme9ce6aa42016-09-21 10:02:25 -07001437 }
1438
Felipe Leme9a523ae2016-10-20 15:10:33 -07001439 if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001440 ExitOnInvalidArgs();
Felipe Leme6e01fa62015-11-11 19:35:14 -08001441 }
1442
Felipe Leme2628e9e2016-04-12 16:36:51 -07001443 if (use_control_socket && !do_zip_file) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001444 ExitOnInvalidArgs();
Felipe Leme2628e9e2016-04-12 16:36:51 -07001445 }
1446
Felipe Leme9a523ae2016-10-20 15:10:33 -07001447 if (ds.update_progress_ && !do_broadcast) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001448 ExitOnInvalidArgs();
Felipe Leme71bbfc52015-11-23 14:14:51 -08001449 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001450
Felipe Leme9a523ae2016-10-20 15:10:33 -07001451 if (is_remote_mode && (ds.update_progress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
Felipe Leme4a0db9f2016-09-28 09:35:01 -07001452 ExitOnInvalidArgs();
Michal Karpinski4db754f2015-12-11 18:04:32 +00001453 }
1454
Felipe Lemed071c682016-10-20 16:48:00 -07001455 if (ds.version_ == VERSION_DEFAULT) {
1456 ds.version_ = VERSION_CURRENT;
Felipe Leme809d74e2016-02-02 12:57:00 -08001457 }
1458
Felipe Lemee184f662016-10-27 10:04:47 -07001459 if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
1460 MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
1461 ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
1462 VERSION_SPLIT_ANR.c_str());
Felipe Lemed071c682016-10-20 16:48:00 -07001463 exit(1);
1464 }
1465
1466 if (show_header_only) {
1467 ds.PrintHeader();
1468 exit(0);
1469 }
1470
Felipe Leme7447d7c2016-11-03 18:12:22 -07001471 /* redirect output if needed */
1472 bool is_redirecting = !use_socket && use_outfile;
1473
1474 // TODO: temporarily set progress until it's part of the Dumpstate constructor
1475 std::string stats_path =
1476 is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
1477 : "";
1478 ds.progress_.reset(new Progress(stats_path));
1479
Felipe Lemed071c682016-10-20 16:48:00 -07001480 /* gets the sequential id */
Felipe Leme7447d7c2016-11-03 18:12:22 -07001481 uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
Felipe Lemed071c682016-10-20 16:48:00 -07001482 ds.id_ = ++last_id;
1483 android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
1484
1485 MYLOGI("begin\n");
1486
1487 if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
1488 MYLOGE("Failed to acquire wake lock: %s \n", strerror(errno));
1489 } else {
1490 MYLOGD("Wake lock acquired.\n");
1491 atexit(wake_lock_releaser);
1492 register_sig_handler();
1493 }
1494
Felipe Leme75876a22016-10-27 16:31:27 -07001495 if (do_start_service) {
1496 MYLOGI("Starting 'dumpstate' service\n");
1497 android::status_t ret;
1498 if ((ret = android::os::DumpstateService::Start()) != android::OK) {
1499 MYLOGE("Unable to start DumpstateService: %d\n", ret);
1500 }
1501 }
1502
Felipe Lemef0292972016-11-22 13:57:05 -08001503 if (PropertiesHelper::IsDryRun()) {
Felipe Lemed071c682016-10-20 16:48:00 -07001504 MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
1505 }
1506
Felipe Leme7447d7c2016-11-03 18:12:22 -07001507 MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
Felipe Lemed071c682016-10-20 16:48:00 -07001508 ds.extra_options_.c_str());
1509
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001510 MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
Felipe Leme809d74e2016-02-02 12:57:00 -08001511
Felipe Leme9a523ae2016-10-20 15:10:33 -07001512 ds.do_early_screenshot_ = ds.update_progress_;
Felipe Lemee338bf62015-12-07 14:03:50 -08001513
Christopher Ferrised9354f2014-10-01 17:35:01 -07001514 // If we are going to use a socket, do it as early as possible
1515 // to avoid timeouts from bugreport.
1516 if (use_socket) {
1517 redirect_to_socket(stdout, "dumpstate");
1518 }
1519
Felipe Leme2628e9e2016-04-12 16:36:51 -07001520 if (use_control_socket) {
1521 MYLOGD("Opening control socket\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001522 ds.control_socket_fd_ = open_socket("dumpstate");
1523 ds.update_progress_ = 1;
Felipe Leme2628e9e2016-04-12 16:36:51 -07001524 }
1525
Felipe Leme71bbfc52015-11-23 14:14:51 -08001526 if (is_redirecting) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001527 ds.bugreport_dir_ = dirname(use_outfile);
1528 ds.base_name_ = basename(use_outfile);
Felipe Leme71bbfc52015-11-23 14:14:51 -08001529 if (do_add_date) {
1530 char date[80];
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001531 strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001532 ds.name_ = date;
Felipe Lemead5f6c42015-11-30 14:26:46 -08001533 } else {
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001534 ds.name_ = "undated";
Felipe Leme71bbfc52015-11-23 14:14:51 -08001535 }
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001536 std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
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
Jeff Brown1dc94e32014-09-11 14:15:27 -07001594 /* open the vibrator before dropping root */
Felipe Leme6e01fa62015-11-11 19:35:14 -08001595 std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
John Michelau1f794c42012-09-17 11:20:19 -05001596 if (do_vibrate) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001597 vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
Jeff Brown1dc94e32014-09-11 14:15:27 -07001598 if (vibrator) {
Felipe Leme6e01fa62015-11-11 19:35:14 -08001599 vibrate(vibrator.get(), 150);
Jeff Brown1dc94e32014-09-11 14:15:27 -07001600 }
John Michelau1f794c42012-09-17 11:20:19 -05001601 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001602
Felipe Leme9a523ae2016-10-20 15:10:33 -07001603 if (do_fb && ds.do_early_screenshot_) {
1604 if (ds.screenshot_path_.empty()) {
Felipe Leme3634a1e2015-12-09 10:11:47 -08001605 // should not have happened
Felipe Lemecbce55d2016-02-08 09:53:18 -08001606 MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
Felipe Leme3634a1e2015-12-09 10:11:47 -08001607 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001608 MYLOGI("taking early screenshot\n");
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001609 ds.TakeScreenshot();
Felipe Lemee338bf62015-12-07 14:03:50 -08001610 }
1611 }
1612
Felipe Leme1e9edc62015-12-21 16:02:13 -08001613 if (do_zip_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001614 if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
1615 MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001616 strerror(errno));
Felipe Leme1e9edc62015-12-21 16:02:13 -08001617 }
1618 }
1619
Felipe Leme71bbfc52015-11-23 14:14:51 -08001620 if (is_redirecting) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001621 redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
1622 if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
1623 MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
1624 ds.log_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001625 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001626 /* TODO: rather than generating a text file now and zipping it later,
1627 it would be more efficient to redirect stdout to the zip entry
1628 directly, but the libziparchive doesn't support that option yet. */
Felipe Leme9a523ae2016-10-20 15:10:33 -07001629 redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
1630 if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
Felipe Leme6fe9db62016-02-12 09:04:16 -08001631 MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
Felipe Leme9a523ae2016-10-20 15:10:33 -07001632 ds.tmp_path_.c_str(), strerror(errno));
Felipe Leme6fe9db62016-02-12 09:04:16 -08001633 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001634 }
Felipe Leme608385d2016-02-01 10:35:38 -08001635 // NOTE: there should be no stdout output until now, otherwise it would break the header.
1636 // In particular, DurationReport objects should be created passing 'title, NULL', so their
Felipe Lemecbce55d2016-02-08 09:53:18 -08001637 // duration is logged into MYLOG instead.
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001638 ds.PrintHeader();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001639
Felipe Leme71a74ac2016-03-17 15:43:25 -07001640 // Dumps systrace right away, otherwise it will be filled with unnecessary events.
Zhengyin Qian068ecc72016-08-10 16:48:14 -07001641 // First try to dump anrd trace if the daemon is running. Otherwise, dump
1642 // the raw trace.
1643 if (!dump_anrd_trace()) {
1644 dump_systrace();
1645 }
Felipe Leme71a74ac2016-03-17 15:43:25 -07001646
Felipe Leme9c74aad2016-02-29 18:15:42 -08001647 // Invoking the following dumpsys calls before dump_traces() to try and
1648 // keep the system stats as close to its initial state as possible.
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001649 RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001650 CommandOptions::WithTimeout(90).DropRoot().Build());
Felipe Lemeb0f669d2016-09-26 18:26:11 -07001651 RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
Felipe Leme30dbfa12016-09-02 12:43:26 -07001652 CommandOptions::WithTimeout(10).DropRoot().Build());
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001653
Felipe Lemee844a9d2016-09-21 15:01:39 -07001654 // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
1655 dump_raft();
1656
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001657 /* collect stack traces from Dalvik and native processes (needs root) */
1658 dump_traces_path = dump_traces();
1659
Felipe Lemec0808152016-06-17 17:37:13 -07001660 /* Run some operations that require root. */
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001661 get_tombstone_fds(tombstone_data);
Felipe Leme1d486fe2016-10-14 18:06:47 -07001662 ds.AddDir(RECOVERY_DIR, true);
1663 ds.AddDir(RECOVERY_DATA_DIR, true);
1664 ds.AddDir(LOGPERSIST_DATA_DIR, false);
Felipe Lemef0292972016-11-22 13:57:05 -08001665 if (!PropertiesHelper::IsUserBuild()) {
Felipe Leme1d486fe2016-10-14 18:06:47 -07001666 ds.AddDir(PROFILE_DATA_DIR_CUR, true);
1667 ds.AddDir(PROFILE_DATA_DIR_REF, true);
David Brazdild2991962016-06-03 14:40:44 +01001668 }
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001669 add_mountinfo();
Felipe Lemec0808152016-06-17 17:37:13 -07001670 dump_iptables();
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001671
Erik Kline32af8c22016-09-28 17:26:26 +09001672 // Capture any IPSec policies in play. No keys are exposed here.
1673 RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
1674 CommandOptions::WithTimeout(10).Build());
1675
Lorenzo Colittid3b809b2016-09-26 13:37:45 +09001676 // Run ss as root so we can see socket marks.
Felipe Lemec7fe8fe2016-09-21 18:13:20 -07001677 RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
Lorenzo Colittid3b809b2016-09-26 13:37:45 +09001678
Felipe Lemef0292972016-11-22 13:57:05 -08001679 if (!DropRootUser()) {
Srinath Sridharanfdf52d32016-02-01 15:50:22 -08001680 return -1;
1681 }
1682
Felipe Lemebbaf3c12016-10-11 14:32:25 -07001683 dumpstate();
Colin Crossf45fa6b2012-03-26 12:38:26 -07001684
Felipe Leme55b42a62015-11-10 17:39:08 -08001685 /* close output if needed */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001686 if (is_redirecting) {
Colin Crossf45fa6b2012-03-26 12:38:26 -07001687 fclose(stdout);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001688 }
1689
Felipe Leme6e01fa62015-11-11 19:35:14 -08001690 /* rename or zip the (now complete) .tmp file to its final location */
1691 if (use_outfile) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001692
1693 /* check if user changed the suffix using system properties */
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001694 std::string name = android::base::GetProperty(
Felipe Leme75876a22016-10-27 16:31:27 -07001695 android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
Felipe Lemead5f6c42015-11-30 14:26:46 -08001696 bool change_suffix= false;
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001697 if (!name.empty()) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001698 /* must whitelist which characters are allowed, otherwise it could cross directories */
1699 std::regex valid_regex("^[-_a-zA-Z0-9]+$");
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001700 if (std::regex_match(name.c_str(), valid_regex)) {
Felipe Lemead5f6c42015-11-30 14:26:46 -08001701 change_suffix = true;
1702 } else {
Felipe Leme96c2bbb2016-09-26 09:21:21 -07001703 MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
Felipe Lemead5f6c42015-11-30 14:26:46 -08001704 }
1705 }
1706 if (change_suffix) {
Felipe Leme2b9b06c2016-10-14 09:13:06 -07001707 MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
1708 ds.name_ = name;
Felipe Leme9a523ae2016-10-20 15:10:33 -07001709 if (!ds.screenshot_path_.empty()) {
1710 std::string new_screenshot_path = ds.GetPath(".png");
1711 if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
1712 MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
1713 new_screenshot_path.c_str(), strerror(errno));
Felipe Lemead5f6c42015-11-30 14:26:46 -08001714 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001715 ds.screenshot_path_ = new_screenshot_path;
Felipe Lemead5f6c42015-11-30 14:26:46 -08001716 }
1717 }
1718 }
1719
Felipe Leme6e01fa62015-11-11 19:35:14 -08001720 bool do_text_file = true;
1721 if (do_zip_file) {
Felipe Leme1d486fe2016-10-14 18:06:47 -07001722 if (!ds.FinishZipFile()) {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001723 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001724 do_text_file = true;
1725 } else {
1726 do_text_file = false;
Felipe Leme91274352016-02-26 15:03:52 -08001727 // Since zip file is already created, it needs to be renamed.
Felipe Leme9a523ae2016-10-20 15:10:33 -07001728 std::string new_path = ds.GetPath(".zip");
1729 if (ds.path_ != new_path) {
1730 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
1731 if (rename(ds.path_.c_str(), new_path.c_str())) {
1732 MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001733 strerror(errno));
Felipe Leme91274352016-02-26 15:03:52 -08001734 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001735 ds.path_ = new_path;
Felipe Leme91274352016-02-26 15:03:52 -08001736 }
1737 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001738 }
1739 }
1740 if (do_text_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001741 ds.path_ = ds.GetPath(".txt");
1742 MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(),
1743 ds.tmp_path_.c_str());
1744 if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
1745 MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(),
Felipe Leme1d486fe2016-10-14 18:06:47 -07001746 strerror(errno));
Felipe Leme9a523ae2016-10-20 15:10:33 -07001747 ds.path_.clear();
Felipe Leme6e01fa62015-11-11 19:35:14 -08001748 }
1749 }
Felipe Leme2628e9e2016-04-12 16:36:51 -07001750 if (use_control_socket) {
1751 if (do_text_file) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001752 dprintf(ds.control_socket_fd_,
Felipe Lemee844a9d2016-09-21 15:01:39 -07001753 "FAIL:could not create zip file, check %s "
1754 "for more details\n",
Felipe Leme9a523ae2016-10-20 15:10:33 -07001755 ds.log_path_.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001756 } else {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001757 dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
Felipe Leme2628e9e2016-04-12 16:36:51 -07001758 }
1759 }
Colin Crossf45fa6b2012-03-26 12:38:26 -07001760 }
1761
Felipe Lemecc2a2fa2016-02-25 14:02:44 -08001762 /* vibrate a few but shortly times to let user know it's finished */
1763 if (vibrator) {
1764 for (int i = 0; i < 3; i++) {
1765 vibrate(vibrator.get(), 75);
1766 usleep((75 + 50) * 1000);
1767 }
1768 }
1769
Jeff Brown1dc94e32014-09-11 14:15:27 -07001770 /* tell activity manager we're done */
Felipe Leme71bbfc52015-11-23 14:14:51 -08001771 if (do_broadcast) {
Felipe Leme9a523ae2016-10-20 15:10:33 -07001772 if (!ds.path_.empty()) {
1773 MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001774 // clang-format off
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001775 std::vector<std::string> am_args = {
Felipe Leme43fd1bb2016-01-29 09:07:57 -08001776 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
Felipe Lemee844a9d2016-09-21 15:01:39 -07001777 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
Felipe Leme75876a22016-10-27 16:31:27 -07001778 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
Felipe Leme7447d7c2016-11-03 18:12:22 -07001779 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
Felipe Leme9a523ae2016-10-20 15:10:33 -07001780 "--es", "android.intent.extra.BUGREPORT", ds.path_,
1781 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001782 };
Felipe Lemeaabfcae2016-07-29 09:49:04 -07001783 // clang-format on
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001784 if (do_fb) {
1785 am_args.push_back("--es");
1786 am_args.push_back("android.intent.extra.SCREENSHOT");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001787 am_args.push_back(ds.screenshot_path_);
Felipe Leme36b3f6f2015-11-19 15:41:04 -08001788 }
Michal Karpinski4db754f2015-12-11 18:04:32 +00001789 if (is_remote_mode) {
1790 am_args.push_back("--es");
1791 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001792 am_args.push_back(SHA256_file_hash(ds.path_));
Michal Karpinski4db754f2015-12-11 18:04:32 +00001793 send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
1794 } else {
1795 send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
1796 }
Felipe Leme6e01fa62015-11-11 19:35:14 -08001797 } else {
Felipe Lemecbce55d2016-02-08 09:53:18 -08001798 MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
Felipe Leme6e01fa62015-11-11 19:35:14 -08001799 }
Jeff Sharkey27f9e6d2013-03-13 15:45:50 -07001800 }
1801
Felipe Leme7447d7c2016-11-03 18:12:22 -07001802 MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
1803 ds.progress_->GetInitialMax());
1804 ds.progress_->Save();
1805 MYLOGI("done (id %d)\n", ds.id_);
Colin Crossf45fa6b2012-03-26 12:38:26 -07001806
Felipe Leme107a05f2016-03-08 15:11:15 -08001807 if (is_redirecting) {
1808 fclose(stderr);
1809 }
1810
Felipe Leme9a523ae2016-10-20 15:10:33 -07001811 if (use_control_socket && ds.control_socket_fd_ != -1) {
Felipe Lemee844a9d2016-09-21 15:01:39 -07001812 MYLOGD("Closing control socket\n");
Felipe Leme9a523ae2016-10-20 15:10:33 -07001813 close(ds.control_socket_fd_);
Felipe Leme2628e9e2016-04-12 16:36:51 -07001814 }
1815
Colin Crossf45fa6b2012-03-26 12:38:26 -07001816 return 0;
1817}