Binder機制3---Native層

來源 http://blog.csdn.net/bathinbreeze/article/details/8990000

Native層流程大綱

介紹完Binder驅動的構架後,下面我們進入到Binder Native的流程分析。Binder的整體流程可分爲如下幾個步驟:

  1. Service Manager成爲守護進程--- Service Manager告知Binder驅動程序它是Binder機制的上下文管理者。

  2. Server和Client獲得Service Manager的遠程接口--- defaultServiceManager接口是如何實現的。

  3. Server向SM註冊服務---- IServiceManager::addService接口是如何實現的

  4. Client從SM獲得服務----IServiceManager::getService接口是如何實現的

其中,第2步是3和4的基礎上面4個步驟,是系統中Binder驅動和Native層的主要工作,而Binder Java層的每次調用底層函數都離不開這4步的操作。這裏介紹Native層,Java層將在下章節介紹。

4.1 SM成爲守護進程

SM成爲守護進程的過程中,與驅動交互頻繁,下面會結合之前的驅動框架來分析:

  • Service Manager在用戶空間的源代碼位於frameworks/base/cmds/servicemanager 目錄下,主要是由binder.h、binder.c和service_manager.c三個文件組成。

  • Service Manager的入口位於service_manager.c文件中的main函數Main函數主要有三個功能:

  1. 打開Binder設備文件;

  2. 調用mmap

  3. 告訴Binder驅動程序自己是Binder上下文管理者,即我們前面所說的守護進程;

  4. 進入一個無窮循環,充當Server的角色,等待Client的請求

4.1.1打開Binder設備文件

在service_manager.c打開Binder設備文件的核心代碼見下圖:

函數首先是執行打開Binder設備文件的操作binder_open,這個函數位於frameworks/base/cmds/servicemanager/binder.c文件中, 代碼如下:


主要做了2件主要的事情:

  1. 打開驅動創建的/dev/binder文件結點,創建binder_proc結構體,保存/dev/binder上下文信息

  2. 調用驅動的mmap分配空間

4.1.2 打開設備詳細分析

  1. 通過文件操作函數open打開/dev/binder設備文件,(/dev/binder是在Binder驅動模塊初始化時創建的,創建入口在binder_init());此處調用驅動函數binder_open(),功能如下:

    1. threads樹:用來保存binder_proc進程內用於處理用戶請求的線程

    2. node樹:保存binder_proc進程內的binder實體

    3. refs_by_desc和refs_by_node:保存binder_proc進程內的Binder引用(前者以句柄,後者以節點地址的key來組織)

    4. 創建struct binder_proc,保存打開設備文件的進程上下文信息到struct file的私有變量private_data中

    5. binder_proc下,會掛4棵紅黑樹的節點:

  2. 調用驅動的binder_mmap(),對打開的設備文件進行內存映射mmap:

    •  好處:這樣,同一塊物理地址分別映射給了內核和server進程,就減少了數據從內核到server的拷貝了。 (一般是:client到內核、內核到server)

    1. 通過filp->private_data得到打開/dev/binder時創建的binder_proc結構。

    2. 同一塊地址,會通過struct vm_area_struct 映射用戶空間server進程的使用信息;通過struct vm_struct 同時映射給內核;

    3. 檢查:映射內存大小不能超過4M(此處是128*1024爲128K)

    4. 調用get_vm_area()獲得空間的vm_struct 空間,初始化binder_proc結構體

    5. 調用binder_update_pange_range()爲虛擬地址空間分配空閒的物理頁面

4.1.3 成爲守護進程

回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函數,下一步 就是調用binder_become_context_manager來通知Binder驅動程序自己是Binder機制的上下文管理者,即守護進程。


binder_become_context_manager函數位於frameworks/base/cmds/servicemanager/binder.c文件中,


這裏通過調用ioctl文件操作函數來通知Binder驅動程序自己是守護進程,命令號是BINDER_SET_CONTEXT_MGR,流程如下:

  1. 通過filp->private_data獲得proc變量

  2. 通過binder_get_thread()獲得線程信息,其流程如下:

    • 把當前線程pid作爲鍵值,在進程proc->thread表示的紅黑樹中進行查找,看是否創建了binder_thread信息;如果沒有創        建,創建完後會插入到proc->threads紅黑樹中,下次就可從proc中找到

  3.  碰到binder_context_mgr_node和binder_context_mgr_uid。由於第一次用 到,binder_context_mgr_node表示SM的實體,此時爲null; binder_context_mgr_uid表示SM守護進程的id,此時爲-1;於是會初始化binder_context_mgr_uid爲 current->cred->euid,這樣當前線程就成爲Binder機制的守護進程了,並且通過binder_new_node爲 Service Manager創建Binder實體。

  4. 如果第3步創建了新的binder_node,就會把新建的binder_node指針保存在binder_context_mgr_node中

4.1.4進入loop循環

回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函數中,繼續往下看,會看到調用了binder_loop()函數進入循環,等待Client來請求。


binder_loop函數定義在frameworks/base/cmds/servicemanager/binder.c文件中,流程如下:

  1. 首先是通過binder_write()執行BC_ENTER_LOOPER命令告訴Binder驅動程序,Service Manager要進入循環了,調用驅動 ioctl():

    • 調用binder_get_thread函數獲取binder_thread,就能從proc中直接找到了,不需要創建一個新的。這裏進入case BINDER_WRITE_READ:

    1. 首先是通過copy_from_user(&bwr, ubuf, sizeof(bwr))語句把用戶傳遞進來的參數轉換成struct binder_write_read 結構,並保存在本地變量bwr中,這裏可以看出bwr.write_size等於4,

    2. 於是進入binder_thread_write函數,這裏我們只關注BC_ENTER_LOOPER相關的代碼

    3. 在執行完BC_ENTER_LOOPER時,thread->looper值就變爲BINDER_LOOPER_STATE_ENTERED了,表明當前線程進入循環狀態了

    4. 回到binder_ioctl函數,由於bwr.read_size == 0,binder_thread_read函數就不會被執行了,這樣,binder_ioctl的任務就完成了   

  2. 回到binder_loop函數,進入for循環,又會執行一個ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 由於bwr.write_size等於0,會執行binder_thread_write函數,bwr.read_size等於32,於是進入到 binder_thread_read()。

4.1.5 SM成爲守護進程-總結

至此,我們就從源代碼一步一步地分析完Service Manager是如何成爲Android進程間通信(IPC)機制Binder守護進程的了。總結一下,Service Manager是成爲Android進程間通信(IPC)機制Binder守護進程的過程是這樣的:
        1. 打開/dev/binder文件:open("/dev/binder", O_RDWR);
        2. 建立128K內存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
        3. 通知Binder驅動程序它是守護進程:binder_become_context_manager(bs);
        4. 進入循環等待請求的到來:binder_loop(bs, svcmgr_handler);
在這個過程中,在Binder驅動程序中建立了一個struct binder_proc結構、一個struct  binder_thread結構和一個struct binder_node結構,這樣,Service Manager就在Android系統的進程間通信機制Binder擔負起守護進程的職責了。

4.2 Server和Client獲得Service Manager遠程接口

我們知道,Service Manager在Binder機制中既充當守護進程的角色,同時它也充當着Server角色,然而它又與一般的Server不一樣。對於普通的 Server來說,Client如果想要獲得Server的遠程接口,那麼必須通過Service Manager遠程接口提供的getService接口來獲得,這本身就是一個使用Binder機制來進行進程間通信的過程。而對於Service Manager這個Server來說,Client如果想要獲得Service Manager遠程接口,卻不必通過進程間通信機制來獲得,因爲Service Manager遠程接口是一個特殊的Binder引用,它的引用句柄一定是0。

獲取Service Manager遠程接口的函數是defaultServiceManager,這個函數聲明在frameworks/base/include/binder/IServiceManager.h文件中:


4.2.1 Service Manager繼承關係

那麼爲什麼要獲取遠程端口呢?!是因爲要實現業務以及完成通信。先來看看網上的一個關於繼承關係的圖示:


IServiceManager類提供的業務函數:getService(), checkService(), addService(); 

BpServiceManager類繼承了BpInterface類,而BpInterface類繼承了BpRefBase類。

在BpRefBase類中,有一個成員變量mRemote,它的類型是IBinder*,實現類爲BpBinder,它表示一個Binder引用,引用句柄值保存在BpBinder類的mHandle成員變量中。

BpBinder類通過IPCThreadState類來和Binder驅動程序並互,而IPCThreadState又通過它的成員變量mProcess來打開/dev/binder設備文件,mProcess成員變量的類型爲ProcessState。
ProcessState類打開設備/dev/binder之後,將打開文件描述符保存在mDriverFD成員變量中,以供後續使用。

4.2.2 defaultServiceManager

理清了上述的繼承關係後,我們再來看看defaultServicemanager這個函數。

從這個函數可以看出:gDefaultServiceManager是單例模式,調用defaultServiceManager函數時,如果 gDefaultServiceManager已經創建,則直接返回,否則通過 interface_cast<IServiceManager> (ProcessState::self()->getContextObject(NULL))來創建一個,並保存在 gDefaultServiceManager全局變量中。
在這個過程中,有4個關鍵步驟:

  1. 調用ProcessStaate::self()

  2.  調用getContextObject(NULL)

  3. 使用interface_cast

  4. 使用 <IserviceManager>

下面來分析這4個步驟

4.2.2.1 ProcessState::self()

ProcessState::self()是ProcessState的靜態成員函數,它的作用是返回一個全局唯一的ProcessState實例 變量,就是單例模式了,這個變量名爲gProcess。如果gProcess尚未創建,就會執行創建操作,在ProcessState的構造函數中,會通 過open文件操作函數打開設備文件/dev/binder,並且返回來的設備文件描述符保存在成員變量mDriverFD中。也就是得到了一個可以和底 層打交道的ProcessState類型的gProcess對象。在addervice()的流程裏,會深入分析。

4.2.2.2 getContextObject()

gProcess->getContextObject(NULL),傳遞的值爲NULL即0,返回的值爲 sp<IBinder>類型的getStrongProxyForHandle(0)。 getStrongProxyForHanlde(int32_t handle)中,handle的值是一個資源項數組中的索引值。

  • 作用:根據索引查找對應的資源,如果lookupHandleLocked發現沒有對應資源項,則創建一個新的BpBinder項,填充BpBinder,並返回(handle值爲0)

結果爲:返回一個handle爲0的Binder引用,即BpBinder;於是創建Service Manager遠程接口的語句可以簡化爲:gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0)); 

4.2.2.3 interface_cast

再來看函數interface_cast<IServiceManager>的實現,它是一個模板函數,定義在framework/base/include/binder/IInterface.h文件中:


這裏的《INTERFACE>是IServiceManager,於是調用了IServiceManager::asInterface函 數,那麼 gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0)); 可以變成:gDefaultServiceManager = IServiceManager::asInterface(new BpBinder(0));

IserviceManager::asInterface是通過DECLARE_META_INTERFACE(ServiceManager) 宏在IServiceManager類中聲明的,它位於framework/base/include/binder/IServiceManger.h 文件中。IServiceManager::asInterface的實現是通過 IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")宏定義的,它位於framework/base/libs/binder /IServiceManager.cpp文件中。

4.2.2.4 IServiceManager::asInterface

最終,在IServiceManager::asInterface函數中會調用:Return intr = new BpServiceManager(obj); 這裏的obj就則剛纔創建的new BpBinder(0),上面的代碼爲:

  • intr = new BpServiceManager(new BpBinder(0));

回到defaultServiceManager函數中,最終結果爲:gDefaultServiceManager = new BpServiceManager(new BpBinder(0)); 

這樣,Service Manager遠程接口就創建完成了,它本質上是一個BpServiceManager,包含了一個句柄值爲0的Binder引用。這裏,實現asInterface函數,是利用BpBinder對象新建了一個BpServiceManager對象

4.3 Server向SM註冊服務

實際上,BnMediaPlayerService並不是直接接收到Client處發送過來的請求,而是使用了IPCThreadState接收 Client處發送過來的請求,而IPCThreadState又藉助了ProcessState類來與Binder驅動程序交互。
IPCThreadState接收到了Client處的請求後,就會調用BBinder類的transact函數,並傳入相關參數,BBinder類的 transact函數最終調用BnMediaPlayerService類的onTransact函數,於是,就開始真正地處理Client的請求了。

以MediaServer作爲Server的例子,這裏我們只看MediaPlayerService:多媒體系統的重要服務。MS的入口函數在 \frameworks\av\media\mediaserver\ main_mediaserver.cpp 如下圖,


可分爲5步:

  1. 創建ProcessState

  2. 創建IServiceManager對象

  3. 初始化MediaPlayerService服務對象

  4. 創建進程的線程池 

  5. 把自己加入線程池

下面來分別分析。

4.3.1  ProcessState

之前分析過,這裏詳細介紹下參數傳遞的流程。ProcessState::self()調用創建一個ProcessState實例。 ProcessState::self()是ProcessState類的一個靜態成員變量,定義在frameworks/base/libs /binder/ProcessState.cpp文件中:

這裏可以看出,這個函數作用是返回一個全局唯一的ProcessState實例gProcess。全局唯一實例變量gProcess定義在frameworks/base/libs/binder/Static.cpp文件中


再來看ProcessState的構造函數:ProcessState::ProcessState()的流程:

  1. 通過open_driver()打開binder設備 /dev/binder,並將打開設備文件描述符保存在成員變量mDriverFD中,這樣,與Binder驅動有了交互的通道。open_driver 這個函數同樣位於frameworks/base/libs/binder/ProcessState.cpp文件中,流程如下:

    1. 通過調用驅動open()打開/dev/binder,在打開/dev/binder設備文件後,Binder驅動程序就爲 MediaPlayerService進程創建了一個struct binder_proc結構體實例來維護MediaPlayerService進程上下文相關信息。

    2. 調用ioctl()執行BINDER_VERSION獲得當前Binder驅動程序的版本號。將BINDER_CURRENT_PROTOCOL_VERSION寫入到傳入的參數arg指向的用戶緩衝區中。

    3. 調 用ioctl()執行BINDER_SET_MAX_THREADS,通知Binder驅動程序最多能設置多少個線 程,MediaPlayerService最多可同時啓動15個線程來處理Client端的請求。把用戶傳進來的參數保存在 proc->max_threads中就完畢了。(注意,這裏再調用binder_get_thread函數的時候,就可以在 proc->threads中找到當前線程對應的struct binder_thread結構了,因爲前面已經創建好並保存在proc->threads紅黑樹中)

  2. 對返回的fd使用mmap,把設備文件/dev/binder映射到內存中(流程見“成爲守護進程mmap"部分)

這樣,ProcessState全局唯一變量gProcess就創建完畢了,回到了frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函數

4.3.2 創建IServiceManager對象

DefaultServiceManager函數的實現在之前分析過,則:sp<IServiceManager> sm = defaultServiceManager(); 爲:sp<IServiceManager> sm = new BpServiceManager(new BpBinder(0)); 

4.3.3 註冊MediaPlayerService


MediaPlayerService::instantiate()調 用:defaultServiceManager()->addService()。這個函數最終會通過 IPCthreadState->transact()和Binder驅動打交道,把數據傳送到SM中,完成MediaPlayerService 的註冊。defaultServiceManager()返回的對象是BpServiceManager,而BpServiceManager是 IServiceManager的後代。IServiceManager是一個抽象類,裏面有我們操作業務層的各種函數。

4.3.3.1 MediaPlayerService::instantiate()

MediaPlayerService::instantiate();的實現如下:


這裏,實際上是調用的BpServiceManger::addService()這個函數實現在frameworks/base/libs /binder/IServiceManager.cpp文件中的addService()。addService是一個業務層的函數,調用 remote()->transact();remote()返回的是mRemote,也就是BpBinder對象。在addService函數 中,把請求數據打包成data後,傳遞給了BpBinder的transact函數,把通信任務交給了BpBinder;即交給了通信層去處理。

4.3.3.2 transact()通信層的工作

BpBinder::transact()調用了:status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
這裏的mHandle爲0,code爲ADD_SERVICE_TRANSACTION。ADD_SERVICE_TRANSACTION是上面以參數形 式傳進來的,這裏表示的是Service Manager遠程接口,mHandle的句柄值一定是0。即,把transact工作交給了IPCThreadState。 IPCThreadState::self()中,TLS: Thread Local Storage,每個線程都有,且不共享。通過pthread_getspecific/pthread_setspecific函數可以獲得/設置這些 空間中的內容。

流程如下:

  1. pthread_getspecific()從線程本地存儲空間中獲得保存在其中的IPCThreadState對象

  2. new一個IPCThreadState對象,調用構造函數,構造函數中會調用pthread_setspecific函數。則上面的調用變爲: new IPCThreadState()->transact(mHandle, code, data, reply, flags);

    • err = writeTransactionData(BC_TRANSACTION,...); 函數裏會創建一個binder_transaction_data tr,這個就是等下要傳給Binder驅動的。發送的消息碼爲:BC_XX

    • err = waitForResponse(reply); binder設備嚮應用程序回覆消息,BR_XX爲回覆的消息碼

    • 其中函數中定義的binder_transaction_data是和binder設備通信的數據結構 binder_transaction_data tr;

    • handle的值傳遞給了target用來標識目的端,其中0爲SM的標誌。tr.target.handle = handle;

    • cmd:發送的命令消息碼  BC_XXX,此處爲BC_TRANSACTION

    • code: 用來switch/case的消息碼

    • 把命令寫到mOut中,並不直接發出去。mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr));

    • 該函數原型爲:IPCTheadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)

    • 這時,已經把addService的請求信息”tr”寫到mOut中了,寫入的內容爲:


    • 寫流程:

    • 讀流程:

    • 其中定義了binder_write_read bwr; 一個與binder設備交換數據的結構;這裏調用了驅動的ioctl()與驅動交互:

    • executeCommand(int32_t cmd)收到cmd後,switch(cmd):

    • sp<BBinder>b((BBinder*)tr.cookie); 設置BnServiceXXX的對象b,BnServiceXXX是從BBinder派生

    • b->transact(); 調用transact函數,發送binder_transaction_data和Parcel類型的數據

    • 收到Binder驅動發來的service死掉的消息,只有Bp端能收到

    • 收到來自驅動的指示以創建一個新線程,用於和Binder通信

    • 接收回復的數據waitForResponse(Rarcel *reply, status_t *acquireResult)。在無限循環中(數據讀完或異常,則退出)做了如下事情:

    • 構造函數 IPCThreadState()的流程:

    • IPCThreadState::transact()調用:

    1. 調用talkWithDriver();

    2. 把數據讀到mIn中

    3. 把命令(BR_XXX)讀出並switch/case

    4. executeCommand(cmd)執行命令

    5. 請求命令填充

    6. 調用ioctl,由binder驅動實現具體操作

    7. 接收數據緩衝區信息的填充,如果以後收到數據,就填到mIn中

    8. 調用ioctl,由binder驅動實現具體操作

    9. case BR_ERROR:

    10. case BR_TRANSACTION:

    11. case BR_DEAD_BINDER:

    12. case BR_SPAWN_LOOPER:

    13. pthread_setspecific() 把自己設置到線程本地存儲中

    14. 設置mIn和mOut搜法命令的緩衝區

4.3.4 StartThreadPool()

StartThreadPool()調用spawnPooledThread()函數:sp<Thread> t = new PoolThread(isMain); isMain參數是true; PoolThread是在IPCThreadState中定義了一個Thread子類。PoolThread類中,調用threadLoop()。 threadLoop()中,在這個線程中又創建了一個IPCThreadState: IPCThreadState::self()->joinThreadPool(mIsMain)。

joinThreadPool()流程:

  1. mOut.writeInt32(isMain?BC_ENTER_LOOPER: BC_REGISTER_LOOPER); 如果isMain爲true,則需要循環處理。把請求寫到mOut中,過會一起發出

  2. 處理已經死亡的BBinder對象

  3. 發送命令,讀取請求:調用talkWithDriver();

4.3.5 MS中的joinThreadPool()

MediaServer進程一共註冊了4個服務。MS中目前有兩個線程在talkWithDriver():

  • 一個是StartThreadPool啓動新線程通過joinThreadPool,調用talkWithDriver(),讀取binder設備;

  • 另一個是MS主線程調用joinThreadPool,調用talkWithDriver(),讀取binder設備

BnService和BpService負責業務的交互;BBinder和BpBinder負責通信的交互


4.3.6 MediaServer註冊服務到SM流程圖


4.4 Client從SM獲得服務

client從SM獲得服務,也就是從SM獲得 BpMediaPlayerService。BpMediaPlayerService的構造函數有一個參數impl,它的類型爲const sp<IBinder>&,從上面的描述中,這個實際上就是一個BpBinder對象。 這樣,要創建一個BpMediaPlayerService對象,首先就要有一個BpBinder對象。再來看BpBinder類的構造函數,它有一個參 數handle,類型爲int32_t,這個參數的意義就是請求MediaPlayerService這個遠程接口的進程對 MediaPlayerService這個Binder實體的引用了。因此,獲取MediaPlayerService這個遠程接口的本質問題就變爲從 Service Manager中獲得MediaPlayerService的一個句柄了。

4.4.1 詳細分析:

這裏我們以MediaServer中的MediaPlayService與Client交互爲例,來了解請求數據是如何從通信層傳遞到業務層並進行處理的:

client想要獲得某個Service的信息,就得先和SM交互,通過調用getService()來獲得對應的Service信息,這裏用到的是IMediaDeathNotifier::getMeidaPlayerService()

  1. 通過defaultServiceManager()獲得SM的遠程接口BpServiceManager的IServiceManager接口

  2. 用while循環通過binder= sm->getService()不斷嘗試獲得名字爲”media.player”的service;向SM查詢對應服務的信息,返回一個與MediaPlayerService通信的BpBinder;如果SM上還沒有註冊對應的服務,則睡0.5秒再嘗試,直到對應服務註冊到SM上才中止

  3. 通過interface_cast,將這個binder轉換成一個BpMediaPlayerService

有了BpMediaPlayerService,client就能夠使用任何IMediaPlayerService提供的業務邏輯函數 了,e.g: createMediaRecorder和createMetadataRetriever等。調用這些函數都將把請求數據打包發給Binder驅動,並 由BpBinder中handle知道對應端的處理者來處理,包括

  1. 通信層接收到請求

  2. 遞交給業務層處理

4.4.2 BpServiceManager::getService()

BpServiceManager::getService通過BpServiceManager::checkService執行操作。

在BpServiceManager::checkService中:

  1. 首先是通過Parcel::writeInterfaceToken往data寫入一個RPC頭;就是寫往data裏面寫入了一個整數和一個字符 串“android.os.IServiceManager”, Service Manager來處理CHECK_SERVICE_TRANSACTION請求之前,會先驗證一下這個RPC頭,看看是否正確。接着再往data寫入一個 字符串name,這裏就是“media.player”了

  2. 調用remote()返回的是一個BpBinder,於是,就進行到 BpBinder::transact函數了。這裏的mHandle = 0,code = CHECK_SERVICE_TRANSACTION,flags = 0。進入到IPCThread::transact函數中:

    1. 首先是調用函數writeTransactionData寫入將要傳輸的數據到IPCThreadState的成員變量mOut中去

    2. 調 用waitForResponse(reply),這個函數通過IPCThreadState::talkWithDriver與驅動程序進行交互,這裏 的needRead爲true,因此,bwr.read_size大於0;outAvail也大於0,因此,bwr.write_size也大於0;

    3. 最後ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)

4.5 c/s Native層通信小結

  • 通信層

    1. 首先server和client都調用了ProcessState的構造函數從而都向驅動申請了一塊物理內存用於通信數據的存放

    2. server 調用SM的addService函數傳遞一個字符串和實際Binder對象在自己虛擬地址空間的地址到Binder驅動,Binder驅動記錄下該地址 值,在SM申請的物理內存中分配一個虛擬地址並連同字符串一起傳遞給SM,而且Binder驅動會記錄下兩個地址之間的對應關係.

    3. client 調用SM的getService函數傳遞一個字符串給SM,SM將相對應的虛擬地址值傳遞給Binder驅動,Binder驅動查詢出實際對象的地址,在 client申請的物理內存中分配一個虛擬地址並傳遞給client,而且Binder驅動會記錄下這個地址和實際Binder對象地址之間的對應關 系,client這裏得到的就是實際Binder的引用了。到了這一步,真正的Binder對象就擁有兩個引用,一個在SM,一個client.

    4. client通過得到的Binder引用調用server中的函數,驅動會根據傳遞過來引用值找到應該處理該請求的進程,並喚醒其中的Binder線程,調用BBinder對象的onTransaction函數,最終調用到實際的函數

  • 從通信層到業務層

    • 從bpxxxService的構造函數可以看出,在Client進程,每一個BpxxxService對象都封裝了一個BpBinder對象,因 此,確切來說,Client進程緩存的是BpBinder對象,每一個BpBinder對象都與一個Binder句柄值對應。每當Client進程需要創 建一個BpxxxService對象時,就會檢查本地緩存中是否已經存在對應的BpBinder對象。如果存在的話,就可以直接使用它來創建一個 BpxxxService對象,否則的話,就要通過Binder驅動程序來獲得一個Binder句柄值,再以這個句柄值來創建一個BpBinder對象, 最後再根據這個BpBinder對象來創建一個BpxxxService對象。

  • 業務層

    • 由於BpMediaPlayerService繼承了IMediaPlayerService,IXXService有比如createMediaRecord(), CreateMetaDataRetrive()等業務層方法,則可以完成相應業務需要

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章