[转]IBinder对象在进程间传递的形式

问题引出:由onServiceConnected()的IBinder类型说起

service被远程调用时,我们常常使用aidl来定义一个接口给serviceclient来使用,这个其实就是使用Binder机制的IPC通信。当client bind Service成功之后,系统AM会调用回调函数onServiceConnected()将service的IBinder传递给client, client再通过调用aidl生成的asInterface()方法获得service的调用接口,此时一个bind过程结束了,我们在client端就可以远程调用的方法了。

我们先来看一下onServiceConnected()方法

public void onServiceConnected(ComponentName className, IBinder service) {
    mSecondaryService = ISecondary.Stub.asInterface(service);
}

aidl生成的asInterface()的定义

public static com.example.android.apis.app.ISecondary asInterface(android.os.IBinder obj)
{
    if ((obj==null)) {
        return null;
    }
    android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.example.android.apis.app.ISecondary))) {
        return ((com.example.android.apis.app.ISecondary)iin);
    }
    return new com.example.android.apis.app.ISecondary.Stub.Proxy(obj);
}

asInterface()方法中会通过queryLocalInterface()来判断传入的IBinder对象是service本身的引用还是代理

  1. asInterface的输入的IBinder为server的引用(Binder类型)时,则直接返回该引用,那么此时调用server的方法不为IPC通信,而是直接的函数调用;
  2. asInterface的输入的IBinder为server的代理(BinderProxy类型)时,则需要创建该server的代理并返回,此时调用server的方法为IPC通信。

那么asInterface()在实际情况下会被传入什么参数类型呢?要想回答这个问题,我们来看一下IBinder传递的流程。

IBinder传递时Driver Module的处理

IBinder作为参数在IPC通信中进行传递,可能会使某些人困惑,IBinder不就是IPC通信的媒介吗?怎么还会被作为参数来传递呢,这样理解就有点狭隘了,拿native层的IPC来说,clientSM(service manager)中获取service端的Interface,这个Interface同时也是IBinder类型,当C/S两端需要双工通信时,即所谓的Service端需要反过来调用Client端的方法时,就需要Client通过前述的那个InterfaceClient端的IBinder传递给Service

拿Java应用层的Service来说更是如此,如本文的这个命题,下面我们会分析,首先来介绍原理性的知识。

Binder IPC通信中,Binder是通信的媒介,Parcel是通信的内容。方法远程调用过程中,其参数都被打包成Parcel的形式来传递的。

IBinder对象也不例外,我们看一下Parcel类中的writeStrongBinder()(由于java层和native层的方法是相对应的,java层只是native的封装,因此我们只需要看native方法即可),

扫描二维码关注公众号,回复: 4495861 查看本文章
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)
{
    flat_binder_object obj;
    
    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            ...
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.handle = handle;
            obj.cookie = NULL;
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local;
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = NULL;
        obj.cookie = NULL;
    }
    
    return finish_flatten_binder(binder, obj, out);
}

上面代码分下面2种情况:

  1. 如果传递的IBinder为service的本地 IBinder对象,那么该IBinder对象为BBinder类型的,因此上面的local不为NULL,故binder type为BINDER_TYPE_BINDER
  2. 如果传递的IBinder对象代理IBinder对象,那么binder type则为BINDER_TYPE_HANDLE

client端将方法调用参数打包成Parcel之后,会发送到内核的Binder模块,因此下面我们将分析一下内核的Binder模块的处理。

kernel/drivers/staging/android/Binder.c中的函数binder_transaction()

binder_transaction()
{
	...
	switch (fp->type) {
	        case BINDER_TYPE_BINDER:
	        case BINDER_TYPE_WEAK_BINDER: {
	            struct binder_ref *ref;
	            struct binder_node *node = binder_get_node(proc, fp->binder);
	            ...
	            ref = binder_get_ref_for_node(target_proc, node);
	            ...
	            if (fp->type == BINDER_TYPE_BINDER)
	                fp->type = BINDER_TYPE_HANDLE;
	            else
	                fp->type = BINDER_TYPE_WEAK_HANDLE;
	            fp->handle = ref->desc;
	            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
	                       &thread->todo);
	        } break;
	        case BINDER_TYPE_HANDLE:
	        case BINDER_TYPE_WEAK_HANDLE: {
	            struct binder_ref *ref = binder_get_ref(proc, fp->handle);
	            ...
	            if (ref->node->proc == target_proc) {
	                if (fp->type == BINDER_TYPE_HANDLE)
	                    fp->type = BINDER_TYPE_BINDER;
	                else
	                    fp->type = BINDER_TYPE_WEAK_BINDER;
	                fp->binder = ref->node->ptr;
	                fp->cookie = ref->node->cookie;
	                ...
	            } else {
	                struct binder_ref *new_ref;
	                new_ref = binder_get_ref_for_node(target_proc, ref->node);
	                ...
	                fp->handle = new_ref->desc;
	                ...
	            }
	        } break;
	        ...

上面代码也分为了2种不同的情况:

  1. 传来的IBinder类型为BINDER_TYPE_BINDER时,会将binder type值为BINDER_TYPE_HANDLE
  2. 传来的IBinder类型为BINDER_TYPE_HANDLE时,会判断该IBinder的实体被定义的进程(也就是该IBinder代表的server被定义的进程)与目标进程(也即IBinder被传递的目标进程)是否相同,如果相同,则将该IBinder type转化为BINDER_TYPE_BINDER,同时使其变为IBinder本地对象的引用。

通过上述的处理,我们可以得出下面结论:

  1. 不同进程间传递的IBinder本地对象引用(BINDER_TYPE_BINDER类型),在内核中均会被转化为代理(BINDER_TYPE_HANDLE类型,目前只是改变其类型,在IBinder接收方会根据其类型转化为代理);
  2. 由于只有不同进程间传递才会将IBinder发送到Binder模块,所以IBinder在多级传递的过程中,有下面2种可能:
进程A-->进程B-->进程A
进程A-->进程B-->进程C

其对应的IBinder类型就是

BINDER_TYPE_BINDER->BINDER_TYPE_HANDLE->BINDER_TYPE_BINDER
BINDER_TYPE_BINDER->BINDER_TYPE_HANDLE->BINDER_TYPE_HANDLE

根据上述结论,我们就会明白:

Binder IPC通信过程
相同进程间的IBinder本地对象,如果不经过不同进程的传递,那么IBinder就不会传给内核的Binder模块,因此它一直是IBinder的本地对象;
如果在进程间传递,即使通过再多的进程间的传递,只要最后的目标是同一个进程的component,那么他得到的IBinder对象就是本地的对象。

在这里插入图片描述

理解了上面的这个模型,我们再回过头看最开始的那个问题可以给出答案了:

1.当client和service处在相同进程中的话,asInterface的输入的IBinder为server的引用
2.当client和service处在不同进程中的话,asInterface的输入的IBinder为server的代理

举个例子:
假如某一个component(例如一个Acitivity)处在进程A,它需要bind()一个service,而该service处在进程B中,我们简单介绍一下bind()的过程。

binder service流程

  1. 进程AAM(进程system_server)发出Bind请求,并将回调ServiceConnection提供给AM(传递给AM的也是一个接口(IServiceConnection),因为AM进程A之间是双工通信,所以进程A需要向AM提供IBinder);
  2. AM启动进程B并创建service进程BserviceIBinder对象传递给AMAM再通过IServiceConnection传递给进程A。所以serviceIBinder对象的传递路径为:
进程B-->进程system_server(AM)-->进程A。

所以进程A中asInterface的输入的IBinder为server的代理对象

IBinder传递时framework的处理

Android中主要通过2种方法来获得service IBinder:

  1. 通过ServiceManager.getService(String Descriptor)来获得Service Manager管理的serviceIBinder
  2. Client获得Application ServiceIBinder,如上图描述的binder service流程。

不管哪种方法,均涉及到IBinder在不同进程间的传递,因为不论是Application Service 还是 System Service,它们在注册时均会涉及到第三方进程,如Application Service注册在Acitivity Manager中(system_server进程),System Service注册在Service Manager中(servicemanager进程)。

Service Manager中获得IBinder涉及到serviceservicemanager进程以及clientservicemanager进程之间的IBinder传递;
获得Application ServiceIBinder,更是涉及到ApplicationServicesystem_server进程以及clientsystem_server进程之间的IBinder传递,如上图描述的binder service流程。

研究这个主题的意义在于,虽然从表面上看,在用到IBinder时,我们在应用中使用的是同一个接口,但是它的实质是怎么样的?是一套什么样的机制保证在同进程间client调用的是service的实体,而在不同进程间则是调用的serviceproxy

关于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实例,但是只有Service对象被IPC传递时,JavaBBinderHolder对象才会创建一个JavaBBinder实例。

发送IBinder

IBinder在IPC通信中,通过Parcel类writeStrongBinder()写入IBinder数据

// java
data.writeStrongBinder(ISERVICE_C_Interface.Stub);

先来看下writeStrongBinder()方法
frameworks/base/core/jni/android_util_Binder.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        ...
    }
}

ibinderForJavaObject()函数会判断JAVAIBinder的类型并转化为nativeIBinder类型,也就是将BinderBinderProxy对象分别转换为JavaBBinderBpBinder

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    ...
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetIntField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env) : NULL; //分析见下1
    }
 
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)
            env->GetIntField(obj, gBinderProxyOffsets.mObject); //分析见下2
    }
    ...
}
  1. IBinder是以JavaBBinder的形式传递的,即是一个ServiceIBinderreference。如上面代码中的第一个return语句。
    这种较常见,作为传输介质的IBinder所处的service发送方在同一进程中。
    在这里插入图片描述
    Service处在Process A中,Process A为IBinder发送方。

  2. IBinder是以BpBinder的形式传递的,即是一个ServiceIBinderProxy。如上面代码中的第二个return语句。
    在这里插入图片描述
    Service 处在Process C`中,Process A为IBinder发送方。

这种情况比较典型的就是bindservice时会用到,如图中最后一步中AMS通知client bind成功时,传递给client的就是一个service IBinderProxy。作为传输介质的IBinder所处的service和发送方在不同的进程中。

kernel中,Binder Module会根据IPC通信双方是否处于同一个进程中,来设置binder object type值。

kernel/drivers/staging/android/Binder.c

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)
{
	...
	switch (fp->type) {
	        case BINDER_TYPE_BINDER: //见下文1
	        case BINDER_TYPE_WEAK_BINDER: {
	            struct binder_ref *ref;
	            struct binder_node *node = binder_get_node(proc, fp->binder);
	            ...
	            ref = binder_get_ref_for_node(target_proc, node);
	            ...
	            if (fp->type == BINDER_TYPE_BINDER)
	                fp->type = BINDER_TYPE_HANDLE;
	            else
	                fp->type = BINDER_TYPE_WEAK_HANDLE;
	            fp->handle = ref->desc;
	            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
	                       &thread->todo);
	        } break;
	        case BINDER_TYPE_HANDLE: //见下文2
	        case BINDER_TYPE_WEAK_HANDLE: {
	            struct binder_ref *ref = binder_get_ref(proc, fp->handle);
	            ...
	            if (ref->node->proc == target_proc) {
	                if (fp->type == BINDER_TYPE_HANDLE)
	                    fp->type = BINDER_TYPE_BINDER;
	                else
	                    fp->type = BINDER_TYPE_WEAK_BINDER;
	                fp->binder = ref->node->ptr;
	                fp->cookie = ref->node->cookie;
	                ...
	            } else {
	                struct binder_ref *new_ref;
	                new_ref = binder_get_ref_for_node(target_proc, ref->node);
	                ...
	                fp->handle = new_ref->desc;
	                ...
	            }
	        } break;
	        ...
  1. IBinder的发送方和Service在同一进程的话,那么传递给内核的binder_objecttypeBINDER_TYPE_BINDER,由于IBinder发送到内核均是在进程间传递的,所以Binder Module driver会将type改为BINDER_TYPE_HANDLE
  2. IBinder的发送方和Service不在同一进程的话,那么传递给内核的binder_objecttype就为BINDER_TYPE_HANDLE,并且这种情况接收方和Service可能处在同一个进程中,因此当这种情况发生时,需要将其改为BINDER_TYPE_BINDER

IBinder发送的流程图:
在这里插入图片描述

接收IBinder

java中用来接收binder driver传来parcel数据的接口

IBinder b = data.readStrongBinder();

看一下readStrongBinder() 方法

frameworks/base/core/java/android/os/Parcel.java

public final IBinder readStrongBinder() {
    return nativeReadStrongBinder(mNativePtr);
}

对应的JNI实现

frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

1.先看一下android_os_Parcel_readStrongBinder调用的Parcel的readStrongBinder()方法
frameworks/native/libs/binder/Parcel.cpp

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

其中调用了unflatten_binder方法
frameworks/native/libs/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 = 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;
}
  1. 当从BinderModule中读出的binder_objecttypeBINDER_TYPE_BINDER说明接收方收到的Service是同进程的,那么此时直接将保存在cookie中的Service的实体传递给JNI层。
    在这里插入图片描述
    此时,JNI层收到的Service实体为一个JavaBBinder对象,由上面的类图可以知道,JavaBBinder对象中包含着JAVAService对象的引用。

  2. 当从Binder Module中读出的binder_objecttypeBINDER_TYPE_HANDLER说明接收方收到的Service不是同进程的,那么会创建或者引用已有的一个BpBinder对象给JNI层。
    在这里插入图片描述
    Service 处在Process C中,Process B为IBinder接收方。

下面我们再来看一下当binder_objecttypeBINDER_TYPE_HANDLER时所调用的getStrongProxyForHandle()方法

frameworks/native/libs/binder/ProcessState.cpp

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        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 {
            ...
        }
    }
    
    return result;
}

首先,lookupHandleLocked方法从参数接收服务Handle,查找与其相对应的Vector并返回,若查找不到,则创建entry并更新Vector。这样做是为了保证ProcessState不会对同一进程中针对指定的服务生成多个重复的对象。

frameworks/native/libs/binder/ProcessState.cpp

// Vector<handle_entry>mHandleToObject;
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);
}

如果没有查找到BpBinder对象,则new BpBinder,生成对应服务的HandleBpBinder对象并保存。(在Binder Modlue中handle可以唯一标识BpBinder对象。)

2.再来看一下android_os_Parcel_readStrongBinder()调用的javaObjectForIBinder()方法

frameworks/base/core/jni/android_util_Binder.cpp

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    ...

    if (val->checkSubclass(&gBinderOffsets)) {
        // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    ...
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // The proxy holds a reference to the native object.
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
    }

    return object;
}

javaObjectForIBinder()分别将JavaBBinderBpBinder对象转换成BinderBinderProxy对象。当是BpBinder时,生成一个BinderProxy对象,将BpBinder保存到BinderProxymObject中。
在这里插入图片描述

如上图所示:

  1. 每个进程中会保存多个当前进程调用过的BpBinder对象;
  2. 每个BpBinder对象都会保存与之对应的JAVA层的BinderProxy。

参考文章:
https://blog.csdn.net/windskier/article/details/6625883
https://blog.csdn.net/windskier/article/details/6913698

猜你喜欢

转载自blog.csdn.net/QWE123ZXCZ/article/details/84645688