summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/cutils/debugger.h15
-rw-r--r--libcutils/debugger.c32
-rw-r--r--sdcard/sdcard.c35
3 files changed, 78 insertions, 4 deletions
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 4bcc8e6..bae687d 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -64,11 +64,26 @@ typedef struct {
*/
int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen);
+/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
+ * Stores the tombstone path in the provided buffer.
+ * If reading debugger data from debuggerd ever takes longer than timeout_secs
+ * seconds, then stop and return an error.
+ * Returns 0 on success, -1 on error.
+ */
+int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs);
+
/* Dumps a process backtrace only to the specified file (requires root).
* Returns 0 on success, -1 on error.
*/
int dump_backtrace_to_file(pid_t tid, int fd);
+/* Dumps a process backtrace only to the specified file (requires root).
+ * If reading debugger data from debuggerd ever takes longer than timeout_secs
+ * seconds, then stop and return an error.
+ * Returns 0 on success, -1 on error.
+ */
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
+
#ifdef __cplusplus
}
#endif
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 4035ee1..b8a2efc 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -19,11 +19,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <unistd.h>
#include <cutils/debugger.h>
#include <cutils/sockets.h>
+#define LOG_TAG "DEBUG"
+#include <log/log.h>
+
#if defined(__LP64__)
#include <elf.h>
@@ -64,7 +69,7 @@ static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) {
return result;
}
-static int make_dump_request(debugger_action_t action, pid_t tid) {
+static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) {
const char* socket_name;
debugger_msg_t msg;
size_t msg_len;
@@ -98,6 +103,19 @@ static int make_dump_request(debugger_action_t action, pid_t tid) {
return -1;
}
+ if (timeout_secs > 0) {
+ struct timeval tm;
+ tm.tv_sec = timeout_secs;
+ tm.tv_usec = 0;
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)) == -1) {
+ ALOGE("WARNING: Cannot set receive timeout value on socket: %s", strerror(errno));
+ }
+
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) == -1) {
+ ALOGE("WARNING: Cannot set send timeout value on socket: %s", strerror(errno));
+ }
+ }
+
if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
TEMP_FAILURE_RETRY(close(sock_fd));
return -1;
@@ -107,7 +125,11 @@ static int make_dump_request(debugger_action_t action, pid_t tid) {
}
int dump_backtrace_to_file(pid_t tid, int fd) {
- int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid);
+ return dump_backtrace_to_file_timeout(tid, fd, 0);
+}
+
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) {
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, timeout_secs);
if (sock_fd < 0) {
return -1;
}
@@ -127,7 +149,11 @@ int dump_backtrace_to_file(pid_t tid, int fd) {
}
int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
- int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid);
+ return dump_tombstone_timeout(tid, pathbuf, pathlen, 0);
+}
+
+int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs) {
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid, timeout_secs);
if (sock_fd < 0) {
return -1;
}
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 247ddd0..9cfb040 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -168,6 +168,11 @@ struct node {
__u32 refcount;
__u64 nid;
__u64 gen;
+ /*
+ * The inode number for this FUSE node. Note that this isn't stable across
+ * multiple invocations of the FUSE daemon.
+ */
+ __u32 ino;
/* State derived based on current position in hierarchy. */
perm_t perm;
@@ -224,6 +229,25 @@ struct fuse {
struct node root;
char obbpath[PATH_MAX];
+ /* Used to allocate unique inode numbers for fuse nodes. We use
+ * a simple counter based scheme where inode numbers from deleted
+ * nodes aren't reused. Note that inode allocations are not stable
+ * across multiple invocation of the sdcard daemon, but that shouldn't
+ * be a huge problem in practice.
+ *
+ * Note that we restrict inodes to 32 bit unsigned integers to prevent
+ * truncation on 32 bit processes when unsigned long long stat.st_ino is
+ * assigned to an unsigned long ino_t type in an LP32 process.
+ *
+ * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
+ * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
+ * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
+ * in fs/fuse/inode.c).
+ *
+ * Accesses must be guarded by |lock|.
+ */
+ __u32 inode_ctr;
+
Hashmap* package_to_appid;
Hashmap* appid_with_rw;
};
@@ -387,7 +411,7 @@ static char* find_file_within(const char* path, const char* name,
static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
{
- attr->ino = node->nid;
+ attr->ino = node->ino;
attr->size = s->st_size;
attr->blocks = s->st_blocks;
attr->atime = s->st_atime;
@@ -575,6 +599,13 @@ struct node *create_node_locked(struct fuse* fuse,
struct node *node;
size_t namelen = strlen(name);
+ // Detect overflows in the inode counter. "4 billion nodes should be enough
+ // for everybody".
+ if (fuse->inode_ctr == 0) {
+ ERROR("No more inode numbers available");
+ return NULL;
+ }
+
node = calloc(1, sizeof(struct node));
if (!node) {
return NULL;
@@ -596,6 +627,7 @@ struct node *create_node_locked(struct fuse* fuse,
}
node->namelen = namelen;
node->nid = ptr_to_id(node);
+ node->ino = fuse->inode_ctr++;
node->gen = fuse->next_generation++;
derive_permissions_locked(fuse, parent, node);
@@ -700,6 +732,7 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
fuse->derive = derive;
fuse->split_perms = split_perms;
fuse->write_gid = write_gid;
+ fuse->inode_ctr = 1;
memset(&fuse->root, 0, sizeof(fuse->root));
fuse->root.nid = FUSE_ROOT_ID; /* 1 */