App层的理解
Binder是Android提供的进程间通信的一种方式,性能相对更高效一些,适用于移动环境。我们把这个通信过程分为客户端Client进程(发送消息),服务端Server进程(接收消息),两个进程无法直接通信,当Client进程想调用Server进程的add函数并获取结果时,就通过Binder来实现。Binder会为Client提供一个Proxy(Binder也无法把真实的Server丢给Client),当Client调用Proxy.add时Binder就会去执行Server.add并把结果通过Proxy返回给Client。Binder底层是一个驱动。大致流程如下
- Client和Server都会向ServiceManager注册自己(或者说所有的Service都需要向SM注册自己)。
- 当Client进程【Server2】要向Server进程【Server1】发送消息时,他会向Binder去请求,我要访问0x1234 Server的add方法
- Binder根据0x1234向SM查询这个Server的信息
- Binder查找到这个Server并调用add方法拿到返回值
- 把返回值丢给Client
Binder通信篇
Binder的通信部分其实很简单,但源码中的业务封装太过复杂使得Binder看起来很复杂。抛开业务封装看下Binder通讯原理。ServiceManager就抛开了Binder的业务封装,直接使用它的通信功能。
首先我们知道,逻辑地址空间有4G,其中3G为用户空间,1G为内核空间;我们的应用进程都在用户空间中且相互隔绝无法直接互相访问。于是乎有了进程间通信的需求。Android基于Linux,Linux提供了很多进程间通信的方案:管道(Pipe)、信号(Signal)、消息队列(Message)、共享内存(Share Memory)、插口(Socket)等。而Android系统有自己独特的Binder进程间通信机制。Android源码中大量的使用Binder进行进程间通信(当然,有些地方也还是会用其他的进程间通信方式的)。Binder有很多优势,其中一个就是性能高,其他进程间通信基本上都需要进行两次的数据拷贝,而Binder只需要一次。
下面看看Binder通信的过程
1.每个进程(C端和S端都一样)在于Binder初次接触的时候,Binder都会为其建立一个物理地址映射,该进程在用户空间地址和Binder在内核空间的地址映射到一个物理内存上(如图:进程C和Binder进程K的地址映射到某物理内存上)。这样的映射在第一次接触的时候只会分配一个物理页大小(映射的最小值),后面在传输有效数据的时候会进行扩充,使用完毕立刻释放。
2.C端向S端传输有效数据的时候,C端需要向Binder驱动写入数据,数据包含Binder实体(即S端)的信息、有效数据在用户空间的地址等。Binder拿到数据后,先找到S端的信息,然后通过Binder与C端的映射(如图中的a)读取有效数据,然后拷贝到Binder与S端的映射(如图中的b)(一次数据拷贝);这个时候S端发现有数据之后就会通过映射去读取数据,完成一次进程间通信。
下面看下具体的ServiceManager注册到Binder成为Binder过程解析
init进程在启动各种服务的时候会启动SM服务,附上init.rc的相关部分
第一行:以服务的形式启动
第二行:以系统用户system的身份运行
第三行:critical表示SM是系统的关键服务(关键服务一旦退出会立刻重启,4分钟退出次数>4则系统重启)
第四、五行:如果SM重启则zygote、media也得重启
下面看下SM注册成为Binder管理的过程
第8行:打开Binder驱动,该动作同时会调用mmap分配一页的物理页来映射SM与Binder
第10行:binder_become_context_manager注册成为Binder的管理者,其实就是把自己的标记设置为0(每个服务在SM中注册都会有一个标记,客户端需要某服务会向SM查询就是查询到这个标记就可以通过Binder访问对