在进行Binder debug或分析问题时,通常需要看一下当前的Binder状态信息。Kernel通过SYS系统提供了一些文件节点供我们读取,它们位于/sys/kernel/debug/binder/,分别为:
- State:当前Binder所有进程的状态。
- Stats:Binder传输的统计信息。
- Transactions:当前Binder所有进程的传输状态。
- transaction_log:最近的Binder传输。
- failed_transaction_log:最近失败的Binder传输。
要理解这些Debug信息,必须Binder驱动中相关的数据结构定义。这些信息几乎涉及到驱动中所有的结构体,下面结合二者看一下信息的具体内容。首先看一下Binder驱动最基本的数据结构binder_proc。Binder_proc是用于描述Binder进程的数据结构,一个进程只有一个binder_proc,其他的结构体都会关联到这个数据结构中。也就是说,通过binder_proc可以查找到所有Binder进程相关的信息,如Binder线程,Binder引用,Binder内存等。
struct binder_proc {
struct hlist_node proc_node; /* hlist节点,连接到全局队列binder_procs中 */
struct rb_root threads; /* Binder线程的红黑树 */
struct rb_root nodes; /* Binder实体的红黑树 */
struct rb_root refs_by_desc; /* Binder引用的红黑树,以handle为key */
struct rb_root refs_by_node; /* Binder引用的红黑树,以node地址为key */
int pid; /* 进程PID */
struct vm_area_struct *vma; /* 进程虚拟地址空间指针 */
struct mm_struct *vma_vm_mm; /* 进程内存结构 */
struct task_struct *tsk; /* 进程task结构 */
struct files_struct *files; /* 进程file结构 */
struct hlist_node deferred_work_node; /* hlist节点,连接到全局队列binder_deferred_list中,用于处理binder退出任务 */
int deferred_work; /* Binder defer flag,包括PUT_FILES,FLUSH,RELEASE */
void *buffer; /* Binder内存内核起始地址 */
ptrdiff_t user_buffer_offset; /* Binder内存用户与内核间的地址偏移量 */
struct list_head buffers; /* Binder buffer的队列 */
struct rb_root free_buffers; /* 空闲Binder buffer的红黑树 */
struct rb_root allocated_buffers; /* 已分配Binder buffer的红黑树 */
size_t free_async_space; /* 异步传输的可用空间 */
struct page **pages; /* 物理内存页 */
size_t buffer_size; /* Binder内存映射的大小 */
uint32_t buffer_free; /* Binder内存的可用空间 */
struct list_head todo; /* Binder进程的todo队列 */
wait_queue_head_t wait; /* Binder进程的等待队列 */
struct binder_stats stats; /* Binder统计信息 */
struct list_head delivered_death; /* Binder已分发的死亡通知 */
int max_threads; /* Binder进程的最大线程数 */
int requested_threads; /* 请求的线程数 */
int requested_threads_started; /* 已启动的请求线程数 */
int ready_threads; /* 准备就绪的线程数 */
long default_priority; /* 缺省优先级 */
struct dentry *debugfs_entry; /* debugfs入口 */
};
State
State最开始记录的时死亡的Binder(dead node)。因为这些Binder的进程已经死掉,它们当前不属于任何进程,所以将它们记录在一个全局的队列中(binder_dead_nodes)。死亡记录展示如下,
Dead nodes相关的数据结构为binder_node,binder_node代表着binder实体。进程中的binder_node由Proc的nodes红黑树管理,死亡的binder_node由全局的hlist binder_dead_nodes管理,还有一个全局binder_context_mgr_node用来记录system_server的binder_node。其定义如下,
struct binder_node {
int debug_id; /* binder node在驱动里的全局id,用于调试 */
struct binder_work work; /* binder工作队列。用于增加/删除binder,更新binder引用计数 */
union {
struct rb_node rb_node; /* Proc nodes红黑树的 rb_node */
struct hlist_node dead_node; /* 死亡的binder_node,当一个进程结束时,它的binder也被销毁。但如果其他进程还在引用它的binder,则binder node无法移除,成为dead node */
};
struct binder_proc *proc; /* binder node所属的进程 */
struct hlist_head refs; /* binder node引用的队列,用于遍历binder node的所有引用 */
int internal_strong_refs; /* binder node的外部强引用计数 */
int local_weak_refs; /* 驱动内部的binder弱引用计数 */
int local_strong_refs; /* 驱动内部的binder强引用计数 */
void __user *ptr; /* 用户空间指向binder的指针,用于索引 */
void __user *cookie; /* 用户空间的附加指针 */
unsigned has_strong_ref:1; /* 是否有强引用 */
unsigned pending_strong_ref:1; /* 是否有等待处理的强引用 */
unsigned has_weak_ref:1; /* 是否有弱引用 */
unsigned pending_weak_ref:1; /* 是否有等待处理的弱引用 */
unsigned has_async_transaction:1; /* 在Todo队列中是否有未完成的异步传输 */
unsigned accept_fds:1; /* 是否同意接受文件方式的binder*/
unsigned min_priority:8; /* 设置处理Binder请求的线程的最低优先级 */
struct list_head async_todo; /* 异步传输等待队列 */
}
Dead nodes信息后面跟着是当前系统中所有的Binder进程的信息,该信息包括:进程中Binder线程的状态,Binder实体信息,Binder引用信息,binder buffer信息。
线程状态显示了Binder进程中所有的Binder线程的PID和线程状态,binder_thread数据结构和线程状态定义如下。
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01, /* 注册线程(BC_REGISTER_LOOPER) */
BINDER_LOOPER_STATE_ENTERED = 0x02, /* 创建主线程(BC_ENTER_LOOPER) */
BINDER_LOOPER_STATE_EXITED = 0x04, /* 已退出 */
BINDER_LOOPER_STATE_INVALID = 0x08, /* 无效 */
BINDER_LOOPER_STATE_WAITING = 0x10, /* 等待中 */
BINDER_LOOPER_STATE_NEED_RETURN = 0x20 /* 需要返回 */
};
struct binder_thread {
struct binder_proc *proc; /* 线程所属的而进程 */
struct rb_node rb_node; /* 红黑树节点,插入到binder_proc->threads中 */
int pid; /* 线程PID */
int looper; /* 线程looper状态,用上面的枚举描述 */
struct binder_transaction *transaction_stack; /* Binder传输栈 */
struct list_head todo; /* Binder线程todo队列 */
uint32_t return_error; /* 写失败时的返回错误码 */
uint32_t return_error2; /* 写失败时的返回错误码2 */
wait_queue_head_t wait; /* Binder线程等待队列 */
struct binder_stats stats; /* Binder线程统计信息 */
};
然后是Binder进程中Binder实体的信息,解释参考Dead nodes。接着打印的是进程中Binder引用的信息,相关数据结构为binder_ref,用做Binder实体的代理。
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
int debug_id; /* 全局id,用于调试 */
struct rb_node rb_node_desc; /* 红黑树节点,用于binder_proc->refs_by_desc */
struct rb_node rb_node_node; /* 红黑树节点,用于binder_proc->refs_by_node */
struct hlist_node node_entry; /* hlist节点,用于binder_node->refs索引 */
struct binder_proc *proc; /* 指向的Binder 进程 */
struct binder_node *node; /* 指向的Binder实体 */
uint32_t desc; /* handle值 */
int strong; /* 强引用 */
int weak; /* 弱引用 */
struct binder_ref_death *death; /* 已注册的死亡通知地址 */
};
最后时Binder进程中Binder buffer的信息。相关数据结构为binder_buffer,用于存储Binder传输数据。
struct binder_buffer {
struct list_head entry; /* list节点,连接到binder_proc->buffers */
struct rb_node rb_node; /* 红黑树节点,插入到binder_proc->free_buffers(buffer空闲时)或binder_proc->allocated_buffers(buffer已分配时) */
unsigned free:1; /* 是否空闲 */
unsigned allow_user_free:1; /* 是否允许用户释放 */
unsigned async_transaction:1; /* 是否为异步传输 */
unsigned debug_id:29; /* 全局id,用于调试 */
struct binder_transaction *transaction; /* 指向的Binder传输事务 */
struct binder_node *target_node; /* 指向的Binder实体 */
size_t data_size; /* 数据大小 */
size_t offsets_size; /* 数据偏移量 */
uint8_t data[0]; /* 数据地址 */
}
Stats
Stats包含的Binder的统计信息,包括传输命令的统计,内部对象的统计等。开始输出的是全部Binder的统计信息,之后按Binder进程逐个输出统计信息。一个输出示例如下,
Binder统计信息通过binder_stats来表示,
struct binder_stats {
int br[_IOC_NR(BR_FAILED_REPLY) + 1]; /* Binder 返回命令的计数 (Binder Driver Return Protocol)*/
int bc[_IOC_NR(BC_DEAD_BINDER_DONE) + 1]; /* Binder 写命令的计数 (Binder Driver Command Protocol)*/
int obj_created[BINDER_STAT_COUNT]; /* Binder 内部对象的计数,创建时加1 */
int obj_deleted[BINDER_STAT_COUNT]; /* Binder 内部对象的计数,删除时加1 */
};
以BC_开头的命令为应用层向Binder驱动发送的请求命令,定义如下,
Cmd | Description | Args | Code |
---|---|---|---|
BC_TRANSACTION | Client向Server发送请求数据 | binder_transaction_data: the sent command | 10763886080x40286300 |
BC_REPLY | Server向Client发送回复(应答)数据 | binder_transaction_data: the sent command | 10763886090x40286301 |
BC_ACQUIRE_RESULT | 暂未实现 | --- | 10740293140x40046302 |
BC_FREE_BUFFER | 释放一块映射的内存。 | void *: ptr to transaction data received on a read | 10740293150x40046303 |
BC_INCREFS | 增加Binder的弱引用计数 | int: descriptor | 10740293160x40046304 |
BC_ACQUIRE | 增加Binder的强引用计数 | int: descriptor | 10740293170x40046305 |
BC_RELEASE | 减少Binder的强引用计数 | int: descriptor | 10740293180x40046306 |
BC_DECREFS | 减少Binder的弱引用计数 | int: descriptor | 10740293190x40046307 |
BC_INCREFS_DONE | Binde实体所在的进程处理完BC_INCREFS的反馈 | void : ptr to bindervoid : cookie | 10742914640x40086308 |
BC_ACQUIRE_DONE | Binde实体所在的进程处理完BC_ACQUIRE的反馈 | void : ptr to bindervoid : cookie | 10742914650x40086309 |
BC_ATTEMPT_ACQUIRE | 暂未实现 | --- | 10742914660x4008630a |
BC_REGISTER_LOOPER | 通知驱动线程池中一个线程已经创建 | --- | 253550x630b |
BC_ENTER_LOOPER | 通知驱动该线程已经进入主循环,可以接收数据 | --- | 253560x630c |
BC_EXIT_LOOPER | 通知驱动该线程退出主循环,不再接收数据 | --- | 253570x630d |
BC_REQUEST_DEATH_NOTIFICATION | Binder引用的进程要求获得Binder的实体死亡通知 | void : ptr to bindervoid : cookie | 10742914700x4008630e |
BC_CLEAR_DEATH_NOTIFICATION | 清除获得Binder的实体死亡通知 | void : ptr to bindervoid : cookie | 10742914710x4008630f |
BC_DEAD_BINDER_DONE | 收到实体死亡通知书的进程在删除引用后用本命令告知驱动 | void *: cookie | 10740293280x40046310 |
以BR_开头的命令为Binder驱动向应用层发送的回复命令,定义如下,
Cmd | Description | Args | Code |
---|---|---|---|
BR_ERROR | 发生内部错误(如内存分配失败) | int: error code | 21477749760x80047200 |
BR_OK | 操作完成 | --- | 291850x7201 |
BR_TRANSACTION | 对应发送方的BC_TRANSACTION | binder_transaction_data: the received command | 21501342740x80287202 |
BR_REPLY | 对应发送方的BC_REPLY | binder_transaction_data: the received command | 21501342750x80287203 |
BR_ACQUIRE_RESULT | 暂未实现 | --- | 21477749800x80047204 |
BR_DEAD_REPLY | 交互过程中如果发现对方进程或线程已经死亡则返回该消息 | --- | 291890x7205 |
BR_TRANSACTION_COMPLETE | 接收方发送该消息作为BC_TRANSACTION或BC_REPLY发送成功的反馈 | --- | 291900x7206 |
BR_INCREFS | 增加Binder本地对象的弱引用计数 | void : ptr to bindervoid : cookie for binder | 21480371270x80287207 |
BR_ACQUIRE | 增加Binder本地对象的强引用计数 | void : ptr to bindervoid : cookie for binder | 21480371280x80287208 |
BR_RELEASE | 减少Binder本地对象的强引用计数 | void : ptr to bindervoid : cookie for binder | 21480371290x80287209 |
BR_DECREFS | 减少Binder本地对象的弱引用计数 | void : ptr to bindervoid : cookie for binder | 21480371300x8028720a |
BR_ACQUIRE_RESULT | 暂未实现 | --- | 21482992750x800c720b |
BR_NOOP | 不做事情, | --- | 291960x720c |
BR_SPAWN_LOOPER | 驱动发现接收方所有线程都处于忙碌状态,向接收方发送该命令要求创建更多线程以备接收数据 | --- | 291970x720d |
BR_FINISHED | 暂未实现 | --- | 291980x720e |
BR_DEAD_BINDER | 向获得Binder引用的进程发送Binder实体死亡通知 | void **cookie | 21477749910x8004720f |
BR_CLEAR_DEATH_NOTIFICATION_DONE | 死亡通知清除完成 | void **cookie | 21477749920x80047210 |
BR_FAILED_REPLY | 如果发送非法引用号则返回该消息 | --- | 292010x7211 |
transaction_log和failed_transaction_log
这两个文件节点提供了最近32次成功与失败的传输记录,输出信息大致相同。
相关的数据结构为binder_transaction_log_entry。这个结构体做为Binder传输的描述,每次发起Binder传输时记录到全局结构体中,用于debug。
struct binder_transaction_log_entry {
int debug_id; /* transaction log ID */
int call_type; /* 传输类型,0:call, 1:async, 2:replay */
int from_proc; /* 发起传输的进程 PID*/
int from_thread; /* 发起传输的线程 PID */
int target_handle; /* Binder实体的引用, 接收时为-1 */
int to_proc; /* 处理传输的进程 PID*/
int to_thread; /* 处理传输的线程 PID,如果不存在值为0 */
int to_node; /* 处理传输的Binder node ID */
int data_size; /* 传输数据的长度 */
int offsets_size; /* 传输数据的偏移量 */
};
struct binder_transaction_log {
int next; /* 传输log计数 */
int full; /* 传输log是否已满 */
struct binder_transaction_log_entry entry[32]; /* 传输log记录 */
};
static struct binder_transaction_log binder_transaction_log;
static struct binder_transaction_log binder_transaction_log_failed;
Transactions
Transactions中记录了当前系统中所有Binder进程的传输状态,一个输出示例如下,
这个输出信息中包含许多数据结构里的内容,buffer信息与binder_buffer相关,thread信息与binder_thread相关,还有一个最重要的传输事件是由binder_transaction来描述的。
struct binder_work {
struct list_head entry; /* 工作队列节点 */
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
} type;
};
......
struct binder_transaction {
int debug_id; /* 全局ID,用于调试 */
struct binder_work work; /* 传输的工作类型 */
struct binder_thread *from; /* 传输发送端线程 */
struct binder_transaction *from_parent; /* 发送端传输事件 */
struct binder_proc *to_proc; /* 传输接收端进程 */
struct binder_thread *to_thread; /* 传输接收端线程 */
struct binder_transaction *to_parent; /* 接收端传输事件 */
unsigned need_reply:1; /* 是否需要回复 */
/* unsigned is_dead:1; */ /* not used at the moment */
struct binder_buffer *buffer; /* 传输数据的buffer */
unsigned int code; /* 传输的命令码 */
unsigned int flags; /* 传输标识,例如TF_ONE_WAY */
long priority; /* 传输优先级 */
long saved_priority; /* 传输缺省优先级 */
kuid_t sender_euid; /* 发送端的uid */
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。