Binder機制的細節補充

weixin_34148340發表於2016-04-02

(1)Binder驅動的核心方法
①使用者態程式呼叫核心驅動,需要陷入核心態,進行系統呼叫。當使用者空間呼叫open方法,最終會呼叫binder驅動的binder_open方法,而mmap和ioctl方法也是同理,這些過程都是依賴於系統呼叫的。
②binder_open方法首先會建立binder_proc這個結構體物件,這個結構體主要包含了當前程式等資訊,它用於管理IPC所需的各種資訊並擁有其他結構體的根結構體。每次建立binder_proc的時候,都會將其加入到全域性連結串列binder_procs中,並將其儲存到檔案指標filp的private_data中。
③binder_mmap方法主要功能為,在核心虛擬地址空間申請一塊和使用者虛擬記憶體相同大小的記憶體,然後在申請一個page大小的實體記憶體,並將其分別對映到核心虛擬地址空間和使用者虛擬記憶體空間,從而實現使用者空間buffer和核心空間buffer的同步操作功能。(計算方式是通過proc->user_buffer_offset,proc_addr = kernel_addr + user_buffer_offset)
④binder_ioctl是一個核心方法,它可以用來收發Binder的IPC資料,這個方法接受三個引數,第二和第三個引數決定函式具體執行什麼操作,其中BINDER_WRITE_READ操作就是收發Binder的IPC資料的操作,它需要一個binder_write_read結構體作為引數,其包含了使用者空間的資料ubuf。函式首先把使用者空間資料拷貝到核心空間bwr,當bwr寫快取中有資料時,執行binder寫操作(binder_thread_write方法);當bwr讀快取中有資料時,執行binder讀操作(binder_thread_read方法)。最後將核心資料bwr拷貝到使用者空間。
(2)Binder記憶體機制高效的原因
在(1)裡我們知道通過binder_mmap方法,虛擬程式地址空間和虛擬核心地址空間都對映到了同一塊實體記憶體空間,當Client端向Server傳送資料時,Client先從自己的程式空間把IPC通訊資料通過copy_from_user拷貝到核心空間,而Server端與核心共享資料,不再需要拷貝資料,而是通過記憶體地址空間的偏移量直接獲得這個地址。整個過程只需要一次拷貝。
(3)ServiceManager是整個Binder IPC的守護程式,啟動ServiceManager的入口函式是service_manager.c中的main方法,主要分為如下幾步:binder_open --> binder_becom_context_manager --> binder_loop
其中binder_open方法開啟binder驅動,並呼叫mmap方法分配128k的記憶體對映空間;binder_becon_context_manager通知binder程式使ServiceManager成為守護程式;binder_loop方法進入迴圈狀態,等待Client端的請求。
①binder_open:首先通過open方法通過系統呼叫,陷入核心,開啟binder裝置驅動(對應於binder驅動層的binder_open方法,會建立binder_proc物件等),然後通過ioctl系統呼叫獲取驗證binder版本資訊,最後通過系統呼叫,利用mmap方法進行記憶體對映(建立binder_buffer物件)
②binder_become_context_manager:這個方法內部是通過ioctl系統呼叫,根據引數BINDER_SET_CONTEXT_MGR,最終呼叫binder_ioctl_set_ctx_mgr方法的,該方法內部通過binder_new_node方法,給ServiceManager建立binder_node實體binder_context_mgr_node,這個實體是一個全域性變數。建立好的binder_node會進行初始化,比如講binder_proc加入到結構體的proc指標,建立async_todo,binder_work兩個佇列等。
③binder_loop:該方法首先通過binder_write方法(內部也是ioctl系統呼叫)將BC_ENTER_LOOPER命令傳送給binder驅動,將binder_thread設為BINDER_LOOPER_STATE_ENTERED表示它進入了loop迴圈,之後的for無限迴圈裡通過ioctl不斷進行binder的讀寫過程,然後通過svcmgr_handler方法,進行binder資訊的處理,包括註冊服務,查詢服務等(服務被儲存在一個list裡)
(4)註冊服務
註冊之前首先要通過defaultServiceManager方法獲得BpServiceManager物件,同時會建立ProcessState物件和BpBinder物件,之後呼叫addService方法。該方法內部會呼叫BpBinder(這相當於一個代理類)的transact方法,引數裡包括一個新增服務的命令。這個方法內部則會建立(如果不存在的話)並呼叫IPCThreadState的transact方法。IPCThreadState儲存在ThreadLocalStorage中,每個執行緒都有自己的一個例項,其內部有一個mIn成員和mOut成員,用來接受和儲存Binder裝置的資料。這個transact方法最終會和binder驅動進行互動,首先他會為這個service建立一個binder_node實體,併為它建立一個引用,然後將待處理的事項加入到todo和work佇列中,然後喚醒ServiceManager進行處理。ServiceManager最終會進行註冊服務的過程(在loop中)。
(5)獲取服務
獲取一個服務的流程和註冊服務類似,也需要獲得BpServiceManager,進行BpBinder的transact,IPCThreadState的transact過程,ServiceManager最終會返回對應服務的Binder引用,客戶端會根據這個引用和其包含的控制程式碼建立一個BpBinder,從而可以通過這個代理物件和這個服務進行通訊了。

相關文章