目錄:
一、binder初始化
二、binder_open()、binder_mmap()
三、binder通訊實現
3.1場景概念
3.2 transaction request
3.3 transaction async request
3.4 receive request
3.5 receive async requet
3.6 transaction reply
3.7 receive reply
3.8關於傳送請求時的一點優化
四、binder_write_read其他功能
五、其他ioctl功能實現
android中重要的ipc:binder,一直是我想研究的部分之一。偶然看到一篇universus的大師級binder理**章: binder設計與實現 – 設計篇),恰巧有點時間,就將binder驅動**好生讀了下。
一、 binder初始化
binder驅動不像其他linux驅動那樣有特定的應該裝置與之對應,唯一和硬體沾點邊
邊的是它需要對記憶體操作,不過只是使用記憶體儲存資料罷了。和其他驅動一樣,binder驅動採用了標準的linux驅動架構,所以才將其納入驅動之列。
驅動都有乙個系統啟動時initcall的初始化函式,當然binder驅動也有,那就是binder_init()函式。這個函式其實也沒做太多的事情:
1. 新建工作佇列:binder_deferred_workqueue和工作者核心執行緒:binder來處理一些可以稍後執行的工作;
2. 為binder驅動註冊乙個misc裝置,裝置節點/dev/binder;
3. 建立proc下的相關目錄和檔案:
proc/binder、proc/binder/proc,
proc/state、proc/stats、proc/transactions、proc/transaction_log、proc/failed_transaction_log。
這些介面檔案對應的proc讀取函式分別是:binder_read_proc_state()、binder_read_proc_stats()、binder_read_proc_transactions()、binder_read_proc_transaction_log()、binder_read_proc_transaction_log()。
另外在binder.c檔案中看到的以print_binder_開頭的函式都是和這些屬性介面檔案有關,如下。所以如果需要對這幾個檔案進行詳細研究的,這些函式就不容錯過了。本文的重點不在這塊,所以略過。
print_binder_transaction()
print_binder_buffer()
print_binder_work()
print_binder_thread()
print_binder_node()
print_binder_ref()
print_binder_proc ()
print_binder_stats()
print_binder_proc_stats()
binder_read_proc_state()
binder_read_proc_stats()
binder_read_proc_transactions()
binder_read_proc_proc()
print_binder_transaction_log_entry()
binder_read_proc_transaction_log()
二、 binder_open()、binder_mmap()
binder驅動實現了自己的mmap函式,正如universus闡述的那樣:它不是為了在物理
介質和使用者空間做對映,而是用來建立資料接收的快取空間。binder資料只在使用者空間和核心空間拷貝一次的秘密也就在於binder驅動對接收緩衝區的管理,關於這部分的討論放在另外一篇文章:binder驅動-接收快取區管理,本文不關心這一部分。
通常上層應用程式在使用的binder的時候,都會有如下呼叫:
fd = open(「/dev/binder」, o_rdwr);
mmap(null, map_size, prot_read, map_private, fd, 0);
但是,如果某應用程式只進行非同步請求,那麼我們可以不用給隊程序分配和管理接收快取區了。另外binder_mmap()只允許最大分配4mb的虛擬位址空間,而且對於應用程式,只擁有對該記憶體的讀許可權。
下面來看一看binder_open()的實現,函式定義如下:
static int binder_open(struct inode *nodp, struct file *filp){
struct binder_proc *proc;
/* 乙個程序開啟binder裝置節點,就會有乙個binder_proc生成來記錄這個程序的一些資訊。*/
proc = kzalloc(sizeof(*proc), gfp_kernel);// 分配binder_proc的記憶體空間
get_task_struct(current); // 增加當前程序的引用計數
proc->tsk = current; // 記錄當前task_struct的位址
init_list_head(&proc->todo); // 程序全域性todo任務鍊錶
init_waitqueue_head(&proc->wait); // 初始化proc的等待佇列頭
proc->default_priority = task_nice(current); // 取得當前程序的nice值儲存
mutex_lock(&binder_lock);
binder_stats_created(binder_stat_proc);
// 在全域性統計計數資料結構binder_stats中記錄下建立了乙個binder_proc
hlist_add_head(&proc->proc_node, &binder_procs);
// 將代表當前程序的binder_proc結構體加入全域性鍊錶binder_procs中
proc->pid = current->group_leader->pid;
/* 如果當前task是程序,那麼取得當前程序的pid;如果當前task是執行緒,那麼此處取得建立該執行緒的程序的pid : current->tgid tgid = thread group id*/
init_list_head(&proc->delivered_death);// 和binder死亡通知有關後續單獨討論
filp->private_data = proc; // binder_proc儲存在file結構體的私有資料中
mutex_unlock(&binder_lock);
if (binder_proc_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
/* 以proc->pid作為名字在proc/binder/proc中建立乙個入口檔案,以方便上層檢視該程序的所有binder通訊 */
remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
create_proc_read_entry(strbuf, s_irugo,
binder_proc_dir_entry_proc,
binder_read_proc_proc, proc);
return 0;
從上面可以看出,binder_open()對binder_proc的以下域做了初始化:
struct binder_proc {
struct hlist_node proc_node; // 鏈結入全域性鍊錶binder_procs的節點
int pid;
struct task_struct *tsk;
struct list_head todo; // 程序的全域性任務佇列
wait_queue_head_t wait; // 程序空閒程序等待任務的等待佇列
struct list_head delivered_death; // 和binder死亡通知有關,後續單獨討論這塊
// binder驅動-訂閱實體死亡通知
long default_priority; // 記錄當前task的預設nice值
WDM驅動和應用的互動
deviceiocontrol的同步和非同步呼叫方式 上層應該可以以同步或非同步的方式.ov ov.hevent createevent null,true,false,null deviceiocontrol ov 執行其它操作.等待驅動事件 handle aevents 2 aevents 0 ...
資料互動時狀態碼的意義
http 錯誤 400 400 請求出錯 由於語法格式有誤,伺服器無法理解此請求。不作修改,客戶程式就無法重複此請求。http 錯誤 401 401.1 未授權 登入失敗 此錯誤表明傳輸給伺服器的證書與登入伺服器所需的證書不匹配。401.2 未授權 伺服器的配置導致登入失敗 此錯誤表明傳輸給伺服器的...
expect 互動時 管道符的問題
今天同事說expect互動出了問題,無法呼叫gzip解壓匯入資料庫,但是手動執行卻沒問題 先來看看問題 usr bin expect set timeout 10000 spawn zcat db xd 20220208 133003.sql.gz mysql u xd p xd expect re...