IPC全名为inter-Process Communication,含义为进程间通信,是指两个进程之间进行数据交换的过程。
内核空间和用户空间
在操作系统中存在用户空间(User space)和内核空间(Kernel space)。
Liunx采用虚拟内存管理技术,每一个进程都都有各自独立的进程地址空间(以32位系统为例,空间为4G大小的线性虚拟空间),无法直接访问物理内存。这样避免了进程直接操作系统内核,保证系统安全,并且让用户程序可使用比实际物理内存更大的地址空间。
进程隔离
进程隔离指的是,一个进程不能直接操作或者访问另外一个进程,也就是进程A不可以直接访问B的数据。
系统调用
用户空间需要访问内核空间,就需要借助系统来实现。系统调用是用户空间访问内核空间的唯一方式,保证了所有的资源访问都是在内核的控制下进行的,避免了用户进程对系统资源的越权访问,提升了系统的安全性和稳定性。
进程A和进程B的用户空间可以通过如下系统函数和内核空间进行交互。
内存映射
由于应用程序不能直接操作设备设备硬件地址,所以操作系统提供了一种机制:内存映射,把设备地址映射到进程虚拟内存区。
内存映射全名为Memory Map,在Liunx中通过系统调用函数mmap来实现内存映射。将用户空间的一块内存区域映射到内核空阿金。映射关系建立后,用户对这块内存的区域的修改可以直接反应到内核空间,反之亦然。内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。
内核程序在内核空间分配内存并开辟一块内核缓存区,发送进程通过copy_from_user函数将数据拷贝到内核空空间的缓冲区中。同样,接收进程在接收数据时再自己的用户空间开辟一块内存缓存区,然后内核程序调用copy_to_user() 函数将数据从内核缓存区拷贝到接收进程。这样数据发送进程和数据接收进程完成了一次数据传输,也就是一次进程间通信。
Linux的IPC通信原理有两个问题:
2、信号
信号是软件层次上对中断机制的一种模拟,是一种异步通信方式,进程不必通过任何操作来等待信号的到达。信号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件。信号不适用于信息交换,比较适用于进程中断控制。
3、信号量
信号量是一个计数器,用来控制多个进程对共享资源的访问。它常用来作为一种锁机制,防止某种进程正在访问共享资源时,其他进程也访问该资源。主要作为进程间以及同意进程内不同线程之间的同步手段。
4、消息队列
消息队列时消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识,并且允许一个或多个进程向它写入与读取消息。信息会复制两次,因此对于频繁或者信息量大的通信不宜使用消息队列。
5、共享内存
多个进程可以直接读写的一块内存空间,是针对其他通信机制运行效率太低而设计的。为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程映射到自己大的私有地址空间。进程就可以直接读写这一块内存而不需要进行数据的拷贝,从而大大的提高效率。
6、套接字
套接字是更为基础的进程间通信机制,与其他方式不同的是,套接字可用于不同机器之间的进程间通信。
Android系统是基于Linux内核的,在Liunx内核基础上又扩展出了一些IPC机制。Android系统除了支持套接字,还支持序列化、Messenger、AIDL、Bundle、文件共享、ContentProvider、Binder等。
1、序列化
序列化指的是Serializable/Parcelable,Serializable是java提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。Parcelable接口时Android中序列化方式。
2、Messenger
Messagner对象可以在不同进程中传递,在Message中加入我们想要传的数据就可以在进程间进行数据传递了。Messagner是一种轻量级的IPC方案并对AIDL进行了封装。
3、AIDL
AIDL全名为Android interface definition Language,即Android接口定义语言。Messenger是以串口的方式来处理客户端发来的信息,如果又大量的消息发到服务端,服务端仍然一个一个处理再响应客户端显然是不适合的。另外还有一点,Messenger用来进程间进行数据传递但是不能满足跨进程的方法调用,这个时候需要使用AIDL了。
4、Bundle
Bundle实现了Parcelable接口,所以它可以方便的在不同的进程间传输。Acitivity、Service、Receiver都是在Intent中通过Bundle来进行数据传递。
5、文件共享
两个进程通过读写同一个文件来进行数据共享,共享的文件可以是文本、XML、JOSN。文件共享适用于对数据同步要求不高的进程间通信。
6、ContentProvider
ContentProvider为存储和获取数据了提供统一的接口,它可以在不同的应用程序之间共享数据,本身就是适合进程间通信的。ContentProvider底层实现也是Binder,但是使用起来比AIDL要容易许多。系统中很多操作都采用了ContentProvider,例如通讯录,音视频等,这些操作本身就是跨进程进行通信。
参考文档:
Android Binder原理
Binder系列
深入理解Android卷1