Binder机制概述
Android是基于Linux的,Linux的进程之间的内存地址空间是相互隔离的,进程之间无法直接访问对方的数据,这就需要有一个进程之间都可以访问的地方做数据交换,这就是内核空间。
传统的Linux跨进程通信机制下,通常是进程A把数据复制到内核中的一个缓冲区中,进程B从内核的缓冲区中读取数据。
Binder进程间通信机制自然也是要通过内核空间来进行的,但是又不是传统的Linux通信机制,怎么样去在内核中做一些操作呢?Linux有一个动态内核可加载模块,Binder就是加载了 Binder驱动 模块,来在内核中做一些操作,实现跨进程通信。
Binder驱动具体做了什么呢 ?
Binder驱动在内核空间中创建一个数据缓冲区,再通过内存映射机制,把缓冲区与数据接受进程用户空间地址做映射,这样数据发送进程的数据把数据拷贝到内核缓冲区过后,数据接受进程就可以直接 获取到数据,避免了一次内核空间的数据拷贝,提高了性能。
Binder机制还保证了进程间通信的安全性。
传统进程通信机制缺乏足够的安全措施:在传统进程通信中,只能由发送进程在请求中自行填入UID与PID,容易被恶意程序利用,是不可靠的。只有内置在进程通信机制内的可靠的进程身份标记才能提供必要的安全保障,Android的应用程序有自己UID,可用于鉴别进程身份。
Binder机制为每个进程分配了UID/PID来作为鉴别身份的标识,并且在Binder通信时会根据UID/PID进行有效性检测。传统的进程通信方式对于通信双方的身份并没有做出严格的验证,如socket通信ip地址是客户端手动填入,容易出现伪造。
Binder通信整体机制
- Server端向ServiceManager注册Binder对象,建立Binder名称和Binder引用的映射关系,这样Client端可以通过Binder名字获取Server中Binder实体的引用。在Android系统启动的时候,会初始化各种系统服务,这些系统服务会注册到ServiceManager。
- Client通过名字从ServiceManager获取到Binder实体引用,通常获取到的是一个Proxy代理对象
- Client调用代理对象的方法,代理对象会把要调用的方法的方法名称、参数等信息封装成Parcel对象,发送给Binder驱动
- Server会读取Binder驱动中的请求数据,解包Parcel对象,并把结果也以Parcel对象的形式返回
- 客户端发起Binder调用的时候会阻塞,服务端会有一个Binder线程池来响应处理客户端的请求
- 全程使用代理模式屏蔽进程间通信细节
Binder的优势是什么?
- 数据拷贝仅需一次,性能仅此于共享内存,优于管道、消息队列、套接字等通信方式
- C/S架构比共享内存清晰
- 传统IPC不做权限校验,由上层使用者自己实现,Binder做了权限控制
Binder的原理什么?
Binder是基于共享内存的,但是使用了mmap内存映射,只有一次用户空间到内核空间的拷贝,速度快。
在实际的实现中,binder 是作为一个特殊的字符型设备而存在的,设备节点为 /dev/binder, 其实现遵循linux设备驱动模型。
Binder机制的安全性是如何保证的?
传统进程通信机制缺乏足够的安全措施:
- 传统进程通信的接收进程无法获得发送进程可靠的用户标识/进程标识(UID/PID),因而无法鉴别对方身份。
- 在传统进程通信中,只能由发送进程在请求中自行填入UID与PID,容易被恶意程序利用,是不可靠的。
- 传统进程通信的访问接入点是公开的,如FIFO与unix domain socket的路径名,socket的ip地址与端口号,lSystem V键值等,知道这些接入点的任何程序都可能试图建立连接,很难阻止恶意程序获得连接,如通过猜测地址获得连接等。
只有内置在进程通信机制内的可靠的进程身份标记才能提供必要的安全保障。
Android的应用程序有自己UID,可用于鉴别进程身份。
Binder的异常传递机制是怎样的?
可以推断所有Binder实体对象方法中发生的异常都会被处理。无非一种是将异常信息发送给对端进程,另一种是将异常信息在本进程输出。而这些处理都不会使Server进程退出。
仔细思考这样设计也是很合理的。作为Server进程,它在什么时候执行,该执行些什么都不由自己掌控,而是由Client进程控制。因此抛出异常本质上与Client进程相关,让一个Client进程的行为导致Server进程退出显然是不合理的。此外,Server进程可能关联着千百个Client,不能由于一个Client的错误行为而影响本可以正常获取服务的其他Client。
系统服务和context.bindService()的方式有什么区别?
服务可分为系统服务与普通服务,系统服务一般是在系统启动的时候,由SystemServer进程创建并注册到ServiceManager中的。而普通服务一般是通过ActivityManagerService启动的服务,或者说通过四大组件中的Service组件启动的服务。这两种服务在实现跟使用上是有不同的,主要从以下几个方面:
- 服务的启动方式
- 服务的注册与管理
- 服务的请求使用方式
Binder缓冲区为什么大小是1MB?为什么不能更大?
因为缓冲区会他通过mmap映射到用户进程的虚拟地址空间,内存映射的空间不能太大。
Binder应用场景?
- 跨进程通信
- 跨进程观察者模式
- App提权