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; }