Android进程间通信(IPC)机制Binder
2014-08-13 14:40
369 查看
功能:Android是基于Linux内核构建的上层系统软件,虽然Linux内核提供了 共享内存、信号、消息队列、socket、管道等等方式来进程进程间通信,但是Android并没有使用这些方式,而是使用一种Binder的机制(当然ril模块中用socket、蓝牙中貌似用了另外一种方式)。
Binder机制用来实现Android进程间的通信,Binder实现了RPC机制。传统的Linux进程间通信实现的都是消息传递的类型,而Binder实现的RPC使得应用程序调用一个远程对象,可以像调用本地对象一样使用。
参考:http://blog.csdn.net/dr8737010/article/details/17657307
原理:从上面的图形我们发现视乎是Client和Server共享了/dev/binder设备文件,ServiceManager用来统一管理添加的Service。我们猜测大致工作流程如下:
1.Server向ServiceManager中注册服务
2.Client向SM中查询某个服务
3.Client通过/dev/binder和Server进行通信
问题:ServiceManager的功能?、Client和Server通信如何知道对方?、Client和Server通信时做了什么?、通信的数据形式?、binder驱动的实现?
ServiceManager的功能
源码frameworks/base/cmds/servicemanager,主要用来登记服务。Server注册服务、Client利用它来查询服务。
初始化函数,ServiceManager是一个单独的进程。1.打开了/dev/binder 2.利用binder_become_context_manager将自己变成ServiceManager服务,服务的handle号置为默认0 3.闭合结构用来读数据、解析数据、并返回结果
int main(int argc, char **argv) { struct binder_state *bs; void *svcmgr = BINDER_SERVICE_MANAGER; bs = binder_open(128*1024); if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); return 0; }
下面是关键操作binder_loop函数,利用ioctl读取bwr包(阻塞方式),并解析bwr包
void binder_loop(struct binder_state *bs, binder_handler func) { int res; struct binder_write_read bwr; unsigned readbuf[32]; bwr.write_size = 0; bwr.write_consumed = 0; bwr.write_buffer = 0; readbuf[0] = BC_ENTER_LOOPER; binder_write(bs, readbuf, sizeof(unsigned)); for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (unsigned) readbuf; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); break; } res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func); if (res == 0) { ALOGE("binder_loop: unexpected reply?!\n"); break; } if (res < 0) { ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); break; } } }接下来是使binder_parse使用状态机解析bwr包,主要完成了下面工作:
解析BR_TRANSACTION(请求数据包)、BR_REPLY(返回数据包)等等,其中BR_TRANSACTION会使用svcmgr_handler回调函数来解析请求(SVC_MGR_GET_SERVICE、SVC_MGR_CHECK_SERVICE、SVC_MGR_ADD_SERVICE、SVC_MGR_LIST_SERVICES)
int binder_parse(struct binder_state *bs, struct binder_io *bio,uint32_t *ptr, uint32_t size, binder_handler func) uint32_t *end = ptr + (size / 4); while (ptr < end) { uint32_t cmd = *ptr++; switch(cmd) { case BR_NOOP: break; case BR_TRANSACTION_COMPLETE: break; case BR_INCREFS: case BR_ACQUIRE: case BR_RELEASE: case BR_DECREFS: ptr += 2; break; case BR_TRANSACTION: { //请求数据包 break; } case BR_REPLY: { //应答数据包 break } case BR_DEAD_BINDER: { //死亡通知 break; } case BR_FAILED_REPLY: //应答失败 break; case BR_DEAD_REPLY: r = -1; break; default: ALOGE("parse: OOPS %d\n", cmd); return -1; } } return r; }
关于SVC_MGR_ADD_SERVICE、SVC_MGR_GET_SERVICE两个关键请求,实现都在svcmgr_handler中:
SVC_MGR_ADD_SERVICE
set服务时,需要创建svcinfo结构添加到svclist中,同时需要利用binder_acquire将服务注册到binder驱动中。添加失败返回-1,无replay。
SVC_MGR_GET_SERVICE
get服务时,需要查询svclist,并返回reply数据到binder驱动中
Client和Server通信如何知道对方
从C++层来看,Client需要请求的服务,必须是Server在ServiceManager中注册过的服务。而ServiceManager实际上本身就是系统注册的一个服务,也就是说Client必须默认就知道ServiceManager服务对应的handle号。在Binder机制实现的时候,ServiceManager服务的handler号默认为0,并且公开,因此所有的Client都知道ServiceManager这个服务号。
知道服务号,请求数据又是如何传递过去的呢。这里Binder驱动中实际上记录了所有服务号和路径,Client的请求数据先发给Binder驱动,Binder驱动实现数据路由的功能(原理在底层), 这样请求就能正确的到答Server端。
Client和Server通信时做了什么
上面的图形强调了Client、Server、ServiceManager是出在同一层次的,它们都是通信的端点。只不过,ServiceManager的地址是公认的,所有其他的Client、Server都知道它的Handle号为0。因此ServiceManger起到了DNS的功能,Server注册服务到其中,Client在其中查询服务。
但是同时,它们有不是直接通信的,它们之间的请求、应答是通过Binder驱动来转发的,因此这里的Binder实现的相当于一个路由的功能。
Server端的工作包括:服务的创建,登记到ServiceManager当中(利用ProcessState打开/dev/binder,并获取defaultServiceManager),创建线程池,线程进入闭合结构“接收数据(IPCThreadState::talkWithDriver)、解析数据(executeCommand)、处理并返回(talkWithDriver)”。
int main(int argc, char** argv) //main_mediaserver.cpp代码 { signal(SIGPIPE, SIG_IGN); sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); ALOGI("ServiceManager: %p", sm.get()); AudioFlinger::instantiate(); MediaPlayerService::instantiate(); CameraService::instantiate(); AudioPolicyService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); }
Client段的工作包括:ServiceManager当中查询服务,获取服务handle号,进行发送数据(IPCThreadState::transact,
该函数利用writeTransactionData到缓存mOut, 并利用waitForResponse的talkWithDriver发送数据),当然waitForResponse里面包括了接受应答。
分析到这里,基本理解了Client与Server端的通信步骤,但是对于数据的形式、数据路由怎么实现,必须得深入到地下了。
Binder通信的数据形式
参考:http://blog.csdn.net/universus/article/details/6211589/
Binder驱动路由功能的实现
Binder总结
参考:http://blog.csdn.net/bathinbreeze/article/details/8989105
http://blog.csdn.net/coding_glacier/article/details/7520199
http://blog.csdn.net/luoshengyang/article/details/6618363
http://blog.csdn.net/universus/article/details/6211589/
Binder驱动路由功能的实现
相关文章推荐
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)
- Android进程间通信(IPC)机制Binder
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- [Binder.4] Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- [Binder.2] 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(1) 推荐
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(3)
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(3)
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路(1)
- [Binder.0] Android进程间通信(IPC)机制Binder简要介绍和学习计划