1.IBinder的傳遞
Binder IPC通信中,Binder是通信的媒介,Parcel是通信的內容。遠程調用過程中,其參數都被打包成Parcel的形式來傳遞。IBinder對象當然也不例外,在前一篇 Binder機制,從Java到C (4. Parcel) 中說到IBinder對象是能夠進行進程間傳遞的。
下面就看一下IBinder對象在傳遞過程中會有什么變化。
在IPC通信的Proxy端,我們經常可以看到下面類似的代碼,一些參數都會打包到Parcel中。看下面的data和reply。
1 public void publishService(IBinder token, 2 Intent intent, IBinder service) throws RemoteException { 3 Parcel data = Parcel.obtain(); 4 Parcel reply = Parcel.obtain(); 5 data.writeInterfaceToken(IActivityManager.descriptor); 6 data.writeStrongBinder(token); 7 intent.writeToParcel(data, 0); 8 data.writeStrongBinder(service); 9 mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0); 10 reply.readException(); 11 data.recycle(); 12 reply.recycle(); 13 }
在IPC通信里,android是通過Parcel類的成員函數writeStrongBinder()向Parcel寫入IBinder,再通過mRemote發送出去。
2.writeStrongBinder()
接下來就看一下writeStrongBinder()這個函數里做了什么。
/frameworks/base/core/java/android/os/Parcel.java
1 public final class Parcel { 2 … 3 /** 4 * Write an object into the parcel at the current dataPosition(), 5 * growing dataCapacity() if needed. 6 */ 7 public final void writeStrongBinder(IBinder val) { 8 nativeWriteStrongBinder(mNativePtr, val); 9 } 10 private static native void nativeWriteStrongBinder(int nativePtr, IBinder val); 11 … 12 }
看,這里又調用了native方法,我們會發現Java 層的一些Parcel其實只是對C/C++層的一個封裝,大部分操作還是依靠JNI去調用Native的操作。
那看一下C++里對應的方法:
/frameworks/base/core/jni/android_os_Parcel.cpp
1 static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object) 2 { 3 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); 4 if (parcel != NULL) { 5 const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); 6 if (err != NO_ERROR) { 7 signalExceptionForError(env, clazz, err); 8 } 9 } 10 }
最主要的就是ibinderForJavaObject 這個函數,繼續跟蹤代碼:
/frameworks/base/core/jni/android_util_Binder.cpp
1 sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) 2 { 3 if (obj == NULL) return NULL; 4 5 if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java層中的Binder class 6 JavaBBinderHolder* jbh = (JavaBBinderHolder*) 7 env->GetIntField(obj, gBinderOffsets.mObject); 8 return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,繼承自BBinder 9 } 10 11 if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java層的BinderProxy class 12 return (IBinder*) 13 env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一個BpBinder,mObject是它的地址值 14 } 15 ALOGW("ibinderForJavaObject: %p is not a Binder object", obj); 16 return NULL; 17 }
這個函數呢,就是根據傳進來的Java對象找到對應的C++對象,這里的參數obj,可能會指向兩種對象:Binder對象或者BinderProxy對象。這兩個對象我們在RemoteService那一篇里其實就遇到過了,Binder對象呢就是Service里實現的那個mRemoteBinder,BinderProxy對象呢就是Activity里回調傳進來的那個service。不記得的話,可以再看一下那一篇:Binder機制,從Java到C (1. IPC in Application Remote Service)
接着說,如果傳進來的是Binder對象,那么就會把gBinderOffsets.mObject轉化成JavaBBinderHolder, 並從中獲得一個JavaBBinder對象。JavaBBinder繼承自BBinder。(在RemoteService那一篇,Service會在onBind回調里把mRemoteBinder傳給AMS,這里傳遞的就是Binder對象)
如果傳進來的是BinderProxy對象。就會返回一個BpBinder,這個BpBinder的地址值就保存在gBinderProxyOffsets.mObject中。(在RemoteService那一篇,AMS要傳遞給Acticity的就是BinderProxy對象)。
到這里,你可能會奇怪,為什么Service把Binder對象傳遞給AMS,后面AMS卻是把BinderProxy對象傳遞給Activity呢?這個我們后面再說,(可以先說一下,其實是因為這些Binder對象都會經過底層傳輸,那在傳輸的過程中,Binder模塊就會根據不同的情況對這些對象進行轉化)
好吧,那還是接着說,有發送,當然會有接收,再來看一下Parcel的readStrongBinder():
3.readStrongBinder()
同樣也是JNI調用:
/frameworks/base/core/jni/android_os_Parcel.cpp
1 static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr) 2 { 3 ... 4 return javaObjectForIBinder(env, parcel->readStrongBinder()); 5 } 6 7 /frameworks/base/core/jni/android_util_Binder.cpp 8 jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) (1) 9 { 10 if (val == NULL) return NULL; 11 if (val->checkSubclass(&gBinderOffsets)) { (2)12 // One of our own! 13 jobject object = static_cast<JavaBBinder*>(val.get())->object(); 14 LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object); 15 return object; 16 } 17 ... 18 jobject object = (jobject)val->findObject(&gBinderProxyOffsets); 19 if (object != NULL) { 20 jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3) 21 if (res != NULL) { 22 ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res); 23 return res; 24 } 25 ... 26 } 27 object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4) 28 if (object != NULL) { 29 …. 30 } 31 return object; 32 }
(1):這里的val和writeStrongBinder類似,不過是反過來,指向的可能是JavaBBinder或者BpBinder。
(2):如果是JavaBBinder,就會通過成員函數object(),返回一個Java對象,這個對象就是Java層的Binder對象。
(3):如果是BpBinder,那就先查找是否已經存在需要使用的BinderProxy對象,如果找到就返回引用
(4):如果沒找到可用的引用,就new 一個BinderProxy對象。
4.Binder Module in Kernel
實際上,在Client端將參數打包成Parcel后,會發送到kernel的Binder module。在Binder module中,會有兩種IBinder類型:BINDER_TYPE_BINDER,BINDER_TYPE_HANDLE。也對應着ava的本地對象和代理對象。
在Binder module收到數據后,會對不同的情況做進一步處理:
1.傳來的IBinder類型是BINDER_TYPE_BINDER, 會將binder_type轉化為BINDER_TYPE_HANDLE;
(這里理解起來有點別扭,因為只有在不同進程間傳遞IBinder時,才會把IBinder傳遞到kernel里,所以傳遞進來的IBinder必定是傳遞給別的process,不會是IBinder所在的process,這時,IBinder所在的process和發送目標process不是同一個,就需要改成BINDER_TYPE_HANDLE。如果IBinder是在同一個進程間傳遞,也不會進入到kernel里。所以一個BINDER_TYPE_BINDER類型的IBinder傳進kernel,就必然需要轉化成BINDER_TYPE_HANDLE)
2.傳來的IBinder類型是BINDER_TYPE_HANDLE,會判斷這個IBinder實體定義的process和發送的目標process是否相同,如果相同,就將binder_type轉化成BINDER_TYPE_BINDER。如果不同,保持BINDER_TYPE_HANDLE。
因為只有不同進程間傳遞才會把IBinder發送到Binder module,所以在IBinder的傳遞中,可能會有2中可能。
1.process A → process B → process A
2.process A → process B → process C
這時候,對應的IBinder類型就會是:
1.BINDER_TYPE_BINDER → BINDER_TYPE_HANDLE → BINDER_TYPE_BINDER
2.BINDER_TYPE_BINDER → BINDER_TYPE_HANDLE → BINDER_TYPE_HANDLE
5.再看 Bind service
實際上,bind一個service的過程,也就是上述的第2中情況。