這篇文章是對IBinder對象在進程間傳遞的形式(一)這篇文章的補充,首先還是把service啟動過程的流程圖貼上來
Android中主要通過2種方法來獲得service IBinder:
1. 通過ServiceManager.getService(String Descriptor)來獲得Service Manager管理的service的IBinder。
2. Client獲得Application Service的IBinder,如下圖描述的binder service流程。
不管哪種方法,均涉及到IBinder在不同進程間的傳遞,因為不論是Application Service 還是System Service,它們在註冊時均會涉及到第三方進程,如Application Service註冊在Acitivity Manager中(system_server進程),System Service註冊在Service Manager中(servicemanager進程)。
從Service Manager中獲得IBinder涉及到service和servicemanager進程以及client和servicemanager進程之間的IBinder傳遞;
獲得Application Service的IBinder,更是涉及到ApplicationService和system_server進程以及client和system_server進程之間的IBinder傳遞,如上圖所示。
研究這個主題的意義在於,雖然從表面上看,在用到IBinder時,我們在應用中使用的是同一個接口,但是它的實質是怎麼樣的?是一套什麼樣的機制保證在同進程間client調用的是service的實體,而在不同進程間則是調用的service的proxy。
關於Binder的傳遞過程,首先需要瞭解一個service的類圖關系。下圖為JNI以上的類圖。涉及到JNI和JAVA層的Binder對應關系。JNI層以下的Binder不涉及到這個文章的主題。
IISERVICEInterface表示aidl文件生成的或者用戶自定義的當前service的接口文件,SERVICE表示當前service的實現。IISERVICEInterface.Proxy表示當前service的代理。
在JNI層,JavaBBinder繼承自BBinder,是Binder的實體,它是在BBinder的基礎上添加瞭成員變量jobjectmObject,該成員變量指向JAVA的SERVICE對象。這麼做的好處就是在同進程間傳遞時,接收方能夠直接向JAVA層返回SERVICE對象。
JavaBBinderHolder類,可以說是JavaBBinder類的一個容器,當JAVA層的SERVICE對象被創建時,就會相應的創建一個JavaBBinderHolder實例(android_os_Binder_init@android_util_Binder.cpp),但是隻有SERVICE對象被IPC傳遞時,JavaBBinderHolder對象才會創建一個JavaBBinder實例(JavaBBinderHolder::get(env)@ android_util_Binder.cpp)。
1. IBinder在IPC通信中的發送過程
IBinder在IPC通信中,android通過Parcel類的成員函數writeStrongBinder()寫入IBinder,在向Parcel寫入IBinder時,首先會判斷JAVA層IBinder的類型並轉化為native的IBinder類型,下面介紹它的的2種類型。
android_os_Parcel_writeStrongBinder()@android_util_Binder.cpp
parcel->writeStrongBinder(ibinderForJavaObject(env, object));@ android_util_Binder.cpp
[java]
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
}
LOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
1.1 IBinder是以JavaBBinder的形式傳遞的,即是一個ServiceIBinder的reference。如上圖中的第一個return語句。
這種較常見,作為傳輸介質的IBinder所處的service和發送方在同一進程中。
Service處在Process A中,ProcessA為IBinder發送方。
1.2 IBinder是以BpBinder的形式傳遞的,即是一個ServiceIBinder的Proxy。如Service bind圖中的第二個return語句。
Service 處在Process C中,Process A為IBinder發送方。
這種情況比較典型的就是bindservice時會用到,如圖中最後一步中AMS通知client bind成功時,傳遞給client的就是一個service IBinder的Proxy。作為傳輸介質的IBinder所處的service和發送方在不同的進程中。
Kernel中,Binder Module會根據IPC通信雙方是否處於同一個進程中,來設置binder object type值,下圖code描述。
當IBinder的發送方和Service在同一進程的話,那麼傳遞給內核的binder_object的type為BINDER_TYPE_BINDER,由於IBinder發送到內核均是在進程間傳遞的,所以Binder Module driver會將type改為BINDER_TYPE_HANDLE.
當IBinder的發送方和Service不在同一進程的話,那麼傳遞給內核的binder_object的type就為BINDER_TYPE_HANDLE,並且這種情況接收方和Service可能處在同一個進程中,因此當這種情況發生時,需要將其改為BINDER_TYPE_BINDER。這一點在下面會介紹。
IBinder發送的流程:
1. IBinder在IPC通信中的接收過程
首先查看一下Parcel的unflatten_binder@Parcel.cpp(readStrongBinder()方法會調用到):
[java]
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = static_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
2.1 當從BinderModule中讀出的binder_object的type為BINDER_TYPE_BINDER,說明接收方收到的Service是同進程的,那麼此時直接將保存在cookie中的Service的實體傳遞給JNI層。
此時,JNI層收到的Service實體為一個JavaBBinder對象,由上面的類圖可以知道,JavaBBinder對象中包含著JAVA層SERVICE對象的引用。
2.2 當從Binder Module中讀出的binder_object的type為BINDER_TYPE_HANDLER,說明接收方收到的Service不是同進程的,那麼會創建或者引用已有
的一個BpBinder對象給JNI層。
Service 處在Process C中,Process B為IBinder接收方。
2.2.1 如何創建BpBinder對象
通過調用ProcessState的方法getStrongProxyForHandle(),來創建或者引用已有的一個BpBinder對象。
A. 首先,檢查當前所要創建的BpBinder是否已經在Vector mHandleToObject中存在,每個進程中均會維護這麼一個Vector,保存當前進程獲得的所有BpBinder對象。沒有分析出這麼做的原因,可能為瞭資源的重復利用,避免每次使用完都得回收的問題。
B. 如果沒有查找到BpBinder對象,創建一個新的BpBinder對象,並會向mHandleToObject保存這個對象。
由於每個Service均會對應一個唯一的handle,因此可以通過這個handle來標示BpBinder對象。
[java]
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
2.2.2 JNI層的特殊處理
javaObjectForIBinder@android_util_Binder.cpp
[java]
// Someone else's… do we know about it?
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);
if (res != NULL) {
LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
return res;
}
LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
LOGV("objectForBinder %p: created new %p!\n", val.get(), object);
// The proxy holds a reference to the native object.
env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
val->incStrong(object);
// The native object needs to hold a weak reference back to the
// proxy, so we can retrieve the same proxy if it is still active.
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
}
① 首先,在BpBinder對象中查找是否保存相關的BinderProxy的對象,如果有,向JAVA層返回這個對象;
② 如果沒有,創建一個BinderProxy對象;
③ 將新創建的BinderProxy對象,attach到BpBinder對象中。
結合下面的關系圖,我們得出這樣的邏輯關系:
a. 每個進程中會保存多個當前進程調用過的BpBinder對象;
b. 每個BpBinder對象都會保存與之對應的JAVA層的BinderProxy。
將創建的BinderProxyattach到BpBinder的意義在於:通過這種方式,JAVA應用層頻繁獲取同一service的IBinder時,獲取的是同一個BinderProxy。
摘自 杜文濤的專欄