Android Binder驅動中的基礎數據結構整理

                  最近突然看到一個博客,是講Binder原理的,以前看深入理解Android I的時候看過,那時候就看不懂。感覺這個還有點意思,就看了好幾天,發現越看越不懂,然後看老羅的博客,發現也不是太懂,現在想根據書上的東西好好梳理下Binder。

感覺裏面應該重點掌握的應是bind_node是註冊的服務在內核中的代表,bind_ref是客戶端連接在驅動的代表。bind_buffer內核緩衝區,通過mmap之後可以在用戶空間操作,然後在內核也可以訪問,bind_proc是進程的代表,客戶端和服務端都有,對上面的進行管理,未完,待續,等看完了藝術探索過來更新。

handle, RPC代碼和RPC數據保存在binder_transaction_data的結構體中,屬於RPC範疇.

binder_write_read 等於binder_transaction_data(用戶空間數據)加上binder協議,是IPC數據範疇.

binder_write_read中的write_size是發送ipc數據時使用,read_size是接收數據時使用.

flat_binder_object在內核中傳輸的時候,會判斷type的類型,來判斷是否創建binder節點(服務註冊的時候存在)

進程間通信根據Client和Server的狀態設置該值  

struct binder_work {//用戶查找binder_transaction結構體
	struct list_head entry;   //
	enum {
		BINDER_WORK_TRANSACTION = 1,  //獲取ipc數據
		BINDER_WORK_TRANSACTION_COMPLETE,
		BINDER_WORK_NODE,
		BINDER_WORK_DEAD_BINDER,      //Binder驅動檢測到Service組件死亡時,找到Binder實體對象中的refs,找到引用它的client進程和Client進程主動註冊死亡通知發現Service組件已死亡兩種情況
                BINDER_WORK_DEAD_BINDER_AND_CLEAR, //Client進程註銷死亡通知時,相應的Service組件已死亡,binder驅動找到之前註冊的binder_ref_death結構體,並修改它work
		BINDER_WORK_CLEAR_DEATH_NOTIFICATION,  //Client進程註銷一個死亡通知,相應的Service組件沒有死亡,Binder驅動程序會找到之前註冊的,一個binder_ref_death結構體,並且將它的work修改爲此, 然後將該結構體封裝成一個工作項添加到Client進程的todo隊列中         
          } type; //工作項的類型
};


binder實體對象   Service中的Binder在內核中的代表

struct binder_node {
	int debug_id;
	struct binder_work work;//引用計數發生變化時 BINDER_WORK_NODE,並且將它添加到響應進程的todo隊列中
	union {
		struct rb_node rb_node;
		struct hlist_node dead_node;
	};
	struct binder_proc *proc;       //指向service進程
	struct hlist_head refs; //所有的Client的binder引用binder_ref->node
	int internal_strong_refs;
	int local_weak_refs;
	int local_strong_refs;
	void __user *ptr;  //指向Service組件內部的一個引用計數  weakref_impl 弱引用計數
	void __user *cookie;              //指向Service組件的地址
	unsigned has_strong_ref:1;        //請求Service組件時 1  結束 0
	unsigned pending_strong_ref:1;    // 請求的時候爲1,service增加後爲0
	unsigned has_weak_ref:1;          //請求Service組件時 1  結束 0
	unsigned pending_weak_ref:1;
	unsigned has_async_transaction:1;  //每一個事務都關聯一個binder實體對象
	unsigned accept_fds:1; //是否接收含有文件描述符的進程間通信數據   防止源進程在目標進程中打開
	unsigned min_priority:8;           //線程優先級 
	struct list_head async_todo;       //異步事務隊列
};
Service組件,在驅動中的binder_node,binder_ref都維護引用計數

描述Client組件的死亡通知在驅動中的代表,

struct binder_ref_death {
	struct binder_work work;   //見第一個數據結構
	void __user *cookie;  //保存Client負責接收死亡通知對象的地址
};

Binder驅動程序決定向客戶端進程發送一個Service組件死亡通知時。會將binder_ref_death結構體封裝成一個工作項。加到Client進程的todo隊列中 ,Client進程在處理這個工作項,會通過binder_ref_death結構體成員變量的work來區是哪一種情況,見第一個結構體中的枚舉值

描述一個Binder引用對象   Client進程中的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;
	struct rb_node rb_node_desc;      //保存進程內部所有的句柄值
	struct rb_node rb_node_node;
	struct hlist_node node_entry;  //hash列表中的節點 對應與binder_node->refs
	struct binder_proc *proc;     //Binder引用對象的宿主進程
	struct binder_node *node;   //Binder引用對象所引用的Binder實體對象
	uint32_t desc;              //在Client進程的用戶空間,Binder引用對象是使用一個句柄值來描述的,BInder驅動程序就可以通過該句柄值找到對於的,Binder引用對象即是binder_ref      
        int strong;
 	int weak;
	struct binder_ref_death *death;  //Client進程註冊的死亡通知保存的地方
};

進程對應內核緩衝區  緩衝區中的事務會隨着請求發送變化

struct binder_buffer {
	struct list_head entry; /* free and allocated entries by addesss */   //內核緩衝區列表的一個節點
	struct rb_node rb_node; /* free entry by size or allocated entry */
				/* by address */   //free 爲1 表示爲空閒內核緩衝區中的一個節點
	unsigned free:1;      //1表示內核緩衝區是空閒的  不會分配物理頁面的
	unsigned allow_user_free:1;//Service組件處理完後發現爲1,Service組件請求Binder驅動釋放該內核緩衝區
        unsigned async_transaction:1;   //爲1表示異步事務
	unsigned debug_id:29;

	struct binder_transaction *transaction;  //每一個事務都關聯一個目標Binder實體對象

	struct binder_node *target_node;         //目標的binder節點
	size_t data_size;     //數據緩衝區的大小
	size_t offsets_size; //偏移數組  記錄了每一個Binder對象再數據緩衝區中的位置
	uint8_t data[0];    //指向大小可變的數據緩衝區,用來保存通信數據的  可保存普通數據和Binder對象   Binder驅動程序只關心Binder對象
};

進程調用open /dev/binder的時候創建 將它保存在全局的hash  進程在驅動中的代表

struct binder_proc {
	struct hlist_node proc_node;   //是hash列表中的節點
        struct rb_root threads;       // 擁有binder_thread結構體的紅黑樹的根
	struct rb_root nodes;         //binder實體對象的紅黑樹的根  以ptr作爲關鍵字
	struct rb_root refs_by_desc;
	struct rb_root refs_by_node;   //帶有binder_ref 結構體紅黑樹的根,使用binder_node結構體區分binder_ref
	int pid;                        //創建binder_proc結構體的進程的pid
	struct vm_area_struct *vma; //內核緩衝區地址     用戶空間地址  在應用程序內部使用
 	struct task_struct *tsk;    //任務控制塊 進程相關
	struct files_struct *files;    //文件結構體數組
	struct hlist_node deferred_work_node;       //進程延遲執行的工作項
	int deferred_work;              //延遲工作項的具體內容
	void *buffer; //內核緩衝區的地址   內核空間地址   大塊空間  劃分爲Binder_buffer小空間 接收ipc數據的結構體指針
	ptrdiff_t user_buffer_offset;  //內核緩衝區中 用戶空間地址和內核空間地址的差值 接收的ipc數據的內核和用戶的地址偏移量,將接收到的ipc數據傳遞到用戶空間

	struct list_head buffers;    //指向指向該列表的頭部  爲接收ipc數據而分配的binder_buffer結構體列表
	struct rb_root free_buffers;    //已分配物理頁面 接收ipc數據後,要釋放的binder_buffer結構體列表   根據RPC數據的大小分配binder_buffer結構體的data
	struct rb_root allocated_buffers;
	size_t free_async_space; //保存異步事務數據緩衝區的大小

	struct page **pages;   //對於的物理頁面   數組中每個元素指向一個物理頁面
	size_t buffer_size;    //mmap後內核緩衝區的大小  內核中開闢的buffer大小
 	uint32_t buffer_free;    //空閒內核緩衝區的大小
	struct list_head todo;   //把待處理請求封裝成一個工作項,加如到待處理工作項隊列 進程從待機狀態喚醒後要做的事情  和binder_work聯繫一塊
	wait_queue_head_t wait;       //空閒binder線程會睡眠在等待隊列裏面  讓進程進入待機狀態
        struct binder_stats stats;    //統計進程數據的,進程見請求的次數
	struct list_head delivered_death;   //死亡通知封裝成一個工作項保存在所描述的一個隊列中,進程收到後會刪除
	int max_threads;
	int requested_threads;  //驅動主動請求進程註冊一個線程時加1,進程響應後減1
	int requested_threads_started;//驅動程序主動請求進程註冊的數目,進程響應後加1
	int ready_threads;   //當前空閒的Binder線程數目
	long default_priority;    //宿主進程的優先級
	struct dentry *debugfs_entry;
};
deferred_work的可能取值

enum binder_deferred_state {
	BINDER_DEFERRED_PUT_FILES    = 0x01,  //進程關閉文件描述符
	BINDER_DEFERRED_FLUSH        = 0x02,   //喚醒線程檢查進程是否有新的工作項需要處理
	BINDER_DEFERRED_RELEASE      = 0x04,  //不再使用binder進程間通信機制,驅動釋放它分配的資源,釋放進程結構體,binder實體對象
};
binder驅動會爲內核緩衝區分配文件描述符,進程可以通過文件描述符把內核緩衝區映射到自己的地址空間

binder線程池中的一個線程,線程註冊到binder驅動時,驅動會創建該結構體

struct binder_thread {
	struct binder_proc *proc;  //指向宿主進程
	struct rb_node rb_node;   //一個節點
	int pid;    //線程ID
	int looper;    //狀態
	struct binder_transaction *transaction_stack;   //一個事務交給一個線程處理時,事務封裝成結構體 處理誰,誰放在最前端 查找另一端接收進程
	struct list_head todo;  //Client進程的請求
	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 */
	wait_queue_head_t wait;    //等待依賴的線程處理結束
	struct binder_stats stats;   //接收到進程間通信請求的次數
};

線程的狀態

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線程處於空閒狀態
	BINDER_LOOPER_STATE_NEED_RETURN = 0x20   //初始化狀態
};
線程是應用程序主動註冊的,那麼它通過BC_ENTER_looper來通知binder驅動

描述進程間通信過程

struct binder_transaction {
	int debug_id;
	struct binder_work work;   //binder驅動爲目標線程創建一個事務後(由驅動負責)設置BINDER_WORK_TRANSACTION,並添加到目標線程的todo隊列中
	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;  //爲1 表示是同步事務
	/* unsigned is_dead:1; */	/* not used at the moment */

	struct binder_buffer *buffer; //binder驅動程序爲該事務分配的一塊內存緩衝區
	unsigned int	code;
	unsigned int	flags;
	long	priority;   //線程優先級
	long	saved_priority; //保存原來的線程優先級
	uid_t	sender_euid;   //線程用戶ID
};
應用程序通過IO命令和驅動交互
#define BINDER_WRITE_READ   		_IOWR('b', 1, struct binder_write_read)

進程間通信

struct binder_write_read {
	signed long	write_size;	/* bytes to write */ 緩衝區大小
	signed long	write_consumed;	/* bytes consumed by driver */ 驅動從緩衝區處理的字節
	unsigned long	write_buffer;   //描述輸入數據 從用戶空間傳輸到binder驅動程序的數據 指向一個用戶緩衝區地址
	signed long	 read_size;	/* bytes to read */
	signed long	read_consumed;	/* bytes consumed by driver */
	unsigned long	read_buffer; //指向一個用戶空間緩衝區的地址
};

全部是進程發送給binder驅動

enum BinderDriverCommandProtocol {
       BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
       BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
       BC_FREE_BUFFER = _IOW('c', 3, int), //指向內核緩衝區

       BC_INCREFS = _IOW('c', 4, int),  //binder引用對象的句柄值 弱引用
       BC_ACQUIRE = _IOW('c', 5, int),   //增加 強引用計數
       BC_RELEASE = _IOW('c', 6, int),
       BC_DECREFS = _IOW('c', 7, int),   //弱引用
       BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
       BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
        BC_REGISTER_LOOPER = _IO('c', 11),  //驅動請求進程註冊線程到驅動
       BC_ENTER_LOOPER = _IO('c', 12),    //線程主動註冊
       BC_EXIT_LOOPER = _IO('c', 13),   //線程要退出時
       BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), //註冊
       BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), //清空
        BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),  //指向一個死亡通知結構體binder_ref_death的地址
          //Client用命令協議碼通知binder驅動程序處理完Service組件的死亡通知了
};
源進程使用命令協議代碼BC_TRANSACTION請求binder驅動將通信數據傳遞到目標進程

目標進程處理完源進程的請求操作之後使用命令協議碼BC_REPLY請求驅動將結果傳遞給源進程

返回協議代碼

enum BinderDriverReturnProtocol {
	BR_ERROR = _IOR('r', 0, int), //驅動處理請求時出錯
     BR_OK = _IO('r', 1), //成功處理
     BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), //通知Server進程來處理該進程間通信請求
     BR_REPLY = _IOR('r', 3, struct binder_transaction_data),//server處理完請求之後,驅動以此協議返回Client進程
        BR_DEAD_REPLY = _IO('r', 5),  //發現目標進程或線程已經死亡 驅動會返回這個協議代碼
        BR_TRANSACTION_COMPLETE = _IO('r', 6),//當binder驅動收到進程發來的BC_TRANSACTION或是BC_REPLY,驅動返回此碼,告知進程已收到

     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),
        BR_NOOP = _IO('r', 12), //通知應用進程執行了一個空操作
        BR_SPAWN_LOOPER = _IO('r', 13),//發現進程沒有足夠的空閒Binder線程來處理進程間通信請求,通知該進程增加一個線程到Binder線程池中
     BR_DEAD_BINDER = _IOR('r', 15, void *),//當驅動檢測到Service組件死亡事件時,通知Client進程
        BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),//binder驅動執行完註銷後返回此碼通知Client進程
     BR_FAILED_REPLY = _IO('r', 17), // 處理進程發送的BC_TRANSACTION異常時,返回此碼
};


描述一個Binder實體對象或是引用

struct binder_ptr_cookie {
	void *ptr;  //Binder引用的句柄 或是
	void *cookie;//接收死亡通知對象的地址
};
進程中線程的通信傳輸的數據   用戶空間數據
struct binder_transaction_data {
	union {
		size_t	handle;	/* target descriptor of command transaction */ //引用對象的句柄值
		void	*ptr;	/* target descriptor of return transaction */  //指向Service組件內部弱引用計數的地址
	} target;
	void		*cookie;	/* target object cookie */  //目標Service組件的地址
	unsigned int	code;		/* transaction command */ //雙方約定好的通信代碼
	/* General information about the transaction. */
	unsigned int	flags;  //描述進程間通信行爲的特徵
	pid_t		sender_pid;  //進程的pid
	uid_t		sender_euid;   //
	size_t		data_size;	/* 通信數據的大小 */
	size_t		offsets_size;	/* 偏移數組的大小 */
	union {
		struct {
			/* transaction data */
			const void	*buffer; //指向數據緩衝區,真正保存通信數據的 大小由data_size決定
			/* offsets from buffer to flat_binder_object structs */
			const void	*offsets; //保存每一個binder對象的位置,分別指向偏平結構的首地址
		 } ptr;//數據量大的時候
 		uint8_t	buf[8]; //數據量小的時候
	 } data;   //數據緩衝區是 來傳輸數據
};
上面的flags取值如下
enum transaction_flags {
	TF_ONE_WAY	= 0x01,	/* 1表示異步的進程間通信過程 */
	TF_ROOT_OBJECT	= 0x04,	/* contents are the component's root object */
	TF_STATUS_CODE	= 0x08,	/* 1表示data數據緩衝區的內容是一個4字節的狀態碼 */
	TF_ACCEPT_FDS	= 0x10,	/* 0表示源進程不允許結果護具中含有文件描述符 */
};
數據緩衝區中每一個Binder對象都使用一個flat_binder_object來描述
struct flat_binder_object {
	/* 8 bytes for large_flat_header. */
	unsigned long		type;   //區分是Binder實體對象還是引用對象,亦或是文件描述符
	unsigned long		flags;  //只有描述的是Binder實體,它纔有意義
	/* 8 bytes of data. */
	union {
		void		*binder;	/* local Binder實體對象 指向一個內部弱引用對象的地址 */
		signed long	handle;		/* remote Binder引用對象的句柄值 */
	};
	/* extra data associated with local object */
	void			*cookie;  //指向該Service組件的地址
};
扁平結構中的type的取值如下
#define B_PACK_CHARS(c1, c2, c3, c4) \
	((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85

enum {
	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引用對象
	BINDER_TYPE_WEAK_HANDLE	= B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),//弱類型引用
	BINDER_TYPE_FD		= B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),//
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章