进程间通信Binder
【摘要】 1 Binder 1.1 Android Binder Model 相同程序中两个函数可以互相调用根本原因是处在相同的内存空间中,虚拟地址的映射完全一致,对于不同进程的函数,是不同互相调用的,如下: Binder就提供了一种方式,允许不同进程的函数可以互相调用: Binder包含四个部分,分别是: 1、 Binder 驱动->路由器 2、 Service Manager->DNS,在binder通
1 Binder
1.1 Android Binder Model
相同程序中两个函数可以互相调用根本原因是处在相同的内存空间中,虚拟地址的映射完全一致,对于不同进程的函数,是不同互相调用的,如下:
Binder就提供了一种方式,允许不同进程的函数可以互相调用:
Binder包含四个部分,分别是:
1、 Binder 驱动->路由器
2、 Service Manager->DNS,在binder通信中的标志永远都是0
3、 Binder Client->客户端
4、 Binder Server->服务端
为了便于理解,可以将这四个角色跟网络服务对应理解,如下:
Client对于Server的请求会经由Binder框架由上至下传递到内核的Binder驱动中,请求中包含了Client将要调用的命令和参数。请求到了Binder驱动之后,在确定了服务的提供方之后,会再从下至上将请求传递给具体的服务。整个调用过程如下图所示(类似网络协议):
1.1.1 Binder IPC数据传递
不同的进程有不同的进程空间,在用户态中是无法互相访问的,但是,内核态的空间是共享的,如下:
Binder机制实际就是利用了上述的特点,将不同的用户态数据放在内核态,通过内核空间进行共享:
Binder驱动是字符设备驱动程序,通过调用open()或者ioctl()即可访问,如下图,通过调用open函数与binder驱动的binder_open函数连接在一起。
下图是服务客户端调用services server的服务函数的过程,服务客户端在尝试RPC调用Services server的foo()函数时,Android采用何种方式传递Binder IPC数据
Android系统提供了几个抽象层,以便服务客户端使用指定的服务。服务客户端通过底层提供的行为,在服务层中进行RPC操作,服务层之下的层会生成binder IPC数据,用于支持服务层的IPC。
服务层:该层包含一系列提供特定功能的服务函数。服务客户端虚拟调用特定功能的服务函数,而实际调用是由services server调用完成的(JAVA)
RPC层:服务客户端在该层生成勇于调用服务函数的RPC代码和RPC数据。Services Server会根据传递过来的RPC代码查找相应的函数,并将RPC数据传递给查找的函数。(JNI)
IPC层:该层将RPC层生成的RPC代码与RPC数据封装成Binder IPC数据,以便将他们传递给Binder Driver。(C++)
Binder Driver层:接收来自IPC层的Binder IPC数据,查找包含特定服务的Service Server,并将IPC数据传递给查找到的Service server。(C)
1.1.2 Binder 协议(Binder Protocol)
两个协议,分别是:
BINDER COMMAND PROTOCOL:RPC层->Binder Driver
BINDER RETURN PROTOCOL: Binder Driver ->RPC层
分类 |
Binder协议 |
含义 |
BINDER COMMAND PROTOCOL |
BC_TRANSACTTION |
在Binder IPC数据发送端通过Binder Driver向接收端发送IPC数据时使用 |
BINDER RETURN PROTOCOL |
BR_TRANSACTTION |
用于Binder IPC数据接收端分析处理IPC数据 |
1.1.3 Binder 寻址(Binder Adressing)
1.2 Android Binder Driver分析
1.2.1 从进程的角度看服务的使用
服务客户端在使用服务的时候必须经历的三个阶段:
1、 服务注册(service server和context Manager之间的IPC)
2、 服务检索(服务客户端和context Manager之间的IPC)
3、 服务使用(服务客户端和service server之间的IPC)
服务注册:
服务检索:
服务使用:
1.2.2 Binder Driver函数分析
Binder驱动是Android专用的,但底层的驱动架构与Linux驱动一样。binder驱动在以misc设备进行注册,作为虚拟设备,没有直接操作硬件,只是对设备内存的处理。主要是驱动设备的初始化(binder_init),打开 (binder_open),映射(binder_mmap),数据操作(binder_ioctl)。需要使用Binder的进程,几乎总是先通过binder_open打开Binder设备,然后通过binder_mmap进行内存映射。在这之后,通过binder_ioctl来进行实际的操作。Client对于Server端的请求,以及Server对于Client请求结果的返回,都是通过ioctl完成的。
通过Binder_mmap,将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,从而实现了用户空间的Buffer和内核空间的Buffer同步操作的功能。
当有Client要发送数据给Server的时候,只需一次,将Client发送过来的数据拷贝到Server端的内核空间指定的内存地址即可,由于这个内存地址在服务端已经同时映射到用户空间,因此无需再做一次复制,Server即可直接访问,整个过程如下图所示:
这个图说明mmap的功能:
1. Server在启动之后,调用对/dev/binder设备调用mmap
2. 内核中的binder_mmap函数进行对应的处理:申请一块物理内存,然后在用户空间和内核空间同时进行映射
3. Client通过BINDER_WRITE_READ命令发送请求,这个请求将先到驱动中,同时需要将数据从Client进程的用户空间拷贝到内核空间
4. 驱动通过BR_TRANSACTION通知Server有人发出请求,Server进行处理。由于这块内存也在用户空间进行了映射,因此Server进程的代码可以直接访问
1.3 “DNS服务器”ServiceManager(Binder Server)
ServiceManager的启动:
Init进程中启动,在init.rc中描述,使用C/C++编写
ServiceManager的步骤和活动:
1、 从Binder驱动读取消息
2、 处理消息
3、 不断循环
使用Binder框架的既包括系统服务,也包括第三方应用。因此,在同一时刻,系统中会有大量的Server同时存在。那么,Client在请求Server的时候,是如果确定请求发送给哪一个Server的呢?这个问题,就和我们现实生活中如何找到一个公司/商场,如何确定一个人/一辆车一样,解决的方法就是:每个目标对象都需要一个唯一的标识。并且,需要有一个组织来管理这个唯一的标识。而Binder框架中负责管理这个标识的就是ServiceManager,整个过程如下图:
参考文档:http://blog.csdn.net/omnispace/article/details/73360655
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)