隔行如隔山,這句話一樣適用於任什麼時候候,即時同一個專業,深刻下去的話,差異也是巨大的。今天,講下本身如何學習binder進程間通訊的機制的一些看法。開始的時候,只知道 Binder 是個很底層的東西,甚至對於具體是什麼用都不是很清楚。java
主要是經過兩種方式:android
看別人寫的Binder博文
目的很簡單,大概瞭解Binder是個什麼東西,有哪些核心的東西,對於看源碼的時候選擇性過濾有幫助,最好是看了後畫下思惟導圖總結下或者能夠畫下流程圖。c++
看Binder源碼
對於切入點的話,從最熟悉的客戶端入手;選擇典型的具體例子,分析下前面從他人那邊看到的重點。git
想下若是兩個進程須要相互通訊,須要作什麼? 假設其中一個進程是客戶端進程,另外一個是服務端進程,這裏約定簡稱客戶端與服務端。數組
1.客戶端須要知道哪個是他要調用的服務端的方法。
2.客戶端如何傳遞和接收數據給服務端。
3.屏蔽底層通訊的細節,包括數據交換經過共享內存。
第一個問題很簡單,搞一個惟一的標識符,經過包名+類名。
第二個問題,可使用實現Parcelable接口的類,why? 這是由於 Android 系統可經過它將對象分解成可編組到各進程的原語。
第三個問題,封裝一個類來具體的實現,他的名字叫Binder,而後這個binder的話,須要服務端來繼承。緩存
[=> ActivityManagerNative::ActivityManagerProxy]架構
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int userId) throws RemoteException { //這一步操做主要實例了兩個Parcel對象,datat是客戶端的發送數據,reply是服務端返回的數據 //具體參考:Parcel的obtain和recycle方法 Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); service.writeToParcel(data, 0); data.writeString(resolvedType); data.writeInt(userId); // mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); ComponentName res = ComponentName.readFromParcel(reply); //具體參考:Parcel的obtain和recycle方法 data.recycle(); reply.recycle(); return res; }
[=> Parcel.java::obtain]app
private static final int POOL_SIZE = 6; private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE]; ... ... ... /** *說明下:這個pool是上面聲明的一個6容量的Parcel數組,方法中省略若干代碼 *從這個pool中檢索一個新的 Parcel 對象 */ public static Parcel obtain() { final Parcel[] pool = sOwnedPool; synchronized (pool) { Parcel p; for (int i=0; i<POOL_SIZE; i++) { p = pool[i]; if (p != null) { pool[i] = null; return p; } } } //這裏參數傳的是0 return new Parcel(0); } ... ... ... private Parcel(int nativePtr) { init(nativePtr); } private void init(int nativePtr) { if (nativePtr != 0) { mNativePtr = nativePtr; mOwnsNativeParcelObject = false; } else { //nativeCreate是個native方法,參考:nativeCreate方法,mNativePtr這個是能夠理解成指針 mNativePtr = nativeCreate(); mOwnsNativeParcelObject = true; } } private void freeBuffer() { if (mOwnsNativeParcelObject) { nativeFreeBuffer(mNativePtr); } }
[=> android_os_Parcel.cpp::android_os_Parcel_create]學習
/** *這裏來看的話,很清楚的看到返回的是parcel的指針 **/ static jint android_os_Parcel_create(JNIEnv* env, jclass clazz) { Parcel* parcel = new Parcel(); return reinterpret_cast<jint>(parcel); }
[=> Parcel.java::recycle]this
/** * 把一個Parcel對象放回到pool池中。在這回調以前,不須要這個對象。You must not touch * the object after this call. */ public final void recycle() { //這個方法內部調的是native方法,實際上是根據指針釋放內存 freeBuffer(); final Parcel[] pool; //這裏實際上是在obtain無參方法中實例化建立過程當中賦值爲true if (mOwnsNativeParcelObject) { pool = sOwnedPool; } else { //mNativePtr能夠看作是指向Parcel對象的指針,sHolderPool也是一個6容量的Parcel數組 mNativePtr = 0; pool = sHolderPool; } //放到緩存數組中 synchronized (pool) { for (int i=0; i<POOL_SIZE; i++) { if (pool[i] == null) { pool[i] = this; return; } } } } ... ... ... private void freeBuffer() { if (mOwnsNativeParcelObject) { nativeFreeBuffer(mNativePtr); } }
看了源碼後發現,其實這個原理相似的,緩存的方式有區別,Message是經過鏈表方式來進行,Parcel是經過固定的數組,殊途同歸之妙。
涉及代碼:須要解決兩個問題,一個是mRemote哪裏來,另外一個是mRemote的transact方法
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
ActivityManagerProxy
類的構造方法進行賦值,而 ActivityManagerProxy(AMP)
這個類又被 asInterface
方法調用。[-> ActivityManagerNative.java::asInterface]
public abstract class ActivityManagerNative extends Binder implements IActivityManager { static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } //此處obj = BinderProxy, descriptor = "android.app.IActivityManager"; IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); if (in != null) { //此處爲null return in; } return new ActivityManagerProxy(obj); } ... }
此時obj爲BinderProxy對象, 記錄着遠程進程system_server中AMS服務的binder線程的handle.
[-> ActivityManagerNative.java::ActivityManagerProxy]
class ActivityManagerProxy implements IActivityManager { public ActivityManagerProxy(IBinder remote){ mRemote = remote; } }
可知mRemote即是指向AMS服務的BinderProxy對象。
[-> Binder.java::BinderProxy]
final class BinderProxy implements IBinder { public native boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
mRemote實際上調用了 BinderProxy
的 transact
方法,而transact
調用了native方法mRemote.transact()
方法中,通過jni調用android_os_BinderProxy_transact
方法。
[-> android_util_Binder.cpp]
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, jobject dataObj, jobject replyObj, jint flags) { ... //將java Parcel轉爲c++ Parcel Parcel* data = parcelForJavaObject(env, dataObj); Parcel* reply = parcelForJavaObject(env, replyObj); //gBinderProxyOffsets.mObject中保存的是new BpBinder(handle)對象 IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); ... //此處即是BpBinder::transact() status_t err = target->transact(code, *data, reply, flags); ... //最後根據transact執行具體狀況,拋出相應的Exception signalExceptionForError(env, obj, err, true , data->dataSize()); return JNI_FALSE; }
gBinderProxyOffsets.mObject中保存的是BpBinder對象, 這是開機時Zygote調用AndroidRuntime::startReg方法來完成jni方法的註冊.
其中register_android_os_Binder()過程就有一個初始並註冊BinderProxy的操做,完成gBinderProxyOffsets的賦值過程. 接下來就進入該方法.
後續分析==