先上一张Binder 的工做流程图。(若是不清晰,能够 复制图片连接到浏览器 或 保存到本地 查看,我常常都是这样看图的哈)浏览器
一开始上手,陌生的东西比较多,But,其实并不复杂。喔,流程图是用 ProcessOn 画的。很棒的在线画图工具。工具
出发前预备子弹
咱们知道进程之间,虚拟地址不一样,是不能直接通讯的,这是一种保护机制。打开任务管理器,查看一下N多的进程,试想一下若是这些进程直接通讯会带来什么后果?学习
而用户空间能够经过System calls(系统回调)与内核空间通讯的,若是在内核空间中有一个模块,可以完成数据的转发,那么是否是两个进程就能够通讯了呢?以下图:动画
上面提到一些用户空间、内核空间的概念,用户空间也能大概猜到是什么东西,而内核空间,就知道它是很底层的东西好了。而模块呢,能够简单的理解为实现一个功能的程序或一个硬件电路等,好比玩单片机的时候,会有红外线模块,蓝牙模块,wifi模块等。这些概念的东西搜索一下百科知道就好。spa
Binder驱动
Binder驱动运行在内核空间,它就是那个内核模块了。Binder驱动很重要,承担了进程间通讯的数据转发等。一提到驱动,也是比较熟悉,你插个U盘,须要驱动吧。而Binder驱动也差很少,虽然名字取得很好,功能还很强大。但也不是什么神奇的东西。设计
Binder跨进程通讯模型
Binder的通讯模型有4个角色:Binder Client、Binder Server、Binder Driver(Binder驱动)、ServiceManager。代理
想象一个情景:我到北京旅行,要给高中同窗寄一张明信片,明信片确定要写上地址吧,否则怎么寄给对方呢?那么我怎么拿到这个地址呢,很简单,翻一下毕业相册就行了。而这个记录着同窗们通讯地址的毕业相册,就至关与一个通信录。在Binder的通讯模型中扮演的是ServiceManager的角色。好,如今已经有了通讯地址了,那么就找到邮局寄出去就行了。过几天同窗就高高兴兴的收到了明信片。那么这个邮局在Binder通讯模型中扮演的是Binder驱动的角色,而做为寄信人的我就是Binder Client,收信人同窗就是Binder Server。对象
先上一张图来描述上面的那个情景:blog
能够看到,ServiceManager、Binder Client、Binder Server处于不一样的进程,他们三个都在用户空间,而Binder驱动在内核空间。(我是特地把Binder驱动画的比较大的,由于Binder驱动的做用最大)进程
那先来简述一下这个通讯模型:
首先是有一个ServiceManager,刚开始这个通信录是空白的,而后Server进程向ServiceManager注册一个映射关系表,好比徐同窗把本身的地址广东省广州市xx区写进通信录,那么就造成了一张表:
徐同窗 —> 广东省广州市xx区
以后Client进程想要和Server进程通讯,首先向ServiceManager查询地址,ServiceManager收到查询的请求以后,返回查询结果给Client。
注意到这里不论是Server进程注册,仍是Client查询,都是通过Binder驱动的,这也真是Binder驱动的做用所在,先不急,下面的原理会分析到。
这时候我就拿着地址就开始寄明信片咯。当我把明信片放扔进邮筒,以后的工做就是由邮局去完成了,也就是Binder驱动去完成通讯的转发。
Binder通讯原理
从寄明信片的例子中,邮递员从邮筒取出明信片,而后跨越千山万水将明信片送达。从这点咱们也能想到,其实Binder驱动完成的工做是很重要的。
咱们来还原一个Binder跨进程通讯的过程。
案例:Client进程调用Server进程的computer对象的add方法。
接下来的内容你可能须要知道代理模式才能更好的理解,不过没学习过代理模式也不要紧,能够先读下去,而后在去补一下代理模式,再回来看这篇文章。思路会清晰不少。
1. Server进程向ServiceManager注册,告诉ServiceManager我是谁,我有什么,我能作什么。就比如徐同窗(Server进程)有一台笔记本(computer对象),这台笔记本有个add方法。这时映射关系表就生成了。
2. Client进程向ServiceManager查询,我要调用Server进程的computer对象的add方法,能够看到这个过程通过Binder驱动,这时候Binder驱动就开始发挥他的做用了。当向ServiceManager查询完毕,是返回一个computer对象给Client进程吗?其实否则,Binder驱动将computer对象转换成了computerProxy对象,并转发给了Client进程,所以,Client进程拿到的并非真实的computer对象,而是一个代理对象,即computerProxy对象。很容易理解这个computerProxy对象也是有add方法,(若是连add方法都没有,岂不是欺骗了Client?),可是这个add方法只是对参数进行一些包装而已。
3. 当Client进程调用add方法,这个消息发送给Binder驱动,这时驱动发现,原来是computerProxy,那么Client进程应该是须要调用computer对象的add方法的,这时驱动通知Server进程,调用你的computer对象的add方法,将结果给我。而后Server进程就将计算结果发送给驱动,驱动再转发给Client进程,这时Client进程还蒙在了鼓里,他觉得本身调用的是真实的computer对象的add方法,其实他只是调用了代理而已。不过Client最终仍是拿到了计算结果。
好了,一个通讯过程就完成了。咱们发现,其实Binder驱动就是一个中转。
总结
再来梳理总结一下:当Client进程向ServiceManager查询Server进程(我要调用你的某个对象的某个方法了),这个过程也是一个跨进程通讯的过程,也通过了Binder驱动,这时Binder驱动发挥它的做用,来了个狸猫换太子,将Server进程中的真实对象转换成代理对象,返回这个代理对象给Client进程。
Client进程拿到了这个代理对象,而后调用这个代理对象的方法,Binder驱动继续发挥他的使命,它会通知Server进程执行计算工做,将Server进程中的真实对象执行的结果返回给了Client进程,这样Client进程仍是如愿的获得了本身想要。跨进程通讯完毕!
这篇文章写的主要是我学习Binder时的痛点,我看过好多篇讲Binder的文章,发现好多都是不讲Binder驱动的,我很懵逼为何那么重要的东西就略过,但仍是有大神写的很好,好比:
Binder学习指南
Android Binder设计与实现
关于用户空间和内核空间,能够阅读阮一峰老师的文章:User space 与 Kernel space
全文完毕!