Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Binder驅動中的基礎數據結構整理

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

編輯:關於Android編程

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

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

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

struct binder_work {
	struct list_head entry;   //
	enum {
		BINDER_WORK_TRANSACTION = 1,
		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;
	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;       // 
	struct rb_root nodes;         //binder實體對象的集合  以ptr作為關鍵字
	struct rb_root refs_by_desc;
	struct rb_root refs_by_node;
	int 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小空間
	ptrdiff_t user_buffer_offset;  //內核緩沖區中 用戶空間地址和內核空間地址的差值

	struct list_head buffers;    //指向指向該列表的頭部
	struct rb_root free_buffers;    //已分配物理頁面
	struct rb_root allocated_buffers;
	size_t free_async_space; //保存異步事務數據緩沖區的大小

	struct page **pages;   //對於的物理頁面   數組中每個元素指向一個物理頁面
	size_t buffer_size;    //mmap後內核緩沖區的大小
 	uint32_t buffer_free;    //空閒內核緩沖區的大小
	struct list_head todo;   //把待處理請求封裝成一個工作項,加如到待處理工作項隊列
	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),//
};
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved