Android IPC –Binder之Linux基础篇(一)

上一篇文章我分析了Android 进程内通信机制Handler,本篇文章我就来扒一扒Android 进程间的通信-Binder 机制。

Linux.png
我们都知道Android 是基于Linux系统来实现的,因此,我们有必要来了解一下,为什么Android 不使用Linux本身有的进程通信机制,而是要自己撸一个Binder 这玩意来实现进程间通信。
接下来,我们简要的介绍下Linux 进程间通信的几种方式。介绍Linux IPC机制,旨在了解其思想,得出其优缺点,便于找到Android中使用Binder 的依据,故不做深入的分析,如果想要深入分析,可以查看本文末尾提到的参考文献列表,读者自行去查阅。

Linux IPC方式 安全 效率 单双向 模型
管道 v 不高 单向 1v1
共享内存 x 最高 双向 多对多
Socket v 很低 双向 多对多
File x 双向 多对多

Linux 下IPC机制

1.管道通信

image.png

管道文件的特性

  • 打开管道必须有两端(两个进程)同时打开一个管道。分别为读(r)和写(w);读取端负责从管道中读取数据,写入端负责向管道中写入数据。
  • 当读端关闭,写端会收到信号,终止程序;当写端关闭,读端不再进入阻塞。
  • 管道文件大小始终为0, 打开管道文件时,为其分配内存空间,管道关闭后数据清除;Linux默认PIPE_SIZE=64K(一个管道最大存储空间);PIPE_BUF(管道缓冲区)=4k;当对管道进行write操作时,若此时有多个进程同时写入一个管道,且写入的数据大小超过PIPE_BUF 时,则写入的数据可能互相穿插(数据不安全)。

管道文件的内存空间中有两个指针head和tail. head 指针随读取数据向后移动,tail 指针随写入数据向后移动。当指针到文件尾时,会造成读阻塞(读取结束)/写阻塞(空间已满)

管道的局限性

  • 数据只能自己读,不能自己写
  • 数据一旦被读走,管道中便不存在,不可重复读取
  • 由于管道采用半双工通信方式,因此,数据只能再一个方向上流动
  • 只能在有公共祖先的进程中实现通信

小结:管道通信是一种1v1 的通信方式,相对来说比较安全的。缺点是:数据只能单向传输。

2.共享内存

共享内存就是允许两个或多个进程共享一定的存储区。当共享的这块存储区中的数据发生改变,所有共享这块存储区的进程都会察觉数据的改变,因为数据不需要在客户端和服务端进行数据拷贝,数据直接写到内存,不用若干次数据拷贝,所以这是最快的IPC。

image.png

共享内存的优势

  • 因为两个进程通过地址映射到同一片物理地址,所以,进程可以给那一片物理空间中写入数据,也可以读取数据—-进程间双向通信。
  • 客户端和服务端都是从内存中直接读取、写入数据的,没有涉及到数据的拷贝,因此,速度最快。
  • 生命周期随内核,不会随着服务端或者客户端的断开而销毁。所有访问共享内存对象的进程都结束了,共享内存区域对象依然存在。

共享内存的缺点

共享内存并未实现同步机制:多个进程可以同时写入数据,这就会造成数据的混乱

小结

是一种多对多的IPC,访问速度最快的IPC。但是,没有提供同步机制,不够安全

3.Socket 通信

Linux 的哲学思想是”一切皆文件”,所以可以使用 打开(open)–> 读写(read/write)–> 关闭(close) 模式来实现,Socket 就是该模式的一个实现,Socket是一种特殊的文件。

使用套接字除了可以实现网络间不同主机间的通信,也可以实现同一主机下不同进程间的通信。且建立的通信是双向的通信,通信流程如下图。从图中就可以看出,客户端与服务端要建立连接,然后读写数据,相当于在两个进程间各自拷贝数据,然后传输数据,这个效率是很慢的。

image.png

小结

Socket 是一种双向多对多模式的IPC机制之一,但数据发生了两次拷贝,因此效率比较低。但是比较安全的。

再看Linux 几种IPC方式的优缺点:

Linux IPC方式 安全 效率 单双向 模型
管道 v 不高 单向 1v1
共享内存 x 最高 双向 多对多
Socket v 很低 双向 多对多
File x 双向 多对多

因此,Android 就决定自己实现一套IPC的实现方式—-Binder Binder只需要一次拷贝,且足够安全。

Android IPC通信Binder

在介绍Binder 之前,我们先来了解下以下概念:

1.内核空间和用户空间

  • 内核空间(内核进程):操作系统所占用的内存区域 ——-只有一份
  • 用户空间(用户进程):用户进程所在的内存区域 ———多份

直白的说,我们开发的APP所对应的字节码就存储在用户空间,其所进行的一系列方法调用,内存的分配都是在用户空间中。而Android系统的代码就在内核空间中。

Q:为什么要这么划分?

A:使用内核空间和用户空间这种分开来划分,可以做到,每个APP(用户空间)不会影响其他APP,也不会造成系统的崩溃。

image.png

使用adb shell ps 可以看到下图
image.png
可以看到手机中PPID为0 的就是内核进程。

2.物理地址和虚拟地址

2.1 虚拟内存

实际上我们写的程序,都是面向虚拟内存的,我们在程序中写的变量的地址,实际上是虚拟内存中的地址,当CPU想要访问该地址的时候,内存管理单元MMU就会将虚拟地址翻译成物理地址。然后,CPU就可以从真实的物理地址处获取到数据。

2.2 MMU:内存管理单元

内存管理单元MMU:它是一个硬件,不是软件。它用于将虚拟地址翻译成实际的物理内存地址,同时它还可以将特定的内存块设置成不同的读写属性,进而实现内存保护。注意,MMU是硬件管理,不是软件实现内存管理。

总结来说,MMU能实现以下功能:

  • 虚拟内存。有了虚拟内存,可以在处理器上运行比实际物理内存大的应用程序。为了使用虚拟内存,操作系统通常要设置一个交换区(通常在硬盘上),通过将内存中不活跃的数据与指令放到交换区,以腾出物理内存来为其他程序服务。
  • 内存保护。通过这一功能,可以将特定的内存块设置为读、写或者可执行的属性。比如将不可变的数据或者代码设为只读的,这样可以防止被恶意串改。

本文只要知道MMU是将虚拟地址转换成物理地址的过程是MMU的核心。
image.png
因为程序具有局部性原则,所以在某一段很小的时间段内,只有很少一部分代码会被CPU执行。
每次从磁盘的缓冲区中加载4K的数据到内存中。

2.2.1 页

我们知道物理内存中执行的是可执行的少部分程序代码和数据,这每次加载可执行的少部分代码和数据这个大小是多少呢?

以存储单元为单位来管理显然不现实,因此Linux把虚存空间分成若干个大小相等的存储分区,Linux把这样的分区叫做页。为了换入、换出的方便,物理内存也就按也得大小分成若干个块。由于物理内存中的块空间是用来容纳虚存页的容器,所以物理内存中的块叫做页框。 页与页框是Linux实现虚拟内存技术的基础。

为了CPU高效且方便管理内存,每次需要拿一个页的代码—-连续的存储空间=4K,也叫做块。

image.png
由于物理内存和虚拟内存分为页和页框的概念,因此,上图中分为了页框码(页码)、偏移量两部分。
页框码(页码)是识别页框(页)的编码,偏移量是识别存储单元在页框(页)内的地址编码。

2.2.2页表

为了将物理内存中的页框和虚拟内存中的页一一对应,由此就产生了页表的概念。页表这个数据结构存储的就是物理内存中的页框码以及虚拟内存中的页码

image.png
通过这个页表就可以从虚拟内存找到物理内存所对应的地址编码,从而获取到物理内存中所对应的数据。就实现了映射关系—–通俗点理解:map这个数据结构有点类似。我们知道这个内存映射,了解其设计思想就可以了。

文章最后,我们来简单看一下Android跨进程通信 Binder中的一直所说的只需一次拷贝—-就是用到了内存映射的这个核心。

image.png
这是Binder IPC 通信模型的经典图,原本两个进程间数据的交互需要两次拷贝(磁盘-> 内核空间->用户空间),由于使用了mmap(内存映射)就减少了一次数据接收进程的数据拷贝(也可以说是服务端)。这样Binder只需要在数据发送进程(客户端)实现一次从磁盘拷贝数据到内核空间即可。

总结

本文从Linux进程间的几种IPC机制谈起,简要分析了其各种IPC机制的优劣,从而引出Android 设计出Binder这种跨进程通信模型。该文是Binder 通信的Linux 基础篇,旨在帮助读者对跨进程通信的几种机制有个大概的了解,从而更好的理解为什么那么Android要设计Binder。下一篇文章,我们将从Binder的架构层面分析一下。

IPC方式 安全 效率 单双向 模型
管道 v 不高 单向 1v1
共享内存 x 最高 双向 多对多
Socket v 很低 双向 多对多
File x 双向 多对多
Binder v 双向 多对多

参考文章

linux管道pipe详解_良月柒-CSDN博客_linux pipe

Linux — 进程间通信之管道_Programmer-CSDN博客

Linux下进程间通信方式——共享内存 – cs_wu – 博客园 (cnblogs.com)

Linux socket 本地进程间通信_GXYandSXP的博客-CSDN博客_linux socket通信

【软件开发底层知识修炼】三 深入浅出处理器之三 内存管理与内存管理单元(MMU)_厚积薄发-CSDN博客

Linux内核学习:虚拟内存详解(MMU、页表结构) – 知乎 (zhihu.com)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享