今天主要对 Android 中的跨进程通信进行总结下,先梳理下里面的涉及的一些概念
1.进程与线程- 进程:系统中正在运行的一个应用程序,某个程序一旦运行就是一个进程,是资源分配的最小单位;
- 线程:程序执行的最小单位,包含在进程中,一个进程可以包含多个线程。
Android 系统的底层任务管理以及驱动都是基于 Linux 系统;一个 Android 系统其实就是一个 Linux 系统,通过 adb shell 进入连接的手机,就可以看到 Linux 系统的文件系统
像在运行一个 Java 程序,我们知道 Linux 系统会启动一个Java虚拟机来运行该 Java 程序,而 Android 系统是一个特殊的 Linux 系统,当启动一个 APP,系统会为该 APP 分配一个 Linux 进程,而该进程中就会有一个 dalivk 虚拟机(又称为 DVM )实例来运行该 APP,所以 dalivk 虚拟机就是用来运行 APP 程序
不同的APP运行在不同的进程中,对应着不同的dalivk虚拟机,就对应着不同的地址空间。反过来在一个应用内,如果新开一个进程,那么由于系统在新开进程的时候会分配独立的dalivk虚拟机,那么对于该APP内的不同进程的实例是互相独立,互不影响。
综上:
- 1)每个进程有独立的dalivk虚拟机,对应着单独的内存空间;
- 2)一个应用可以有多个进程,就有多个dalivk虚拟机,对应多个内存空间;
- 3)一个进程可以被多个应用访问,多个应用可以共享该进程
在 Linux 系统中,虚拟内存空间(我理解的就是运行软件程序的空间,是对物理空间的映射)只有 4G;最高的 1GB(对应虚拟地址0xC0000000到0xFFFFFFFF)被成为内核空间,而较低的 3GB(对应虚拟地址0x00000000到0xBFFFFFFF)被成为用户空间。内核空间是Linux内核运行空间,用户空间是应用程序的运行空间。如图所示:
- 内核空间:可以访问受保护的内存空间,有访问底层硬件设备的所有权限;
- 用户空间:上层应用程序和Native层的运行空间,用户空间没法直接访
- 内核空间,需要系统调用才可以访问内核空间。
不同进程之间,用户空间是不共享,但是内核空间是可以共享。
(3)定义多进程默认情况下,启动一个APP,仅仅启动了一个进程,该进程名为包名,那如何定义多进程呢?Android 提供了一种方式,就是在 AndroidManifest 文件中可以通过 “android:process” 来指定进程:
- 1)不指定 process:默认的进程,进程名为包名;
- 2)指定 process,但以":"开头:该进程为当前APP的私有进程,不允许其他APP访问
- 3)指定process,但以小写字母开头的字符串:该进程为全局进程 ,其他应用可设置相同的shareUID来共享该进程
为什么一个 Android 应用要引入多进程?多进程有哪些应用场景呢?
通常在下面两种情况下需要引入多进程:
- 由于 Android 系统会限制每个应用的最大内存,所以如果一个应用需要更多可用的内存时,就需要引入多进程,让某些模块运行在另外的进程中,获取更多的内存;
- 由于不同的应用运行在不同的进程中,但是如果两个不同的应用之间需要进行数据通信
既然在 Android 中引入了多进程,而对于进程的用户空间不共享,那么多进程之间怎么通信呢?
这种多进程通信又称为IPC(Inter Process Communication)
对于IPC,并不是Android系统特有的,在Linux系统中就存在的跨进程通信,在Linux系统中常见的IPC方式有:
- 1)管道Pipe:在内存中创建一个共享文件,利用共享文件传递信息。该共享文件并不是文件系统,只存在于内存中;只能在一个方向上流动
- 2)信号Signal:异步通信。信号在用户空间和内核空间之间交互,内核可利用信号来通知用户空间的进程发生哪些系统事件。不适用于信号交换,适用于过程中断控制;
- 3)信号量Semaphore:控制多个进程对共享资源的访问。主要是进程间以及同一进程不同线程之间的同步手段;
- 4)消息队列 Message Queue:存放在内存中并由消息对了标识符标识,允许一个或多个进程对它进行读写消息。信息会复制两次,不适用于频繁或信息量大的通信
- 5)共享内存Shared Memory:直接读写内核的一块内存空间。不需要进行数据拷贝
- 6)套接字Socket:不同机器之间进程间通信。
而在 Android 中,场景的 IPC 方式有:
- 1)Bundle:实现了Parcelable接口,常用于Activity、Service、BroadcastReceive之间的通信
- 2)文件共享:常用于无并发,交换实时性不高的数据
- 3)Messenger:低并发的一对多即时通信。串行的方式处理Client发来的消息,只能传输数据,不能方法调用(RPC)
- 4)ContentProvider:存储和获取数据,不同程序之间共享数据。一对多的数据共享
- 5)AIDL
- 6)Socket:网络数据交换
除去 Socket,其他的都是基于 Binder 机制实现的
(6)多进程带来的问题
在进程结构中也提到了用户空间是不共享的,并且每个进程都是对应单独的系统堆栈区、静态区等,那么多进程也引入了一些问题:
- 每个进程都是保持自己单独的静态成员变量和单例;
- 每个进程都是单独的进程锁;
- SharedPreferences可靠性下降,不支持并发写;
- 对于单个APP的多进程,就会创建多个Application,每个进程都会拥有己的Application对象。
题外话: 最后的这个信息让我想起之前看 web 开发相关的一些信息:Tomcat 也是运行在 Linux 系统中,在部署 web 应用的时候,可以把一个 web 应用部署到多个 Tomcat 服务器上,那么每个 Tomcat 服务器都会给该 web 应用分配一个 ServletContext
这篇文章,其实不难;主要是将 Android 中的跨进程通信以及开发当中经常用到的一些知识点,总结了一下
想要往向更深入学习难免需要寻找很多的学习资料辅助,我在这里推荐网上整合的一套《 Android 跨进程通信学习手册》;鉴于出自大佬之手,可以帮助到大家,能够少走些弯路
篇幅原因,就不在这里为大家赘述了,有需要的小伙伴:可以私信发送“学习手册”即可 免费领取这份《Android 跨进程通信学习手册》,助你早日成为底层原理大师!
最后大家如果觉得手册内容有用的话,可以点赞分享一下哦~
,