Commit 5249f488 authored by Arve Hjønnevåg's avatar Arve Hjønnevåg Committed by Greg Kroah-Hartman

binder: Use seq_file for debug interface.

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