summaryrefslogtreecommitdiffstats
path: root/cmds/dumpstate
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2015-02-26 11:01:57 -0800
committerChristopher Ferris <cferris@google.com>2015-02-26 11:01:57 -0800
commit123edd9f812c93973de923397f2a5cb6fdaa4135 (patch)
treecf1451cf355bbc0e3cbdad0c4fe889abccdc4d93 /cmds/dumpstate
parent59b0b568d0ce20394e6d491342ad0b06682dfa45 (diff)
parent04e13acdbf208277cfea17d331e702ad6afd6603 (diff)
downloadframeworks_native-123edd9f812c93973de923397f2a5cb6fdaa4135.zip
frameworks_native-123edd9f812c93973de923397f2a5cb6fdaa4135.tar.gz
frameworks_native-123edd9f812c93973de923397f2a5cb6fdaa4135.tar.bz2
resolved conflicts for merge of 04e13acd to master
Change-Id: I9bbc9907a5cbde8b374398493bc0dc6b056ea734
Diffstat (limited to 'cmds/dumpstate')
-rw-r--r--cmds/dumpstate/dumpstate.c6
-rw-r--r--cmds/dumpstate/dumpstate.h4
-rw-r--r--cmds/dumpstate/utils.c137
3 files changed, 108 insertions, 39 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 96ffca5..0cad9d8 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -64,7 +64,8 @@ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
time_t thirty_minutes_ago = time(NULL) - 60*30;
for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
- int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ int fd = TEMP_FAILURE_RETRY(open(data[i].name,
+ O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
struct stat st;
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
(time_t) st.st_mtime >= thirty_minutes_ago) {
@@ -184,7 +185,8 @@ static void dumpstate() {
if (!anr_traces_path[0]) {
printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
} else {
- int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
+ O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
if (fd < 0) {
printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
} else {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index aa99e6d..8335e26 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -30,7 +30,9 @@ typedef void (for_each_tid_func)(int, int, const char *);
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
-/* prints the contents of the fd */
+/* prints the contents of the fd
+ * fd must have been opened with the flag O_NONBLOCK.
+ */
int dump_file_from_fd(const char *title, const char *path, int fd);
/* forks a command and waits for it to finish -- terminate args with NULL */
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index d196c72..48f59e1 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -53,6 +53,35 @@ static const char* native_processes_to_dump[] = {
NULL,
};
+static uint64_t nanotime() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uint64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+}
+
+void for_each_userid(void (*func)(int), const char *header) {
+ DIR *d;
+ struct dirent *de;
+
+ if (header) printf("\n------ %s ------\n", header);
+ func(0);
+
+ if (!(d = opendir("/data/system/users"))) {
+ printf("Failed to open /data/system/users (%s)\n", strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(d))) {
+ int userid;
+ if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
+ continue;
+ }
+ func(userid);
+ }
+
+ closedir(d);
+}
+
static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
DIR *d;
struct dirent *de;
@@ -75,7 +104,7 @@ static void __for_each_pid(void (*helper)(int, const char *, void *), const char
sprintf(cmdpath,"/proc/%d/cmdline", pid);
memset(cmdline, 0, sizeof(cmdline));
- if ((fd = open(cmdpath, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY))) < 0) {
strcpy(cmdline, "N/A");
} else {
read(fd, cmdline, sizeof(cmdline) - 1);
@@ -126,7 +155,7 @@ static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
sprintf(commpath,"/proc/%d/comm", tid);
memset(comm, 0, sizeof(comm));
- if ((fd = open(commpath, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY))) < 0) {
strcpy(comm, "N/A");
} else {
char *c;
@@ -157,7 +186,7 @@ void show_wchan(int pid, int tid, const char *name) {
memset(buffer, 0, sizeof(buffer));
sprintf(path, "/proc/%d/wchan", tid);
- if ((fd = open(path, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY))) < 0) {
printf("Failed to open '%s' (%s)\n", path, strerror(errno));
return;
}
@@ -211,22 +240,7 @@ void do_showmap(int pid, const char *name) {
run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
}
-/* prints the contents of a file */
-int dump_file(const char *title, const char *path) {
- int fd = open(path, O_RDONLY);
- if (fd < 0) {
- int err = errno;
- if (title) printf("------ %s (%s) ------\n", title, path);
- printf("*** %s: %s\n", path, strerror(err));
- if (title) printf("\n");
- return -1;
- }
- return dump_file_from_fd(title, path, fd);
-}
-
-int dump_file_from_fd(const char *title, const char *path, int fd) {
- char buffer[32768];
-
+static int _dump_file_from_fd(const char *title, const char *path, int fd) {
if (title) printf("------ %s (%s", title, path);
if (title) {
@@ -240,26 +254,76 @@ int dump_file_from_fd(const char *title, const char *path, int fd) {
printf(") ------\n");
}
- int newline = 0;
- for (;;) {
- int ret = read(fd, buffer, sizeof(buffer));
- if (ret > 0) {
- newline = (buffer[ret - 1] == '\n');
- ret = fwrite(buffer, ret, 1, stdout);
+ bool newline = false;
+ fd_set read_set;
+ struct timeval tm;
+ while (1) {
+ FD_ZERO(&read_set);
+ FD_SET(fd, &read_set);
+ /* Timeout if no data is read for 30 seconds. */
+ tm.tv_sec = 30;
+ tm.tv_usec = 0;
+ uint64_t elapsed = nanotime();
+ int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm));
+ if (ret == -1) {
+ printf("*** %s: select failed: %s\n", path, strerror(errno));
+ newline = true;
+ break;
+ } else if (ret == 0) {
+ elapsed = nanotime() - elapsed;
+ printf("*** %s: Timed out after %.3fs\n", path,
+ (float) elapsed / NANOS_PER_SEC);
+ newline = true;
+ break;
+ } else {
+ char buffer[65536];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ if (bytes_read > 0) {
+ fwrite(buffer, bytes_read, 1, stdout);
+ newline = (buffer[bytes_read-1] == '\n');
+ } else {
+ if (bytes_read == -1) {
+ printf("*** %s: Failed to read from fd: %s", path, strerror(errno));
+ newline = true;
+ }
+ break;
+ }
}
- if (ret <= 0) break;
}
- close(fd);
+ TEMP_FAILURE_RETRY(close(fd));
if (!newline) printf("\n");
if (title) printf("\n");
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;
+/* prints the contents of a file */
+int dump_file(const char *title, const char *path) {
+ int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+ if (fd < 0) {
+ int err = errno;
+ if (title) printf("------ %s (%s) ------\n", title, path);
+ printf("*** %s: %s\n", path, strerror(err));
+ if (title) printf("\n");
+ return -1;
+ }
+ return _dump_file_from_fd(title, path, fd);
+}
+
+/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
+ * it's possible to avoid issues where opening the file itself can get
+ * stuck.
+ */
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+ int flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
+ return -1;
+ } else if (!(flags & O_NONBLOCK)) {
+ printf("*** %s: fd must have O_NONBLOCK set.\n", path);
+ return -1;
+ }
+ return _dump_file_from_fd(title, path, fd);
}
bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
@@ -309,7 +373,7 @@ bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
fflush(stdout);
- int64_t start = nanotime();
+ uint64_t start = nanotime();
pid_t pid = fork();
/* handle error case */
@@ -511,7 +575,8 @@ const char *dump_traces() {
}
/* create a new, empty traces.txt file to receive stack dumps */
- int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW,
+ 0666)); /* -rw-rw-rw- */
if (fd < 0) {
fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
return NULL;
@@ -561,7 +626,7 @@ const char *dump_traces() {
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 cfd = open(path, O_RDONLY);
+ int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
len = read(cfd, data, sizeof(data) - 1);
close(cfd);
if (len <= 0) {
@@ -573,7 +638,7 @@ const char *dump_traces() {
}
++dalvik_found;
- int64_t start = nanotime();
+ uint64_t start = nanotime();
if (kill(pid, SIGQUIT)) {
fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
continue;
@@ -603,7 +668,7 @@ const char *dump_traces() {
fprintf(stderr, "lseek: %s\n", strerror(errno));
} else {
static uint16_t timeout_failures = 0;
- int64_t start = nanotime();
+ uint64_t start = nanotime();
/* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
if (timeout_failures == 3) {