1、結構體binder_work
2、結構體binder_thread
3、構體binder_stats
4、結構體binder_proc
5、結構體binder_node
6、結構體binder_ref
7、結構體binder_ref_death
8、結構體binder_state
9、結構體binder_buffer
10、結構體binder_transaction
11、結構體binder_transaction_data
12、結構體transaction_flags
13、結構體flat_binder_object
14、結構體binder_write_read
15、結構體binder_ptr_cookie
16、總結
1 結構體binder_work
1.1 位置
位置在
Linux的binder.c 240行
1.2 代碼注釋
binder_work代表binder驅動中進程要處理的工作項
struct binder_work {
struct list_head entry; //用于實現一個雙向鏈表,存儲的所有binder_work隊列
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; //描述工作項的類型
};
2 結構體binder_thread
2.1 代碼位置
位置在
Linux的binder.c 368行
2.2 代碼注釋
binder_thread 代表Binder線程池中的每個線程信息
struct binder_thread {
//宿主進程,即線程屬于那么Binder進程
struct binder_proc *proc;
//紅黑樹的一個節點,binder_proc使用紅黑樹來組織Binder線程池中的線程
struct rb_node rb_node;
// 當前線程的PID
int pid;
// 當前線程的狀態信息
int looper;
//事務堆棧,將事務封裝成binder_transaction,添加到事務堆棧中,
//定義了要接收和發送的進程和線程消息
struct binder_transaction *transaction_stack;
//隊列,當有來自Client請求時,將會添加到to_do隊列中
struct list_head todo;
// 記錄閱讀buf事務時出現異常錯誤情況信息
uint32_t return_error; /* Write failed, return error code in read buf */
// 記錄閱讀事務時出現異常錯誤情況信息
uint32_t return_error2; /* Write failed, return error code in read */
/* buffer. Used when sending a reply to a dead process that */
/* we are also waiting on */
// 等待隊列,當Binder處理事務A依賴于其他Binder線程處理事務B的情況
// 則會在sleep在wait所描述的等待隊列中,知道B事物處理完畢再喚醒
wait_queue_head_t wait;
// Binder線程相關統計數據
struct binder_stats stats;
};
這里面說下上面looper對應的值
enum {
// Binder驅動 請求創建該線程,通過BC_REGISTER_LOOPER協議通知
//Binder驅動,注冊成功設置此狀態
BINDER_LOOPER_STATE_REGISTERED = 0x01,
//該線程是應用程序主動注冊的 通過 BC_ENTER_LOOPER 協議
BINDER_LOOPER_STATE_ENTERED = 0x02,
// Binder線程退出
BINDER_LOOPER_STATE_EXITED = 0x04,
// Binder線程處于無效
BINDER_LOOPER_STATE_INVALID = 0x08,
// Binder線程處于空閑狀態
BINDER_LOOPER_STATE_WAITING = 0x10,
// Binder線程處于需要返回用戶控件
// 使用場景是:1、線程注冊為Binder線程后,還沒有準備好去處理進程間通信
//,需要返回用戶空間做其他初始化準備;2、調用flush來刷新Binder線程池
BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};
3 結構體binder_stats
binder_stats 代表d的是Binder線程相關統計數據
3.1 代碼位置
位置在
Linux的binder.c 173行
3.2 代碼注釋
struct binder_stats {
// 統計各個binder響應碼的個數
int br[_IOC_NR(BR_FAILED_REPLY) + 1];
// 統計各個binder請求碼的個數
int bc[_IOC_NR(BC_REPLY_SG) + 1];
// 統計各種obj創建的個數
int obj_created[BINDER_STAT_COUNT];
// 統計各種obj刪除個數
int obj_deleted[BINDER_STAT_COUNT];
};
4 結構體binder_proc
binder_proc 代表的是一個正在使用Binder進程通信的進程,binder_proc為管理其信息的記錄體,當一個進程open /dev/binder 時,Binder驅動程序會為其創建一個binder_proc結構體,用以記錄進程的所有相關信息,并把該結構體保存到一個全局的hash表中
4.1 代碼位置
位置在
Linux的binder.c 322行
4.2 代碼注釋
struct binder_proc {
/** 進程相關參數 */
//上述全局hash表中一個節點,用以標記該進程
struct hlist_node proc_node;
// 進程組ID
int pid;
// 任務控制模塊
struct task_struct *tsk;
// 文件結構體數組
struct files_struct *files;
/** Binder線程池每一個Binder進程都有一個線程池,由Binder驅動來維護,Binder線程池中所有線程由一個紅黑樹來組織,RB樹以線程ID為關鍵字 */
//上述紅黑樹的根節點
struct rb_root threads;
/** 一系列Binder實體對象(binder_node)和Binder引用對象(binder_ref) */
/** 在用戶控件:運行在Server端稱為Binder本地對象,運行在Client端稱為Binder代理對象*/
/** 在內核空間:Binder實體對象用來描述Binder本地對象,Binder引用對象來描述Binder代理對象 */
// Binder實體對象列表(RB樹),關鍵字 ptr
struct rb_root nodes;
// Binder引用對象,關鍵字 desc
struct rb_root refs_by_desc;
// Binder引用對象,關鍵字 node
struct rb_root refs_by_node;
// 這里有兩個引用對象,是為了方便快速查找
/** 進程可以調用ioctl注冊線程到Binder驅動程序中,當線程池中沒有足夠空閑線程來處理事務時,Binder驅動可以主動要求進程注冊更多的線程到Binder線程池中 */
// Binder驅動程序最多可以請求進程注冊線程的最大數量
int max_threads;
// Binder驅動每主動請求進程添加注冊一個線程的時候,requested_threads+1
int requested_threads;
// 進程響應Binder要求后,requested_thread_started+1,request_threads-1,表示Binder已經主動請求注冊的線程數目
int requested_threads_started;
// 進程當前空閑線程的數目
int ready_threads;
// 線程優先級,初始化為進程優先級
long default_priority;
//進程的整個虛擬地址空間
struct mm_struct *vma_vm_mm;
/** mmap 內核緩沖區*/
// mmap——分配的內核緩沖區 用戶控件地址(相較于buffer)
struct vm_area_struct *vma;
// mmap——分配內核緩沖區,內核空間地址(相交于vma) 兩者都是虛擬地址
void *buffer;
// mmap——buffer與vma之間的差值
ptrdiff_t user_buffer_offset;
/** buffer指向的內核緩沖區,被劃分為很多小塊進行性管理;這些小塊保存在列表中,buffer就是列表的頭部 */
// 內核緩沖列表
struct list_head buffers;
// 空閑的內存緩沖區(紅黑樹)
struct rb_root free_buffers;
// 正在使用的內存緩沖區(紅黑樹)
struct rb_root allocated_buffers;
// 當前可用來保存異步事物數據的內核緩沖區大小
size_t free_async_space;
// 對應用于vma 、buffer虛擬機地址,這里是他們對應的物理頁面
struct page **pages;
// 內核緩沖區大小
size_t buffer_size;
// 空閑內核緩沖區大小
uint32_t buffer_free;
/** 進程每接收到一個通信請求,Binder將其封裝成一個工作項,保存在待處理隊列to_do中 */
//待處理隊列
struct list_head todo;
// 等待隊列,存放一些睡眠的空閑Binder線程
wait_queue_head_t wait;
// hash表,保存進程中可以延遲執行的工作項
struct hlist_node deferred_work_node;
// 延遲工作項的具體類型
int deferred_work;
//統計進程相關數據,具體參考binder_stats結構體
struct binder_stats stats;
// 表示 Binder驅動程序正在向進程發出死亡通知
struct list_head delivered_death;
// 用于debug
struct dentry *debugfs_entry;
// 連接 存儲binder_node和binder_context_mgr_uid以及name
struct binder_context *context;
};
5 結構體binder_node
binder_node 代表的是Binder實體對象,每一個service組件或者ServiceManager在Binder驅動程序中的描述,Binder驅動通過強引用和弱引用來維護其生命周期,通過node找到空間的Service對象
5.1 代碼位置
位置在
Linux的binder.c 252行
5.2 代碼注釋
struct binder_node {
// debug調試用的
int debug_id;
struct binder_work work; //binder驅動中進程要處理的工作項
/** 每一個binder進程都由一個binder_proc來描述,binder進程內部所有Binder實體對象,
由一個紅黑樹來進行組織(struct rb_root nodes) ; rb_node 則對應nodes的一個節點 */
union {
//用于本節點連接紅黑樹
struct rb_node rb_node;
// 如果Binder 實體對象對應的進程死亡,銷毀節點時需要將rb_node從紅黑樹中刪除,
//如果本節點還沒有引用切斷,則用dead_node將其隔離到另一個鏈表中,
//直到通知所有進程切斷與該節點的引用后,該節點才能銷毀
struct hlist_node dead_node;
};
// 指向該Binder實體對象 對應的進程,進程由binder_proc描述
struct binder_proc *proc;
// 該 Binder實體對象可能同時被多個Client組件引用,所有指向本實體對象的引用都
//保存在這個hash隊列中refs表示隊列頭部;這些引用可能隸屬于不同進程,遍歷該
//hash表能夠得到這些Client組件引用了這些對象
struct hlist_head refs;
/** 引用計數
* 1、當一個Binder實體對象請求一個Service組件來執行Binder操作時。會增加該Service
* 組件的強/弱引用計數同時,Binder實體對象將會has_strong_ref與has_weak_ref置為1
*2、當一個Service組件完成一個Binder實體對象請求的操作后,Binder對象會請求減少該
* Service組件的強/弱引用計數
* 3、Binder實體對象在請求一個Service組件增加或減少強/弱引用計數的過程中,
* 會將pending_strong_ref和pending_weak_ref置為1,當Service組件完成增加
* 或減少計數時,Binder實體對象會將這兩個變量置為0
*/
//遠程強引用 計數
int internal_strong_refs; //實際上代表了一個binder_node與多少個binder_ref相關聯
//本地弱引用技數
int local_weak_refs;
//本地強引用計數
int local_strong_refs;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
/** 用來描述用戶控件中的一個Service組件 */
// 描述用戶控件的Service組件,對應Binder實體對應的Service在用戶控件的(BBinder)的引用
binder_uintptr_t ptr;
// 描述用戶空間的Service組件,Binder實體對應的Service在用戶控件的本地Binder(BBinder)地址
binder_uintptr_t cookie;
// 異步事務處理,單獨講解
unsigned has_async_transaction:1;
struct list_head async_todo;
// 表示該Binder實體對象能否接收含有該文件描述符的進程間通信數據。當一個進程向
//另一個進程發送數據中包含文件描述符時,Binder會在目標進程中打開一個相同的文件
//故設為accept_fds為0 可以防止源進程在目標進程中打開文件
unsigned accept_fds:1;
// 處理Binder請求的線程最低優先級
unsigned min_priority:8;
};
這里說下binder_proc和binder_node關系:
可以將binder_proc理解為一個進程,而將binder_noder理解為一個Service。binder_proc里面有一個紅黑樹,用來保存所有在它所描述的進程里面創建Service。而每一個Service在Binder驅動里面都有一個binder_node來描述。
5.3 異步事物處理
- 異步事務處理,目的在于為同步交互讓路,避免長時間阻塞發送送端
- 異步事務定義:(相對于同步事務)單向進程間通信要求,即不需要等待應答的進程間通信請求
- Binder驅動程序認為異步事務的優先級低于同步事務,則在同一時刻,一個Binder實體對象至多只有一個異步事物會得到處理。而同步事務則無此限制。
- Binder將事務保存在一個線程binder_thread的todo隊列中,表示由該線程來處理該事務。每一個事務都關聯Binder實體對象(union target),表示該事務的目標處理對象,表示要求該Binder實體對象對應的Service組件在制定線程中處理該事務,而如果Binder發現一個事務時異步事務,則會將其保存在目標Binder對象的async_todo的異步事務中等待處理
6 結構體binder_ref
binder_ref 代表的是Binder的引用對象,每一個Clinet組件在Binder驅動中都有一個Binder引用對象,用來描述它在內核中的狀態。
6.1 代碼位置
位置在
Linux的binder.c 281行
6.2 代碼注釋
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
//debug 調試用的
int debug_id;
/** binder_proc中使用紅黑樹(對應兩個rb_root變量) 來存儲器內部所有引用對象,
*下面的rb_node則是紅黑樹中的節點
*/
//Binder引用的宿主進程
struct binder_proc *proc;
//對應 refs_by_desc,以句柄desc索引 關聯到binder_proc->refs_by_desc紅黑樹
struct rb_node rb_node_desc;
//對應refs_by_node,以Binder實體對象地址作為關鍵字關聯到binder_proc->refs_by_node紅黑樹
struct rb_node rb_node_node;
/** Client通過Binder訪問Service時,僅需指定一個句柄,Binder通過該desc找到對應的binder_ref,
* 再根據該binder_ref中的node變量得到binder_node(實體對象),進而找到對應的Service組件
*/
// 對應Binder實體對象中(hlist_head) refs引用對象隊列中的一個節點
struct hlist_node node_entry;
// 引用對象所指向的Binder實體對象
struct binder_node *node;
// Binder引用的句柄值,Binder驅動為binder驅動引用分配一個唯一的int型整數(進程范圍內唯一)
// ,通過該值可以在binder_proc->refs_by_desc中找到Binder引用,進而可以找到Binder引用對應的Binder實體
uint32_t desc;
// 強引用 計數
int strong;
// 弱引用 計數
int weak;
// 表示Service組件接受到死亡通知
struct binder_ref_death *death;
};
7 結構體binder_ref_death
- binder_ref_death 一個死亡通知的結構體
- Client組件無法控制它所引用的Service組件的生命周期,由于Service組件所在的進程可能意外崩潰。
- Client進程需要能夠在它所引用的Service組件死亡時獲的通知,進而進行響應。則Client進程就需要向Binder驅動注冊一個用來接收死亡通知的對象地址(這里的cookie)
7.1 代碼位置
位置在
Linux的binder.c 276行
7.2 代碼注釋
struct binder_ref_death {
//標志該通知具體的死亡類型
struct binder_work work;
// 保存負責接收死亡通知的對象地址
binder_uintptr_t cookie;
};
這里隨帶說一下Binder驅動向Client進程發送死亡通知的情況:
- Binder驅動檢測到Service組件死亡時,會找到對應Serivce實體對象(binder_node),再通過refs變量找到引用它的所有Client進程(binder_ref),再通過death變量找到Client進程向Binder注冊的死亡通知接收地址;Binder將死亡通知binder_ref_death封裝成工作項,添加到Client進程to_do隊列中等待處理。這種情況binder_work類型為BINDER_WORK_DEAD_BINDER
- Client進程向Binder驅動注冊一個死亡接收通知時,如果它所引用的Service組件已經死亡,Binder會立即發送通知給Client進程。這種情況binder_work類型為BINDER_WORK_DEAD_BINDER
- 當Client進程向Binder驅動注銷一個死亡通知時,也會發送通知,來響應注銷結果
- ①當Client注銷時,Service組件還未死亡:Binder會找到之前Client注冊的binder_ref_death,當binder_work修改為BINDER_CLEAR_NOTIFICATION,并將通知按上述步驟添加到Client的to_do隊列中
- ②當Client注銷時,Service已經死亡,Binder同理將binder_work修改為WORK_DEAD_BINDER_AND_CLEAR,然后添加到todo中
8 結構體binder_state
binder_state 代表著binder設備文件的狀態
8.1 代碼位置
位置在
/frameworks/native/cmds/servicemanager/binder.c 89行
8.2 代碼注釋
struct binder_state
{
//打開 /dev/binder之后得到的文件描述符
int fd;
//mmap將設備文件映射到本地進程的地址空間,映射后的到地址空間中,映射后得到的地址空間地址,及大小。
void *mapped;
// 分配內存的大小,默認是128K
size_t mapsize;
};
9 結構體binder_buffer
- binder_buffer 內核緩沖區,用以在進程間傳遞數據。
- binder驅動程序管理這個內存映射地址空間方法,即管理buffer~(buffer+buffer_size)這段地址空間的,這個地址空間被劃分為一段一段來管理,每一段是結構體struct binder_buffer來描述。
- 每一個binder_buffer通過其成員entry從低到高地址連入到struct binder_proc中的buffers表示鏈表中去
9.1 代碼位置
位置在
Linux的binder.c 298行
9.2 代碼注釋
struct binder_buffer {
//entry對應內核緩沖區列表的buffers(內核緩沖區列表)
struct list_head entry; /* free and allocated entries by address */
//結合free,如果free=1,則rb_node對應free_buffers中一個節點(內核緩沖區)
//如果free!=1,則對應allocated_buffers中的一個節點
struct rb_node rb_node; /* free entry by size or allocated entry */
/* by address */
unsigned free:1;
/** Binder將事務數據保存到一個內核緩沖區(binder_transaction.buffer),然后交由Binder
* 實體對象(target_node) 處理,而target_node會將緩沖區的內容交給對應的Service組件
* (proc) 來處理,Service組件處理完事務后,若allow_user_free=1,則請求Binder釋放該
* 內核緩沖區
*/
unsigned allow_user_free:1;
// 描述一個內核緩沖區正在交給那個事務transaction,用以中轉請求和返回結果
struct binder_transaction *transaction;
// 描述該緩沖區正在被那個Binder實體對象使用
struct binder_node *target_node;
//表示事務時異步的;異步事務的內核緩沖區大小是受限的,這樣可以保證事務可以優先放到緩沖區
unsigned async_transaction:1;
//調試專用
unsigned debug_id:29;
/**
* 存儲通信數據,通信數據中有兩種類型數據:普通數據與Binder對象
* 在數據緩沖區最后,有一個偏移數組,記錄數據緩沖區中每一個Binder
* 對象在緩沖區的偏移地址
*/
// 數據緩沖區大小
size_t data_size;
// 偏移數組的大小(其實也是偏移位置)
size_t offsets_size;
// 用以保存通信數據,數據緩沖區,大小可變
uint8_t data[0];
// 額外緩沖區大小
size_t extra_buffers_size;
};
10 結構體binder_transaction
binder_transaction 描述Binder進程中通信過程,這個過程稱為一個transaction(事務),用以中轉請求和返回結果,并保存接受和要發送的進程信息
10.1 代碼位置
位置在
Linux的binder.c 383行
10.2 代碼注釋
struct binder_transaction {
//調試調用
int debug_id;
// 用來描述的處理的工作事項,這里會將type設置為BINDER_WORK_TRANSACTION,具體結構看binder_work
struct binder_work work;
/** 源線程 */
// 源線程,即發起事務的線程
struct binder_thread *from;
// 源線程的優先級
long priority;
//源 線程的用戶 ID
kuid_t sender_euid;
/** 目標線程*/
// 目標進程:處理該事務的進程
struct binder_proc *to_proc;
// 目標線程:處理該事務的線程
struct binder_thread *to_thread;
// 表示另一個事務要依賴事務(不一定要在同一個線程中)
struct binder_transaction *from_parent;
// 目標線程下一個需要處理的事務
struct binder_transaction *to_parent;
// 標志事務是同步/異步;設為1表示同步事務,需要等待對方回復;設為0異步
unsigned need_reply:1;
/* unsigned is_dead:1; */ /* not used at the moment */
/* 參考binder_buffer中解釋,指向Binder為該事務分配內核緩沖區
* code與flag參見binder_transaction_data
*/
struct binder_buffer *buffer;
unsigned int code;
unsigned int flags;
/** 目標線程設置事務錢,Binder需要修改priority;修改前需要將線程原來的priority保存到
* saved_priority中,用以處理完事務回復到原來優先級
* 優先級設置:目標現場處理事務時,優先級應不低于目標Serivce要求的線程優先級,也
* 不低于源線程的優先級,故設為兩者的較大值。
*/
long saved_priority;
};
11 結構體binder_transaction_data
binder_transaction_data 代表進程間通信所傳輸的數據:Binder對象的傳遞時通過binder_transaction_data來實現的,即Binder對象實際是封裝在binder_transaction_data結構體中
11.1 代碼位置
位置在
Linux的binder.h 217行
11.2 代碼注釋
struct binder_transaction_data {
//target很重要,我下面重點介紹
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
/* target descriptor of command transaction */
__u32 handle;
/* target descriptor of return transaction */
binder_uintptr_t ptr;
} target;
//Binder實體帶有的附加數據
binder_uintptr_t cookie; /* target object cookie */
// code是一個命令,描述了請求Binder對象執行的操作,表示要對目標對象請求的命令代碼
__u32 code; /* transaction command */
/* General information about the transaction. */
// 事務標志,詳細看transaction_flag結構體
__u32 flags;
// 發起請求的進程PID
pid_t sender_pid;
// 發起請求的進程UID
uid_t sender_euid;
// data.buffer緩沖區的大小,data見最下面的定義;命令的真正要傳輸的數據就保存data.buffer緩沖區
binder_size_t data_size; /* number of bytes of data */
// data.offsets緩沖區的大小
binder_size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
binder_uintptr_t buffer;
/* offsets from buffer to flat_binder_object structs */
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
} data;
};
這里重點說兩個共用體target和data
target
- 一個共用體target,當這個BINDER_WRITE_READ命令的目標對象是本地Binder的實體時,就用ptr來表示這個對象在本進程的地址,否則就使用handle來表示這個Binder的實體引用。
- 只有目標對象是Binder實體時,cookie成員變量才有意義,表示一些附加數據。
- 詳解解釋一下:傳輸的數據是一個復用數據聯合體,對于BINDER類型,數據就是一個Binder本地對象。如果是HANDLE類型,這個數據就是遠程Binder對象。很多人會說怎么區分本地Binder對象和遠程Binder對象,主要是角度不同而已。本地對象還可以帶有額外數據,保存在cookie中。
data
- 命令的真正要傳輸的數據就保存在data.buffer緩沖區中,前面的一成員變量都是一些用來描述數據的特征。
- data.buffer所表示的緩沖區數據分為兩類,一類是普通數據,Binder驅動程序不關心,一類是Binder實體或者Binder引用,這需要Binder驅動程序介入處理。
- 為什么?因為如果一個進程A傳遞了一個Binder實體或Binder引用給進程B,那么,Binder驅動程序就需要介入維護這個Binder實體或者引用引用計數。
- 防止B進程還在使用這個Binder實體時,A卻銷毀這個實體,這樣的話,B進程就會crash了。所以在傳輸數據時,如果數據中含有Binder實體和Binder引用,就需要告訴Binder驅動程序他們的具體位置,以便Binder驅動程序能夠去維護它們。data.offsets的作用就在這里,它指定在data.buffer緩沖區中,所以Binder實體或者引用的偏移位置。
- 進程間傳輸的數據被稱為Binder對象(Binder Object),它是一個flat_binder_object。
- Binder對象的傳遞時通過binder_transaction_data來實現的,即Binder對象實際是封裝在binder_transaction_data結構體中。
12 結構體transaction_flags
transaction_flags 描述傳輸方式,比如同步或者異步等
12.1 代碼位置
位置在
Linux的binder.h 210行
12.2 代碼注釋
enum transaction_flags {
//當前事務異步,不需要等待
TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
// 包含內容是根對象
TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
// 表示data所描述的數據緩沖區內 同時一個4bit的狀態碼
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
// 允許數據中包含文件描述
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
};
13 結構體flat_binder_object
flat_binder_object 描述進程中通信過程中傳遞的Binder實體/引用對象或文件描述符
13.1 代碼位置
位置在
Linux的binder.h 68行
13.2 代碼注釋
/*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
struct binder_object_header hdr;
__u32 flags;
/* 8 bytes of data. */
union {
binder_uintptr_t binder; /* local object */
__u32 handle; /* remote object */
};
/* extra data associated with local object */
binder_uintptr_t cookie;
};
這個比較重要我們就一個一個來說,首先看下struct binder_object_header hdr;
里面涉及到一個結構體binder_object_header,這個結構體在Linux的binder.h 57行,代碼如下:
/**
* struct binder_object_header - header shared by all binder metadata objects.
* @type: type of the object
*/
struct binder_object_header {
__u32 type;
};
flat_binder_object通過type來區分描述類型,可選的描述類型如下:
代碼在
Linux的binder.h 30行
enum {
//強類型Binder實體對象
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
//弱類型Binder實體對象
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
// 強類型引用對象
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
// 弱類型引用對象
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
// 文件描述符
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE),
BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),
};
當描述實體對象時,cookie表示Binder實體對應的Service在用戶空間的本地Binder(BBinder)地址,binder表示Binder實體對應的當描述引用對象時,handle表示該引用的句柄值。
14 結構體binder_write_read
binder_write_read 描述進程間通信過程中所傳輸的數據
14.1 代碼位置
位置在
Linux的binder.h 165行
14.2 代碼注釋
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
* translate the buffer (and local binder) addresses appropriately.
*/
struct binder_write_read {
/** 輸入數據 從用戶控件傳輸到Binder驅動程序的數據
* 數據協議代碼為命令協議碼,由binder_driver_command_protocol定義
*/
// 寫入的大小
binder_size_t write_size; /* bytes to write */
// 記錄了從緩沖區取了多少字節的數據
binder_size_t write_consumed; /* bytes consumed by driver */
// 指向一個用戶控件緩沖區的地址,里面的內容即為輸入數據,大小由write_size指定
binder_uintptr_t write_buffer;
/** 輸出數據,從Binder驅動程序,返回給用戶空間的數據
* 數據協議代碼為返回協議代碼,由binder_driver_return_protocol定義
*/
//讀出的大小
binder_size_t read_size; /* bytes to read */
// read_buffer中讀取的數據量
binder_size_t read_consumed; /* bytes consumed by driver */
// 指向一個用戶緩沖區一個地址,里面保存輸出的數據
binder_uintptr_t read_buffer;
};
里面涉及到兩個協議,我們就在這里詳細講解下
14.3 binder_driver_command_protocol協議
代碼在Linux的binder.h 366行
enum binder_driver_command_protocol {
/** 下面這兩個命令數據類型為binder_transaction_data,是最常用到的 */
/**一個Client進程請求目標進程執行某個事務時,會使用BC_TRANSACTION請求Binder驅
*動程序將通信數據傳遞到Server目標進程
* 使用者:Client進程 用處:傳遞數據
*/
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
/** 當Server目標進程處理完事務后,會使用BC_REPLY請求Binder將結果返回給Client源進程
* 使用者:Server進程 用處:返回數據
*/
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
/*
* binder_transaction_data: the sent command.
*/
//當前版本not support 在Linux中的binder.c就是這么寫的
BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
// 數據類型為int類型,指向Binder內部一塊內核緩沖區
// 目標進程處理完源進程事務后,會使用BC_FREE_BUFFER來釋放緩沖區
BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
/*
* void *: ptr to transaction data received on a read
*/
//通信類型為int類型,表示binder_ref的句柄值handle
// 增加弱引用數
BC_INCREFS = _IOW('c', 4, __u32),
// 減少弱引用數
BC_DECREFS = _IOW('c', 7, __u32),
// 增加強引用數
BC_ACQUIRE = _IOW('c', 5, __u32),
// 減少強引用數
BC_RELEASE = _IOW('c', 6, __u32),
/*
* int: descriptor
*/
/** Service進程完成增加強/弱引用的計數后,會使用這兩個命令通知Binder */
// 增加強引用計數后
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
//增加弱引用計數后
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
//當前版本不支持
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
/*
* not currently supported
* int: priority
* int: descriptor
*/
// Binder驅動程序 請求進程注冊一個線程到它的線程池中,新建立線程會使用
//BC_REGISTER_LOOPER來通知Binder準備就緒
BC_REGISTER_LOOPER = _IO('c', 11),
/*
* No parameters.
* Register a spawned looper thread with the device.
*/
//一個線程自己注冊到Binder驅動后,會使用BC_ENTER_LOOPER通知Binder準備就緒
BC_ENTER_LOOPER = _IO('c', 12),
// 線程發送退出請求
BC_EXIT_LOOPER = _IO('c', 13),
/*
* No parameters.
* These two commands are sent as an application-level thread
* enters and exits the binder loop, respectively. They are
* used so the binder can have an accurate count of the number
* of looping threads it has available.
*/
// 進程向Binder注冊一個死亡通知
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14,
struct binder_handle_cookie),
/*
* int: handle
* void *: cookie
*/
// 進程取消之前注冊的死亡通知
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15,
struct binder_handle_cookie),
/*
* int: handle
* void *: cookie
*/
// 數據指向死亡通知binder_ref_death的地址,進程獲得Service組件的死亡通知,
// 會使用該命令通知Binder其已經處理完死亡通知
BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
/*
* void *: cookie
*/
BC_TRANSACTION_SG = _IOW('c', 17, struct binder_transaction_data_sg),
BC_REPLY_SG = _IOW('c', 18, struct binder_transaction_data_sg),
/*
* binder_transaction_data_sg: the sent command.
*/
};
在上述枚舉命令成員中,最重要的是BC_TRANSACTION和BC_REPLY命令,被作為發送操作的命令,其數據參數都是binder_transaction_data結構體。其中前者用于翻譯和解析將要被處理的事務數據,而后者則是事務處理完成之后對返回"結果數據"的操作命令。
14.4 binder_driver_return_protocol協議
Binder驅動的響應(返回,BR_)協議,定義了Binder命令的數據返回格式
代碼在Linux的binder.h 278行
enum binder_driver_return_protocol {
// Binder驅動程序處理進程發送的請求時,發生異常,在返回BR_ERROR通知該進程
// 數據類型為int,表示錯誤代碼
BR_ERROR = _IOR('r', 0, __s32),
/*
* int: error code
*/
// 表示通知進程成功處理了該事務
BR_OK = _IO('r', 1),
/* No parameters! */
// 與上面的 BC_ 相對應
// Client進程向Server進程發送通信請求(BC_) ,Binder使用BR_TRANSACTION通知Server
// 使用者 : Binder驅動程序 用途:通知Server
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
// Server處理完 請求 使用 BC_ 通知Binder,Binder使用BR_REPLY通知Client
// 使用者:Binder驅動程序,用途:通知Client
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/*
* binder_transaction_data: the received command.
*/
// 當前不支持
BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
* Else the remote object has acquired a primary reference.
*/
// Binder處理請求時,發現目標進程或目標線程已經死亡,通知源進程
BR_DEAD_REPLY = _IO('r', 5),
/*
* The target of the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
*/
// Binder 接收到BC_TRANSACATION或BC_REPLY時,會返回 BR_TRANSACTION_COMPLETE通知源進程命令已經接收
BR_TRANSACTION_COMPLETE = _IO('r', 6),
/*
* No parameters... always refers to the last transaction requested
* (including replies). Note that this will be sent even for
* asynchronous transactions.
*/
// 增加弱引用計數
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
// 增加強引用計數
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
// 減少強引用計數
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
// 減少弱引用計數
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
//當前不支持
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/*
* not currently supported
* int: priority
* void *: ptr to binder
* void *: cookie for binder
*/
// Binder通過源進程執行了一個空操作,用以可以替換為BR_SPAWN_LOOPER
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
// Binder發現沒有足夠的線程處理請求時,會返回BR_SPAWN_LOOPER請求增加新的新城到Binder線程池中
BR_SPAWN_LOOPER = _IO('r', 13),
/*
* No parameters. The driver has determined that a process has no
* threads waiting to service incoming transactions. When a process
* receives this command, it must spawn a new service thread and
* register it via bcENTER_LOOPER.
*/
// 當前暫不支持
BR_FINISHED = _IO('r', 14),
/*
* not currently supported
* stop threadpool thread
*/
/** Binder檢測到Service組件死亡時,使用BR_DEAD_BINDER通知Client進程,Client請求
* 注銷之前的死亡通知,Binder完成后,返回BR_CLEAR_DEATH_NOTIFACTION_DONE
*/
// 告訴發送方對象已經死亡
BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
/*
* void *: cookie
*/
//清理死亡通知
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
/*
* void *: cookie
*/
// 發生異常,通知源進程
BR_FAILED_REPLY = _IO('r', 17),
/*
* The the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
*/
};
14.5 Binder通信協議流程
單獨看上面的協議可能很難理解,這里我們以一次Binder請求為過程來詳細看一下Binder協議是如何通信的,就比較好理解了。這幅圖的說明如下:
- 1 Binder是C/S架構的,通信過程牽涉到Client、Server以及Binder驅動三個角色
- 2 Client對于Server的請求以及Server對于Client的回復都需要通過Binder驅動來中轉數據
- 3 BC_XXX命令是進程發送給驅動命令
- 4 BR_XXX命令是驅動發送給進程的命令
- 5 整個通信過程由Binder驅動控制
PS:這里補充說明一下,通過上面的Binder協議的說明,我們看到,Binder協議的通信過程中,不僅僅是發送請求和接收數據這些命令。同時包括了對于引用計數的管理和對于死亡通知的管理(告知一方,通訊的另外一方已經死亡)。這個功能的流程和上述的功能大致一致。
15 結構體binder_ptr_cookie
binder_ptr_cookie 用來描述一個Binder實體對象或一個Service組件的死亡通知
15.1 代碼位置
位置在
Linux的binder.h 257行
15.2 代碼注釋
struct binder_ptr_cookie {
binder_uintptr_t ptr;
binder_uintptr_t cookie;
};
- 當描述Binder實體對象:ptr,cookie見binder_node
- 當描述死亡通知:ptr指向一個Binder引用對象的句柄值,cookie指向接收死亡通知的對象地址
16 總結
如果以結構體為標的來看整個Binder傳輸過程則如下: