浅谈Android之Binder原理介绍(三)

2.4 C++层传输数据封装

使用ProcessState和IPCThreadState建立好binder运行环境后,后续要做的,就是对发送和接收数据的封装,先从基础接口和类开始:

1:IBinder binder发送和接收基础功能接口,最终要的接口函数是transact,对应数据传输

2:BpBinder 实现IBinder,对应于binder proxy,主要用于binder数据的发送,初始化必须关联对应的binder handle

3:BBinder 实现IBinder,对应native binder,它不同于BpBinder的点是,它定义了onTransact这个虚函数

 

所以很明显,如果是binder客户端,就要通过拿到要通信service对应binder的handle来初始化BpBinder,反之,如果是binder服务端,那就必须实现BBinder

 

BpBinder和BBinder都实现了IBinder,它们最大的不同是对transact接口的实现

先看BpBinder::transact

status_t BpBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    // Once a binder has died, it will never come back to life.

    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函数,然后传递目标handle和transaction code以及对应的参数。

 

再看BBinder:: transact

status_t BBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    data.setDataPosition(0);

 

    status_t err = NO_ERROR;

    switch (code) {

        case PING_TRANSACTION:

            reply->writeInt32(pingBinder());

            break;

        default:

            err = onTransact(code, data, reply, flags);

            break;

    }

 

    if (reply != NULL) {

        reply->setDataPosition(0);

    }

 

    return err;

}

 

transact基本没做啥,直接把请求转发到onTransact,看到这里,基本明白了,如果要定义自己的native binder,那肯定要派生自BBinder并实现onTransact

 

BBinder的transact是在IPCThreadState收到BR_TRANSACTION时被调用的:

if (tr.target.ptr) {

                sp b((BBinder*)tr.cookie);

                error = b->transact(tr.code, buffer, &reply, tr.flags);

}

 

代码在IPCThreadState::executeCommand中,这个函数比较长,就不全部贴出了

 

Transact code对应各种传输功能,如果要继续简化开发,最好把transact code也隐藏掉,直接定义业务接口给外部使用,由于binder service和binder serviceproxy相关类的封装还是有点区别,这里分开讲解。

 

Binder Service:

binder service通过多继承同时派生于业务接口和IBinder,接着在实现时将transactcode和各服务接口做关联,但这里会有一个问题,就是无法将两个子接口在对象内地址偏移直接进行转换问题,这个是接口多继承导致的,解决也很简单,就是在各个接口都定义虚函数用以地址转换,然后让binder service去实现:

1)  IInterface,服务基础接口,主要定义接口asBinder用于获取IBinder在对象内地址偏移

2)  IBinder接口定义queryLocalInterface用于得到IInterface在对象内地址偏移

 

接着实现模板类BnInterface:

template

class BnInterface : public INTERFACE, public BBinder

{

public:

    virtual sp      queryLocalInterface(const String16& _descriptor);

    virtual const String16&     getInterfaceDescriptor() const;

 

protected:

    virtual IBinder*            onAsBinder();

};

 

INTERFACE就是我们最终要实现的服务接口,它要派生自IInterface

接着看queryLocalInterface的实现:

template

inline sp BnInterface::queryLocalInterface(

        const String16& _descriptor)

{

    if (_descriptor == INTERFACE::descriptor) return this;

    return NULL;

}

 

descriptor是binder service定义的一个静态变量,主要用于binderservice 接口描述,它的初始化在后续再介绍,接着看onAsBinder:

template

IBinder* BnInterface::onAsBinder()

{

    return this;

}

 

Binder Service Proxy:

Binder service proxy对服务接口和binder proxy则不是通过多继承来实现的,而是通过包含,在构造的时候,直接传入BpBinder对象来初始化内部的remoteIBinder变量,然后通过

onAsBinder拿到其内部的remote IBinder对象。

 

同样的,它也有一个模板类:

template

class BpInterface : public INTERFACE, public BpRefBase

{

public:

    BpInterface(const sp& remote);

 

protected:

    virtual IBinder*            onAsBinder();

};

 

INTERFACE跟BnInterface一样,对应最终要实现的服务接口,构造必须传入remote BpBinder,否则数据发哪去都不知道,这个proxy就没任何意义

接着看onAsBinder的实现:

template

inline IBinder* BpInterface::onAsBinder()

{

    return remote();

}

 

通过上面解析,我们可惜清晰的看出,如果拿到BnInterface或者BpInterface的实例,拿到其关联的IBinder数据,很简单,直接调用asBinder()就可以了

 

将IBinder转换成BnInterface调用queryLocalInterface,如果要转换成BpInterface,直接

new BpInterface,但是对开发人员来说,他拿到一个IBinder对象,还得先判断是nativebinder还是binder proxy,还是不大方便,再封装下吧

 

Android对应的实现是定义了两个宏,分别是DECLARE_META_INTERFACE(INTERFACE)和

IMPLEMENT_META_INTERFACE(INTERFACE, NAME),对应声明和实现

任何binder service接口类,也就是上面模板的INTERFACE,都必须要添加这两个宏,这个宏主要实现:

1)  binder service接口描述名,对应静态变量descriptor

2)  接口描述名获取接口,对应函数getInterfaceDescriptor

3)  接口转换函数,对应函数asInterface

 

下面是宏张开后的完整代码:

#define DECLARE_META_INTERFACE(INTERFACE)                               \

    static const android::String16 descriptor;                          \

    static android::sp asInterface(                       \

            const android::sp& obj);                  \

    virtual const android::String16& getInterfaceDescriptor() const;    \

    I##INTERFACE();                                                     \

    virtual ~I##INTERFACE();                                            \

 

 

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \

    const android::String16 I##INTERFACE::descriptor(NAME);             \

    const android::String16&                                            \

            I##INTERFACE::getInterfaceDescriptor() const {              \

        return I##INTERFACE::descriptor;                                \

    }                                                                   \

    android::sp I##INTERFACE::asInterface(                \

            const android::sp& obj)                   \

    {                                                                   \

        android::sp intr;                                 \

        if (obj != NULL) {                                              \

            intr = static_cast(                          \

                obj->queryLocalInterface(                               \

                        I##INTERFACE::descriptor).get());               \

            if (intr == NULL) {                                         \

                intr = new Bp##INTERFACE(obj);                          \

            }                                                           \

        }                                                               \

        return intr;                                                    \

    }                                                                   \

    I##INTERFACE::I##INTERFACE() { }                                    \

    I##INTERFACE::~I##INTERFACE() { }                                   \

 

asInterface先用调用IBinder的queryLocalInterface来尝试获取binder service,如果不为空,直接返回,如果为空,说明这个是binder service proxy,直接newBp##INTERFACE,将该IBinder对象传入作为remote binder

 

接下去,介绍跟我们开发最相关的部分,就是transactioncode的绑定,这部分我就直接拿ICamera这个binder service接口来介绍,为了简洁起见,我只贴出ICamera两个transactioncode的代码

 

首先,根据业务功能定义transactioncode:

//ICamrea.cpp

enum {

    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,

    SET_PREVIEW_TARGET,

};

 

Transaction code的值不能随便定义,要基于IBinder::FIRST_CALL_TRANSACTION递增

接着,实现ICamera接口类:

class ICamera: public IInterface

{

 

public:

    DECLARE_META_INTERFACE(Camera);

 

    virtual void            disconnect() = 0;

    // pass the buffered IGraphicBufferProducer to the camera service

    virtual status_t        setPreviewTarget(

            const sp& bufferProducer) = 0;

}

 

一般transaction code跟虚函数都是一一对应的,还有就是添加

DECLARE_META_INTERFACE(Camera);

 

接着还要添加宏的实现:

//ICamera.cpp

IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");

 

从这里可以看出,这个接口的描述名为android.hardware.ICamera

接口定义好了,接着就是实现BnCamera类,对应binder service,并实现onTransact函数:

类声明:

class BnCamera: public BnInterface

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    const Parcel& data,

                                    Parcel* reply,

                                    uint32_t flags = 0);

};

 

对应实现:

status_t BnCamera::onTransact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    switch(code) {

        case DISCONNECT: {

            ALOGV("DISCONNECT");

            CHECK_INTERFACE(ICamera, data, reply);

            disconnect();

            reply->writeNoException();

            return NO_ERROR;

        } break;

        case SET_PREVIEW_TARGET: {

            ALOGV("SET_PREVIEW_TARGET");

            CHECK_INTERFACE(ICamera, data, reply);

            sp st =

                interface_cast(data.readStrongBinder());

            reply->writeInt32(setPreviewTarget(st));

            return NO_ERROR;

        } break;

        default:

            return BBinder::onTransact(code, data, reply, flags);

    }

}

 

将DISCONNECT与SET_PREVIEW_TARGET分别与函数disconnect()和setPreviewTarget做绑定

 

接着看binder service proxy类的实现,对应BpCamera:

class BpCamera: public BpInterface

{

public:

    BpCamera(const sp& impl)

        : BpInterface(impl)

    {

    }

 

    // disconnect from camera service

    void disconnect()

    {

        ALOGV("disconnect");

        Parcel data, reply;

        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());

        remote()->transact(DISCONNECT, data, &reply);

        reply.readExceptionCode();

    }

 

    // pass the buffered IGraphicBufferProducer to the camera service

    status_t setPreviewTarget(const sp& bufferProducer)

    {

        ALOGV("setPreviewTarget");

        Parcel data, reply;

        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());

        sp b(bufferProducer->asBinder());

        data.writeStrongBinder(b);

        remote()->transact(SET_PREVIEW_TARGET, data, &reply);

        return reply.readInt32();

}

}

 

很简单,将相关参数封装到Parcel中后,调用remote()->transact将数据发送出去。

 

接下去,把这个binder service注册到service manager中

首先,先初始化service manager对应的binder proxy service:

代码如下:

//通过调用ProcessState:: getStrongProxyForHandle获取service manager对应的BpBinder

//service manager的handle固定为0

Sp bpSM = ProcessState::self()->getStrongProxyForHandle(0);

//接着将其转换成IServiceManager对应的binder proxy service

sp servicemanager = IServiceManager::asInterface(bpSM);

 

注册代码:

sp bnCamera = new BnCamera();

sevicemanager->addService(“demoCamera”,  bnCamera);

 

就这样,我们在service manager添加了一个名叫demoCamera的binder service

 

客户进程如果要连接这个binderservice,只需要使用如下代码,创建binderservice proxy对象即可:

Sp pp = servicemanager->getService(“demoCamera”);

Sp proxyCamera = ICamera::asInterface(pp);

 

接着就可以直接通过proxyCamera与binder service进行通信了

So easy!!!

 

2.5 JAVA(Android)层封装

JAVA层的封装主要分三部分:

1)  定义Binder和BinderProxy两个类,然后通过JNI,跟C++层的BBinder和BpBinder做绑定

2)  使用AIDL接口描述语言和相关解析工具,来封装bindertransaction code的定义和与对应接口函数的绑定

3)  通过Service的onBind接口,将Binder返回给ActivityManagerService统一管理,在有应用申请连接这个Binder服务时,AMS再将Binder服务对应的Binder proxy通过回调传给应用,从而实现通过Intent来找到指定Binder服务

 

先说第一部分

Binder相关的JNI代码文件android_util_binder.cpp

Java对象跟C++对象数据进行绑定的基本都是通过在Java类定义一个long类型的变量,然后在jni调用c++代码时,将创建的C++对象地址保存到Java对象的这个long类型变量中。

接着在Java类定义native函数,然后通过JNI跟C++的函数做一一绑定

 

除了上面说的这些以外,Java端的Binder和BinderProxy和C++层的BBinder和BpBinder还有两个问题需要解决:

1)  BBinder的收到onTransact事件后,如何回调到java Binder?

2)  如何将基于Parcel.java的binder数据反序列化成Java Binder或BinderProxy对象

 

第一个问题,Android在C++层定义了一个派生自BBinder的类JavaBBinder来解决:

class JavaBBinder : public BBinder

 

如何在JavaBBinder::onTransact时回调Java对象的onTransact函数:

jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,

    code, reinterpret_cast(&data), reinterpret_cast(reply), flags);

 

第二个问题直接看Parcel.java的jni映射函数看其怎么反序列binder对象就可以了,

JavaParcel类对应的jni代码文件为 android_os_parcel.cpp

 

Parcel反序列化binder函数为readStringBinder,对应jni代码:

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)

{

    Parcel* parcel = reinterpret_cast(nativePtr);

if (parcel != NULL) {

    return javaObjectForIBinder(env, parcel->readStrongBinder());

}

return NULL;

}

 

通过parcel->readStrongBinder()反序列后,得到对应的BBinder或BpBinder对象,接着传给

javaObjectForIBinder

jobject javaObjectForIBinder(JNIEnv* env, const sp& val)

{

    if (val == NULL) return NULL;

 

    if (val->checkSubclass(&gBinderOffsets)) {

        // One of our own!

        jobject object = static_cast(val.get())->object();

        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);

        return object;

    }

 

    // For the rest of the function we will hold this lock, to serialize

    // looking/creation of Java proxies for native Binder proxies.

    AutoMutex _l(mProxyLock);

 

    // Someone else's...  do we know about it?

    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);

    if (object != NULL) {

        jobject res = jniGetReferent(env, object);

        if (res != NULL) {

            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);

            return res;

        }

        LOGDEATH("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) {

        LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);

        // The proxy holds a reference to the native object.

        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());

        val->incStrong((void*)javaObjectForIBinder);

 

        // 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);

 

        // Also remember the death recipients registered on this proxy

        sp drl = new DeathRecipientList;

        drl->incStrong((void*)javaObjectForIBinder);

        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast(drl.get()));

 

        // Note that a new object reference has been created.

        android_atomic_inc(&gNumProxyRefs);

        incRefsCreated(env);

    }

 

    return object;

}

先通过checkSubClass来判断这个Binder是否是JavaBBinder对象,如果是,说明是nativebinder,直接静态强转成JavaBBinder类型,然后调用object拿到对应的java Binder对象,否则,通过env->newObject来创建JavaBinderProxy对象

接着将其返回给Java层

 

接着说第二部分

其实C++层将binder transactioncode和自定义功能接口函数的绑定这块封装的已经比较方便了,不过如果我们回过头来看看绑定相关代码,其实会发现,这些代码都非常标准化,都有两个Parcel对象用来保存输入和返回数据,还有就是将每一个定义的transaction code和某函数调用一一对应起来,既然这么标准化,那能不能让这块代码自动生成,我们只需要写一个接口,把所有的函数名,以及函数对应的输入和返回数据类型描述清楚就好了

 

android就是这么做的:

1)使用AIDL语言描述binder传输接口信息,并保存到.aidl文

2)使用AIDL语言解析工具,将.aidl文件内容解析后,生成对应的.java文件,这个java文件会自动生成transaction code列表,然后实现派生自Binder的Stub类做binder service,还有实现派生自BinderProxy的Proxy类作为binder service proxy,这两个类内部实现的代码跟C++类似,这里就不再介绍

 

最后说第三部分

 

通过第二部分AIDL相关描述,我们知道通过定义AIDL文件,就可以自动生成Stub类做binder service,那如何将这个binder service添加到binder kernel呢?

之前说过可以通过servicemanager,但是servicemanager.addService对普通的android app来说是没有权限的

 

Android采用的方法是,可以在Service的onBind函数返回Stub类对应的binder service,然后用startService启动这个service后,ActivityThread在调用pushService将其push到ActivityManagerService之前,会调用service.onBinder获取这个binderservice,接着作为pushService的参数传到ActivityManagerService,由于ActivityThread和ActivityManagerService之间就是基于Binder进行通信的,还记得上面说的吗?Native binder化身数据流在binder传过,最终反序列化后拿到的就是对应的handle(binder proxy),然后ActivityManagerService将这个binderproxy相关数据保存到ServiceRecord的bindings列表中。

 

接下去,app就可以通过context.bindService,传入ServiceConnection,如果绑定成功,则会将对应的binderproxy回调回来,大体的流程是这样的:

1)ContextImpl.bindService回调用LoadedApk的成员函数getServiceDispatcher并传入

   Serviceconnection对象

2)getServiceDispatcher会创建ServiceDispatcher来跟ServiceConnection绑定, 在

ServiceDispatche内部会创建类型为IServiceConnection.Stub的binder service

3)接着调用AMS的bindService,将IServiceConnection对应的binderservice和intent等数    

据传到AMS

4)AMS收到bindService后,首先会根据Intent从对应ServiceRecord的bindings列表中拿到  对应的binder proxy(对应Service.onBind),然后保存到创建connectionRecord中,接着添加到  ServiceRecord的connections这个Map中,map的key为binder,value为connectionRecord列表

5)接着再回调IServiceConnection.Connected将binder proxy(对应Service.onBind)传到第2条中的ServiceDispatcher中,然后ServiceDispatcher再将其回调给ServiceConnection,ServiceConnection.onServiceConnected再通过对应接口的.asInterface将IBinder 转换后,就可以使用了。

 

上面只是一个简单的介绍,详细代码就不贴了,大家可自行看源码。

你可能感兴趣的:(Android)