天天看點

從AIDL來看Binder的通信原理(基于Andorid8.0)

首先感謝:

​​​從AILD與bindService談Binder程序間通信原理(上)​​ 解答了我很多疑惑, 但由于上述文章的源碼是7.0的,Java架構層沒有用AIDL,是以我想根據新的源碼(8.0)來了解Binder的知識。

前幾天在學習一些Binder機制(較淺)後,我就在趁熱打鐵看看AIDL的一些東西,在學習的時候發現了幾點疑問,并且網上鮮有解答:

  1. ​ServiceManager​

    ​管理的是系統服務,那我們自定義的Service會注冊到ServiceManager中嗎?
  2. 為什麼AIDL中的跨程序下asInterface()會傳回​

    ​BinderProxy​

    ​?我們在Service的啟動流程沒有留意到這個類呀?

不過最後我一些地方還是有些模糊,如果大神能有幸閱讀我的文章,請麻煩指出我文中的錯誤!我定查閱改正。

1.關于系統Service和自定義Service的差別

這裡是 bindService在應用層 - framwork層的綁定流程,源碼基于8.0:​​Service的startService和bindService源碼流程​​​ 或者閱讀《Android進階解密》第四章

這裡是關于系統服務和ServiceManager在基于Binder角度 注冊、擷取、使用上的流程,源碼基于9.0,也是皇叔寫的:​​​Binder原理​​

可以大概總結出他們的差別:

  1. 系統Service

    是指在 SystemServer程序開啟後,通過​​

    ​startBootstrapServices()​

    ​​、​

    ​startCoreServices()​

    ​​、​

    ​startOtherServices()​

    ​​所開啟的服務,他們顯示地通過​

    ​add_service()​

    ​​注冊在了​

    ​ServiceManager​

    ​​中。

    之後用戶端程序想要使用系統Service,需要通過 ServiceManager的程序來檢視是否有目标Service,然後再來擷取和使用

  2. 自定義Service

    通過​​

    ​startService()​

    ​​和​

    ​bindService()​

    ​​兩種方式開啟,在framwork架構層中沒有發現流程中使用add_service方法(甚至都沒出現ServiceManager)。

    ↑ 這就看出無論自定義Service最後在不在ServiceManager中,Android本身是不希望我們通過ServiceManager的途徑去擷取使用自定義Service的。

上述第二條的結論,原因是什麼?我不是很清楚,但是基于結論來看:

隻要一個程序持有另一程序的BinderProxy類,那我還去找 ServiceManager幹什麼,這不更加省事嗎?

是以,在自定義的流程中把ServiceManager忽略掉,我們就不用考慮Service到底有沒有注冊在ServiceManager中了。

2. 從AIDL上看Binder

AIDL本質上是在Java層對Binder進行了封裝。是以Android8.0前後AMS是否使用了AIDL,本質都是使用Binder + 代理模式,隻是說使用了 AIDL通過編譯時生成代碼,節省了一些代碼的編寫,提高了開發效率。

那麼我們就從編譯時産生的代碼開始,來看看Binder的運作機制,這裡使用的例子是:​​使用AIDL來進行程序間通信​​,就是一個 Service遠端服務 + User類 + IUserManager代理類

2.1 用于程序傳輸的Stub類

在編譯檔案産生的 IUserManager中,它是一個接口類,同時它有一個靜态内部類 ​

​Stub​

​:

// IUserManager.java
// 0 
public static abstract class Stub extends android.os.Binder implements com.rikkatheworld.aidl_demo.IUserManager {
        private static final java.lang.String DESCRIPTOR = "com.rikkatheworld.aidl_demo.IUserManager";

        // 1
        public Stub() {
             this.attachInterface(this, DESCRIPTOR);
        }

        // 2
        public static com.rikkatheworld.aidl_demo.IUserManager asInterface(android.os.IBinder obj) {
           ...
        }

        // 3
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        // 4
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            ...
        }

        // 5
        private static class Proxy implements com.rikkatheworld.aidl_demo.IUserManager {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
            ...
  
            // 6
            @Override
            public com.rikkatheworld.aidl_demo.User getUser(java.lang.String name) throws android.os.RemoteException {
                ....
            }
        }
    }      

Stub類分成兩個部分,一個是自己本身的成員方法,另一個是Proxy類,先來看看這些成員。

(1)自身部分

  1. 注釋0

    Stub類繼承自​​

    ​Binder​

    ​,說明這個類是用于程序間傳輸的。
  2. 注釋1​

    ​Stub()​

    ​ 構造方法,把自身和标記自身的descriptor傳入,後者用于表明身份
  3. 注釋2​

    ​asInterface(obj)​

    ​ 靜态方法, 處理ActivityManagerService丢給我們的 IBinder,将它轉換成 用戶端程序想要的類。
  4. 注釋3:​

    ​asBinder()​

    ​ 用于Binder傳輸的過程,需要轉換自身的類型,Stub(A程序)->IBinder(Binder)->Stub(B程序),就用到這個方法,這個例子非常粗糙,可能也有問題,但是這個方法是輔助用的,我們不需要對這個方法深入了解。
  5. 注釋4 :​

    ​onTransact()​

    ​ 重寫父類的 onTrancsact,這個方法是用戶端程序在使用Binder進行資料傳輸時需要用到的資料。

(2)Proxy代理類

  1. 注釋5

    靜态内部類,實作了 IUserManager接口

    内部定義了一個 IBinder類型的 mRemote對象

  2. 注釋6

    實作方法,如果用戶端程序要跨程序調用Server端的方法,就要通過調用這些方法。

我們看看用戶端程序是怎麼使用這個類的:

private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 1
            IUserManager userManager = IUserManager.Stub.asInterface(service);
            try {
                User user = userManager.getUser("Rikka");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };      

AIDL的用戶端程序,在 ​

​onServiceConnected()​

​​中拿到 AMS傳過來的 service,通過 ​

​asInterface()​

​轉化成 IUserManager,然後調用它的方法,就能完成跨程序的方法調用了。

我們來看看 ​

​asInterface()​

​具體實作:

// IUserManager.java
...
public static com.rikkatheworld.aidl_demo.IUserManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.rikkatheworld.aidl_demo.IUserManager))) {
                return ((com.rikkatheworld.aidl_demo.IUserManager) iin);
            }
            return new com.rikkatheworld.aidl_demo.IUserManager.Stub.Proxy(obj);
        }
...      

可以看出調用了 ​

​queryLocalInterface()​

​獲得一個 IInterface類型的對象iin,如果iin不為空,則傳回iin,如果為空,則 new一個 Proxy類并傳回。

我們知道AMS給我們傳回的一定是Binder的對象,是以我們去 Binder中看看​

​queryLocalInterface()​

​:

// Binder.java
public class Binder implements IBinder {
    ...
    // 1
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
...
}
// 2
final class BinderProxy implements IBinder {
     // 3
     public IInterface queryLocalInterface(String descriptor) {
        return null;
    }
    ...
}      

可以發現Binder檔案中,有兩處實作了這個方法,在Binder類中。

注釋1中 通過 descriptor辨別來傳回,mOwner是Bidner本身。

注釋2、3是 ​​

​BinderProxy​

​實作的,直接傳回一個空。

在Stub類的構造方法裡我們就看到了隻要​

​Stub​

​被建構就會調用:

public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }      

按理來說,​

​queryLocalInterface​

​不可能傳回為空,我們應該都是得到一個正宗的 Stub類才對,但是實際上這裡出現了偏出。

在跨程序服務中,我們通過 asInterface() 傳回的是一個 ​

​IUserManager.Stub.Proxy​

​​的對象。這就說明 ​

​queryLocalInterface()​

​​傳回了空,隻有一種情況會導緻這種結果, 那就是 ServiceConnection傳回來的值是一個 ​

​BinderProxy​

​類型的對象。

這就是我最開始的疑問點,為什麼 ​

​onServiceConnection()​

​​中遠端程序和同程序下傳回的是Binder,而不同程序下傳回的是​

​BinderProxy​

​。

2.2 BindService 用戶端程序傳出流程

Binder機制是C/S架構,任意兩個程序,請求方是C端,接收方是S端

C端通過 ​​

​BpBinder​

​​來通路S端,S端通過 ​

​BBinder​

​​來通路C端,而​

​BpProxy​

​就是BpBinder的封裝類。他們的具體知識這裡就不再贅述了。詳情請看皇叔的文章。下面以架構層角度畫個圖來看下 用戶端程序的資料傳出經過了什麼方法:

從AIDL來看Binder的通信原理(基于Andorid8.0)

萬物的開端在于BindService,在 ​​Service的startService和bindService源碼流程​​​中,我們知道主程序的最終代碼是到 ​

​ContextImpl.bindServiceCommon()​

​:

// ContextImpl.java
    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        IServiceConnection sd;
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        ...
        try {
            IBinder token = getActivityToken();
            ...
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            ...
        } ...
    }
// ActivityManager
public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
 
 private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };      

ActivityManager.getService()是 ​

​IActivityManager.Stub.asInterface(b)​

​,這個肯定是Proxy類(套娃了,不過問題不大),我們要來看看bindService做了什麼,由于IActivityManager是編譯産生的,是以我暫時還沒有找到IActivityManager,但是我們知道 它的實作肯定和我們自己所編譯出來的如出一轍,甚至我們自己都可以寫出來:

// 這個地方是照着 IUserManger.Stub.Proxy 仿寫的,也看了開篇Blog的内容
// IActivityManager.Stub.Proxy 
      @Override
      public int bindService(IApplicationThread caller, IBinder token,
           Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();  // 1
                android.os.Parcel _reply = android.os.Parcel.obtain();  // 2
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeStrongBinder(caller != null ? caller.asBinder() : null);  // 3 
                    _data.writeStrongBinder(token);  // 4
                    service.writeToParcel(data, 0);
                    _data.writeString(resolvedType);
                    _data.writeStrongBinder(connection.asBinder()); // 5
                    _data.writeInt(flags);
                    _data.writeInt(userId);
                    mRemote.transact(TRANSACTION_bindService, data, reply, 0);  // 6
                    reply.readException();
                    _result = reply.readInt(); // 7
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
      }      

注釋1:獲得一個傳出去的序列化資料 data

注釋2:獲得一個用于接收的序列化資料 reply

注釋3、4、5: 通過 ​​

​writeStrongBinder()​

​​把 Binder資料寫入到 data中

注釋6:調用原生層的 ​​

​transact()​

​​,傳入資料

注釋7:在傳回結果reply讀出資料result

其中,注釋3、4、5、6是這個方法的關鍵。就是參數是這麼從用戶端程序傳出去的。

我們來看看 ​​

​writeStrongBinder()​

​,它是一個native方法:

// frameworks/base/core/jni/android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}      

這裡調用了兩個函數, 一個是調用了 ​

​ibindForJavaObject​

​​得到一個IBinder,在傳入到 ​

​Parcel->writeStrongBinder()​

​​中:

先來看看前者

// frameworks/base/core/jni/android_os_Parcel.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;  // 1
    }
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)
            env->GetLongField(obj, gBinderProxyOffsets.mObject); // 2
    }
    return NULL;
}      

注釋1:如果傳進來的binder是 gBinderOffsets,則 new一個 ​

​JavaBBinder​

​​并傳回。

注釋2:如果傳進來的bind是 gBinderProxyOffsets(代理類),類中的 代理對象。(也就是封裝在裡面了,取出來用)

由于我們是用戶端程序,是以進來的并不是代理類,是以 ​

​ibinderForJavaObject()​

​​會傳回一個 JavaBBinder傳回給我們。

再來看看 Parcel.writeStrongBinder():

// frameworks\native\libs\binder\Parcel.cpp
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    ...
    if (binder != NULL) {
        IBinder *local = binder->localBinder();  // 1
        if (!local) {
            BpBinder *proxy = binder->remoteBinder(); 
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            obj.type = BINDER_TYPE_BINDER;  // 2
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}

inline static status_t finish_flatten_binder(
    const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
    return out->writeObject(flat, false);
}      

在writeStrongBinder中調用了 ​

​flatten_binder()​

​​,

注釋1:localBinder()是取出Binder中的資料,用來辨別傳入Binder的程序是否是目前程序,是以local不為null,會走到else中去

注釋2:設定 type為 ​​

​BIND_TYPE_BINDER​

最後把這些資料寫到輸出資料中。也就是一開始我們的 _data。

接下來看下 ​

​mRemote.transact()​

​​這個方法,mRemote是 ​

​ServiceManager​

​​傳回給我們的,它是一個 BinderProxy對象,是以會調用 ​

​BinderProxy.transact()​

​:

// Binder.java
// BinderProxy -> 
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        ....
        try {
            return transactNative(code, data, reply, flags);
        } ...
    }      

調用了 native層的 ​

​transactNative()​

​:

// android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    ...
    Parcel* data = parcelForJavaObject(env, dataObj);  // 1
    ..
    Parcel* reply = parcelForJavaObject(env, replyObj); // 2
    ...
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);  // 3
    ....
    status_t err = target->transact(code, *data, reply, flags); // 4
    ....
}      

注釋1、2:通過 ​

​parcelForJavaObject()​

​​ 把 Java層的Parce -> Natve層的Parcel,data是參數資料,reply是結果資料

注釋3:把 java層的 ActivityManagerService的 ​​

​BinderProxy​

​​ 轉換成 Native層的 ​

​BpBinder​

​​ 注釋4:調用 ​

​BpBinder.transact()​

到這裡我就不往下說了,BpBinder會調用 ​

​IPCThreadState.transact()​

​​ 、​

​writeData()​

​​、​

​talkWithDriver()​

​​、​

​waitForResponse()​

​​等方法去深入到 Kernel層的Binder,具體請看: ​​Android Binder原理(三)系統服務的注冊過程​​,裡面寫了一個系統服務注冊到ServiceManager的過程,其中就有上述接下來的過程。

這樣我們的Binder資料就從用戶端程序傳出去了。

2.3 ActivityManagerService接收資料

如果一個支援Binder通信的程序被建立後,它會開啟一條線程加入到Binder線程池中,并通過 ​

​joinThreadPool()​

​​開啟死循環,讀 Binder驅動中的 ​

​BR_TRANSACTION​

​​(因為用戶端程序傳入的是 ​

​BC_TRANSACTION​

​)指令,具體可以看 《Android進階解密》第三章 應用程式程序的建立。

// IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
    ...
    do {
        ...
        result = getAndExecuteCommand(); 
        ...
    } while (result != -ECONNREFUSED && result != -EBADF);
    ...
    talkWithDriver(false);
}      

可以看到在死循環中不斷調用 ​

​getAndExecuteCommand()​

​:

status_t IPCThreadState::getAndExecuteCommand()
{
    ...
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        if (IN < sizeof(int32_t)) return result;
        cmd = mIn.readInt32();
        ...
        result = executeCommand(cmd);

       ...
    }

    return result;
}

// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }
    //和Binder驅動通信的結構體
    binder_write_read bwr; //1
    //mIn是否有可讀的資料,接收的資料存儲在mIn
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();//2
    //這時doReceive的值為true
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();//3
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
   ...
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(__ANDROID__)
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//4
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
     ...
    } while (err == -EINTR);
    ...
    return err;
}      

​talkWithDriver()​

​​ 就是通過 ​

​ioctl​

​​讀取有沒有想要的BR資料,有就響應,調用 ​

​executeCommand()​

​:

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;

    switch ((uint32_t)cmd) {
    ....
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;  // 1
            result = mIn.read(&tr, sizeof(tr)); // 2
            ....
            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),  
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); // 3
            ....
            Parcel reply;
            status_t error;
            if (tr.target.ptr) {
                if (....) {
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);  // 4
                } 
            } ...
           ....
        }
        break;
    ...
    return result;
}      

這裡隻要截取 ​

​BR_TRANSACTION​

​​,因為用戶端程序發的是 ​

​BC_TRANSATION​

​​ 注釋1:建立 ​

​binder_transaction_data​

​ 結構體的對象tr,它是IPCThread專用的 Parcel包, 在用戶端程序的IPCThreadState調用transact時也是用這個類型

注釋2:mIn是Binder驅動的讀到的Parcel資料,通過 read()方法把這些資料寫入到 tr中

注釋3:通過寫好的資料重新構造一個 Parcel包。(把它修改成AMS用的包)

注釋4:調用 ​

​BBinder.transact()​

​,這裡的 BBinder是指 ActivityManagerService在Service端的對象,也就是自己。最後會調用自己的 ​

​onTransact()​

​,會調用父類也就是 ​

​IActivityManager.onTransact()​

在 ​

​IActivityManager​

​​對 onTransact應該是對 ​

​TRANSACTION_bindService()​

​​case處理,雖然我們沒有 IActivityManager這個類,但是我們通過 ​

​IUserManager​

​檔案,可以仿寫一份 IActivityManager的代碼:

// 跟IActivityManager.Stub.Proxy類一樣, 根據 IUserManager 仿寫 IActivityManager.Stub.onTransact(),
// 代碼參照開篇Blog,即Android7.0 的Binder傳回的處理
    @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                ...
                case TRANSACTION_bindService: {
                    data.enforceInterface(descriptor);
                    IBinder b = data.readStrongBinder();   // 1
                    IApplicationThread app = ApplicationThreadNative.asInterface(b);
                    IBinder token = data.readStrongBinder();  
                    Intent service = Intent.CREATOR.createFromParcel(data);
                    String resolvedType = data.readString();
                    b = data.readStrongBinder(); 
                    IServiceConnection conn = IServiceConnection.Stub.asInterface(b); 
                    int fl = data.readInt();
                    int userId = data.readInt();
                    int res = bindService(app, token, service, resolvedType, conn, fl, userId); // 5
                    reply.writeNoException();
                    reply.writeInt(res);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }      

在拿到 natvie層的Pacel包後,進行拆包。

注釋1-2前:通過readString() 、readInt()、 ​​

​readStrongBinder()​

​​拆包,怎麼裝包的就怎麼拆包

注釋2:執行 ​​

​ActivityManagerService.bindService()​

​,正式開啟 AMS之旅。

我們來看看解包的一個方法 ​

​readStrongBinder()​

​​,它和裝包的 ​

​writeStrongBinder()​

​對應:

// Parcel.cpp
status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
    status_t status = readNullableStrongBinder(val);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return status;
}

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
    return unflatten_binder(ProcessState::self(), *this, val);
}      

readStrongBinder()調用了 ​

​readNullableStrongBinder()​

​​,它裡面調用了 ​

​unflatten_binder()​

​:

// Parcel.cpp
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 = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle); // 1
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}      

我們在用戶端程序傳入進來flat的是 ​

​BINDER_TYPE_BINDER​

​​, 但是我跟你講,這裡拿到的是 ​

​BINDER_TYPE_HANDLE​

​,因為

  1. 如果是非跨程序調用

    資料Parcel包在kernel層不會做修改

  2. 如果是跨程序調用

    kernel層的​​

    ​binder_transaction()​

    ​​會修改這個值,即​

    ​BINDER_TYPE_BINDER​

    ​​ ->​

    ​BINDER_TYPE_HANDLE​

是以這裡會在注釋1中得到一個 ​

​BpBinder​

​,然後傳回。

也就是說 ​

​readStrongBinder(Parcel)​

​​可以拿到 parcel包裡面的 的Binder資料并轉化為 BpBinder, 然後把BpBinder通過 ​

​Parcel.javaObjectForIBinder()​

​​轉換成 ​

​BinderProxy​

​。在Android7.0可以找到這個轉換,8.0後我突然找不到了…不知道為什麼。以後找機會再查查吧。

到這裡,就已經明了了,用戶端程序的 Binder 到了 服務端程序後 會包裝成 BinderProxy。

這句話也可以換成:

任意一個程序的IBinder 通過 Binder機制 到達了另外一個程序後,就會包裝成一個 BinderProxy。

這就回到了我最開始的第二點疑問,通過Service -> AMS -> MainActivity.onServiceConnection(IBinder) 中的 IBinder是一個BindProxy類。

3. 總結

從一開始我的兩個問題,到現在也算是解決了。

自定義Service并不需要通過 ​​

​addService()​

​​來加入到 ServiceManager,因為它隻要别的程序能夠持有它的BinderProxy,就可以調用它的方法。

其次 Binder在跨程序後會轉換成 BindProxy,這也是為什麼AIDL中能夠拿到 Proxy類。

  1. ​IActivityManager​

    ​的代碼到底時怎麼樣的?
  2. Android7.0 的​

    ​readStrongBinder()​

    ​​顯示的用了​

    ​javaObjectForIBinder()​

    ​把 unflatten_binder得到 BpBinder轉換成了 BinderProxy,但是Andorid8.0我卻沒有看到這樣的代碼,到了BpBinder就好了…不知道是不是我看漏了,反正查了半天沒查到…