BInder

Posted 白嫩豆腐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BInder相关的知识,希望对你有一定的参考价值。

前言

Binder是android核心中的核心。Android各种服务都是通过Binder来实现进程间通讯的,我计划分三部分大概剖析一下binder的具体原理。

  1. Binder的具体使用案例
  2. 源码分析大概流程
  3. 实现最简单的binder

正文

binder是分为两部分的,一部分是服务端,通过线程池,等待其他进程通过binder驱动通知服务。另一部分是客户端,主要通过mmap函数,得到内核的内存映射区,写入数据,然后通知服务端。一个最简单的服务端如下:

在这里插入图片描述

主要操作流程大概是

  1. Bnservice向binder驱动注册自己(主要包括名称和线程池)
  2. 客户端通过defaultServiceManager(binder驱动模块)获取注册的Bpservice。
  3. 客户端吧需要传输的消息写入到通过map共享的内存中,然后通知binder,唤醒服务端。
  4. 服务端进程启动,调用onTransact,读取共享缓冲区的内容。做出相应,写会相应。
  5. 阻塞的客户端得到相应。完成一次通讯。

下面我们先简要介绍一个最简答的HelloWorld的binder程序

首先介绍一下:binder使用的接口:

无论任何一对客户端和服务端的binder通讯对(可以一对多),都需要一个IXXXService,

比如IHelloService

class IHelloService: public IInterface
{
public:
    DECLARE_META_INTERFACE(HelloService);
/*                                
public:                                                                 
    static const ::android::String16 descriptor;                        
    static ::android::sp<IHelloService> asInterface(                     
            const ::android::sp<::android::IBinder>& obj);              
    virtual const ::android::String16& getInterfaceDescriptor() const;  
    IHelloService();                                                     
    virtual ~IHelloService();                                            
    static bool setDefaultImpl(std::unique_ptr<IHelloService> impl);     
    static const std::unique_ptr<IHelloService>& getDefaultImpl();       
private:                                                                
    static std::unique_ptr<IHelloService> default_impl;                  
public:     

*/
                                                            

    virtual int    SayHello(char *str) = 0;
    virtual char*    getHi() = 0;
    
};

一般开发过程中都直接使用预编译的DECLARE_META_INTERFACE的定义一些公共方法,最终等效于注释部分,主要定义一些函数、和default_impl变量。而IInterface的代码如下:

class IInterface : public virtual RefBase
{
public:
            IInterface();
            static sp<IBinder>  asBinder(const IInterface*);
            static sp<IBinder>  asBinder(const sp<IInterface>&);

protected:
    virtual                     ~IInterface();
    virtual IBinder*            onAsBinder() = 0;
};

这个类主要是关于binder的静态方法。

下面我们介绍一下BnService的实现

class HelloService: public BnInterface<IHelloService>
{
public:

    static void instantiate(){
    defaultServiceManager()->addService(
            String16("hello.service"), new HelloService());
	};

    int    SayHello(char *str){
    return 1;
	}

    char*    getHi(){
    return NULL;
     }

status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags){
      
    switch (code) {
    	case SAY_HELLO: {
            CHECK_INTERFACE(IHelloService, data, reply);
            const char *name = data.readCString();
            return NO_ERROR;
        }

        case GET_REPLAY: {
            CHECK_INTERFACE(IHelloService, data, reply);
            reply->writeCString("hello");
            return NO_ERROR;
        }

        default:
            return BBinder::onTransact(code, data, reply, flags);
        
        }
        
        return -1;       
    }  
};

其实代码逻辑比较简单,主要是实现了IHelloService的接口,以及核心收到binder有消息时写入时,被线程池调用的函数onTransact。

BnInterface其实比较简单,主要通过BBinder管理binder。

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};

一个最简单的binder服务端代码如下:

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
    
    hello::HelloService::instantiate();
    //打开线程池。            
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

}

服务端本质就是一个线程池,阻塞式的调用binder文件的ioctl系统调用,式再rocessState::self()->startThreadPool()中进入一个死循环,当驱动中收到client发送的消息后,阻塞函数会开始调用,进而开始调用onTransact函数。

客户端

客户端代码如下

class BpHelloService: public BpInterface<IHelloService>
{
public:
    BpHelloService(const sp<IBinder>& imp);
    int    SayHello(char *str);
    char* getHi();
};

BpHelloService::BpHelloService(const sp<IBinder>& imp) : BpInterface<IHelloService>(imp) {
    ALOGV("MediaTranscodingService is created");

}

int BpHelloService::SayHello(char *str) {
    // TODO(hkuang): Add implementation.
	
	const char *tmp = str;
		ALOGE("---what the fuck---%s",str);
	
	Parcel data, reply;
        data.writeInterfaceToken(IHelloService::getInterfaceDescriptor());
        data.writeCString(tmp);
        status_t status __unused = remote()->transact(SAY_HELLO, data, &reply);
	ALOGE("------%s",str);
	return 1;
}

char* BpHelloService::getHi() {
	Parcel data, reply;
        data.writeInterfaceToken(IHelloService::getInterfaceDescriptor());
        
        status_t status __unused = remote()->transact(GET_REPLAY, data, &reply);
        
        const char *rep = reply.readCString();
        
        char *ret = (char*)malloc(10);;
        strcpy(ret,rep);
    return ret;
}


//IMPLEMENT_META_INTERFACE(HelloService,"hello.world.service");
//下半部分等效与宏定义
const ::android::StaticString16                                     
        IHelloService_descriptor_static_str16(__IINTF_CONCAT(u, "hello.world.service"));
    const ::android::String16 IHelloService::descriptor(                 
        IHelloService_descriptor_static_str16);                        
    const ::android::String16&                                          
            IHelloService::getInterfaceDescriptor() const {              
        return IHelloService::descriptor;                                
    }                                                                   
    ::android::sp<IHelloService> IHelloService::asInterface(              
            const ::android::sp<::android::IBinder>& obj)               
    {                                                                   
        ::android::sp<IHelloService> intr;                               
        if (obj != nullptr) {                                           
            intr = static_cast<IHelloService*>(                          
                obj->queryLocalInterface(                               
                        IHelloService::descriptor).get());               
            if (intr == nullptr) {                                      
                intr = new BpHelloService(obj);                          
            }                                                           
        }                                                               
        return intr;                                                    
    }                                                                   
    std::unique_ptr<IHelloService> IHelloService::default_impl;           
    bool IHelloService::setDefaultImpl(std::unique_ptr<IHelloService> impl)
    {                                                                   
        /* Only one user of this interface can use this function     */ 
        /* at a time. This is a heuristic to detect if two different */ 
        /* users in the same process use this function.              */ 
        assert(!IHelloService::default_impl);                            
        if (impl) {                                                     
            IHelloService::default_impl = std::move(impl);               
            return true;                                                
        }                                                               
        return false;                                                   
    }                                                                   
    const std::unique_ptr<IHelloService>& IHelloService::getDefaultImpl() 
    {                                                                   
        return IHelloService::default_impl;                              
    }                                                                   
    IHelloService::IHelloService() { }                                    
    IHelloService::~IHelloService() { }         
    

这里的核心就是remote()->transact(SAY_HELLO, data, &reply);原理是

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    
    ......

        status_t status = IPCThreadState::self()->transact()

	......

    return DEAD_OBJECT;
}

就是通过IPCThreadState的transact函数完成任务

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{

    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);

    err = waitForResponse(reply);
      
    return err;
}


status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{

    while (1) {
    	//把out通过iotl写入到驱动,然后被驱动程序处理,
        if ((err=talkWithDriver()) < NO_ERROR) break;
        //结果进行处理,返回到之前的函数,
          cmd = (uint32_t)mIn.readInt32();

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
        case BR_ACQUIRE_RESULT:
            {
                ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;

        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

    return err;
}

talkWithDriver就是通过ioctl把数据写入到binder中的,代码比较简单
status_t IPCThreadState::talkWithDriver(bool doReceive)
{

    if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)

return err;

}

后记

binder好复杂啊,整体原理还是比较简单的,但是binder中混入了一个无用的servicemanage以及多线程的支持,让代码晦涩难懂,以后有机会再分析一下。

以上是关于BInder的主要内容,如果未能解决你的问题,请参考以下文章

Binder的Native实现libbinder

Binder源码解析(从客户端到服务端代码流程)

Binder源码解析(从客户端到服务端代码流程)

Android binder介绍

Android Binder 跟踪

结合Binder机制看ActivityManager