Binder机制分析(1)——Binder结构简介

转载于:http://blog.csdn.net/ljsbuct/article/details/7106718

本文是对《Android技术内幕-系统卷》第三章的摘抄和整理。


一、Binder 介绍
Binder机制实际上就是一个类似于C/S的构架:客户端进程要想与服务端进程通信就必须在客户端建立一个 服务端进程代理对象(services stub),然后将请求发送到代理对象上;代理对象通过Binder驱动将请求转发给服务端进程处理;当处理完成之后,再次通过Binder驱动传回给代理对象,客户端从代理对象获取响应信息。
client和service之间通过binder通信,但是两者都不会直接与Binder driver打交道,而是交给Binder Adapter来做。
Binder Adapter由 ProcessStateIPCThreadState组成。
其中ProcessState类中包含了通信细节,利用open_binder打开Linux设备dev\binder。
每个进程只有一个ProcessState对象,ProcessState是一个singleton类型,其作用是维护当前进程中的所有Service代理。 一个客户端进程可能需要多个Service的服务,这样可能会创建多个Service代理,客户端进程中的ProcessState对象就负责维护这些Service代理。
每一个线程中都会有一个IPCThreadState对象,它主要负责Binder数据读取、写入和请求处理框架。

1. ProcessState分析

1.1 ProcessState::self()的实现

     头文件:ProcessState.h (native\include\binder)  
     源码文件:ProcessState.cpp (native\libs\binder)  
 

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);//互斥锁
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}
ProcessState放置在全局变量gProcess中,如果gProcess为NULL,则新建一个ProcessState,下面是它的实现

1.2 ProcessState::ProcessState()的实现

 ProcessState::ProcessState()  
        : mDriverFD(open_driver())//打开Binder设备驱动  
        , mVMStart(MAP_FAILED)//映射内存的起始地址  
        , mManagesContexts(false)  
        , mBinderContextCheckFunc(NULL)  
        , mBinderContextUserData(NULL)  
        , mThreadPoolStarted(false)  
        , mThreadPoolSeq(1)  
        {  
            if (mDriverFD >= 0) {  
        #if !defined(HAVE_WIN32_IPC)  
                //将fd映射为内存  
                mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,  
                mDriverFD, 0);  
                if (mVMStart == MAP_FAILED) {  
                    close(mDriverFD);  
                    mDriverFD = -1;  
                }  
        #else  
                mDriverFD = -1;  
        #endif  
            }  
            if (mDriverFD < 0) {  
            }  
        }
该构造函数首先通过open_driver()打开Binder设备驱动(/dev/binder),然后通过ioctrl建立基本的通信框架

1.3 getStrongProxyForHandle的实现

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> result;
        AutoMutex _l(mLock);
        handle_entry* e = lookupHandleLocked(handle);
        if (e != NULL) {
            // We need to create a new BpBinder if there isn't currently one, OR we
            // are unable to acquire a weak reference on this current one.  See comment
            // in getWeakProxyForHandle() for more info about this.
            IBinder* b = e->binder;
            if (b == NULL || !e->refs->attemptIncWeak(this)) {
                b = new BpBinder(handle);
                e->binder = b;
                if (b) e->refs = b->getWeakRefs();
                result = b;
            } else {
                // This little bit of nastyness is to allow us to add a primary
                // reference to the remote proxy when this team doesn't have one
                // but another team is sending the handle to us.
                result.force_set(b);
                e->refs->decWeak(this);
            }
        }
        return result;
    }
    当需要创建一个服务端代理对象时,就会调用getStrongProxyForHandle来实现
    该函数首先调用 lookupHandleLocked函数,查询当前进程维护的Service代理对象的列表,查看要创建的Service代理对象是否已经在当前进程中创建。如果已经创建过了,则直接返回其引用就可以了;否则,将会在Service代理对象的列表中增加相应的位置,保存将要创建的代理对象。这里大家已经看到的所谓的服务端代理对象,其实就是BpBinder对象。
    
2. IPCThreadState分析

源码和头文件路径:、

IPCThreadState.cpp (native\libs\binder)
IPCThreadState.h (native\include\binder)

2.1 在构造ProcessSate的时候,使用open_binder打开/driver/binder,并将句柄记录在mDriverFD中。但是在ProcessState中并不使用这个句柄,真正使用这个Binder设备句柄的是IPCThreadState,所有关于Binder的操作都放置在IPCThreadState中,以下是3个重要的函数。

    talkWithDriver()  读取/写入
    executeCommand(...)  请求处理

    joinThreadPool()  循环结构

2.2 talkWithDriver分析

        status_t IPCThreadState::talkWithDriver(bool doReceive)  
        {  
            //省略部分代码  
        #if defined(HAVE_Android_OS)  
                if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)  
                    err = NO_ERROR;  
                else  
                    err = -errno;  
        #else  
            //省略部分代码  
            return err;  
        }
talkWithDriver负责读取和写入,实际上就是通过ioctl对ProcessState打开的句柄进行读写,用户可以不直接通过ioctl来操作Binder设备,通过IPCThreadState对象来代理即可。
    
二、Service Manager分析
1. Android启动时就会自动运行的一个核心进程。下面是init.rc中的servicemanager片段:
    service servicemanager /system/bin/servicemanager  
        user system  
        critical  
        onrestart restart zygote  
        onrestart restart media
2. Service Manager的main函数。 路径:Service_manager.c (base\cmds\servicemanager)
   int main(int argc, char **argv)  
    {  
        struct binder_state *bs;  
        void *svcmgr = BINDER_SERVICE_MANAGER;  
        bs = binder_open(128*1024);                 //128*1024是映射的内存大小 
        if (binder_become_context_manager(bs)) {  
            LOGE("cannot become context manager (%s)\n", strerror(errno));  
            return -1;  
        }  
        svcmgr_handle = svcmgr;  
        binder_loop(bs, svcmgr_handler);  
        return 0;  
    }
该函数首先调用binder_open打开Binder设备(/dev/binder),其次,它调用了binder_become_ context_manager函数,将自己设置为Service Manager。因为Service Manager本身就是一个服务,只是它比较特殊,会管理其他所有的服务,也正是binder_become_context_manager函数将其变为服务管理器的。
3. binder_become_context_manager的实现
 int binder_become_context_manager(struct binder_state *bs)  
    {  
        return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);  
    }
4. svcmgr_handler的实现
在main函数最后调用binder_loop进入循环状态,并设置一个回调函数,等待用户的请求。
    int svcmgr_handler(struct binder_state *bs,  
                   struct binder_txn *txn,  
                   struct binder_io *msg,  
                   struct binder_io *reply)  
    {  
        //省略部分代码  
        switch(txn->code) {  
        //获取服务和查询服务  
        case SVC_MGR_GET_SERVICE:  
        case SVC_MGR_CHECK_SERVICE:  
            s = bio_get_string16(msg, &len);  
            ptr = do_find_service(bs, s, len);  
            if (!ptr)  
                break;  
            bio_put_ref(reply, ptr);  
            return 0;  
        //添加服务  
        case SVC_MGR_ADD_SERVICE:  
            s = bio_get_string16(msg, &len);  
            ptr = bio_get_ref(msg);  
            if (do_add_service(bs, s, len, ptr, txn->sender_euid))  
                return -1;  
            break;  
     
        case SVC_MGR_LIST_SERVICES: {  
         //省略部分  
        }  
        default:  
            LOGE("unknown code %d\n", txn->code);  
            return -1;  
        }  
        bio_put_uint32(reply, 0);  
        return 0;  
    }
    
5. do_add_service的实现
当有新要获的服务需要添加或者客户端得某个已经添加的服务时都会触发该回调函数,添加函数(SVC_MGR_ADD_SERVICE)操作则会调用do_add_service来完成。
    int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len,  
                   void *ptr, unsigned uid)  
    {  
        struct svcinfo *si;  
        if (!ptr || (len == 0) || (len > 127))  
            return -1;  
        if (!svc_can_register(uid, s)) {  
            return -1;  
        }  
        si = find_svc(s, len);  
        if (si) {  
            //省略部分代码  
            si->ptrptr = ptr;  
        } else {  
            si = malloc(sizeof(*si) + (len + 1)  
    sizeof(uint16_t));  
            //省略部分代码  
            si->next = svclist;  
            svclist = si;  
        }  
        binder_acquire(bs, ptr);  
        binder_link_to_death(bs, ptr, &si->death);  
        return 0;  
    }
添加过程为:首先,检查是否有权限注册Service;然后,检查是否已经注册过Service,注册过的Service将不能再次注册;接下来构造一个svcinfo对象,并将其加入到一个全局链表(svclist)中;最后,通知Binder设备有一个Service注册进来了。添加Binder设备之后会为每一个服务都维护一个句柄,当查询和获得某个服务时就会使用这个句柄。当然,Service Manager的句柄在调用了binder_become_context_manager之后就变为0了,作为服务管理器。当客户端需要获得一个服务时,就会触发SVC_MGR_GET_SERVICE命令,再调用do_find_service来查询指定的服务,查找过程就是在服务列表中查找即可,找到之后写入reply中返回给客户端。

三、Binder的机制    
1. IBinder
Android对Binder机制进行了抽象,定义了IBinder接口,该接口是对跨进程对象的抽象,在C/C++和Java层都有定义。IBinder定义了一套使用Binder机制来实现客户程序与服务器的通信协议。
     一个普通对象只能在当前进程中被访问,如果希望它能被其他进程访问,就必须实现IBinder接口。 IBinder接口可以指向本地对象,也可以指向远程对象,关键就在于IBinder接口中的transact函数。如果IBinder指向的是一个服务端代理(stub),那么transact只是负责把请求发送给服务器;如果IBinder指向的是一个服务端,那么transact只负责提供服务即可。因此,不管是服务端还是服务端代理对象,都必须实现该接口,这样才能进行Binder通信。

2. 服务端代理对象BpBinder

BpBinder是服务端代理对象,即远程对象在当前进程的代理。实际上,它也是Binder通信存在于客户端的进程,它实现了IBinder接口,它的transact函数的实现:

路径:BpBinder.cpp (native\libs\binder)  BpBinder.h (native\include\binder)

    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::self()的transact函数,将请求通过内核模块发送给了服务端,服务端处理完请求之后,沿原路返回结果给调用者。注意transact方法是同步方法,将会挂起客户进程的当前线程,直到Service把请求处理完成并返回结果。
3. 服务端BBinder 路径:Binder.cpp (native\libs\binder)
    服务端同样需要实现IBinder接口,这里我们以Android默认的服务端实现类(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;  
    }    
    其中, PING_TRANSACTION请求用来检查对象是否还存在,这里简单地把 pingBinder的返回值返回给调用者,其他的请求交给onTransact处理。onTransact是Bbinder中声明的一个protected类型的虚函数,这个要求它的子类去实现,在下一节分析Binder的具体实现时会详细
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值