Android中的IPC-(Binder)

最近在重新看<Android開發(fā)藝術(shù)探索>準(zhǔn)備將閱讀的記錄下來,加深理解

Binder

  1. 從來類的角度來說,Binder就是Android的一個(gè)類,它繼承了IBinder接口

  2. 從IPC的角度來說,Binder是Android中的一個(gè)中的一種跨進(jìn)程通信方式,Binder還可以理解為一種虛擬的物理設(shè)備,它的設(shè)備驅(qū)動(dòng)是/dev/binder,該通信方式在Linux中沒有(由于耦合性太強(qiáng),而Linux沒有接納)

  3. 從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager等)和相應(yīng)的ManagerService的橋梁

  4. 從Android應(yīng)用層的角度來說,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介,當(dāng)你bindService的時(shí)候,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對象,通過這個(gè)Binder對象,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù),這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)

Android開發(fā)中,Binder主要是用于Service中,包括了Aidl和Messenger,Messenger的底層實(shí)現(xiàn)其實(shí)就是AIDL.

我們新建一個(gè)aidl文件,build之后系統(tǒng)會(huì)自動(dòng)根據(jù)創(chuàng)建的aidl文件生成一個(gè)同名的java文件,他本質(zhì)是一個(gè)繼承了android.os.IInterface的接口,所有可以在Binder中傳輸?shù)慕涌诙夹枰^承IInterface這個(gè)接口.

系統(tǒng)生成的代碼中,會(huì)有之前在aidl中聲明的方法 同時(shí)有一個(gè)抽象的Stub類,這個(gè)Stub其實(shí)就是一個(gè)Binder類,同時(shí)在Stub中還有一個(gè)內(nèi)部Proxy類。

這里我繞了很久才明白為什么在Proxy內(nèi)的方法是運(yùn)行在客戶端的,onTransact的方法是運(yùn)行于服務(wù)端的,我們這里可以先看一下概念,后續(xù)會(huì)通過代碼進(jìn)行分析
首先可以查看一下Stub內(nèi)部的元素:


  • DESCRIPTOR:唯一標(biāo)識(shí)符
  • Stub():構(gòu)造函數(shù)
  • asInterface(android.os.IBinder obj) :用于將遠(yuǎn)程的Binder對象轉(zhuǎn)換為客戶端所需要的AIDL對象.在此函數(shù)中,如果服務(wù)端和客戶端是處于同一進(jìn)程,返回的就是服務(wù)端的Stub對象,如果不是則會(huì)返回封裝的Stub.Proxy對象
  • asBinder:返回當(dāng)前的Binder對象
  • onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags):該方法運(yùn)行與服務(wù)端的Binder線程池中,當(dāng)客戶端發(fā)起了跨進(jìn)程的請求時(shí),遠(yuǎn)程請求會(huì)通過系統(tǒng)底層封裝后交給該函數(shù)進(jìn)行處理,服務(wù)端可以通過code知道遠(yuǎn)程調(diào)用的是哪一個(gè)方法,將傳入的data中取出方法需要的參數(shù)(如果方法需要的話),然后執(zhí)行目標(biāo)方法.執(zhí)行完畢后將返回值放入到reply中,返回false的話客戶端的調(diào)用會(huì)失敗
    Proxy類:代理類
    內(nèi)部有一個(gè)android.os.IBinder的內(nèi)部變量mRemote,代表了遠(yuǎn)程的Ibinder對象,構(gòu)造函數(shù)為

Proxy(android.os.IBinder remote) {

mRemote = remote;

}

Proxy#聲明的方法:

這個(gè)方法會(huì)運(yùn)行在客戶端,當(dāng)客戶端進(jìn)行調(diào)用時(shí),首先會(huì)獲取到兩個(gè)Parcel對象,一個(gè)為傳入的數(shù)據(jù),一個(gè)為返回的數(shù)據(jù). 通過函數(shù)_data.writeInterfaceToken(DESCRIPTOR);將當(dāng)前遠(yuǎn)程的唯一描述符寫入,接著通過函數(shù)transact調(diào)用相應(yīng)的函數(shù)方法, 接著函數(shù)掛起,等待執(zhí)行完畢后會(huì)讀取返回到的數(shù)據(jù)然后返回.接著我們通過代碼來查看一下這個(gè)過程.


@Override

public java.util.List<Book> getBookList() throws android.os.RemoteException {

   android.os.Parcel _data = android.os.Parcel.obtain();

    android.os.Parcel _reply = android.os.Parcel.obtain();

    java.util.List<Book> _result;

    try {

       _data.writeInterfaceToken(DESCRIPTOR);

        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);

        _reply.readException();

        _result = _reply.createTypedArrayList(com.hy.bindertest.Book.CREATOR);

    }finally {

        _reply.recycle();

        _data.recycle();

    }

return _result;

}

接著我們進(jìn)入mRemote.transact()這個(gè)函數(shù)中.


/**

* Default implementation rewinds the parcels and calls onTransact.  On

* the remote side, transact calls into the binder to do the IPC.

*/

public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, 
                              int flags)throws RemoteException {

    if (false) Log.v("Binder", "Transact: " + code +" to " +this);

    if (data !=null) {

        data.setDataPosition(0);

    }

    boolean r = onTransact(code, data, reply, flags);//這里代用了onTransact方法

    if (reply !=null) {

        reply.setDataPosition(0);

    }
 
    return r;

}

會(huì)發(fā)現(xiàn)他最后調(diào)用的就是mRemote中的onTransact函數(shù),而mRemote這個(gè)遠(yuǎn)程Binder對象,是運(yùn)行于服務(wù)端的BInder線程中,所以這里也就是所說的onTransact方法運(yùn)行于服務(wù)端的Binder線程池中的原因,這時(shí)候當(dāng)前線程會(huì)被掛起,等待RPC過程結(jié)束后,當(dāng)前線程繼續(xù)進(jìn)行,然后從_replay中獲取到RPC過程返回的結(jié)果,最后返回_replay中的數(shù)據(jù).

所以,我們就知道,當(dāng)客戶端發(fā)起一次遠(yuǎn)程的調(diào)用時(shí),當(dāng)前的線程會(huì)被掛起知道服務(wù)端返回?cái)?shù)據(jù),所以一個(gè)遠(yuǎn)程函數(shù)是很耗時(shí)的,我們不能在UI線程中進(jìn)行調(diào)用,而服務(wù)器端的Binder方法是運(yùn)行于Binder的線程池中的,所以Binder中的方法我們不需要再開線程進(jìn)行執(zhí)行.

所以整個(gè)過程就比較清晰了:

首先客戶端發(fā)起一個(gè)遠(yuǎn)程的請求->Binder收到之后,將參數(shù)寫入到data中,調(diào)用transact方法執(zhí)行,遠(yuǎn)程的Service中的OnTransact函數(shù)指定函數(shù)被調(diào)用,將結(jié)果寫入到reply返回到Binder中,Binder獲取到結(jié)果,返回給Client;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容