Binder通訊相關的類簡要分析
一、BpBinder
這個類通常作為IPC通訊的Client端,或者說Remote端,提供實際的IPC基礎通訊服務。在程式碼中通常不直接使用到該類,一般以成員變數的形式,包含於BpRefBase類中,通過remote()方法引用該成員變數。繼承關係如下:
BpXXX --> BpInterface<IXXX> --> BpRefBase
在BpXXX方法中,就可以直接通過remote()方法引用到BpBinder例項,繼而利用其提供的IPC通訊功能,通過Binder協議與另一端進行通訊。
BpBinder類的定義說明
成員變數分析:
const int32_t mHandle;//handle for remote obj void reportOneDeath(const Obituary& obit); bool isDescriptorCached() const; mutable Mutex mLock; volatile int32_t mAlive; volatile int32_t mObitsSent; //we have already send Obit? can notify is object is already dead Vector<Obituary>* mObituaries;//dead notification listerners ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache;
mHandle: 這是一個重要的成員變數,代表Binder驅動為一個遠端物件分配的一個控制代碼,在Binder驅動中,通過該控制代碼號,找到對應的Binder引用結點,通過Binder引用結點,找到其引用的位於不同程序中的一個Binder結點,從而將利用該Binder結點將通訊資料路由到通訊的另一端所在的程序。
mLock:保護BpBinder物件的一些方法的訪問,從而保證任何時刻不會同時執行兩個或以上方法。
mAlive:Binder IPC通訊是否處於活躍狀態。
mObjects:物件管理,主要是對Java Binder物件的管理。
mConstantData:未使用
mDescriptorCache:儲存介面描述資訊。
主要方法分析:
virtual status_t transact( uint32_t code,
const Parcel&data,
Parcel*reply,
uint32_tflags = 0);
該方法是Binder IPC通訊的入口,其實質上是呼叫IPCThreadState類的transact方法。
如下兩個介面則是提供監聽遠端物件死亡通知的介面。
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void*cookie = NULL,
uint32_tflags = 0);
virtual status_t unlinkToDeath( constwp<DeathRecipient>& recipient,
void*cookie = NULL,
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = NULL);
BpBinder物件作為遠端物件的代理,它會跟蹤遠端物件的狀態(實質上是在驅動中,跟蹤Binder通訊結點,結點死亡的資訊也是通過驅動層向用戶空間傳送的),一旦接收到死亡通知,則會呼叫如下介面通知所有監聽者:
void sendObituary();
其會呼叫如下方法呼叫所有監聽者提供的回撥函式:
void reportOneDeath(const Obituary& obit);
二、BBinder
BBinder類作為Binder IPC通訊的Server端或Local端,處理來自Client端或Remote端的服務請求。它的主要方法就是處理請求:
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
在IPCThreadState中,是通過如下方式呼叫到上述的介面的:
IPCThreadState(979):
case BR_TRANSACTION:
…
if (tr.target.ptr) {//local
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
} else {//remote
const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
三、Java層類
Java層的類主要有Binder和BinderProxy,其中Binder跟BBinder一樣,屬於Server或Local端,而BinderProxy則與BpBinder一樣,屬於Client端或Remote端。
對於BinderProxy類物件,跟BpBinder一樣,同樣是作為XXXProxy的成員變數的形式包含於其中。
XXXProxy --> IXXX --> IInterface.
在JNI層,定義了兩個轉換函式:
jobject javaObjectForIBinder(JNIEnv* env,const sp<IBinder>& val);
sp<IBinder>ibinderForJavaObject(JNIEnv* env, jobject obj);
上述兩種函式提供了Java物件(主要是Binder和BinderProxy物件)與Native層IBinder物件之間的相互轉換介面。
當我們呼叫transact方法時,會經歷如下一些過程:
in BinderProxy.java
public native boolean transact(int code,Parcel data, Parcel reply,
int flags) throws RemoteException;
-->in android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
…
IBinder* target = (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
…
//printf("Transact from Java code to %p sending: ", target); data->print();
status_t err = target->transact(code, *data, reply, flags);
…
return JNI_FALSE;
}
其中gBinderProxyOffsets.mObject是通過javaObjectForIBinder設定的,它的原型如下:
jobject javaObjectForIBinder(JNIEnv* env,const sp<IBinder>& val);
對於上述函式,除非引數val是JavaBBinder(繼承自BBinder)物件,否則,就建立一個BinderProxy物件,它與一個BpBinder物件關聯。
-->接下來就會呼叫某個IBinder(C++類)物件的transact方法。
這個IBinder物件是BpBinder型別的,即:
BpBinder::transact(…)
--> IPCThreadState::transact(…)
它會向Binder驅動傳送一個BC_TRANSACTION命令,Binder驅動進行處理,將請求路由給通訊的另一端,並通過命令BR_TRANSACTION告知使用者空間,有新的通訊請求。在介紹BBinder的時候,我們提到過,接收端會呼叫BBinder::transact(…)來處理請求,對於Java層的通訊來說,則會實際呼叫JavaBBinder::transact(…)來處理請求,而實際上會呼叫onTransact(…)(過載了BBinder的方法),如下所示:
class JavaBBinder : public BBinder
{
…
protected:
…
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
…
//printf("Transact from %p to Java code sending: ", this);
//data.print();
//printf("\n");
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags);
…
// Need to always call through the native implementation of
// SYSPROPS_TRANSACTION.
if (code == SYSPROPS_TRANSACTION) {
BBinder::onTransact(code, data, reply, flags);
}
…
}
…
};
-->
in Binder.java
// Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, int dataObj, int replyObj,
int flags) {
…
boolean res;
try {
res = onTransact(code, data, reply, flags);
} …
return res;
}
最終呼叫到了Binder類的onTransact方法。從Binder類派生的類都會過載該方法。