Android Binder系列之IPC简介(1)

开篇

Binder是一个Android开发从初级进阶的必经之路,想来自己做Android开发也有两年多的时间了,尽然还没有研究过这一块的东西,真是惭愧。 从这篇文章开始会有一个系列对Binder进行分析,涵盖了Binder的使用、构成、原理以及Binder牵连的一些知识点。注意:我们不会深入到C层,想要看Binder完整源码的人这篇文章可能不适合你,但是我讲的东西足够日常使用和应付面试了,毕竟大部分人都不是做framework层工作的。

IPC简介

IPC全名为inter-Process Communication,含义为进程间通信,是指两个进程之间进行数据交换的过程。
为什么要进程间通信呢?
因为在Linux或者所有的操作系统中,不同的应用运行在自己独自的进程中,而进程间是隔离的,这很好理解,如果数据是进程间共享,那么所有的应用都是相互透明的,微信可以使用支付宝的数据,这你敢想,但是应用间又不能完全不通信,所以这时候就需要一些方法来进行进程间通信。

Linux中的IPC机制种类

大致了解一下
Linux中提供了很多进程间通信机制,主要有管道(pipe)、信号(sinal)、信号量(semophore)、消息队列(Message)、共享内存(Share Memory)、套接字(Socket)等。

  • 管道:管道是Linux由Unix那里继承过来的进程间的通信机制,它是Unix早期的一个重要通信机制。管道的主要思想是,在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。这个共享文件比较特殊,它不属于文件系统并且只存在于内存中。另外还有一点,管道采用的是半双工通信方式的,数据只能在一个方向上流动。
  • 信号:信号是软件层次上对中断机制的一种模拟,是一种异步通信方式,进程不必通过任何操作来等待信号的到达。信号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件。信号不适用于信息交换,比较适用于进程中断控制。
  • 信号量:信号量是一个计数器,用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。主要作为进程间以及同一进程内不同线程之间的同步手段。
  • 消息队列:消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识,并且允许一个或多个进程向它写入与读取消息。信息会复制两次,因此对于频繁或者信息量大的通信不宜使用消息队列。
  • 共享内存:多个进程可以直接读写的一块内存空间,是针对其他通信机制运行效率较低而设计的。为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。进程就可以直接读写这一块内存而不需要进行数据的拷贝,从而大大的提高效率。
  • 套接字:套接字是更为基础的进程间通信机制,与其他方式不同的是,套接字可用于不同机器之间的进程间通信。

Android中的IPC机制

有个印象
Android系统是基于Linux内核的,在Linux内核基础上,又拓展出了一些IPC机制。Android系统除了支持套接字,还支持序列化、Messenger、AIDL、Bundle、文件共享、ContentProvider、Binder等。

  • 序列化:序列化指的是Serializable/Parcelable,Serializable是Java提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。Parcelable接口是Android中的序列化方式,更适合在Android平台上使用,用起来比较麻烦,效率很高。
  • Messenger:Messenger在Android应用开发中的使用频率不高,可以在不同进程中传递Message对象,在Message中加入我们想要传的数据就可以在进程间的进行数据传递了。Messenger是一种轻量级的IPC方案并对AIDL进行了封装。
  • AIDL:AIDL全名为Android interface definition Language,即Android接口定义语言。Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的。另外还有一点,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,这个时候就需要使用AIDL了。
  • Bundle:Bundle实现了Parcelable接口,所以它可以方便的在不同的进程间传输。Acitivity、Service、Receiver都是在Intent中通过Bundle来进行数据传递。
  • 文件共享:两个进程通过读写同一个文件来进行数据共享,共享的文件可以是文本、XML、JOSN。文件共享适用于对数据同步要求不高的进程间通信。
  • ContentProvider:ContentProvider为存储和获取数据了提供统一的接口,它可以在不同的应用程序之间共享数据,本身就是适合进程间通信的。ContentProvider底层实现也是Binder,但是使用起来比AIDL要容易许多。系统中很多操作都采用了ContentProvider,例如通讯录,音视频等,这些操作本身就是跨进程进行通信。

IPC通信原理

前面将的东西很无聊,但是没办法这些东西必须讲,你也一定要看一下,看不太明白也没关系。
讲了那么多进程间通信的方法,他们的原理是什么呢?

1.共享文件

文件共享通过访问同一个文件实现进程间通信,看似很简单,但是文件是由系统管理的,进程如何访问文件呢,这就要讲到Linux的内核空间和用户空间,User space(用户空间)和 Kernel space(内核空间)。

为了保护用户进程不能直接操作内核,保证内核的安全,操作系统从逻辑上将虚拟空间划分为用户空间和内核空间。Linux 操作系统将最高的1GB字节供内核使用,称为内核空间,较低的3GB 字节供各进程使用,称为用户空间。
内核空间是Linux内核的运行空间,用户空间是用户程序的运行空间。为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不会受到影响。内核空间的数据是可以进程间共享的。

文件管理驱动是在内核空间中的,用户空间的进程要访问文件就需要访问内核空间,用户空间访问内核空间,需要借助系统调用来实现。系统调用是用户空间访问内核空间的唯一方式,保证了所有的资源访问都是在内核的控制下进行的,避免了用户程序对系统资源的越权访问,提升了系统安全性和稳定性。

  • copy_from_user:将用户空间的数据拷贝到内核空间。
  • copy_to_user:将内核空间的数据拷贝到用户空间。
    在这里插入图片描述
    通过内核空间作为中介,间接实现了进程间的通信,这只是进程通信的其中一种方式,接下来再介绍一下共享内存实现进程间通信的原理。

2.共享内存

为了进程间通信,内核空间有一块专门的内存区可以由需要访问的进程将其映射到自己的私有地址空间,如果两个进程想要通信,直接映射到相同的内存就可以共享数据了。
在这里插入图片描述

3.Binder

简单来说Binder是共享文件和共享内存的合体,数据接收进程建立一个内核空间的内存映射区,数据发送进程通过copy_from_user将数据拷贝到内存映射区,这样就完成了通信。
在这里插入图片描述
既然Linux已经有那么多进程间通信的方式了,为什么Android还要自己创造一个呢?主要有下面几点原因:

  • 性能方面:性能方面主要影响的因素是拷贝次数,管道、消息队列、Socket的拷贝次书都是两次,性能不是很好,共享内存不需要拷贝,性能最好,Binder的拷贝次书为1次,性能仅次于内存拷贝。
  • 稳定性方面:Binder是基于C/S架构的,这个架构通常采用两层结构,在技术上已经很成熟了,稳定性是没有问题的。共享内存没有分层,难以控制,并发同步访问临界资源时,可能还会产生死锁。从稳定性的角度讲,Binder是优于共享内存的。
  • 安全方面:Android是一个开源的系统,并且拥有开放性的平台,市场上应用来源很广,因此安全性对于Android 平台而言极其重要。传统的IPC接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),无法鉴别对方身份。Android 为每个安装好的APP分配了自己的UID,通过进程的UID来鉴别进程身份。另外,Android系统中的Server端会判断UID/PID是否满足访问权限,而对外只暴露Client端,加强了系统的安全性。
发布了65 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/shanshui911587154/article/details/105511462