Binder c++代码

这篇博客主要看一下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原理。



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值