android framwork 分析之binder

来源:互联网 发布:电视网络机顶盒多少钱 编辑:程序博客网 时间:2024/06/06 06:31

   binder是用来实现进程间通信的,当两个进程需要通信时候比方说A进程需要使用B进程的服务 由于进程间的是不允许的 (他们分别运行在自己的用户空间),那怎么解决这个问题呢?

那就是利用binder驱动来中转了  binder驱动是运行在内核空间的 所有的进程共享!所以我们可以利用binder的中转来实现B进程的服务,怎么实现的呢 ?首先把B进程的服务可以共享给其他进程的功能注册到binder驱动中  当A进程要使用的时候 请求binder驱动程序执行相应的B进程服务的功能后返回给A 这就好像A也有了这样的功能了。

现在的关系是: A进程(client)  --> binder驱动  <--B 进程(service);   

由于A进程或者B进程需要额外的专门来给binder驱动打交道 所以为何不搞一个代理来完成这样的事情呢?!于是关系就成这样了 : A进程(client) --> 客户端代理 (proxy)--> binder驱动<--服务器代理(stub)  <--B 进程(service);

现在A进程他还不够透明化 因为他知道要调用的是本地对象还是代理对象以及代理的一些方法  所以得搞个类manager来专门的负责这些调用代理的方法或者本地的方法 这样上层应用就不需要关心这些东西了 只需调用manager暴露的方法即可,比如我们常用的 获取一些服务的方法getServiceManager(xxx)获取一个manager对象,后面就直接调用manager中封装好的服务方法即可;所以现在的关系应该是这样的: A进程(client)-->封装好的代理服务(manager) --> 客户端代理 (proxy)--> binder驱动<--服务器代理(stub)  <--B 进程(service);

那最后还有个问题,当A需要调用B服务的时候 那前提使用获得该服务的manager或者proxy才可以呢,那怎么获取呢 ?这个时候servicemanager就出场了 他是init进程启动的(init进程是系统启动的第一个进程)所以他早就启动了;我们可以利用servicemanager来获取需要的服务B 当然B服务要先把自己注册到servicemanager中,那B是一个进程 而servicemanager也是一个进程 那又是一个进程间的通信了,那怎么办?也就是B服务怎么来获取servicemanager的proxy或者manager呢?由于servicemanager的特殊身份 ,这个manager我们可以直接拿到的!这样的话那B服务就可以注册到servicemanager中了,然后A进程直接从某处拿到servicemanager查询servicemanager中的B服务而调用它的功能了!

那首先来看看servicemanager这个类 他在frameworks/base/cmds/servicemanager目录下,先来看看main方法:

int main(int argc, char **argv){    struct binder_state *bs;//结构体 里面有文件的描述符 映射的大小及地址    void *svcmgr = BINDER_SERVICE_MANAGER;//宏定义 用来表示servicemanager的特殊之处    bs = binder_open(128*1024);//打开binder文件    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_state  那就来看看他的定义

struct binder_state{    int fd;//打开的/dev/binder设备文件描述符    void *mapped;//设备文件/dev/binder映射到进程空间的起始地址    unsigned mapsize;//内存映射空间的大小};


再来看看这代码:void *svcmgr = BINDER_SERVICE_MANAGER;  这里BINDER_SERVICE_MANAGER是一个宏,定义frameworks/base/cmds/servicemanager/binder.h文件中  下面是他的宏定义:

/* the one magic object */
#define BINDER_SERVICE_MANAGER ((void*) 0)

这代表他的句柄是0 (句柄是用来标识远程接口的,由binder自动创建),其余的句柄都是大于0的 这就是刚才说的servicemanager的特殊之处

现在代码执行到: bs = binder_open(128*1024); 这表明打开一个binder文件了 看看他的代码实现:

struct binder_state *binder_open(unsigned mapsize){    struct binder_state *bs;    bs = malloc(sizeof(*bs));//分配内存    if (!bs) {        errno = ENOMEM;        return 0;    }    bs->fd = open("/dev/binder", O_RDWR);//打开目标文件 /dev/binder    if (bs->fd < 0) {        fprintf(stderr,"binder: cannot open device (%s)\n",                strerror(errno));        goto fail_open;    }    bs->mapsize = mapsize;//给mapsize大小赋值    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//赋值指向的地址值    if (bs->mapped == MAP_FAILED) {        fprintf(stderr,"binder: cannot map device (%s)\n",                strerror(errno));        goto fail_map;    }        /* TODO: check version */    return bs;fail_map:    close(bs->fd);fail_open:    free(bs);    return 0;

最后执行到binder_loop时候就一直循环等待!servicemanager的大概原理就是这样的 其中会涉及到内核驱动的 由于现在还不是很理解 所以暂时不去分析了!

一开始就提到了要请求服务的话 就得拿到servicemanager后才能获取相应的服务 那怎么拿到这个manager呢?刚才知道了servicemanager的句柄值是0 所以可以通过他来获取 ,获取Service Manager远程接口的函数是defaultServiceManager,这个函数声明在frameworks/base/include/binder/IServiceManager.h,实现在frameworks/base/libs/binder/IServiceManager.cpp 

sp<IServiceManager> defaultServiceManager(){//单列模式    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;        {        AutoMutex _l(gDefaultServiceManagerLock);//锁保护        if (gDefaultServiceManager == NULL) {            gDefaultServiceManager = interface_cast<IServiceManager>(                ProcessState::self()->getContextObject(NULL));        }    }        return gDefaultServiceManager;}




0 0