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的主要内容,如果未能解决你的问题,请参考以下文章

Android Binder实现浅析-Binder驱动

Binder 机制分析 Android 内核源码中的 Binder 驱动源码 binder.c ( googlesource 中的 Android 内核源码 | 内核源码下载 )

Binder 机制Native 层 Binder 机制分析 ( 查找 Binder 服务 | svcmgr_handler | do_find_service )

Android 跨进程通信-Binder机制传输数据限制—罪魁祸首Binder线程池

BInder

BInder