Android—Camera Client/Server的binder IPC機制


       
        本文首先參考Android Binder IPC分析一文分析了Android Binder IPC通信機制過程及涉及到的各個子元素相關概念,從代碼細節脫離出來,因而整體上把握Android binder IPC通信機制,是能夠理解文章最后Camera Framework進程間通信實現的基礎。參考Android 4.4版本源碼。
  
Binder通信概述
        Android進程間通信(Inter-Process Communication, IPC)采用binder通信機制,是一種client/server結構。一個典型的binder單工通信過程如下述示意圖。
 
        其基本點為:
        1. 表面上看client通過獲得一個server的代理接口,對server進行調用。
        2. 代理接口中定義的方法與server中定義的方法時一一對應的。
        3. client調用某個代理接口中的方法時,代理接口的方法會將client傳遞的參數打包成Parcel對象。
        4. 代理接口將Parcel發送給內核中的binder driver。
        5. server會讀取binder driver中的請求數據,如果是發送給自己的,解包Parcel對象,處理並將結果返回。
        6. 整個的調用過程是一個同步過程,在server處理的時候,client會block住。
 
ServiceManager
        ServiceManager(SM)是service的管理器,任何service在被使用之前,均要向SM注冊,客戶端需要訪問某個service時,應該首先向SM查詢是否存在該服務。如果SM存在這個service,那么會將該service的handle返回給client,handle是每個service的唯一標識符。
        SM的入口函數int main(int argc, char **argv) 在service_manager.c中,進程主要工作為:
        1. 初始化binder,打開/dev/binder設備,在內存中為binder映射128k字節空間;
        2. 指定SM對應的代理binder的handle為0,當client嘗試與SM通信時,需要創建一個handle為0的代理binder;
        3. 通知binder driver(BD)使SM成為BD的context manager;
        4. 維護一個死循環,在這個死循環中,不停地去讀內核中binder driver,查看是否有可讀的內容,即是否有對service的操作需求,如果有,則調用svcmgr_handler回調來處理請求的操作。
        5. SM維護了一個svclist列表來存儲service的信息。
 
        當service在向SM注冊時,該service就是一個client,而SM則作為了server。而某個進程需要與service通信時,此時這個進程為client,service才作為server。
        應用和service之間的通信會涉及到2次binder通信:
        1. 應用向SM查詢service是否存在,如果存在獲得該service的代理binder,為第一次binder通信;
        2. 應用通過binder調用service的方法,為第二次binder通信。
 
ProcessState
        ProcessState是以單例模式設計的。每個進程在使用binder機制通信時,均需要維護一個ProcessState實例來描述當前進程在binder通信時的binder狀態。
        ProcessState有2個主要功能:
        1. 創建一個thread,該線程負責與內核中的binder模塊進行通信,該線程稱為Poolthread;
        2. 為指定的handle創建一個BpBinder對象,並管理該進程中所有的BpBinder對象。
 
        在binder IPC中,所有進程均會啟動一個thread來負責與BD來直接通信,也就是不聽的讀寫BD。Poolthread的啟動方式為,
ProcessState::self()->startThreadPool();
        BpBinder主要功能是負責client向BD發送調用請求的數據,它是client端binder通信的核心對象,通過調用transact函數向BD發送調用請求的數據。BpBinder構造函數為,
BpBinder(int32_t handle);

        通過該構造函數可見,BpBinder會將當前通信中server的handle記錄下來,當有數據發送時,會通知BD數據的發送目標。

        ProcessState通過下述方式來獲取BpBinder對象,
ProcessState::self()->getContextObject(handle);

        ProcessState創建的BpBinder實例,一盤情況下回作為參數創建一個client端的service代理接口,形如BpXXXX,例如與SM通信時,client會創建一個代理接口BpServiceManager。

IPCThreadState
        IPCThreadState是以單例模式設計的。因每個進程只維護了一個ProcessState實例,同時ProcessState只啟動一個Poolthread,因此每個進程只需要一個IPCThreadState即可。
        Poolthread實際內容為:
IPCThreadState::self()->joinThreadPool();

        ProcessState中有兩個Parcel成員,mIn和mOut。Poolthread會不停查詢BD中是否有數據可讀,如果有,將其讀出並保存到mIn;同時不停檢查mOut是否有數據需要向BD發送,如果有,則將其內容寫入到BD中。總而言之,從BD中讀出的數據保存到mIn,待寫入到BD中的數據保存在mOut中。

        ProcessState中生成的BpBinder實例通過調用IPCThreadState的transact函數來向mOut中寫入數據,這樣binder IPC過程的client端的調用請求的發送過程就明了了。
        IPCThreadState 有兩個重要的函數, talkWithDriver 函數負責從 BD 讀寫數據, executeCommand 函數負責解析並執行mIn 中的數據。
 
Binder IPC基本元素分析
基類IInterface
        為client/server端提供接口,它的子類分別聲明了client/service能夠實現的所有的方法。
 
基類IBinder
        定義了binder IPC的通信協議。BBinder和BpBinder均為IBinder的子類,是在IBinder協議框架內進行的收和發操作,構建了基本的binder IPC機制。
 
基類BpRefBase
        client端在查詢ServerManager獲得所需的BpBinder后,BpRefBase負責管理當前獲得的BpBinder實例。
 
接口類BpInterface
        如果client端想要使用binder IPC與Service通信,那么首先會從ServiceManager處查詢並獲得server端service的BpBinder,在client端,這個對象被認為是server端的遠程代理。為了使client能夠像本地調用一樣調用一個遠程server,server端需要向client提供一個接口,client在這個接口的基礎上創建一個BpInterface,使用這個對象,client的應用能夠像本地調用一樣直接調用server端的方法。而不用去關心具體的binder IPC實現。
        BpInterface的原型:
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase

        BpInterface是一個模板類,當server提供了INTERFACE接口(形如IXXXService)后,通常會繼承BpInterface模板類實現一個BpXXXService:

class BpXXXService: public BpInterface<IXXXService>

        實際上BpXXXService實現了雙繼承IXXXService和BpRefBase,這樣既實現了service中各方法的本地操作,將每個方法的參數以Parcel的形式發給binder driver;同時又將BpBinder作為了自己的成員來管理,將BpBinder存儲在mRemote中,通過調用BpRefBase的remote()來獲得BpBinder指針。

 
接口類BnInterface
        BnInterface也是一個模板類。在定義native端的service時,基於server提供的INTERFACE接口(IXXXService),通常會繼承BnInterface模板類實現一個BnXXXService,而native端的service繼承自BnXXXService。BnXXXService定義了一個onTransact函數,這個函數負責解包收到的Parcel並執行client端的請求的方法。
        BnInterface的原型是:
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder

        BnXXXService形如:

class BnXXXService: public BnInterface<IXXXService>

        IXXXService為client端的代理接口BpXXXService和server端的BnXXXService的共同接口類,這個共同接口類的目的就是保證service方法在C/S兩端的一致性。

        每個service都可視為一個binder,而真正的service端的binder的操作及狀態的維護就是通過繼承自BBinder來實現的。BBinder是service作為binder的本質所在。
        那么,BBinder與BpBinder的區別是什么呢?BpBinder是client端創建的用於向server發送消息的代理,而BBinder是server端用於接收消息的通道。他們的代碼中雖然均有transact方法,但兩者的作用不同,BpBinder的transact方法時想IPCThreadState實例發送消息,通知其有消息要發送給binder driver;而BBinder則是當IPCThreadState實例收到binder driver消息時,通過BBinder的transact方法將其傳遞給它的子類BnXXXService的onTransact函數執行server端的操作。
 
Parcel類
        Parcel是binder IPC中的最基本的通信單元,它存儲C/S間函數調用的參數。Parcel只能存儲基本的數據類型,如果是復雜的數據類型的話,在存儲時,需要將其拆分為基本的數據類型來存儲。
         
        binder通信的雙方既可以作為client,也可以作為server,此時的binder通信是一個半雙工的通信,操作的過程會比單工的情況復雜,但是基本原理是一樣的。
 
Camera Framework的IPC機制
        Camera Framework C/S實現類圖如下:
 
        仔細閱讀本文前面的內容,能夠很容易理解Camera Framework采取的C/S結構設計方式。Camera C/S binder IPC通信采用的是半雙工通信的方式。client端提供的接口為ICameraClient,分別通過繼承BpInterface與BnInterface模板類的方式實現代理BpCameraClient(server端的client代理)與client端本地BnCameraClient,Camera為本地具體的實現;server端提供的接口為ICameraServer,分別通過繼承BpInterface與BnInterface模板類的方式實現代理BpCameraService(client端的server代理)與server端本地BnCameraService。
 
        下一篇文章Camera Framework C/S架構服務請求,我們從代碼細節入手,用實例闡述Camera中binder IPC通信的具體過程。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM