IBinder对象在进程间传递的形式(二)

这篇文章是对IBinder对象在进程间传递的形式(一)这篇文章的补充,首先还是把service启动过程的流程图贴上来

 

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

1.       通过ServiceManager.getService(String Descriptor)来获得Service Manager管理的service的IBinder。

2.       Client获得Application Service的IBinder,如下图描述的binder service流程。


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

    从Service Manager中获得IBinder涉及到service和servicemanager进程以及client和servicemanager进程之间的IBinder传递;

    获得Application Service的IBinder,更是涉及到ApplicationService和system_server进程以及client和system_server进程之间的IBinder传递,如上图所示。

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

    关于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实例(android_os_Binder_init@android_util_Binder.cpp),但是只有SERVICE对象被IPC传递时,JavaBBinderHolder对象才会创建一个JavaBBinder实例(JavaBBinderHolder::get(env)@ android_util_Binder.cpp)。



    

1.      IBinder在IPC通信中的发送过程

    

   IBinder在IPC通信中,android通过Parcel类的成员函数writeStrongBinder()写入IBinder,在向Parcel写入IBinder时,首先会判断JAVA层IBinder的类型并转化为native的IBinder类型,下面介绍它的的2种类型。

    android_os_Parcel_writeStrongBinder()@android_util_Binder.cpp

       parcel->writeStrongBinder(ibinderForJavaObject(env, object));@ 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)) {  
  6.         JavaBBinderHolder* jbh = (JavaBBinderHolder*)  
  7.             env->GetIntField(obj, gBinderOffsets.mObject);  
  8.         return jbh != NULL ? jbh->get(env) : NULL;  
  9.     }  
  10.   
  11.     if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {  
  12.         return (IBinder*)  
  13.             env->GetIntField(obj, gBinderProxyOffsets.mObject);  
  14.     }  
  15.   
  16.     LOGW("ibinderForJavaObject: %p is not a Binder object", obj);  
  17.     return NULL;  
  18. }  
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetIntField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env) : NULL;
    }

    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)
            env->GetIntField(obj, gBinderProxyOffsets.mObject);
    }

    LOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}


1.1  IBinder是以JavaBBinder的形式传递的,即是一个ServiceIBinder的reference。如上图中的第一个return语句。

这种较常见,作为传输介质的IBinder所处的service和发送方在同一进程中。


    Service处在Process A中,ProcessA为IBinder发送方。

1.2  IBinder是以BpBinder的形式传递的,即是一个ServiceIBinder的Proxy。如Service bind图中的第二个return语句。


    

     Service 处在Process C中,Process A为IBinder发送方。

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


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

    当IBinder的发送方和Service在同一进程的话,那么传递给内核的binder_object的type为BINDER_TYPE_BINDER,由于IBinder发送到内核均是在进程间传递的,所以Binder Module driver会将type改为BINDER_TYPE_HANDLE.


    当IBinder的发送方和Service不在同一进程的话,那么传递给内核的binder_object的type就为BINDER_TYPE_HANDLE,并且这种情况接收方和Service可能处在同一个进程中,因此当这种情况发生时,需要将其改为BINDER_TYPE_BINDER。这一点在下面会介绍。


    IBinder发送的流程:


 

1.      IBinder在IPC通信中的接收过程

    首先查看一下Parcel的unflatten_binder@Parcel.cpp(readStrongBinder()方法会调用到):

  1. status_t unflatten_binder(const sp<ProcessState>& proc,  
  2.     const Parcel& in, sp<IBinder>* out)  
  3. {  
  4.     const flat_binder_object* flat = in.readObject(false);  
  5.       
  6.     if (flat) {  
  7.         switch (flat->type) {  
  8.             case BINDER_TYPE_BINDER:  
  9.                 *out = static_cast<IBinder*>(flat->cookie);  
  10.                 return finish_unflatten_binder(NULL, *flat, in);  
  11.             case BINDER_TYPE_HANDLE:  
  12.                 *out = proc->getStrongProxyForHandle(flat->handle);  
  13.                 return finish_unflatten_binder(  
  14.                     static_cast<BpBinder*>(out->get()), *flat, in);  
  15.         }          
  16.     }  
  17.     return BAD_TYPE;  
  18. }  
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;
}

2.1   当从BinderModule中读出的binder_object的type为BINDER_TYPE_BINDER,说明接收方收到的Service是同进程的,那么此时直接将保存在cookie中的Service的实体传递给JNI层。

    此时,JNI层收到的Service实体为一个JavaBBinder对象,由上面的类图可以知道,JavaBBinder对象中包含着JAVA层SERVICE对象的引用。


2.2 当从Binder Module中读出的binder_object的type为BINDER_TYPE_HANDLER,说明接收方收到的Service不是同进程的,那么会创建或者引用已有

的一个BpBinder对象给JNI层。


    

    Service 处在Process C中,Process B为IBinder接收方。


2.2.1         如何创建BpBinder对象

通过调用ProcessState的方法getStrongProxyForHandle(),来创建或者引用已有的一个BpBinder对象。

A.     首先,检查当前所要创建的BpBinder是否已经在Vector mHandleToObject中存在,每个进程中均会维护这么一个Vector,保存当前进程获得的所有BpBinder对象。没有分析出这么做的原因,可能为了资源的重复利用,避免每次使用完都得回收的问题。

B.     如果没有查找到BpBinder对象,创建一个新的BpBinder对象,并会向mHandleToObject保存这个对象。

由于每个Service均会对应一个唯一的handle,因此可以通过这个handle来标示BpBinder对象。

  1. ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)  
  2. {  
  3.     const size_t N=mHandleToObject.size();  
  4.     if (N <= (size_t)handle) {  
  5.         handle_entry e;  
  6.         e.binder = NULL;  
  7.         e.refs = NULL;  
  8.         status_t err = mHandleToObject.insertAt(e, N, handle+1-N);  
  9.         if (err < NO_ERROR) return NULL;  
  10.     }  
  11.     return &mHandleToObject.editItemAt(handle);  
  12. }  
  13. sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)  
  14. {  
  15.     sp<IBinder> result;  
  16.     AutoMutex _l(mLock);  
  17.     handle_entry* e = lookupHandleLocked(handle);  
  18.     if (e != NULL) {  
  19.         // We need to create a new BpBinder if there isn't currently one, OR we   
  20.         // are unable to acquire a weak reference on this current one.  See comment   
  21.         // in getWeakProxyForHandle() for more info about this.   
  22.         IBinder* b = e->binder;  
  23.         if (b == NULL || !e->refs->attemptIncWeak(this)) {  
  24.             b = new BpBinder(handle);   
  25.             e->binder = b;  
  26.             if (b) e->refs = b->getWeakRefs();  
  27.             result = b;  
  28.         } else {  
  29.             // This little bit of nastyness is to allow us to add a primary   
  30.             // reference to the remote proxy when this team doesn't have one   
  31.             // but another team is sending the handle to us.   
  32.             result.force_set(b);  
  33.             e->refs->decWeak(this);  
  34.         }  
  35.     }  
  36.     return result;  
  37. }  
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);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        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 {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}


2.2.2         JNI层的特殊处理

    

     javaObjectForIBinder@android_util_Binder.cpp

  1. // Someone else's...  do we know about it?   
  2.     jobject object = (jobject)val->findObject(&gBinderProxyOffsets);  
  3.     if (object != NULL) {  
  4.         jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);  
  5.         if (res != NULL) {  
  6.             LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);  
  7.             return res;  
  8.         }  
  9.         LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());  
  10.         android_atomic_dec(&gNumProxyRefs);  
  11.         val->detachObject(&gBinderProxyOffsets);  
  12.         env->DeleteGlobalRef(object);  
  13.     }  
  14.     object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);  
  15.     if (object != NULL) {  
  16.         LOGV("objectForBinder %p: created new %p!\n", val.get(), object);  
  17.         // The proxy holds a reference to the native object.   
  18.         env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());  
  19.         val->incStrong(object);  
  20.         // The native object needs to hold a weak reference back to the   
  21.         // proxy, so we can retrieve the same proxy if it is still active.   
  22.         jobject refObject = env->NewGlobalRef(  
  23.                 env->GetObjectField(object, gBinderProxyOffsets.mSelf));  
  24.         val->attachObject(&gBinderProxyOffsets, refObject,  
  25.                 jnienv_to_javavm(env), proxy_cleanup);  
  26.         // Note that a new object reference has been created.   
  27.         android_atomic_inc(&gNumProxyRefs);  
  28.         incRefsCreated(env);  
  29.     }  
// Someone else's...  do we know about it?
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);
        if (res != NULL) {
            LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        LOGV("objectForBinder %p: created new %p!\n", val.get(), object);
        // The proxy holds a reference to the native object.
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
        val->incStrong(object);
        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }


①   首先,在BpBinder对象中查找是否保存相关的BinderProxy的对象,如果有,向JAVA层返回这个对象;

②   如果没有,创建一个BinderProxy对象;

③   将新创建的BinderProxy对象,attach到BpBinder对象中。

结合下面的关系图,我们得出这样的逻辑关系:

a.      每个进程中会保存多个当前进程调用过的BpBinder对象;

b.      每个BpBinder对象都会保存与之对应的JAVA层的BinderProxy。

    将创建的BinderProxyattach到BpBinder的意义在于:通过这种方式,JAVA应用层频繁获取同一service的IBinder时,获取的是同一个BinderProxy。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值