前言
隔行如隔山,這句話同樣適用於任何時候,即時同一個專業,深入下去的話,差別也是巨大的。今天,講下自己如何學習binder進程間通信的機制的一些見解。開始的時候,只知道 Binder 是個很底層的東西,甚至對於具體是什么用都不是很清楚。
主要是通過兩種方式:
-
看別人寫的Binder博文
目的很簡單,大概了解Binder是個什么東西,有哪些核心的東西,對於看源碼的時候選擇性過濾有幫助,最好是看了后畫下思維導圖總結下或者可以畫下流程圖。 -
看Binder源碼
對於切入點的話,從最熟悉的客戶端入手;選擇典型的具體例子,分析下前面從他人那邊看到的重點。
Binder世界之門
- 學習如何使用東西和思考為什么要創造東西是完全不一樣的,很多人寫文章往往是忽略了后者。
想下如果兩個進程需要相互通信,需要做什么? 假設其中一個進程是客戶端進程,另一個是服務端進程,這里約定簡稱客戶端與服務端。
-
1.客戶端需要知道哪一個是他要調用的服務端的方法。
-
2.客戶端如何傳遞和接收數據給服務端。
-
3.屏蔽底層通信的細節,包括數據交換通過共享內存。
第一個問題很簡單,搞一個唯一的標識符,通過包名+類名。
第二個問題,可以使用實現Parcelable接口的類,why? 這是因為 Android 系統可通過它將對象分解成可編組到各進程的原語。
第三個問題,封裝一個類來具體的實現,他的名字叫Binder,然后這個binder的話,需要服務端來繼承。
具體看源碼
找好切入點
- 由於binder是支撐Android系統的重要組成部分,binder從源碼來說是很龐大的,所以這里找一個好的切入點變得非常重要。正所謂,前人栽樹,后人乘涼,參考 徹底理解Android Binder通信架構 此文,切入點是startService開始的,具體分析的是客戶端進程調用服務端進程的過程。
[=> 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的obtain和recycle方法
- 這兩個方法看名字很熟悉有沒有?前次講的handler中生成的Message其實也有這兩個方法,知覺告訴我,這兩處地方的原理是一樣的,心動不如行動,馬上進入驗證環節。
obtain方法
[=> Parcel.java::obtain]
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);
}
}
- obtain方法:如果緩存Parcel數組不為空則使用緩存數組,否則自家創建一個Parcel。
nativeCreate方法
[=> 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);
}
recycle方法
[=> Parcel.java::recycle]
/**
* 把一個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);
}
}
- recycle方法:根據mOwnsNativeParcelObject的值,若為true,則不帶參數的obtain方法獲取的對象,把其放入sOwnedPool中,否則帶nativePtr的obtain(int obj)方法獲取nativePtr指向的對象,把其放入sHolderPool中。
看了源碼后發現,其實這個原理類似的,緩存的方式有區別,Message是通過鏈表方式來進行,Parcel是通過固定的數組,異曲同工之妙。
探秘mRemote
涉及代碼:需要解決兩個問題,一個是mRemote哪里來,另一個是mRemote的transact方法
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
mRemote哪里來
- 搜尋發現,
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對象。
mRemote的transact方法
[-> 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_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的賦值過程. 接下來就進入該方法.
后續分析==