Binder纯理论分析

2021-01-24 22:25:19 浏览数 (1)

接下来的一段时间,我们会来深入认识一下Android中的Binder机制。

今天的主要是来对Binder做一个较全面的介绍,为之后的深入分析做一个预热准备。

Linux IPC

首先BinderAndroid中的一种独有的跨进程通信方式,简称IPC。它是专门为Android平台设计的。

那为什么要设计出Binder这个烦人的东西呢?我们都知道Android是基于Linux系统进行演变过来的,所以理应也能直接使用LinuxIPC通信方式。

所以在理解Binder的设计初衷之前,我们先来了解一下Linux系统中现有的IPC通信方式。

Linux现有的IPC通信方式有6种:

  1. 管道
  2. 信号量
  3. 信号
  4. 共享内存
  5. 消息队列
  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种,分为可靠信号与不可靠信号,多用于消息传递与通知,不适合传递信息。

共享内存

共享内存顾名思义,允许不同的进程访问同一块内存地址空间,它也需要进行两次数据拷贝操作,分别是将数据拷贝到共享内存中,又从共享内存中间将数据拷贝出来。

但需要注意的是,共享内存是不提供同步机制。

意思就是说,在其中一个进程进行写操作时,并不能放在另一进程进行读操作。

为了解决这个问题,共享内存一般都与前面说的信号量一起使用。

消息队列

消息队列通过一个进程向另一个进程发生消息块的方式进行通信,它与管道非常类似,都需要发送与接收,数据拷贝两次。

不同点是

  1. 消息队列可以防止同步与阻塞问题。
  2. 消息队列的接收方可以进行选择性接收。
  3. 发送的消息块有最大限制

socket

Linux中的socket是基于C/S架构的,传输效率低,多用于跨网络与跨设备的通信。

Android底层使用socket来进行initzygote等进程间的通信。

最后简单的来看一张图来了解在Linux中不同进程中的通信过程。

所以通过上面的分析,Linux现有的几种IPC通信方式都不是很适合Android间的进程通信。

例如管道、共享内存与消息队列都需要拷贝两次数据,同时有的还会存在阻塞与同步问题;另外的信号、信号量与socket由于使用场景的原因,都不适合用于Android中快速的进程间的数据通信。

Binder

那么Binder通信方式是怎么样的呢?

Binder本身是基于C/S架构的,层次分明,架构稳定,同时Binder内部只需使用一次数据拷贝操作,就能达到进程间数据的通信;另外Binder还支持鉴别用户进程的Uid,为Android提供身份的验证。

我们先来通过一张图来简单看下基于Binder的进程通信过程

Binder数据通信流程是,将数据从client端拷贝到内核空间,在内核空间中会提前通过mmap方式建立与server端的内存地址映射,通过内存地址映射server端可以直接访问内核空间中的数据,从而避免将数据拷贝到server端,提高进程间的通信速度。

在整个通信的过程中主要做的事情是:

  1. 通过/dev/binder打开binder驱动
  2. 通过mmap建立内存地址映射
  3. 通过ioctlbinder驱动交互,进行数据传输
  4. client使用BpBindertransact方法进行事务请求
  5. server使用BBinderonTransact方法来接收相应的事务

由于Android中主要使用Binder来进行service的注册与获取,所以为了更好的管理service的注册,使用了ServiceManager来进行统一管理service的注册。

service的注册过程中ServiceManager就相当于server端,内部开启loop循环,不断接收消息将注册的service保存到注册表svclist中。

最终关于Binder的整个大致流程如下图所示

其中clientserver位于应用层,ServiceManager位于用户空间,binder驱动位于内核空间。

对于开发者来说,用户空间与内核空间是透明的,我们只需关注应用层clientserver的实现,就可以方便的使用Binder的通信机制。

以上是对Binder的一个理论分析,接下来的一段时间,我将结合源码来分析service的注册过程,从而探索Binder的整个工作流程,感兴趣的读者可以关注一下。

0 人点赞