在進行Binder debug或分析問題時,一般須要看一下當前的Binder狀態信息。Kernel經過SYS系統提供了一些文件節點供咱們讀取,它們位於/sys/kernel/debug/binder/,分別爲:node
要理解這些Debug信息,必須Binder驅動中相關的數據結構定義。這些信息幾乎涉及到驅動中全部的結構體,下面結合兩者看一下信息的具體內容。首先看一下Binder驅動最基本的數據結構binder_proc。Binder_proc是用於描述Binder進程的數據結構,一個進程只有一個binder_proc,其餘的結構體都會關聯到這個數據結構中。也就是說,經過binder_proc能夠查找到全部Binder進程相關的信息,如Binder線程,Binder引用,Binder內存等。cookie
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最開始記錄的時死亡的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數據結構和線程狀態定義以下。async
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實體的代理。oop
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傳輸數據。ui
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包含的Binder的統計信息,包括傳輸命令的統計,內部對象的統計等。開始輸出的是所有Binder的統計信息,以後按Binder進程逐個輸出統計信息。一個輸出示例以下,spa
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 |
這兩個文件節點提供了最近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中記錄了當前系統中全部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 */ }