Binder c++代码

来源:互联网 发布:淘宝猪哼少是正品吗 编辑:程序博客网 时间:2024/04/29 07:53

这篇博客主要看一下binder的一些实现,以及自己写一个实例:

Binder中service组件和client组件分别使用模板类BnInterface和BpInterface来描述,前者为Binder的本地对象,后者为代理对象。

// ----------------------------------------------------------------------template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder{public:    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);    virtual const String16&     getInterfaceDescriptor() const;protected:    virtual IBinder*            onAsBinder();};// ----------------------------------------------------------------------template<typename INTERFACE>class BpInterface : public INTERFACE, public BpRefBase{public:                                BpInterface(const sp<IBinder>& remote);protected:    virtual IBinder*            onAsBinder();};

模板参数INTERFACE是一个由进程自定义的的接口,Bninterface和BpInterface都需要实现该接口,自己必须实现Bninterface和BpInterface这两个类

下面是自己实现的一个.h文件

class IExampleService : public IInterface{    public:    DECLARE_META_INTERFACE(ExampleSercie);    virtual int get () = 0;    virtual void set (int value) = 0;}class BnExampleService : public BnInterface<IExampleService>//这边的模板其实对应上面的定义,就是继承这个接口类而已{        virtual status_t    onTransact( uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);}
对应实现一个.cpp文件,Bp和Bn的实现在一个文件中,但是实际上是在两个进程中,两个类都要实现IExampleService中的方法

enum {    EXAMPLE_GET = IBinder::FIRST_CALL_TRANSACTION,    EXAMPLE_SET,};class BpExampleService : public BpInterface<IExampleService>{public:    virtual int get()    {        Parcel data, reply;        data.writeInterfaceToken(IExampleService::getInterfaceDescriptor());        remote()->transact(EXAMPLE_GET, data, &reply);        return reply.readInt();    }    virtual void set(int value)    {        Parcel data, reply;        data.writeInterfaceToken(IExampleService::getInterfaceDescriptor());        data.writeInt(value);        remote()->transact(EXAMPLE_SET, data, &reply);        return;    }};IMPLEMENT_META_INTERFACE(ExampleService, "ExampleDescriptor");status_t BnExampleService::onTransact(uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags){    switch(code) {        case EXAMPLE_GET:            CHECK_INTERFACE(IExampleService, data, &reply);            reply->writeInt(get());            break;        case EXAMPLE_SET:            CHECK_INTERFACE(IExampleService, data, &reply);            set(data->readInt());            break;        default:            return BBinder::onTransact(code,data,reply,flags);    }    return NO_ERROR;}

最后实现service,ExampleService需要继承BnExampleService,并实现虚函数,添加一个instantiate函数将当前service加入到servicemanager中。

class ExampleService : pulic BnExampleService{public:    ExampleService ():mValue(0);    public int get() {return mValue};    public void set (int value) { mValue = value;}    public static void instantiate() {        defaultServiceManager()->addService(String16("example"), new ExampleService());    }private:    int mValue;    }

Bninterface类继承了BBinder,定义如下:

class BBinder : public IBinder{public:    .....    virtual status_t    transact(   uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);protected:    ......    virtual status_t    onTransact( uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);    ......};

当有一个Binder代理对象(客户端)通过binder驱动程序向一个binder本地对象(server端)发出一个进程间通信请求时,Binder驱动程序就会调用该Binder本地对象的成员函数tracsact来处理该请求。onTransact由子类实现,负责分发与业务相关的进程间通信请求,我们的例子中在BnExampleService实现了该函数,负责处理进程间发送过来的请求。

class BpRefBase : public virtual RefBase{protected:                            BpRefBase(const sp<IBinder>& o);    virtual                 ~BpRefBase();........    inline  IBinder*        remote()                { return mRemote; }    inline  IBinder*        remote() const          { return mRemote; }private:........    IBinder* const          mRemote;......};

mRemote指向一个BpBinder对象,可以通过remote函数来获取

class BpBinder : public IBinder{public:                        BpBinder(int32_t handle);    inline  int32_t     handle() const { return mHandle; }......    virtual status_t    transact(   uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);......private:    const   int32_t             mHandle;....};

BpBinder类的成员变量mHandle表示一个client组件的句柄,可以通过handle函数获取,它是binder驱动程序中一个client的binder引用对象,client组件通过这个句柄和binder对象引用对象建立对应关系。

BpBinder类的transact用来向运行在server进程中的service组件发送进程间通信请求,通过binder驱动实现。transact会把mHandle,以及通信数据发送给binder驱动,这样驱动可以根据这个句柄值找到对应的binder引用对象,然后找到binder实体对象,最后把通信数据发给对应的service组件。

无论是BBinder,BpBinder同事通过IPCThreadState类和binder驱动交互的。

class IPCThreadState{public:    static  IPCThreadState*     self();.......            status_t            transact(int32_t handle,                                         uint32_t code, const Parcel& data,                                         Parcel* reply, uint32_t flags);    private:.....            status_t            talkWithDriver(bool doReceive=true);....    const   sp<ProcessState>    mProcess;....};

每一个使用binder的进程都有一个binder线程池,用来处理进程通信请求。每个binder线程,内部都有一个IPCThreaState对象,可以通过self获取,transact函数和binder驱动交互,在transact函数内部调用talkwithDriver来实现,它一方面负责向binder驱动发送通信请求,一方面接受binder驱动通信请求。

IPCThreadState类有一个mProcess,指向ProcessState对象。对于每个使用binder的进程,内部都有一个ProcessState对象,负责初始化Binder设备,即打开设备文件/dev/binder,以及将设备文件/dev/binder映射到进程的地址空间。由于ProcessState对象在进程唯一,binder线程池中每一线程都可以通过它与驱动程序连接。

class ProcessState : public virtual RefBase{public:    static  sp<ProcessState>    self();....private:            int                 mDriverFD;            void*               mVMStart;....};

进程中可以通过self函数获取ProcessState 对象,第一次调用创建一个对象,并且打开设备文件/dev/binder, 然后调用函数mmap将它映射到进程的地址空间,即请求binder驱动为进程分配内核缓冲区。得到的内核缓冲区的用户地址保存在mVMStart中。

前面实例中有两个宏还没有分析

#define DECLARE_META_INTERFACE(INTERFACE)                               \    static const android::String16 descriptor;                          \    static android::sp<I##INTERFACE> asInterface(                       \            const android::sp<android::IBinder>& 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> I##INTERFACE::asInterface(                \            const android::sp<android::IBinder>& obj)                   \    {                                                                   \        android::sp<I##INTERFACE> intr;                                 \        if (obj != NULL) {                                              \            intr = static_cast<I##INTERFACE*>(                          \                obj->queryLocalInterface(                               \                        I##INTERFACE::descriptor).get());               \            if (intr == NULL) {                                         \                intr = new Bp##INTERFACE(obj);                          \            }                                                           \        }                                                               \        return intr;                                                    \    }                                                                   \    I##INTERFACE::I##INTERFACE() { }                                    \    I##INTERFACE::~I##INTERFACE() { }   

其中就是实现自己的IExample一些固定接口,这边主要看下asInterface这个函数,IBinder中有两个接口,localBinder,remoteBinder,localBinder指的是Binder实体对象,remoteBInder指的是引用对象。

对于服务进程,localBinder有意义,remoteBinder没有意义。在客户端就相反,remoteBinder有意义。因此在asInterface中,querLocalInterface返回为空代表是在客户端,因此需要new Bp##INTERFACE对象。即BpBinder没有重载querLocalInterface这函数,返回为null

下面我们实现service进程的主函数。

int main(){    ExampleService::instantiate();//将service加入到serviceManager中        processState::self()->startThreadPool();//开启了一个线程读取binder请求    IPCThreadState::self()->joinThreadPool();//主线程joinThreadPool读取binder请求,因此有两个binder线程。    return 0;}



最后我们看看客户端如何通过binder跨进程通信,调用接口。

int main(){    sp<IBinder> binder = defaultServiceManager()->getService(string16("example"));    if (binder == null)    {        LOGE("failed");        return -1;    }        sp<IExampleService> service = IExampleService::asInterface(binder);//将IBinder转换成    int value = service->get();    printf("%d", value);}
binder c++的分析完了,后面分析下java的binder原理。



1 0
原创粉丝点击