ipc由調用服務號,調用函數名,binder協議構成
handle是指服務號, 區分服務, binder driver通過handle值確定binder ipc數據傳遞到哪個服務中
RPC代碼表示待調函數 RPC數據 是傳遞的參數
文件運算符函數 open系統調用到內核binder_open __open()是系統調用
mmap函數,在內核中開闢一塊區域,存放接收IPC數據. 調用ioctl()方法,將IPC數據作爲參數,傳遞給Binder
BINDER_WRITE_READ 進程間接收發送Binder IPC數據 struct binder_write_read
BINDER_SET_MAX_THREADS 設定註冊到binder driver中binder線程的最大個數 size_t
BINDER_SET_CONTEXT_MGR 設定服務管理者
BINDER_THREAD_EXIT 刪除Binder線程
根據Binder協議,決定是否傳輸協議
IPC層傳遞給binder driver的BINDER_COMMAND_PROTOCOL 通過Binder driver向接收端發送IPC數據時使用
binder driver傳遞給ipc層的BINDER_RETURN_PROTOCOL
/home/mec/goldfish/drivers/staging/android/bind.h
驅動收到信息會查詢ipc數據中的handle信息查找相應的Service,然後driver將協議更改爲BR_TRANSACTION,並將其重新插入IPC數據中,然後傳遞到server中 具體調用IPC數據中的哪個函數由ipc數據中的RPC代碼決定
IPC應答數據 BR_REPLY BC_REPLY
調用一個已經定義好的函數,通常需要提出函數的名稱,並傳遞相應的參數.
binder驅動通過handle查找server,我們稱爲Binder尋址. 爲了順利實現尋址,server一般必須先把自身服務的訪問信息註冊到Manager中. 註冊的過程中 server會向binder驅動傳輸IPC數據,其中包含RPC代碼 ADD_SERVICE RPC數據(註冊服務名稱)
並且handle值設置爲0, service會將IPC數據傳遞給Manager,然後driver驅動會生成一個binder節點.用來表示server中的服務A.
接下來生成binder節點引用數據,以便manager識別binder節點,並將相關節點連接起來,根據生成的順序,引用數據會被編號.這種編號會將插入IPC數據中,傳遞給Manager, manager會根據IPC數據中服務的名稱和BInder節點編號,將服務註冊到自身的服務目錄列表中
manager根據請求的服務名稱 在自身持有的服務列表中查找相對應的服務編號. 驅動將客戶端的引用數據和manager引用數據所指的binder節點連接起來.
manager(接收IPC數據,發送IPC應答數據)中mmap函數在內核中開闢一塊用於接收ipc數據的buffer 再調用ioctl函數進入待機狀態 等待ipc數據.
server((發送IPC數據,接收IPC應答數據)中調用mmap函數在內核中開闢一塊用於接收ipc 應答數據 的buffer 移動的數據是RPC數據和binder協議,ipc數據在內核組裝
服務的編號 就是服務引用
註冊是時候 RPC數據是服務名稱 RPC代碼註冊函數ADD_SERVICE
使用服務 RPC代碼 制定服務函數,RPC數據 服務函數的參數
驅動角度分析 binder_proc open的時候創建 接收IPC數據的buffer 大小爲調用mmap時制定的大小,保存在binder_buffer結構體中 而後binder_buffer結構體註冊到binder_proc
驅動通過handle查找到manager的binder_node和binder_proc結構體,然後爲要註冊的服務,生成binder_node結構體.驅動將binder_node分別註冊到server的binder_proc和manager的binder_proc,(驅動會分別將binder_node註冊到server的binder_proc和manager的binder_proc結構體之中)然後驅動找到manager的binder_buffer發送IPC數據.
進程 buffer發送ipc數據->驅動,驅動通過handle找到服務和binder_proc,然後把數據通過其中的buffer繼續轉發
檢索的時候 是指向manager 請求指定名稱的handle作爲返回值
驅動將服務的binder_node結構體註冊到客戶端的binder_proc
一般server向manager註冊的時候纔會生成binder_node結構體,但是manager直接訪問驅動,生成binder_node.並且該binder_node的編號爲0.
發送請求的時候會在驅動中找到 請求的binder_proc結構體,向其中接收的buffer中複製ipc數據.
請求返回的時候會把服務的binder節點註冊到請求的binder_proc結構體,將ipc應答數據複製到buffer進去,喚醒客戶端傳遞ipc應答數據.
驅動根據manager返回的服務編號handle查找相對於的binder_node結構體,而後將查找到的binder_node結構體註冊到客戶端的binder_proc,binder_node結構體用於在服務使用階段查找server的binder_proc結構體.
服務使用
驅動接收到數據,經過處理,會喚醒一方,然後讓一方進入待機狀態.
函數分析
進程使用binder驅動第一步就是打開文件binder_open 會初始化binder_proc結構體,初始化待機隊列(wait queue).用來將進程切換到待機狀態下.
binder_proc稱爲binder驅動的根結構體
mmap將用戶空間的特定區域映射到內核空間的特定區域. 用戶空間中的進程不能直接訪問內核空間,所以只能通過內核空間的特定映射區域來訪問內核空間.
cat pid/maps查看鏈接信息
/home/mec/froyo/build/core/prelink-linux-arm.map
使用binder的進程調用驅動的mmap函數創建與用戶空間映射的binder mmap區域, 並且 驅動只在內核空間的數據接收區保存數據,
用戶空間的接收區域與內核空間的ipc數據接收區域由binder_mmap函數映射在一起.
在內核中開闢buffer,然後和用戶空間的buffer映射起來
用戶空間和內核空間的buffer要映射到實際的物理內存上.
binder_update_page_range分配物理頁,
binder_insert_free_buffer free_buffers變量是接收ipc數據的buffer 根據ipc數據的大小,分配不同大小的free_buffer
//binder_write_read是在RPC代碼中 BINDER_WRITE_READ命令碼在在RPC中
上面的應該是ipc代碼???????????
binder_write_read中的write_buffer成員變量 在傳遞經由驅動的數據時使用,來發送ipc數據或ipc應答數據
中的read_buffer 接收來自驅動的數據 ipc數據以何種形態存在binder_write_read結構體中的write_buffer 和read_buffer
handle RPC代碼和RPC數據保存在binder_transaction_data的結構體中 加上binder協議 就是IPC數據
binder協議在前,後面依次是handle RPC代碼和RPC數據 包含在了write_buffer中228圖有問題
binder_write_read結構體在傳輸的過程中(用戶空間到內核空間) 使用了copy_from_user
接收完數據要傳遞到用戶空間處理
將用戶空間中的數據拷貝到自身的binder_write_read結構體中
根據read_size和write_size 變量是發送ipc數據還是接收ipc數據
接收時將生成相應的read_buffer,並且read_size大於零
interruptible可中斷的 exclusive獨有的 通過當前進程的binder_proc結構體wait變量將當前任務註冊到待機隊列中. 然後將task_truct結構體內的state變量又TASK_RUNNING 更改爲TASK_INTERRUPTIBLE再調用schedule函數
wake_up即可喚醒
binder_write_read
中的結構體,一個是接收ipc數據,一個是發送ipc數據.
服務名稱和flat_binder_object(數據,註冊和檢索時,用於生成或查找binder節點)結構體會被註冊到ipc數據的RPC數據中flat_binder_object要麼代碼節點(BINDER_TYPE_BINDER)要麼是引用 傳送write_size就大於零
consumed指ipc數據的個數 get_user獲取binder協議
在binder_transaction_data中 協議排在第一位,然後是RPC數據 將指針所指向的內容重新拷貝到內核空間中
接收端和發送端通過binder_transaction結構體收發數據
target_proc指向了接收端的binder_proc結構體 wait_queue_head_t用來幫助接收端脫離待機狀態
通過handle找到binder_node然後找到對於的接收端進程
binder_proc中有很多Binder_node,且binder_node中的binder_proc指向同一個
向接收端發送數據
t->from 來自線程此處的thread爲binder_get_thread獲取的 通過線程查找到所在進程
t->to_proc 到達進程
t.buffer 爲binder驅動程序爲該事務分配的一塊內存緩衝區然後把事務註冊
struct binder_transaction *transaction; //每一個事務都關聯一個目標Binder實體對象
一個事務中含有一個小的binder_buffer結構體,來傳送ipc數據
/////////////////////////////////////////////
一個copy_from_user完成了從發送進程到接收進程的轉換
binder_buffer結構體是小的.
新生成的binder節點會被註冊到當前進程的binder_proc中
binder_get_ref_for_node檢查binder節點是否存在於binder_proc進程中 若存在,則返回,不然新建,並將binder節點註冊其中.並且binder_ref也註冊到進程中refs_by_node變量中
desc首次註冊服務時生成,編號用來在manager中管理服務列表中不同的服務. 這些東西都註冊到了binder_proc中
wait_queue_head_t *target_wait; target_list 接收端的 是todo(數據在這裏面找 binder_work(更底層了) 傳輸數據協議) 添加到wait中執行
wake_up_interruptible函數喚醒
//////////////////////////////////驅動中完成
發送端執行
binder_thread_write函數進入等待 在binder_ioctl層面
在接收端先查找出來binder_work,
Container_of第一參數是結構體成員變量的地址,第二個是結構體定義,第三個是第一個參數在結構體中的名稱
接收的時候不要調用copy_to_user,應用內核和用戶空間都映射到了物理空間上面BR_TRANSACTION是在接收端的內核進程中加的.
binder_write_read.read_buffer 等於binde協議BR_TRANSACTION + binder_transaction_data
把binder_transaction保存在線程的transaction_stack 查找另一端接收進程
服務檢索階段 的時候返回會創建flat_binder_object
binder_write_read.write_buffer 等於binde協議BC_TRANSACTION + binder_transaction_data
handle(0) RPC代碼 RPC數據(服務名稱)
服務端應答
binder_write_read.write_buffer 等於binde協議BC_REPLY + binder_transaction_data
handle(0) RPC代碼 RPC數據(binder_object)服務目錄編號 type設爲HANDLE
服務使用階段
binder_write_read.write_buffer 等於binde協議BC_TRANSACTION + binder_transaction_data
handle(binder_ref中的desc) RPC代碼服務函數 RPC數據(服務函數參數)
handle-> binder_ref->binder_node->binder_proc
通過handle獲取binder_ref(此結構體由manager持有)
還要向服務客戶端註冊binder節點,都會生成一個binder_ref,同時desc加1,然後修改handle編號的值
服務目錄 通過/system/service程序即可查看 service list查看服務列表
manager採用c語言編寫 驅動編寫