为什么要使用Binder?

既然要搞清楚为什么要使用binder,那就要理解binder的作用。

binder在java层的作用就是一个通信的媒介。那我们就需要理解,binder到底解决的问题是什么,原来的IPC通信机制有什么不足之处。

1.现有的Linux的IPC机制种类

1.共享内存

2.管道

3.消息队列

4.socket

1.1性能方面

我们来看看一次通信,这些方式分别需要拷贝的内存次数。

内存拷贝次数越多,通信效率越低。

Binder的内存拷贝次数是1,低于共享内存,高于其他方式。

1.2安全性方面

传统的IPC方式,毫无安全性可言,这也无可厚非,因为android平台会面对海量的应用,需要区分恶意的应用,阻止他们访问。传统的IPC方式无法取得对应进程的UID(UID是android系统对每个APP赋予的唯一标识,可以用它做权限验证),无法做到权限的验证。


2.Binder的优势在哪?是如何解决其他种类的问题

Binder通信可以获得UID,保证了安全性。虽然效率不是最高,但是可以被接受。

3.Binder的原理

 为什么Binder能做到拷贝一次内存就可以完成通信?首先需要了解一下Linux上的概念。

3.1进程隔离

Linux中使用了进程隔离技术,也就是说,各个进程之间的内存是互相不共享的。自己玩自己的内存,保证数据的安全性。因此如果进程之间需要通信,则需要相应的IPC机制进行处理。

进程隔离技术使用到了虚拟内存的概念。虚拟内存是一种提高物理内存利用率的技术,它是物理内存的映射,可以使得程序看到的都是一片连续的内存,可以使用代理模式来理解一下,它是物理内存的代理,实际上映射的物理内存可能都是零散的内存碎片,以及磁盘。它可以交换一些不常用的内存到磁盘,提高内存的效率。

3.2进程空间:用户空间和内核空间

内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。

再具体一点来说,假设操作系统是32位的,寻址能力就是2的32次方,就是4G,将高位的1GB字节供内核使用,称之为内核空间。剩下的3GB字节供用户进程使用,称之为用户空间。

他们都运行在虚拟地址上,但是是相互隔离的。

如果用户空间想要访问内核空间的资源(因为内核空间占有系统资源,例如读写文件,访问网络),那就需要两者之间进行通信。这时候系统内核可以提供接口,给用户进行调用,这样保证了系统的安全和稳定。也就是说,传统的IPC进程间通信就是通过系统内核来完成的。

3.3用户态和系统态

当进程在执行用户的代码的时候,此时进程处于用户态。当在进程在执行内核代码的时候,此时进程处于内核态。

3.4内核模块和驱动

传统的IPC方式是通过系统内核来完成的,Binder也是一样,内核中存在一个binder的驱动。


4.传统IPC机制的通信原理

此处偷盗一波rushjs大神的图

通常是下面两个步骤(非共享内存机制):

  1. 发送方进程通过系统调用(copy_from_user)将要发送的数据存拷贝到内核缓存区中。
  2. 接收方开辟一段内存空间,内核通过系统调用(copy_to_user)将内核缓存区中的数据拷贝到接收方的内存缓存区。

这种传统IPC机制存在2个问题:

  1. 需要进行2次数据拷贝,第1次是从发送方用户空间拷贝到内核缓存区,第2次是从内核缓存区拷贝到接收方用户空间。
  2. 接收方进程不知道事先要分配多大的空间来接收数据,可能存在空间上的浪费。

5.Binder的底层原理

传统IPC机制需要拷贝2次内存,Binder是如何只用1次内存拷贝就实现进程间通信的呢?前面我们已经了解到,Linux是使用的是虚拟内存寻址方式,用户空间的虚拟内存地址是映射到物理内存中的,对虚拟内存的读写实际上是对物理内存的读写,这个过程就是内存映射,这个内存映射过程是通过系统调用mmap()来实现的。

Binder借助了内存映射的方法,在内核空间和接收方用户空间的数据缓存区之间做了一层内存映射。这样一来,从发送方用户空间拷贝到内核空间缓存区的数据,就相当于直接拷贝到了接收方用户空间的数据缓存区,从而减少了一次数据拷贝。


6.Binder调用过程



猜你喜欢

转载自juejin.im/post/5b6e98d66fb9a04f885704f3