Binder纯理论分析
点
击
蓝
字
关
注
我
们
吧
接下来的一段时间,我们会来深入认识一下 Android
中的 Binder
机制。
今天的主要是来对 Binder
做一个较全面的介绍,为之后的深入分析做一个预热准备。
Linux IPC
首先 Binder
是 Android
中的一种独有的跨进程通信方式,简称 IPC
。它是专门为 Android
平台设计的。
那为什么要设计出 Binder
这个烦人的东西呢?我们都知道 Android
是基于 Linux
系统进行演变过来的,所以理应也能直接使用 Linux
的 IPC
通信方式。
所以在理解 Binder
的设计初衷之前,我们先来了解一下 Linux
系统中现有的 IPC
通信方式。
Linux
现有的 IPC
通信方式有 6
种:
-
管道
-
信号量
-
信号
-
共享内存
-
消息队列
-
socket
管道
英文为 pipe
,在 Linux
中它的本质是一个文件系统,通过一个进程以写的方式打开文件,另一个进程以读的方式进行打开文件,通过这样读写的方式,实现了进程间的通信。
只不过该文件是位于 Linux
内存中,所以操作管道就是以文件的方式操作 Linux
内存缓存区。
由于管道是通过读写文件的方式进行运作的,所以它需要进行两次数据的拷贝;分别是 copy_form_user
从写进程拷贝到文件内存缓存区,再通过 copy_to_user
从文件缓存区拷贝到读进程中。
同时管道还有大小限制,默认为 4k
,一旦写入端超过大小限制,管道将会阻塞。
信号量
主要作用于进程间的资源互斥访问,通过 PV
两种操作等待与发送信号。
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行 V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
所以信号量主要是用来解决多个进程对同一资源的竞争问题,类似于多线程的同步锁。
信号
Linux
中定义的一种软中断,有 64
种,分为可靠信号与不可靠信号,多用于消息传递与通知,不适合传递信息。
共享内存
共享内存顾名思义,允许不同的进程访问同一块内存地址空间,它也需要进行两次数据拷贝操作,分别是将数据拷贝到共享内存中,又从共享内存中间将数据拷贝出来。
但需要注意的是,共享内存是不提供同步机制。
意思就是说,在其中一个进程进行写操作时,并不能放在另一进程进行读操作。
为了解决这个问题,共享内存一般都与前面说的信号量一起使用。
消息队列
消息队列通过一个进程向另一个进程发生消息块的方式进行通信,它与管道非常类似,都需要发送与接收,数据拷贝两次。
不同点是
-
消息队列可以防止同步与阻塞问题。
-
消息队列的接收方可以进行选择性接收。
-
发送的消息块有最大限制
socket
Linux
中的 socket
是基于 C/S
架构的,传输效率低,多用于跨网络与跨设备的通信。
在 Android
底层使用 socket
来进行 init
与 zygote
等进程间的通信。
最后简单的来看一张图来了解在 Linux
中不同进程中的通信过程。
所以通过上面的分析, Linux
现有的几种 IPC
通信方式都不是很适合 Android
间的进程通信。
例如管道、共享内存与消息队列都需要拷贝两次数据,同时有的还会存在阻塞与同步问题;另外的信号、信号量与 socket
由于使用场景的原因,都不适合用于 Android
中快速的进程间的数据通信。
Binder
那么 Binder
通信方式是怎么样的呢?
Binder
本身是基于 C/S
架构的,层次分明,架构稳定,同时 Binder
内部只需使用一次数据拷贝操作,就能达到进程间数据的通信;另外 Binder
还支持鉴别用户进程的 Uid
,为 Android
提供身份的验证。
我们先来通过一张图来简单看下基于 Binder
的进程通信过程
Binder
数据通信流程是,将数据从 client
端拷贝到内核空间,在内核空间中会提前通过 mmap
方式建立与 server
端的内存地址映射,通过内存地址映射 server
端可以直接访问内核空间中的数据,从而避免将数据拷贝到 server
端,提高进程间的通信速度。
在整个通信的过程中主要做的事情是:
-
通过
/dev/binder
打开
binder
驱动 -
通过
mmap
建立内存地址映射 -
通过
ioctl
与
binder
驱动交互,进行数据传输 -
client BpBinder transact
-
server BBinder onTransact
由于 Android
中主要使用 Binder
来进行 service
的注册与获取,所以为了更好的管理 service
的注册,使用了 ServiceManager
来进行统一管理 service
的注册。
在 service
的注册过程中 ServiceManager
就相当于 server
端,内部开启 loop
循环,不断接收消息将注册的 service
保存到注册表 svclist
中。
最终关于 Binder
的整个大致流程如下图所示
其中 client
与 server
位于应用层, ServiceManager
位于用户空间, binder
驱动位于内核空间。
对于开发者来说,用户空间与内核空间是透明的,我们只需关注应用层 client
与 server
的实现,就可以方便的使用 Binder
的通信机制。
以上是对 Binder
的一个理论分析,接下来的一段时间,我将结合源码来分析 service
的注册过程,从而探索 Binder
的整个工作流程,感兴趣的读者可以关注一下。
福 利
为了感谢大家大支持,我特意搞了一个粉丝抽奖福利,只需在公众号后台回复【Android补给站,必出精品】关键字,即可获取二维码进行抽奖,小憩提前预祝大家中奖。
扫码二维码
获取更多精彩
壹伴编辑器