dump_file("BUDDYINFO", "/proc/buddyinfo");
dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
-
dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
do_dmesg();
run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+ for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
+ for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
if (screenshot_path[0]) {
ALOGI("taking screenshot\n");
ALOGI("wrote screenshot: %s\n", screenshot_path);
}
- for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
- for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
-
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
_exit(EXIT_FAILURE);
}
+static void vibrate(FILE* vibrator, int ms) {
+ fprintf(vibrator, "%d\n", ms);
+ fflush(vibrator);
+}
+
int main(int argc, char *argv[]) {
struct sigaction sigact;
int do_add_date = 0;
int do_compress = 0;
int do_vibrate = 1;
char* use_outfile = 0;
- char* begin_sound = 0;
- char* end_sound = 0;
int use_socket = 0;
int do_fb = 0;
int do_broadcast = 0;
// correct program.
return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL);
}
- ALOGI("begin\n");
+ ALOGI("begin\n");
+ /* clear SIGPIPE handler */
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = sigpipe_handler;
sigaction(SIGPIPE, &sigact, NULL);
-
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
FILE *oom_adj = fopen("/proc/self/oom_adj", "w");
fclose(oom_adj);
}
- /* very first thing, collect stack traces from Dalvik and native processes (needs root) */
- dump_traces_path = dump_traces();
-
+ /* parse arguments */
int c;
- while ((c = getopt(argc, argv, "b:de:ho:svqzpB")) != -1) {
+ while ((c = getopt(argc, argv, "dho:svqzpB")) != -1) {
switch (c) {
- case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
- case 'e': end_sound = optarg; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
}
}
+ /* open the vibrator before dropping root */
FILE *vibrator = 0;
if (do_vibrate) {
- /* open the vibrator before dropping root */
vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
- if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ if (vibrator) {
+ fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ vibrate(vibrator, 150);
+ }
}
/* read /proc/cmdline before dropping root */
fclose(cmdline);
}
+ /* collect stack traces from Dalvik and native processes (needs root) */
+ dump_traces_path = dump_traces();
+
+ /* Get the tombstone fds here while we are running as root. */
+ get_tombstone_fds(tombstone_data);
+
+ /* ensure we will keep capabilities when we drop root */
if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
return -1;
}
- /* Get the tombstone fds here while we are running as root. */
- get_tombstone_fds(tombstone_data);
-
/* switch to non-root user and group */
gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
AID_MOUNT, AID_INET, AID_NET_BW_STATS };
return -1;
}
+ /* redirect output if needed */
char path[PATH_MAX], tmp_path[PATH_MAX];
pid_t gzip_pid = -1;
gzip_pid = redirect_to_file(stdout, tmp_path, do_compress);
}
- if (begin_sound) {
- play_sound(begin_sound);
- } else if (vibrator) {
- fputs("150", vibrator);
- fflush(vibrator);
- }
-
dumpstate();
- if (end_sound) {
- play_sound(end_sound);
- } else if (vibrator) {
- int i;
- for (i = 0; i < 3; i++) {
- fputs("75\n", vibrator);
- fflush(vibrator);
+ /* done */
+ if (vibrator) {
+ for (int i = 0; i < 3; i++) {
+ vibrate(vibrator, 75);
usleep((75 + 50) * 1000);
}
fclose(vibrator);
fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno));
}
+ /* tell activity manager we're done */
if (do_broadcast && use_outfile && do_fb) {
run_command(NULL, 5, "/system/bin/am", "broadcast", "--user", "0",
"-a", "android.intent.action.BUGREPORT_FINISHED",
#include "dumpstate.h"
+static const int64_t NANOS_PER_SEC = 1000000000;
+
/* list of native processes to include in the native dumps */
static const char* native_processes_to_dump[] = {
"/system/bin/drmserver",
return 0;
}
+static int64_t nanotime() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (int64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+}
+
/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
fflush(stdout);
- time_t start = time(NULL);
+ int64_t start = nanotime();
pid_t pid = fork();
/* handle error case */
for (;;) {
int status;
pid_t p = waitpid(pid, &status, WNOHANG);
- time_t elapsed = time(NULL) - start;
+ int64_t elapsed = nanotime() - start;
if (p == pid) {
if (WIFSIGNALED(status)) {
printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
} else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
}
- if (title) printf("[%s: %ds elapsed]\n\n", command, (int) elapsed);
+ if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);
return status;
}
- if (timeout_seconds && elapsed > timeout_seconds) {
+ if (timeout_seconds && elapsed / NANOS_PER_SEC > timeout_seconds) {
printf("*** %s: Timed out after %ds (killing pid %d)\n", command, (int) elapsed, pid);
kill(pid, SIGTERM);
return -1;
if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
/* skip zygote -- it won't dump its stack anyway */
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- int fd = open(path, O_RDONLY);
- len = read(fd, data, sizeof(data) - 1);
- close(fd);
+ int cfd = open(path, O_RDONLY);
+ len = read(cfd, data, sizeof(data) - 1);
+ close(cfd);
if (len <= 0) {
continue;
}
}
++dalvik_found;
+ int64_t start = nanotime();
if (kill(pid, SIGQUIT)) {
fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
continue;
struct inotify_event ie;
read(ifd, &ie, sizeof(ie));
}
+
+ if (lseek(fd, 0, SEEK_END) < 0) {
+ fprintf(stderr, "lseek: %s\n", strerror(errno));
+ } else {
+ snprintf(data, sizeof(data), "[dump dalvik stack %d: %.3fs elapsed]\n",
+ pid, (float)(nanotime() - start) / NANOS_PER_SEC);
+ write(fd, data, strlen(data));
+ }
} else if (should_dump_native_traces(data)) {
/* dump native process if appropriate */
if (lseek(fd, 0, SEEK_END) < 0) {
fprintf(stderr, "lseek: %s\n", strerror(errno));
} else {
+ int64_t start = nanotime();
dump_backtrace_to_file(pid, fd);
+ snprintf(data, sizeof(data), "[dump native stack %d: %.3fs elapsed]\n",
+ pid, (float)(nanotime() - start) / NANOS_PER_SEC);
+ write(fd, data, strlen(data));
}
}
}
return result;
}
-void play_sound(const char* path) {
- run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL);
-}
-
void dump_route_tables() {
const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
dump_file("RT_TABLES", RT_TABLES_PATH);