码迷,mamicode.com
首页 > 其他好文 > 详细

Binder的Native实现libbinder

时间:2019-06-07 20:56:33      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:不用   ping   优先   不同类   kernel   组织   ali   返回值   接收   

libbinder – Binder的Native实现

出于性能和代码统一性的角度考虑,Binder IPC并不Java和Native环境里各实现一次,而只是分别在不同的执行环境里提供使用的接口。使用Binder的Java代码,通过一些使用Binder的Java类之后,必须会走入到Native环境,将具体的分发的工作交给执行效率更高的Native代码。

最后这些接口都将被统一到一个统一的Binder交互环境,这一环境可以被称为Binder环境,而Binder IPC通信的过程,最终是在libbinder这样一种库文件里实现,最终会通过libbinder.so提供到Android系统里。

 libbinder是由C++编写的,这便Binder传输在实现上也具备面向对象的特点,这种能力不仅给Java环境里的概念映射提供了方便,同时,也使在Native环境里也以面向对象的方向来使用Binder进行多种环境的互相通信提供了一种机制。于是,直接使用libbinder提供的编程接口,也可以编写Native环境里的System Service,由C++语言直接给Java语言提供服务端实现,这就得到了NativeService。

对于libbinder的使用,可以还是先从Java环境的Binder类开始分析。

技术图片

 

Java环境如何访问到libbinder

技术图片

在对于Java环境的Remote Service分析时,我们可以看到Binder在Java环境里的表现形式,除去只作为接口类的IInterface、IBinder,实际上在Android系统里,只会使用一个Binder基类来托管一个远程对象。从交互过程来看,使用某个Binder上托管的对象,都可以通过Binder之上搭建的IPC消息“桥”进行互通过,在实现上,一个通过继承的Binder的对象,分别将在发送端产生Proxy部分,而在接收端生成Stub部分。这样的Binder通过IInterface将对象暴露出来之后,发送端就可以使用这一引用找到Proxy,通过Proxy对象的transact()方法发送,而接收端对应的也使用同一IInterface,通过其上onTransact()回调接收。这样便构成了交互的能力。

但从Java环境里,实际上,我们根本不知道是如何处理完成的,我们跟踪所有的Binder相关的Java实现,也不看不出来。比如,我们在客户端经常会使用这样的方法来写Proxy端方法:

 public IBinder getService(String name) throws RemoteException {   
       Parcel data = Parcel.obtain();  
       Parcel reply = Parcel.obtain();  
       data.writeInterfaceToken(IServiceManager.descriptor);  
       data.writeString(name);  
       mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);  
       IBinder binder = reply.readStrongBinder();  
       reply.recycle();  
       data.recycle();  
       return binder;  
}  

这种Proxy端的大部分代码,都可以在Java源代码里跟踪到其具体实现,但mRemote.transact()这行,则没有跟踪代码到具体是如何完成Binder通信的,我们前面只是说这一行便是送数据从BinderIPC通道上发送了出去,但并没有解释如何发送出去的。

这就会涉及到Binder的“跨界”实现,Binder这种特殊跨进程对象,实际上会映射到三层环境里,Kernel层,C/C++层,Java层。

如图:

技术图片

其中Kernel的Binder驱动是提供跨进程实现的基础,能够支持访问Binder驱动只有C/C++层,Java层则必须要通过JNI访问到C/C++层。Java语言实现里并不会支持任何对于底层操作系统功能,因为这样势必会破坏Java在各平台之上直接运行能力,但Java语言又将访问几乎所有的操作系统功能,这些都得通过JNI整合到Java环境的。在JNI编程这种限制之下,如果Binder对象在Java环境里保持一份、C++环境一份,则将加大开发与维护的开销。于是在Android世界里,JNI层一般都很薄(甚至大部分还很难理解),尽可能将代码集中在C++层实现,这样保持了实现上的简洁,同时还收获了执行上的更高的效率。

技术图片

我们的Binder.java实现了IBinder接口类,于是它拥有如下的结构:

public class Binder implements IBinder {
    public static final native int getCallingPid();
    public static final native int getCallingUid();
    public static final int getOrigCallingUid();
    private static final native int getOrigCallingUidNative();
    public static final int getOrigCallingUser();
   
    public static final native long clearCallingIdentity();
    public static final native void restoreCallingIdentity(long token);
    public static final native void setThreadStrictModePolicy(int policyMask);
    public static final native int getThreadStrictModePolicy();
    public static final native void flushPendingCommands();
    public static final native void joinThreadPool();
   
    public Binder() {
        init();
        ...
    }
   
    public void attachInterface(IInterface owner, Stringdescriptor) ;
    public String getInterfaceDescriptor();
    public boolean pingBinder() ;
    public boolean isBinderAlive();
    public IInterface queryLocalInterface(Stringdescriptor);
    protected boolean onTransact(int code, Parcel data, Parcel reply,
                                 int flags) throws RemoteException;
    public void dump(FileDescriptor fd, String[] args);
 
    protected void dump(FileDescriptor fd, PrintWriter fout,String[] args);
    public final boolean transact(int code, Parcel data, Parcel reply,
                                  int flags) throws RemoteException;
 
    public void linkToDeath(DeathRecipient recipient, int flags) ;
    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
   
    protected void finalize() throws Throwable {
            destroy();
    }
   
    private native final void init();
    private native final void destroy();
 
    private boolean execTransact(int code, int dataObj, int replyObj,
            int flags) {
        res = onTransact(code, data, reply,flags);
        return res;
    }
}

作为一个继承至IBinder接口的类,Binder这个类势必要实现所有的接口方法。但比较特殊的是Binder类的构造方法Binder()会调用到一个init()方法,析构方法finalize()会调用到一个destroy()方法,这两个方法并不是由Java实现,而是被标识为native的JNI实现的方法。另外需要注意到的是,Binder类本身实现了transact()与onTransact()收发两端的代码,但只是进程类的直接交互,并不会进程间的Binder交互。

另外,我们在同一Binder.java类里,还可以找到另一个BinderProxy类的定义,在这一类里会使用一个native标识的transact()方法。虽然在源代码里找不到任何使用这一类的地方,但从命名方式上来看,这一类应该会是被创建的默认的Proxy端。BinderProxy.java的定义如下:

final class BinderProxy implements IBinder {
    public native boolean pingBinder();
    public native boolean isBinderAlive();
    public IInterface queryLocalInterface(Stringdescriptor);
    public native String getInterfaceDescriptor() throws RemoteException;
    public native boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
    public native void linkToDeath(DeathRecipient recipient,int flags)
            throws RemoteException;
    public native boolean unlinkToDeath(DeathRecipient recipient,int flags);
    public void dump(FileDescriptor fd, String[] args) throws RemoteException;
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
 
    BinderProxy() {
        mSelf = new WeakReference(this);
    }
   
    @Override
    protected void finalize() throws Throwable {
            destroy();
    }
   
    private native final void destroy(); 
    private static final void sendDeathNotice(DeathRecipient recipient) {
            recipient.binderDied();
    }
   
    final private WeakReference mSelf;
    private int mObject;
    private int mOrgue;
}

BinderProxy的transact会调用android_util_Binder.cpp

android_os_BinderProxy_transact

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
    jint code, jobject dataObj, jobject replyObj, jint flags)
{
    ...
    //java Parcel转为native Parcel
    Parcel* data = parcelForJavaObject(env, dataObj);
    Parcel* reply = parcelForJavaObject(env, replyObj);
    ...

    //gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    ...

    //此处便是BpBinder::transact(), 经过native层
    status_t err = target->transact(code, *data, reply, flags);
    ...
    return JNI_FALSE;
}

BpBinder::transact

BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

IPCThreadState.transact

IPCThreadState.cpp

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck(); //数据错误检查
    flags |= TF_ACCEPT_FDS;
    ....
    if (err == NO_ERROR) {
         // 传输数据
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    ...

    // 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            //等待回应事件
            err = waitForResponse(reply);
        }else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    return err;
}

IPCThreadState.waitForResponse

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break; 
        ...
        cmd = mIn.readInt32();
        switch (cmd) {
          case BR_REPLY:
          {
            binder_transaction_data tr;
            err = mIn.read(&tr, sizeof(tr));
            if (reply) {
                if ((tr.flags & TF_STATUS_CODE) == 0) {
                    //当reply对象回收时,则会调用freeBuffer来回收内存
                    reply->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);
                } else {
                    ...
                }
            }
          }
          case :...
        }
    }
    ...
    return err;
}

binder_send_reply

 servicemanager/binder.c

void binder_send_reply(struct binder_state *bs, struct binder_io *reply, binder_uintptr_t buffer_to_free, int status) {
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER; //free buffer命令
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY; // reply命令
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        ...
    } else {=
    
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    //向Binder驱动通信
    binder_write(bs, &data, sizeof(data));
}

binder_write将BC_FREE_BUFFER和BC_REPLY命令协议发送给驱动,进入驱动。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,由于是BC_REPLY命令协议,则进入binder_transaction, 该方法会向请求服务的线程Todo队列插入事务。

接下来,请求服务的进程在执行talkWithDriver的过程执行到binder_thread_read(),处理Todo队列的事务。

 readStrongBinder

Parcel.java

eadStrongBinder的过程基本是writeStrongBinder逆过程。

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

javaObjectForIBinder 将native层BpBinder对象转换为Java层BinderProxy对象。

readStrongBinder(C++)

Parcel.cpp

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

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);
                //创建BpBinder对象
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

getStrongProxyForHandle

ProcessState.cpp

    //查找handle对应的资源项
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            ...
            //当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象
            b = new BpBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

经过该方法,最终创建了指向Binder服务端的BpBinder代理对象。回到[小节4.8] 经过javaObjectForIBinder将native层BpBinder对象转换为Java层BinderProxy对象。 也就是说通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。

 

 

对于Framework层实现,其基本功能都是通过frameworks/base/core/jni目录里,可以找到所有JNI实现。对应于Java环境里Binder实现,我们可以找到frameworks/base/core/jni/android_util_Binder.cpp。可以在这一JNI实现里看到,实际上所有基于Binder的交互,会通过javaObjectForIBinder()方法基于IBinder引用来创建或是找到对应的Java对象,通过ibinderForJavaObject()通过Java对象找到IBinder引用:

jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
{
    if (val == NULL) return NULL;
    if(val->checkSubclass(&gBinderOffsets)) {
       jobject object = static_cast<JavaBBinder*>(val.get())->object();
       LOGDEATH("objectForBinder%p: it‘s our own %p!\n", val.get(), object);
       return object;
    }
   AutoMutex _l(mProxyLock);
   jobject object = (jobject)val->findObject(&gBinderProxyOffsets); //1
    if (object != NULL) {
       jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet);     //2
       if(res != NULL) {
           ALOGV("objectForBinder%p: found existing %p!\n", val.get(), res);
           return res;
       }
       LOGDEATH("Proxyobject %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);         //3
    if (object != NULL) {
       LOGDEATH("objectForBinder%p: created new proxy %p !\n", val.get(), object);
       env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
       val->incStrong(object);
       jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object,gBinderProxyOffsets.mSelf));
       val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env),proxy_cleanup);
       sp<DeathRecipientList> drl = new DeathRecipientList;
       drl->incStrong((void*)javaObjectForIBinder);
       env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));
       android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
    return object;
}

在javaObjectForIBinder()方法里,

1.先会通过传入的IBinder引用,来查找是否已经存在所需要使用的BinderProxy对象;

2.如果存在,则通过BinderProxy的WeakReference引用,然后返回该引用;

3.如果没有,则在后面会创建这一BinderProxy对象。除去这几行,实际上其他代码都是在进行引用计数的维护。而在3代码的操作里之后,调用incRefsCreated()方法,于是又会索引到另一个BinderInternal对象,使用其ForceGc()方法。

而对于Binder类本身,我们也会看到其init()的native实现,

static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
   JavaBBinderHolder* jbh = new JavaBBinderHolder();
    if (jbh == NULL) {
       jniThrowException(env, "java/lang/OutOfMemoryError",NULL);
       return;
    }
   jbh->incStrong((void*)android_os_Binder_init);
   env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}

有了这三部分的代码,我们的Java环境里的Binder,便与Native态的Binder结合到一起了,最终会得到如下所示的即有Java,也有C++代码的复杂关系:

技术图片

在Java环境里,某个Binder对象的IBinder引用,则可以通过javaObjectForIBinder()创建或是取得某个已有的BinderProxy对象,BinderProxy对象的transact()是以JNI的方式实现的,于是有可能进一步通过它来构建底层的Binder交互。同时,Java环境里的Binder对象,会通过init()方法来为该对象创建JavaBBinderHolder,从而使自己被映射到Native环境里的Binder(在Native环境里叫BBinder),最终将两个环境里的Binder对象被映射到一起。

在这时不光需要完成Binder的实现由Java层转入Native层,更重要是需要一种机制,可以使Native态发生的变动,再回到Java层。Java语言环境本身提供自动垃圾回收机制,我们需要将Binder对象能够自动地被Java的GC所管理,同时,我们大部分使用Binder通信的代码还是Java写的,我们需要能够在合适的状态点回调到Javag玩意。JavaBBinderHolder本身只是JavaBBinder的包装类,在JavaBBinder之上再包装上引用计数(继承Refbase),于是同时使用一个能处理GC的BinderInternal便可以自动处理。另外,值得注意的是Java环境里的Binder类,Binder类提供一个不常见的private的execTransact()方法,这其实就是Binder环境的回调,JNI代码在执行Native环境的onTransact()方法时,会通过回调Java环境里的execTransact()方法,从而回调到Java里实现的onTransact()方法。于是,Java环境里的Binder,实际上只是一层封装,直正的Binder通讯是由底层来完成的,由Android系统里使用C++编写的一个libBinder库来完成,如下所示:
技术图片

ibbinder的构成

实现了从Java环境到Native实现的Binder环境之间的交互之后,还需要可以在多个范围内完成对象的映射。Binder这个概念在Java环境里大量使用了面向对象的重构技巧,尽可能实现通用操作,而只预留出来需要定制的接口。于是,我们为了支持给Java环境提供的灵活功能,在Native层的Binder,也需要具备面向对象的能力。综合这两种需求,我们得到了frameworks/base/libs/binder目录里,用C++实现的libbinder(在Android 4.1里,为了更好地兼容NDK被移到frameworks/native/libs/binder)。当然,C++跟Java的分析方式则有不同,C++的头文件与实现,跟C一样,是分开的,从头文件更容易分析其构成,与实现对应,一般我们都可以在同级目录里找到头文件,libbinder的头文件位于frameworks/base/include/binder。

出于跟Java层代码进行不同语言空间的映射之用,C++实现的Binder库也会与Java环境里的Binder概念有着互通之处。

IInterface.h,定义IInterface接口类。与Java的IInterface接口类对应,用于通过统一的asBinder()接口方法返回IBinder引用。但与Java环境不同,C++环境里需要提供Binder通信实现,于是IInterface类,在内部被进一步拆分成BpInterface(Proxy端对象)、BnInterface(Stub端对象)两个模板,从而使用不同模板参数,可以使用对同一IInterface接口的访问,得到不同功能实现。
IBinder.h,定义IBinder接口类。与Java环境的IBinder对应,提供Binder引用,并定义Binder对象所应实现的方法。跟Java环境一样,IBinder对象会是分别引用到Proxy对象或是Stub对象,通过localBinder()方法返回Binder Stub端的BBinder对象,或是通过remoteBinder()方法返回Binder Proxy端的BpBinder对象。但与Java环境不同,C++环境里没有标准的自动化内存管理(GabageCollection),于是会内置一个DeathRecipient类,通过Refbase来进行垃圾管理,就像我们前面分析JNI部分,这一管理内容,最终会通过BinderInternal类回调到Java的自动化内存管理。
Binder.h,定义BBinder类与BpRefBase类。BBinder类与Java环境里的Binder类对应,是Binder的Stub实现,通过onTransact()回调方法接收与处理Binder事件。但它更属于Binder通讯的基础类,并不会被直接使用,系统只会通过BBinder类的派生类进行通信,所以它的类名是BBinder,Base Binder的意思。BBinder里维护了Extras对象,可在线程完全情况下访问到BpBinder里实现的objectManager,从而自动管理Proxy对象。BpRefBase类,用于通过IBinder引用来找到合适的BpBinder类,进一步被应用于BpInterface模板类。
BpBinder.h,定义BpBinder类。与Java环境里的Stub.Proxy对象对应,是Binder的Proxy端实现。作为Proxy端,又是Binder最底层的封装,这一类的本质作用只是提供一个transact()方法,从而给上层封装的RPC请求提供最终的Binder通信接口。与此同时,BpBinder创建的对象,必须与BBinder加入绑定,于是也提供objectManager类,用于提供Proxy端的对象管理,但与BBinder使用单一objectManager对象不同,这里存在多重映射的可能性,在Proxy对象里的objectManager会以队列形式被管理。
Parcel.h,定义Parcel类。虽然概念上与Java里实现序列化的Parcel类是对应的,也提供同样的操作方法。但在实现上,Native环境里的Parcel是提供Java环境里的Parcel概念的一种基础,所有的Parcel的read|write_*()系列的方法,底层全是由Native代码来实现具体的读写操作。这也是基于Binder的RPC操作的基础,我们进行进程间的方法调用时,都会基于Parcel来完成参数与返回值的序列化,然后再通过Binder进行传输。最终,所有通过实现Parcelable方法得到的对象,都将在传递时被映射到Binder驱动所需要的一种平滑过的对象结构,被存入一种叫flat_binder_object的变量里,从而可以以线性空间的方式保存并传输。
上面的这些基本类,便构成了Binder通信的基础。通过这些基本类,不但完成了Java环境与Binder的Native在实现上的概念统一,两种环境里的对象都有一一对应的关系。而且这些概念上也通过JNI被关联到一起,Java环境里的Binder最终会通过底层的Binder类来进行操作,而底层Binder对象,则会通过RefBase嵌入到Java环境的垃圾回收池。libBinder便拥有了如下所示的构成:
技术图片

但此时,我们还是没有解决最核心的问题,这些在Native环境里进行Binder通信封装的类,如何操作Binder驱动来达到通信的目的。在libbinder的实现里,我们都会通过两个专门的类来完成真正的Binder消息的读写操作,ProcessState与IPCThreadState,因为此时已经是全系统唯一的概念了,则不会提供Java代码的映射,只由C++代码来实现。

ProcessState.h,定义ProcessState类。正如这个类的名字所表述的,这个类的作用就是维护与IPC相关的进程状态,对于任一使用Binder的进程而言,进程空间里只会有一个ProcessState对象。Binder通信与其他的IPC机制不同,其他的IPC基本上都是基于文件描述符fd来标识出不同的通信过程,而Binder在整个传输过程里都是以进程为单位来进行传输。Binder通信在传输时虽然也会使用/dev/binder的文件描述符,但只是用于与驱动通信,IPC消息只以进程为单位进行传输,并且也可以通过binder知道进程是否还处于存活状态,从而可以实现整个系统的垃圾回收。
IPCThreadState.h,定义类IPCThreadState。这个类描述以线程为基础的IPC传输状态,Binder通信的读写过程便在这个类里完成。在Binder提供底层的跨进程通信能力之后,基于其上建立通信过程,可以以单线程循环方式完成,也可以使用多线程。如果使用单线程,在处理某个大数据量的消息的收发过程里容易发生阻塞,数据传递的效率降低,同时也会使底层的Binder驱动承载的压力变大。如果使用简单多线程,有线程则创建线程加以接收处理,则又产生线程维护开销,并引发多线程编程失控。在IPCThreadState类的实现里,是以线程池的方式来维护Binder的通信请求,对于/dev/binder设备的读写请求都是通过线程方式并行执行的IPCThreadState的线程对象来完成,但并非总是创建,而只是通过IPCThreadState的self()方法取回一个合适的实例来进行处理。
多了这两个与Binder进行通信的基本类之后,libbinder的构成便进一步被扩大,但此时已经可以完成Binder通信,并提供对上层的封装功能了。于是,从Binder通信的功能上来看,libbinder的构成实际上是如下如示的样子:
技术图片

在libbinder的构成里,ProcessState,只是一个用于描述进程状态的类,于是并不直接跟Binder通信。但Binder驱动会在ProcessState对象里被打开,对于进程来说,Binder的使用实例是唯一的,被保存到mDriverFD里。同时,由Binder派生出来的远程对象,也会在ProcessState里通过getContextObject()和setContextObject()来维护。最后,对于进程当前的线程池环境,也是通过ProcessState对象来维护。

至于IPCThreadState类,则实现上会复杂一些,所有的Binder命令,最终都会通过一个IPCThreadState来进行处理。一个IPCThreadState对象,就是通过talkWitheDriver()方法来循环地操作ProcessState的mDriverFD,完成Binder驱动的实际读写操作。所有命令的发送操作,都是通过IPCThreadState的transact()方法来完成,而Binder驱动返回过来的消息,会通过executeCommand()回调到具体的onTransact()实现。

综合libbinder的实现,与Java环境的Remote Service,最终得到的Binder通信便是如下的流程:
技术图片

Remote Service的访问者,也就是应用程序进程,会使用Stub.Proxy对象来调用transact()方法,而Proxy对象本身会在使用里创建一个BinderProxy对象,并调用这一BinderProxy对象的transact()方法。而Java环境里的BinderProxy对象的使用,会在libbinder里创建BpBinder与之对应,BinderProxy的transact()本身是使用JNI实现的,会调用BpBinder的transact()实现。这时,在BpBinder的transact()方法里,Binder命令便会经由IPCThreadState对象的transact()、waiteForResponse()、talkWithDriver(),写入当当前进程维护的mDriverFD,也就是Binder驱动里。

Remote Service则是Binder命令的接收与处理者,会一直在自己的ProcessState对象维护的mDriverFD上监听,Remote Service则都使用joinThreadPool()来创建监听Binder的线程。当Binder命令过来之后,监听的IPCThreadState对象会从talkWithDriver()方法里返回,读回相应的命令,然后调用executeCommand()方便处理这一命令。在executeCommand()方法里,当接收到交互请求(命令是BR_TRANSACTION)时,会调用Binder命令里指定BBinder对象的transact()方法。此时,因为Java环境里Binder对象,在JNI实现里会自动创建JavaBBinder类,于是BBinder对象的transact()方法,会通过JavaBBinder的onTransact()回调到Java环境里Binder对象的execTransact()方法,然后再调用到最终的RemoteService里实现的onTransact()方法。

当然,前面通过aidl编程也可以看出,虽然底层实现上如此复杂,九转十八弯才得到了这样的远程调用,但对于编程使用却异常简单,只是需要简单地使用一个Stub对象即可,所有的底层操作都将系统封装掉了,在aidl编程时甚至都不知道有Proxy对象,全由aidl自动生成。这便是Android的优点之一,无论底层多么复杂,但上层都是很简单的接口。而对于系统设计的一个可借鉴之处是,当我们把这套逻辑封装得非常易于编程时,对于底层的改进也将更加平滑,因为用户并不知道底层发生了怎样的变动,仍使用同样的编程方式进行调用。

这种方式,绕来绕去的,不太容易理解,Java环境与Native环境的互相穿越,也容易迷失方向。这是否有必要呢?如果没有Java,这种复杂逻辑是没有理由的,复杂便会效率低下。而且在整个Binder概念的实现上,大量使用面向对象技巧,即便是在C++实现的部分,也会通过虚拟继承来实现访问上的灵活性,在嵌入式环境里使用虚拟继承来进行动态访问,本身就是低效之源。但是,因为有了Java语言的需求,这样设计就很合理了。通过Binder,不但完成了Binder在Java环境与Native环境的成功映射,在Java环境的Binder概念之下通过机器代码实现了高效安全的Binder通信,更进一步的好处是,Binder被托管到了Java虚拟机的自动化垃圾回收机制里。假设Android并没有选择Java语言,而是选择了另一种支持垃圾回收的编程语言,我们只需要简单地将Java态的绑定,也就是Binder概念相关的Java类、JNI实现实现一次即可。

至此,基本上libbinder的基本功能便已经完备了,可以支持上层的基于Binder传递对象、使用IBinder引用来进行调用远程进程中的方法、以及通过Parcel来传递复杂对象的功能。

除了基本功能之外,libbinder里还会实现一些C++环境里的辅助类:

实现在C++环境里的ServiceManager类,从而在C++环境里可以直接调用getService()方法取得其他System Service
实现IMemory接口方法,从而可以灵活实现多种内存共享方式
libbinder里实现的ServiceManager

ServiceManager本身就是Native Service的一个典型的例子,Java环境里编程会使用ServiceManager,调用到SystemServer里实现的系统功能。而整个Android系统各个组成部分也会不停地进行交互,Native Service之间也会进行相互调用。我们可以看到servicemanager是一个C语言写的独立进程,Stub端的功能便会由这一servicemanager进程来完成,于是从Binder领域来说,所有以面向对象实现的ServiceManager类,只需要提供Proxy功能。

以Native Service方式来提供ServiceManager功能,则是一个跟我们的前面的ITask很类似一种实现。出于代码完整性角度考虑,在IServiceManager里也提供了BnServiceManager的实现,但由于没有将这一Service加入到IPCThreadState里,于是只是空的实现。

在frameworks/native/include/binder/IServiceManager.h定义了以Native方式实现的Service,

namespace android {
    class IServiceManager: publicIInterface   1
    {
    public:
       DECLARE_META_INTERFACE(ServiceManager); 2
       virtual sp<IBinder> getService( const String16& name) const = 0;  3
       virtual sp<IBinder> checkService( const String16& name) const = 0;
       virtual status_t      addService( const String16&name,
                                     constsp<IBinder>& service,
                                     bool allowIsolated =false) = 0;
       virtual Vector<String16>   listServices() =0;
       enum {            4
GET_SERVICE_TRANSACTION=  
IBinder::FIRST_CALL_TRANSACTION,
           CHECK_SERVICE_TRANSACTION,
           ADD_SERVICE_TRANSACTION,
           LIST_SERVICES_TRANSACTION,
       };
    };
   
   sp<IServiceManager> defaultServiceManager();
   
    template<typename INTERFACE>
   status_t getService(const String16& name, sp<INTERFACE>* outService) 5
    {
       const sp<IServiceManager> sm = defaultServiceManager();
       if(sm != NULL) {
           *outService = interface_cast<INTERFACE>(sm->getService(name));
           if((*outService) != NULL) return NO_ERROR;
       }
       return NAME_NOT_FOUND;
    }
   
    boolcheckCallingPermission(const String16& permission);   6
    boolcheckCallingPermission(const String16& permission,
                                int32_t*outPid, int32_t* outUid);
    bool checkPermission(const String16&permission, pid_t pid, uid_t uid);
   
    class BnServiceManager: publicBnInterface<IServiceManager>   7
    {
    public:
       virtual status_t    onTransact(uint32_t code,
                                       const Parcel&data,
                                       Parcel*reply,
                                       uint32_t flags = 0);
    };
}; // namespace android

 IServiceManager这一接口类,继承自IInterface
 进入IServiceManager的类定义部分,就会通过DECLARE_META_INTERFACE来完成通用部分的定义。
 定义所需要的接口方法,所有接口方法必然会是纯虚方法。
 定义IServiceManager所支持的Binder命令,跟Java环境里的ServiceManager类一致,支持四种命令,分别对应到第3步里定义的四个接口方法。并且跟其他Native Service一样,Binder命令都是从IBinder::FIRST_CALL_TRANSACTION开始。
 这里使用了C++的多态,一般的getService()是直接通过一个Service的名字来取回一个IBinder实现,通过返回的IBinder引用是否为NULL来判断是否成功完成调用。而在这里定义的getService()方法,进一步封装了一次,可以返回一个调用的状态值,并且会直接通过interface_cast()宏来确保Proxy对象被创建。
 checkCallingPermission()、checkPermission()相当于IServiceManager里提供的一层Proxy功能,这部分的功能是由IPermissionController.cpp来提供,而这部分功能并不适合暴露出来,于是会透过IServiceManager将权限检测功能提供出来。
 出于实现上的统一性考虑,在这里也会提供BnServiceManager的实现。
有了这个IServiceManager接口类的定义,在IServiceManager实现就跟

sp<IServiceManager>defaultServiceManager()     1
{
    if(gDefaultServiceManager != NULL) return gDefaultServiceManager;
    {
       AutoMutex _l(gDefaultServiceManagerLock);
       if(gDefaultServiceManager == NULL) {
           gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));    2
       }
    }
    returngDefaultServiceManager;
}
…
class BpServiceManager : public BpInterface<IServiceManager> 3
{
public:
   BpServiceManager(const sp<IBinder>& impl)
       : BpInterface<IServiceManager>(impl)
    {
}
…
    virtualsp<IBinder> checkService( const String16& name) const    4
    {
       Parcel data, reply;
       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
       remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
       return reply.readStrongBinder();
}
     …
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); 5
…
}

defaultServiceManager(),每个进程都需要通过getService()来取回RemoteService,所以必然需要调用到defaultServiceManager()来取回一个IServiceManager的Proxy对象。
在defaultServiceManager()里使用了Singleton模式,对于某个进程只会创建一个唯一的IServiceManager的Proxy实例。值得注意的是getContextObject()会通过一个handle变量来取得一个IBinder引用,然后再通过interface_cast()转换成IServiceManager接口类。getContextObject()方法的参数会是整型的handle,handle的值会随着不同Service的引用,每使用一个,handle的值便会加1,这样每个进程空间会拥有各自不同的handle值,使得基于Binder通信的安全变高,不容易简单地抓取Binder命令来分析程序的行为。这里使用的handle值为0,于是对于每个进程,handle为0的Service都会是IServiceManager。
实现IServiceManager的Proxy类,于是实现上便会继承自BpInterface的模板。
跟Java环境的ServiceManager一致,getService()内部也会是调用checkService()来取得Service的IBinder引用。所有的Proxy端方法,都使用统一的模式,就是将调用的方法转换成Binder命令,然后发送出去。
IMPLEMENT_META_INTERFACE()宏,会实现通用部分的代码,同时也会设定特定的descriptor。
       通过这样的方式,最终就得到了简单而且高效的,并且与ServiceManager.java实现并行的ServiceManager的Proxy端。

通过libbinder灵活使用内存

在我们传统的Unix/Linux编程环境里,为了保持进程之间的互相独立性,都是用户进程空间里的内容互相独立,使用不同的内存映射,内核空间便会共享同一份内容,使用同一份内存映射。这样的情况下,如果需要在进程之间传递数据,必然是先通过copy_from_user()系统调用从用户空间先拷贝到内核空间,然后再在另一个进程空间里通过copy_from_user()系统调用从内核空间拷贝回用户空间。这种方式就保证了不同进程可以传递数据,同时进程之间互相不会有干扰,任一进程出错,对另一进程完全没有影响,因为进程空间本身是独立的。在Linux内核之上,任何IPC机制都采用了这种实现,Binder也不例外。比如Remote Service,在任一交互过程里,数据始终会有三份,内核一份、进程空间各一份拷贝:
技术图片

但这种方式比较低效,多次内存拷贝会造成内存的开销,同时由于copy_from_user()和copy_to_user()系统调用,会造成计算上的开销。假设已经确定内存的传递时一方只读,此时就可以改进内存的使用,在发生内存写请求的进程里,仍然使用copy_from_user(),而读取内存的部分,则不再使用copy_to_user(),而是通过mmap()直接映射一段内存到自己的进程空间内,这样只会发生一次内存拷贝。
技术图片

最后,还有一种可能性,所有进程都共享同一块内存区域,不管内存里保存的内容发生了任何改变,所有进程都应该见得到。这种使用在Linux编程里也很普遍,但一般只用于驱动访问,很少被用于IPC进程间通信。这种使用情境下,如果所共享的页源自于用户空间,则难以保证在物理分配上的连续性,更重要的是不要求,如果承载内存页的进程挂掉,则所有涉及交互的进程都不得不挂掉,所以内存页要在内核空间里。同时,在内核态则需要有一定的实体存放这样的页面映射引用,IPC机制并不支持这样的页面映射管理。但Binder IPC不受限于此,Binder驱动实际上只是一个基于内存映射的虚拟字符设备,于是可以天然地在传输过程里使用内存页的映射功能。于是,又有了第三种使用内存页的方式,就是灵活地内存映射功能:
技术图片

如上所示,内存页实际上是在使用时通过内核态来分配的,内存只在内核态有一份拷贝,所有的用户进程都只通过mmap()系统调用来引用这样的页。但是这样的方式会引发内存管理上的混乱,内核空间的页面在分配上的优先级要远大于用户空间,而且必须以连续物理页来分配,也容易造成内存使用上的失控。于是,Android在原有的内存管理机制上拓展出来两种“特殊”内存管理机制,准确地说是共享内存的实现机制,pmem和ashmem,这两种机制可以将内核里内存分配机制暴露到用户态来操作。Pmem是一种预留出来一段物理内存供用户态分配连续物理内存来使用,而ashmem则是Android对原有的Shared Memory(共享内存机制)的一种改进,这两种机制我们后台再详细。虽然这种共享内存方式本身跟Binder机制没有关系的,并非由Binder IPC来实现这样共享功能,但得益于Binder通信与Java垃圾回收的绑定,于是Binder为这种内存共享提供了自动的内存管理功能。

IMemory.h,定义两个基于IBinder的远程类,生成两个远程接口类,IMemory与IMemoryHeap,分别用于使用内存和分配内存。这是Android在系统设计上灵活性的一种体现,我们也知道IBinder是提供远程引用的,对于内存使用两个基于IBinder的接口类,则意味着申请内存与分配内存可分别由单独进程来提供。试想一下,比如一个照相机应用程序,通过IMemory接口向mediaserver进程申请内存,但在mediaserver进程里发出内存申请之后,则会由负责显示的surfaceflinger来负责分配所需要的空间。这样复杂的供给关系,只取决于代码如何实现,也不受限于进程空间,而且不会影响效率,因为无论多少进程交互,在底层实际上还是只有一份拷贝。当然,同时使用IMemory与IMemoryHeap远程接口,并不一定要发生在多进程环境里,当两个接口都在同一进程空间里提供Proxy与Stub时,实际上只是多绕了一层Binder IPC,但还是当前进程空间内,也不影响效率。另外,这两个接口类,出于性能的考虑,会是以Native Service的方式来提供。
MemoryDealer.h,定义一个默认的分配内存的MemoryDealer类。在这一类里内置了一个最简化的列表式内存管理算法,这样需要提供内存分配部分,可以使用这一类来创建内存空间,并通过IMemoryHeap共享出去。
MemoryBase.h,通过MemoryBase类来提供IMemory接口类的Stub端实现。MemoryBase会通过getMemory()的远程方法来返回一个IMemoryHeap实例,同时也会是MemoryDealer的操作对象。命名为Base,就说明这会是该类型的基类定义,如果有其他使用IMemory接口的地方可以继承该类,再派出生新的特性。
MemoryHeapBase.h,通过MemoryHeapBase类来实现IMemoryHeap接口类的Stub端。在这个类里实现可用于远程共享的堆空间分配,如果不用于远程共享,则直接使用malloc()即可,IMemoryHeap接口相当于是远程实现的malloc(),new()等操作方法。在这一方法里会定义一些基本的Heap分配操作,根据不同的应用情境分配不同类型的内存(基于文件的、匿名空间等)。
MemoryHeapPmem.h,实现基于Pmem机制并实现IMemoryHeap接口的MemoryHeapHmem类。如果有特殊内存堆的使用需求,则可以通过MemoryHeadBase类派生出新的MemoryHead类,比如在MemoryHeapPmem。所有的的特殊
最终,针对内存的分配与使用,在底层也会灵活地组织起来,在内存使用“食物链”最上流的使用内存的部分,只需要调用MemoryBase对象的getMemory()接口方法,这一请求会通过IMemory接口转发到能处理该请求的另一进程。而getMemory()又会返回一个IMemoryHeap引用,这样会自动地又将请求分发到可以处理这一IMemoryHeap分配的进程来处理内存分配。于是,在libbinder实现里针对跨进程的内存使用与分配,又可以得到如下的关系图:
技术图片

有了IMemory这样的接口类之后,在Android系统里就可以更灵活地定义不同的内存使用方法。

 

Binder的Native实现libbinder

标签:不用   ping   优先   不同类   kernel   组织   ali   返回值   接收   

原文地址:https://www.cnblogs.com/mingfeng002/p/10678417.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!