Loading drivers/staging/android/binder.c +201 −374 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <linux/proc_fs.h> #include <linux/rbtree.h> #include <linux/sched.h> #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/vmalloc.h> #include <linux/slab.h> Loading @@ -48,8 +49,22 @@ static struct binder_node *binder_context_mgr_node; static uid_t binder_context_mgr_uid = -1; static int binder_last_id; static int binder_read_proc_proc(char *page, char **start, off_t off, int count, int *eof, void *data); #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ { \ return single_open(file, binder_##name##_show, PDE(inode)->data); \ } \ \ static const struct file_operations binder_##name##_fops = { \ .owner = THIS_MODULE, \ .open = binder_##name##_open, \ .read = seq_read, \ .llseek = seq_lseek, \ .release = single_release, \ } static int binder_proc_show(struct seq_file *m, void *unused); BINDER_DEBUG_ENTRY(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K Loading Loading @@ -2880,9 +2895,9 @@ static int binder_open(struct inode *nodp, struct file *filp) char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); remove_proc_entry(strbuf, binder_proc_dir_entry_proc); create_proc_read_entry(strbuf, S_IRUGO, proc_create_data(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); &binder_proc_fops, proc); } return 0; Loading Loading @@ -3105,47 +3120,39 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) mutex_unlock(&binder_deferred_lock); } static char *print_binder_transaction(char *buf, char *end, const char *prefix, static void print_binder_transaction(struct seq_file *m, const char *prefix, struct binder_transaction *t) { buf += snprintf(buf, end - buf, "%s %d: %p from %d:%d to %d:%d code %x " "flags %x pri %ld r%d", seq_printf(m, "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, t->to_proc ? t->to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, t->code, t->flags, t->priority, t->need_reply); if (buf >= end) return buf; if (t->buffer == NULL) { buf += snprintf(buf, end - buf, " buffer free\n"); return buf; seq_puts(m, " buffer free\n"); return; } if (t->buffer->target_node) { buf += snprintf(buf, end - buf, " node %d", if (t->buffer->target_node) seq_printf(m, " node %d", t->buffer->target_node->debug_id); if (buf >= end) return buf; } buf += snprintf(buf, end - buf, " size %zd:%zd data %p\n", seq_printf(m, " size %zd:%zd data %p\n", t->buffer->data_size, t->buffer->offsets_size, t->buffer->data); return buf; } static char *print_binder_buffer(char *buf, char *end, const char *prefix, static void print_binder_buffer(struct seq_file *m, const char *prefix, struct binder_buffer *buffer) { buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n", seq_printf(m, "%s %d: %p size %zd:%zd %s\n", prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, buffer->transaction ? "active" : "delivered"); return buf; } static char *print_binder_work(char *buf, char *end, const char *prefix, static void print_binder_work(struct seq_file *m, const char *prefix, const char *transaction_prefix, struct binder_work *w) { Loading @@ -3155,79 +3162,65 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); buf = print_binder_transaction(buf, end, transaction_prefix, t); print_binder_transaction(m, transaction_prefix, t); break; case BINDER_WORK_TRANSACTION_COMPLETE: buf += snprintf(buf, end - buf, "%stransaction complete\n", prefix); seq_printf(m, "%stransaction complete\n", prefix); break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n", prefix, node->debug_id, node->ptr, node->cookie); seq_printf(m, "%snode work %d: u%p c%p\n", prefix, node->debug_id, node->ptr, node->cookie); break; case BINDER_WORK_DEAD_BINDER: buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix); seq_printf(m, "%shas dead binder\n", prefix); break; case BINDER_WORK_DEAD_BINDER_AND_CLEAR: buf += snprintf(buf, end - buf, "%shas cleared dead binder\n", prefix); seq_printf(m, "%shas cleared dead binder\n", prefix); break; case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: buf += snprintf(buf, end - buf, "%shas cleared death notification\n", prefix); seq_printf(m, "%shas cleared death notification\n", prefix); break; default: buf += snprintf(buf, end - buf, "%sunknown work: type %d\n", prefix, w->type); seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); break; } return buf; } static char *print_binder_thread(char *buf, char *end, static void print_binder_thread(struct seq_file *m, struct binder_thread *thread, int print_always) { struct binder_transaction *t; struct binder_work *w; char *start_buf = buf; char *header_buf; size_t start_pos = m->count; size_t header_pos; buf += snprintf(buf, end - buf, " thread %d: l %02x\n", thread->pid, thread->looper); header_buf = buf; seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); header_pos = m->count; t = thread->transaction_stack; while (t) { if (buf >= end) break; if (t->from == thread) { buf = print_binder_transaction(buf, end, print_binder_transaction(m, " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { buf = print_binder_transaction(buf, end, print_binder_transaction(m, " incoming transaction", t); t = t->to_parent; } else { buf = print_binder_transaction(buf, end, " bad transaction", t); print_binder_transaction(m, " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", " pending transaction", w); print_binder_work(m, " ", " pending transaction", w); } if (!print_always && buf == header_buf) buf = start_buf; return buf; if (!print_always && m->count == header_pos) m->count = start_pos; } static char *print_binder_node(char *buf, char *end, struct binder_node *node) static void print_binder_node(struct seq_file *m, struct binder_node *node) { struct binder_ref *ref; struct hlist_node *pos; Loading @@ -3238,100 +3231,67 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node) hlist_for_each_entry(ref, pos, &node->refs, node_entry) count++; buf += snprintf(buf, end - buf, " node %d: u%p c%p hs %d hw %d ls %d lw %d " "is %d iw %d", seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", node->debug_id, node->ptr, node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); if (buf >= end) return buf; if (count) { buf += snprintf(buf, end - buf, " proc"); if (buf >= end) return buf; hlist_for_each_entry(ref, pos, &node->refs, node_entry) { buf += snprintf(buf, end - buf, " %d", ref->proc->pid); if (buf >= end) return buf; } seq_puts(m, " proc"); hlist_for_each_entry(ref, pos, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } buf += snprintf(buf, end - buf, "\n"); list_for_each_entry(w, &node->async_todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", seq_puts(m, "\n"); list_for_each_entry(w, &node->async_todo, entry) print_binder_work(m, " ", " pending async transaction", w); } return buf; } static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref) static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { buf += snprintf(buf, end - buf, " ref %d: desc %d %snode %d s %d w %d d %p\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); return buf; seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); } static char *print_binder_proc(char *buf, char *end, static void print_binder_proc(struct seq_file *m, struct binder_proc *proc, int print_all) { struct binder_work *w; struct rb_node *n; char *start_buf = buf; char *header_buf; size_t start_pos = m->count; size_t header_pos; buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); header_buf = buf; seq_printf(m, "proc %d\n", proc->pid); header_pos = m->count; for (n = rb_first(&proc->threads); n != NULL && buf < end; n = rb_next(n)) buf = print_binder_thread(buf, end, rb_entry(n, struct binder_thread, for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) print_binder_thread(m, rb_entry(n, struct binder_thread, rb_node), print_all); for (n = rb_first(&proc->nodes); n != NULL && buf < end; n = rb_next(n)) { for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); if (print_all || node->has_async_transaction) buf = print_binder_node(buf, end, node); print_binder_node(m, node); } if (print_all) { for (n = rb_first(&proc->refs_by_desc); n != NULL && buf < end; n != NULL; n = rb_next(n)) buf = print_binder_ref(buf, end, rb_entry(n, struct binder_ref, print_binder_ref(m, rb_entry(n, struct binder_ref, rb_node_desc)); } for (n = rb_first(&proc->allocated_buffers); n != NULL && buf < end; n = rb_next(n)) buf = print_binder_buffer(buf, end, " buffer", rb_entry(n, struct binder_buffer, rb_node)); list_for_each_entry(w, &proc->todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", " pending transaction", w); } for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) print_binder_buffer(m, " buffer", rb_entry(n, struct binder_buffer, rb_node)); list_for_each_entry(w, &proc->todo, entry) print_binder_work(m, " ", " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { if (buf >= end) break; buf += snprintf(buf, end - buf, " has delivered dead binder\n"); seq_puts(m, " has delivered dead binder\n"); break; } if (!print_all && buf == header_buf) buf = start_buf; return buf; if (!print_all && m->count == header_pos) m->count = start_pos; } static const char *binder_return_strings[] = { Loading Loading @@ -3385,7 +3345,7 @@ static const char *binder_objstat_strings[] = { "transaction_complete" }; static char *print_binder_stats(char *buf, char *end, const char *prefix, static void print_binder_stats(struct seq_file *m, const char *prefix, struct binder_stats *stats) { int i; Loading @@ -3394,21 +3354,16 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { if (stats->bc[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, binder_command_strings[i], stats->bc[i]); if (buf >= end) return buf; seq_printf(m, "%s%s: %d\n", prefix, binder_command_strings[i], stats->bc[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { if (stats->br[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, seq_printf(m, "%s%s: %d\n", prefix, binder_return_strings[i], stats->br[i]); if (buf >= end) return buf; } BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != Loading @@ -3417,47 +3372,34 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { if (stats->obj_created[i] || stats->obj_deleted[i]) buf += snprintf(buf, end - buf, "%s%s: active %d total %d\n", prefix, seq_printf(m, "%s%s: active %d total %d\n", prefix, binder_objstat_strings[i], stats->obj_created[i] - stats->obj_deleted[i], stats->obj_created[i] - stats->obj_deleted[i], stats->obj_created[i]); if (buf >= end) return buf; } return buf; } static char *print_binder_proc_stats(char *buf, char *end, static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; struct rb_node *n; int count, strong, weak; buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); if (buf >= end) return buf; seq_printf(m, "proc %d\n", proc->pid); count = 0; for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " threads: %d\n", count); if (buf >= end) return buf; buf += snprintf(buf, end - buf, " requested threads: %d+%d/%d\n" seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, proc->ready_threads, proc->free_async_space); if (buf >= end) return buf; count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " nodes: %d\n", count); if (buf >= end) return buf; seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; Loading @@ -3468,17 +3410,12 @@ static char *print_binder_proc_stats(char *buf, char *end, strong += ref->strong; weak += ref->weak; } buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", count, strong, weak); if (buf >= end) return buf; seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); count = 0; for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " buffers: %d\n", count); if (buf >= end) return buf; seq_printf(m, " buffers: %d\n", count); count = 0; list_for_each_entry(w, &proc->todo, entry) { Loading @@ -3490,222 +3427,110 @@ static char *print_binder_proc_stats(char *buf, char *end, break; } } buf += snprintf(buf, end - buf, " pending transactions: %d\n", count); if (buf >= end) return buf; buf = print_binder_stats(buf, end, " ", &proc->stats); seq_printf(m, " pending transactions: %d\n", count); return buf; print_binder_stats(m, " ", &proc->stats); } static int binder_read_proc_state(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; struct binder_node *node; int len = 0; char *buf = page; char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); buf += snprintf(buf, end - buf, "binder state:\n"); seq_puts(m, "binder state:\n"); if (!hlist_empty(&binder_dead_nodes)) buf += snprintf(buf, end - buf, "dead nodes:\n"); hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) { if (buf >= end) break; buf = print_binder_node(buf, end, node); } seq_puts(m, "dead nodes:\n"); hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) print_binder_node(m, node); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (buf >= end) break; buf = print_binder_proc(buf, end, proc, 1); } hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); if (buf > page + PAGE_SIZE) buf = page + PAGE_SIZE; *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_stats(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; int len = 0; char *p = page; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); p += snprintf(p, PAGE_SIZE, "binder stats:\n"); seq_puts(m, "binder stats:\n"); p = print_binder_stats(p, page + PAGE_SIZE, "", &binder_stats); print_binder_stats(m, "", &binder_stats); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (p >= page + PAGE_SIZE) break; p = print_binder_proc_stats(p, page + PAGE_SIZE, proc); } hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc_stats(m, proc); if (do_lock) mutex_unlock(&binder_lock); if (p > page + PAGE_SIZE) p = page + PAGE_SIZE; *start = page + off; len = p - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_transactions(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; int len = 0; char *buf = page; char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); buf += snprintf(buf, end - buf, "binder transactions:\n"); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (buf >= end) break; buf = print_binder_proc(buf, end, proc, 0); } seq_puts(m, "binder transactions:\n"); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 0); if (do_lock) mutex_unlock(&binder_lock); if (buf > page + PAGE_SIZE) buf = page + PAGE_SIZE; *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_proc(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_proc_show(struct seq_file *m, void *unused) { struct binder_proc *proc = data; int len = 0; char *p = page; struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); p += snprintf(p, PAGE_SIZE, "binder proc state:\n"); p = print_binder_proc(p, page + PAGE_SIZE, proc, 1); seq_puts(m, "binder proc state:\n"); print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); if (p > page + PAGE_SIZE) p = page + PAGE_SIZE; *start = page + off; len = p - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static char *print_binder_transaction_log_entry(char *buf, char *end, static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { buf += snprintf(buf, end - buf, "%d: %s from %d:%d to %d:%d node %d handle %d " "size %d:%d\n", seq_printf(m, "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->to_node, e->target_handle, e->data_size, e->offsets_size); return buf; } static int binder_read_proc_transaction_log( char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = data; int len = 0; struct binder_transaction_log *log = m->private; int i; char *buf = page; char *end = page + PAGE_SIZE; if (off) return 0; if (log->full) { for (i = log->next; i < ARRAY_SIZE(log->entry); i++) { if (buf >= end) break; buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); } } for (i = 0; i < log->next; i++) { if (buf >= end) break; buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); for (i = log->next; i < ARRAY_SIZE(log->entry); i++) print_binder_transaction_log_entry(m, &log->entry[i]); } *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; for (i = 0; i < log->next; i++) print_binder_transaction_log_entry(m, &log->entry[i]); return 0; } static const struct file_operations binder_fops = { Loading @@ -3724,6 +3549,11 @@ static struct miscdevice binder_miscdev = { .fops = &binder_fops }; BINDER_DEBUG_ENTRY(state); BINDER_DEBUG_ENTRY(stats); BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); static int __init binder_init(void) { int ret; Loading @@ -3734,30 +3564,27 @@ static int __init binder_init(void) binder_proc_dir_entry_root); ret = misc_register(&binder_miscdev); if (binder_proc_dir_entry_root) { create_proc_read_entry("state", proc_create("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL); create_proc_read_entry("stats", &binder_state_fops); proc_create("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL); create_proc_read_entry("transactions", &binder_stats_fops); proc_create("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL); create_proc_read_entry("transaction_log", &binder_transactions_fops); proc_create_data("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_fops, &binder_transaction_log); create_proc_read_entry("failed_transaction_log", proc_create_data("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_fops, &binder_transaction_log_failed); } return ret; Loading Loading
drivers/staging/android/binder.c +201 −374 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <linux/proc_fs.h> #include <linux/rbtree.h> #include <linux/sched.h> #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/vmalloc.h> #include <linux/slab.h> Loading @@ -48,8 +49,22 @@ static struct binder_node *binder_context_mgr_node; static uid_t binder_context_mgr_uid = -1; static int binder_last_id; static int binder_read_proc_proc(char *page, char **start, off_t off, int count, int *eof, void *data); #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ { \ return single_open(file, binder_##name##_show, PDE(inode)->data); \ } \ \ static const struct file_operations binder_##name##_fops = { \ .owner = THIS_MODULE, \ .open = binder_##name##_open, \ .read = seq_read, \ .llseek = seq_lseek, \ .release = single_release, \ } static int binder_proc_show(struct seq_file *m, void *unused); BINDER_DEBUG_ENTRY(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K Loading Loading @@ -2880,9 +2895,9 @@ static int binder_open(struct inode *nodp, struct file *filp) char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); remove_proc_entry(strbuf, binder_proc_dir_entry_proc); create_proc_read_entry(strbuf, S_IRUGO, proc_create_data(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); &binder_proc_fops, proc); } return 0; Loading Loading @@ -3105,47 +3120,39 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) mutex_unlock(&binder_deferred_lock); } static char *print_binder_transaction(char *buf, char *end, const char *prefix, static void print_binder_transaction(struct seq_file *m, const char *prefix, struct binder_transaction *t) { buf += snprintf(buf, end - buf, "%s %d: %p from %d:%d to %d:%d code %x " "flags %x pri %ld r%d", seq_printf(m, "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, t->to_proc ? t->to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, t->code, t->flags, t->priority, t->need_reply); if (buf >= end) return buf; if (t->buffer == NULL) { buf += snprintf(buf, end - buf, " buffer free\n"); return buf; seq_puts(m, " buffer free\n"); return; } if (t->buffer->target_node) { buf += snprintf(buf, end - buf, " node %d", if (t->buffer->target_node) seq_printf(m, " node %d", t->buffer->target_node->debug_id); if (buf >= end) return buf; } buf += snprintf(buf, end - buf, " size %zd:%zd data %p\n", seq_printf(m, " size %zd:%zd data %p\n", t->buffer->data_size, t->buffer->offsets_size, t->buffer->data); return buf; } static char *print_binder_buffer(char *buf, char *end, const char *prefix, static void print_binder_buffer(struct seq_file *m, const char *prefix, struct binder_buffer *buffer) { buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n", seq_printf(m, "%s %d: %p size %zd:%zd %s\n", prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, buffer->transaction ? "active" : "delivered"); return buf; } static char *print_binder_work(char *buf, char *end, const char *prefix, static void print_binder_work(struct seq_file *m, const char *prefix, const char *transaction_prefix, struct binder_work *w) { Loading @@ -3155,79 +3162,65 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); buf = print_binder_transaction(buf, end, transaction_prefix, t); print_binder_transaction(m, transaction_prefix, t); break; case BINDER_WORK_TRANSACTION_COMPLETE: buf += snprintf(buf, end - buf, "%stransaction complete\n", prefix); seq_printf(m, "%stransaction complete\n", prefix); break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n", prefix, node->debug_id, node->ptr, node->cookie); seq_printf(m, "%snode work %d: u%p c%p\n", prefix, node->debug_id, node->ptr, node->cookie); break; case BINDER_WORK_DEAD_BINDER: buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix); seq_printf(m, "%shas dead binder\n", prefix); break; case BINDER_WORK_DEAD_BINDER_AND_CLEAR: buf += snprintf(buf, end - buf, "%shas cleared dead binder\n", prefix); seq_printf(m, "%shas cleared dead binder\n", prefix); break; case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: buf += snprintf(buf, end - buf, "%shas cleared death notification\n", prefix); seq_printf(m, "%shas cleared death notification\n", prefix); break; default: buf += snprintf(buf, end - buf, "%sunknown work: type %d\n", prefix, w->type); seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); break; } return buf; } static char *print_binder_thread(char *buf, char *end, static void print_binder_thread(struct seq_file *m, struct binder_thread *thread, int print_always) { struct binder_transaction *t; struct binder_work *w; char *start_buf = buf; char *header_buf; size_t start_pos = m->count; size_t header_pos; buf += snprintf(buf, end - buf, " thread %d: l %02x\n", thread->pid, thread->looper); header_buf = buf; seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); header_pos = m->count; t = thread->transaction_stack; while (t) { if (buf >= end) break; if (t->from == thread) { buf = print_binder_transaction(buf, end, print_binder_transaction(m, " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { buf = print_binder_transaction(buf, end, print_binder_transaction(m, " incoming transaction", t); t = t->to_parent; } else { buf = print_binder_transaction(buf, end, " bad transaction", t); print_binder_transaction(m, " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", " pending transaction", w); print_binder_work(m, " ", " pending transaction", w); } if (!print_always && buf == header_buf) buf = start_buf; return buf; if (!print_always && m->count == header_pos) m->count = start_pos; } static char *print_binder_node(char *buf, char *end, struct binder_node *node) static void print_binder_node(struct seq_file *m, struct binder_node *node) { struct binder_ref *ref; struct hlist_node *pos; Loading @@ -3238,100 +3231,67 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node) hlist_for_each_entry(ref, pos, &node->refs, node_entry) count++; buf += snprintf(buf, end - buf, " node %d: u%p c%p hs %d hw %d ls %d lw %d " "is %d iw %d", seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", node->debug_id, node->ptr, node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); if (buf >= end) return buf; if (count) { buf += snprintf(buf, end - buf, " proc"); if (buf >= end) return buf; hlist_for_each_entry(ref, pos, &node->refs, node_entry) { buf += snprintf(buf, end - buf, " %d", ref->proc->pid); if (buf >= end) return buf; } seq_puts(m, " proc"); hlist_for_each_entry(ref, pos, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } buf += snprintf(buf, end - buf, "\n"); list_for_each_entry(w, &node->async_todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", seq_puts(m, "\n"); list_for_each_entry(w, &node->async_todo, entry) print_binder_work(m, " ", " pending async transaction", w); } return buf; } static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref) static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { buf += snprintf(buf, end - buf, " ref %d: desc %d %snode %d s %d w %d d %p\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); return buf; seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); } static char *print_binder_proc(char *buf, char *end, static void print_binder_proc(struct seq_file *m, struct binder_proc *proc, int print_all) { struct binder_work *w; struct rb_node *n; char *start_buf = buf; char *header_buf; size_t start_pos = m->count; size_t header_pos; buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); header_buf = buf; seq_printf(m, "proc %d\n", proc->pid); header_pos = m->count; for (n = rb_first(&proc->threads); n != NULL && buf < end; n = rb_next(n)) buf = print_binder_thread(buf, end, rb_entry(n, struct binder_thread, for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) print_binder_thread(m, rb_entry(n, struct binder_thread, rb_node), print_all); for (n = rb_first(&proc->nodes); n != NULL && buf < end; n = rb_next(n)) { for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); if (print_all || node->has_async_transaction) buf = print_binder_node(buf, end, node); print_binder_node(m, node); } if (print_all) { for (n = rb_first(&proc->refs_by_desc); n != NULL && buf < end; n != NULL; n = rb_next(n)) buf = print_binder_ref(buf, end, rb_entry(n, struct binder_ref, print_binder_ref(m, rb_entry(n, struct binder_ref, rb_node_desc)); } for (n = rb_first(&proc->allocated_buffers); n != NULL && buf < end; n = rb_next(n)) buf = print_binder_buffer(buf, end, " buffer", rb_entry(n, struct binder_buffer, rb_node)); list_for_each_entry(w, &proc->todo, entry) { if (buf >= end) break; buf = print_binder_work(buf, end, " ", " pending transaction", w); } for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) print_binder_buffer(m, " buffer", rb_entry(n, struct binder_buffer, rb_node)); list_for_each_entry(w, &proc->todo, entry) print_binder_work(m, " ", " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { if (buf >= end) break; buf += snprintf(buf, end - buf, " has delivered dead binder\n"); seq_puts(m, " has delivered dead binder\n"); break; } if (!print_all && buf == header_buf) buf = start_buf; return buf; if (!print_all && m->count == header_pos) m->count = start_pos; } static const char *binder_return_strings[] = { Loading Loading @@ -3385,7 +3345,7 @@ static const char *binder_objstat_strings[] = { "transaction_complete" }; static char *print_binder_stats(char *buf, char *end, const char *prefix, static void print_binder_stats(struct seq_file *m, const char *prefix, struct binder_stats *stats) { int i; Loading @@ -3394,21 +3354,16 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { if (stats->bc[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, binder_command_strings[i], stats->bc[i]); if (buf >= end) return buf; seq_printf(m, "%s%s: %d\n", prefix, binder_command_strings[i], stats->bc[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { if (stats->br[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, seq_printf(m, "%s%s: %d\n", prefix, binder_return_strings[i], stats->br[i]); if (buf >= end) return buf; } BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != Loading @@ -3417,47 +3372,34 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { if (stats->obj_created[i] || stats->obj_deleted[i]) buf += snprintf(buf, end - buf, "%s%s: active %d total %d\n", prefix, seq_printf(m, "%s%s: active %d total %d\n", prefix, binder_objstat_strings[i], stats->obj_created[i] - stats->obj_deleted[i], stats->obj_created[i] - stats->obj_deleted[i], stats->obj_created[i]); if (buf >= end) return buf; } return buf; } static char *print_binder_proc_stats(char *buf, char *end, static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; struct rb_node *n; int count, strong, weak; buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); if (buf >= end) return buf; seq_printf(m, "proc %d\n", proc->pid); count = 0; for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " threads: %d\n", count); if (buf >= end) return buf; buf += snprintf(buf, end - buf, " requested threads: %d+%d/%d\n" seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, proc->ready_threads, proc->free_async_space); if (buf >= end) return buf; count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " nodes: %d\n", count); if (buf >= end) return buf; seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; Loading @@ -3468,17 +3410,12 @@ static char *print_binder_proc_stats(char *buf, char *end, strong += ref->strong; weak += ref->weak; } buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", count, strong, weak); if (buf >= end) return buf; seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); count = 0; for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) count++; buf += snprintf(buf, end - buf, " buffers: %d\n", count); if (buf >= end) return buf; seq_printf(m, " buffers: %d\n", count); count = 0; list_for_each_entry(w, &proc->todo, entry) { Loading @@ -3490,222 +3427,110 @@ static char *print_binder_proc_stats(char *buf, char *end, break; } } buf += snprintf(buf, end - buf, " pending transactions: %d\n", count); if (buf >= end) return buf; buf = print_binder_stats(buf, end, " ", &proc->stats); seq_printf(m, " pending transactions: %d\n", count); return buf; print_binder_stats(m, " ", &proc->stats); } static int binder_read_proc_state(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; struct binder_node *node; int len = 0; char *buf = page; char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); buf += snprintf(buf, end - buf, "binder state:\n"); seq_puts(m, "binder state:\n"); if (!hlist_empty(&binder_dead_nodes)) buf += snprintf(buf, end - buf, "dead nodes:\n"); hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) { if (buf >= end) break; buf = print_binder_node(buf, end, node); } seq_puts(m, "dead nodes:\n"); hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) print_binder_node(m, node); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (buf >= end) break; buf = print_binder_proc(buf, end, proc, 1); } hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); if (buf > page + PAGE_SIZE) buf = page + PAGE_SIZE; *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_stats(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; int len = 0; char *p = page; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); p += snprintf(p, PAGE_SIZE, "binder stats:\n"); seq_puts(m, "binder stats:\n"); p = print_binder_stats(p, page + PAGE_SIZE, "", &binder_stats); print_binder_stats(m, "", &binder_stats); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (p >= page + PAGE_SIZE) break; p = print_binder_proc_stats(p, page + PAGE_SIZE, proc); } hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc_stats(m, proc); if (do_lock) mutex_unlock(&binder_lock); if (p > page + PAGE_SIZE) p = page + PAGE_SIZE; *start = page + off; len = p - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_transactions(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; int len = 0; char *buf = page; char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); buf += snprintf(buf, end - buf, "binder transactions:\n"); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { if (buf >= end) break; buf = print_binder_proc(buf, end, proc, 0); } seq_puts(m, "binder transactions:\n"); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 0); if (do_lock) mutex_unlock(&binder_lock); if (buf > page + PAGE_SIZE) buf = page + PAGE_SIZE; *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static int binder_read_proc_proc(char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_proc_show(struct seq_file *m, void *unused) { struct binder_proc *proc = data; int len = 0; char *p = page; struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; if (off) return 0; if (do_lock) mutex_lock(&binder_lock); p += snprintf(p, PAGE_SIZE, "binder proc state:\n"); p = print_binder_proc(p, page + PAGE_SIZE, proc, 1); seq_puts(m, "binder proc state:\n"); print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); if (p > page + PAGE_SIZE) p = page + PAGE_SIZE; *start = page + off; len = p - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; return 0; } static char *print_binder_transaction_log_entry(char *buf, char *end, static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { buf += snprintf(buf, end - buf, "%d: %s from %d:%d to %d:%d node %d handle %d " "size %d:%d\n", seq_printf(m, "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->to_node, e->target_handle, e->data_size, e->offsets_size); return buf; } static int binder_read_proc_transaction_log( char *page, char **start, off_t off, int count, int *eof, void *data) static int binder_transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = data; int len = 0; struct binder_transaction_log *log = m->private; int i; char *buf = page; char *end = page + PAGE_SIZE; if (off) return 0; if (log->full) { for (i = log->next; i < ARRAY_SIZE(log->entry); i++) { if (buf >= end) break; buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); } } for (i = 0; i < log->next; i++) { if (buf >= end) break; buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); for (i = log->next; i < ARRAY_SIZE(log->entry); i++) print_binder_transaction_log_entry(m, &log->entry[i]); } *start = page + off; len = buf - page; if (len > off) len -= off; else len = 0; return len < count ? len : count; for (i = 0; i < log->next; i++) print_binder_transaction_log_entry(m, &log->entry[i]); return 0; } static const struct file_operations binder_fops = { Loading @@ -3724,6 +3549,11 @@ static struct miscdevice binder_miscdev = { .fops = &binder_fops }; BINDER_DEBUG_ENTRY(state); BINDER_DEBUG_ENTRY(stats); BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); static int __init binder_init(void) { int ret; Loading @@ -3734,30 +3564,27 @@ static int __init binder_init(void) binder_proc_dir_entry_root); ret = misc_register(&binder_miscdev); if (binder_proc_dir_entry_root) { create_proc_read_entry("state", proc_create("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL); create_proc_read_entry("stats", &binder_state_fops); proc_create("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL); create_proc_read_entry("transactions", &binder_stats_fops); proc_create("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL); create_proc_read_entry("transaction_log", &binder_transactions_fops); proc_create_data("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_fops, &binder_transaction_log); create_proc_read_entry("failed_transaction_log", proc_create_data("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_fops, &binder_transaction_log_failed); } return ret; Loading