简单理解Binder机制的原理和从AIDL层解析使用方法
推荐参考资料:
如果不想看我下面的一堆文字,建议顺序依次看一下下面的3篇文章,很有收获
https://www.jianshu.com/p/4920c7781afe?from=jiantop.com
http://www.cnblogs.com/zc9527/p/5638688.html
https://www.cnblogs.com/itgungnir/p/6640120.html
以下内容做记录帮助记忆吧
1.什么是Binder
Binder机制具体有两层含义:
- Binder是一种跨进程通信(IPC,Inter-Process Communication)的手段;
- Binder是一种远程过程调用(RPC,Remote Procedure Call)的手段。
Binder是安卓进程间通信机制,linux中没有时android中特有的。为什么要进程间通信呢?当一个进程想为其它进程提供服务时,或其他进程想访问你提供的服务,就需要通过进程间通信的方式来实现了。
打个比方:
我们有一个APP1,里面有个service可以提供很牛逼的测量计算功能,而这个功能又很复杂很难实现。
当另外一个APP2想使用APP1里面的service的测量计算功能,由于不同的APP运行在不同的进程中,
所以,APP2是无法直接使用APP1里面的service的测量计算功能。由于跨越了进程,只能通过进程间通信机制来完成。
2.为什么要使用Binder?
1.历史原因
Binder最早并不是为Android系统而设计的,最开始有一个OpenBinder的东西,用在一个叫做Palm Cobaltw的为内核操作系统上。后来,Palm Cobaltw移植到了Linux系统上,OpenBinder也跟着移植了过来。Google在组建Android开发团队的时候,聘请了一位叫做Dianne Hackborn的工程师,而他就是OpenBinder的核心人员。后面在做android进程间通信时,发现binder很合适,就理所当然的在android系统上使用了Binder。
2.性能方面
在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严格的要求,Binder相对出传统的Socket方式,更加高效。Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比较复杂。
3.安全方面
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。
3.Binder有哪些组成部分?
一个Binder系统由四部分组成:Binder客户端、Binder服务端、Binder驱动、服务登记查询模块
-
Binder客户端:想要使用服务的进程
-
Binder服务端:实际提供服务的进程
-
Binder驱动
我们在客户端先通过Binder拿到一个服务端进程中的一个对象的引用Proxy,通过这个引用,直接调用对象的方法获取结果。在这个引用对象执行方法时,它是先将方法调用的请求传给binder驱动;然后binder驱动再将请求传给服务端进程代理Stub;服务端进程收到请求后,调用服务端“真正”的对象来执行所调用的方法;得出结果后,将结果发给binder驱动;binder驱动再将结果发给我们的客户端;最终,我们在客户端进程的调用就有了返回值。Binder驱动,相当于一个中转者的角色。通过这个中转者的帮忙,我们就可以调用其它进程中的对象。 -
服务登记查询模块
我们调用其它进程里面的对象时,首先要获取这个对象。这个对象其实代表了另外一个进程能给我们提供什么样的服务(再直接一点,就是:对象中有哪些方法可以让客户端进程调用)。首先服务端进程要在某个地方注册登记一下,告诉系统我有个对象可以公开给其它进程来提供服务。当客户端进程需要这个服务时,就去这个登记的地方通过查询来找到这个对象。
4.Binder工作流程
假设:客户端的程序Client运行在进程A中,服务端的程序Server运行在进程B中。
-
由于进程的隔离性,Client不能读写Server中的内容,但内核可以,而Binder驱动就是运行在内核态,因此Binder驱动帮我们进行请求的中转。
-
有了Binder驱动,Client和Server之间就可以打交道了,但是为了实现功能的单一性,我们为Client和Server分别设置一个代理:Client的代理Proxy和Server的代理Stub。这样,由进程A中的Proxy和进程B中的Stub通过Binder驱动进行数据交流,Server和Client直接调用Stub和Proxy的接口返回数据即可。
-
此时,Client直接调用Proxy这个聚合了Binder的类,我们可以使用一系列的Manager来屏蔽掉Binder的实现细节,Client直接调用Manager中的方法获取数据,这样做的好处是Client不需要知道Binder具体怎么工作。
-
最后还有一个问题,就是Client想要获得的服务多种多样,那么它是怎么获取Proxy或Manager的呢?答案是通过Service Manager进程来获取的。Service Manager总是第一个启动的服务,其他服务端进程启动后,可以在Service Manager中注册,这样Client就可以通过Service Manager来获取服务器的服务列表,进而选择具体调用的服务器进程方法。
-
上面的叙述总结为如下图所示的工作流程图:
----------------------------------分割线----------------------------
对上图进行简化大概如下图:.
- client通过获得一个server的代理接口,对server进行调用。
- 代理接口中定义的方法与server中定义的方法时一一对应的。
- client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成Parcel对象。
- 代理接口将Parcel发送给内核中的binder driver。
- server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回。
整个的调用过程是一个同步过程,在server处理的时候,client会block住。因此client调用过程不应在主线程。