简介
理解Android的跨进程通信原理的关键是Binder。Binder是Android中独有的跨进程通信方式,底层的支持是Binder Driver,需要知道的是Linux 内核中并不包含Binder Driver,也就是说Linux并不对Android中的Binder跨进程通信方式提供支持。
跨进程通信是需要内核空间作为支持的。传统的IPC机制如管道、Socket都是内核的一部分,因此通过内核支持实现进程间通信自然是没问题的。但是Binder并不是Linux系统内核的一部分,那该怎么办呢?幸好,Linux支持动态内核可加载模块的机制,模块是具有独立功能的程序,它可以被单独的编译,但是不能独立运行。它在运行时被链接到内核作为内核的一部分运行。这样Android就可以动态添加一个内核模块运行在内核空间,用户进程通过这个内核模块作为桥梁实现通信。
在Android系统中,这个运行在内核空间,负责各个用户进程通过Binder实现通信的内核模块就是Binder驱动。
本文基于Binder分析Android中的跨进程通信方式 - AIDL。
Android中的Messenger、ContentProvider底层都是基于AIDL,因此,掌握了AIDL的工作原理也就间接掌握了其余的跨进程通讯方案了。
本文资料来源“艺术探索”,重读此书,仅作学习笔记,备忘。
Android中的多进程模式
在Android中使用多进程只有一种方法,那就是给四大组件在AndroidManifest中指定android:process属性,除此之外没有其他方法。
关于android:process属性的设置,有两种方式:
<service
android:name=".localProcess.RemoteProcessService1"
android:process="com.json.ipctest.remote" />
<service
android:name=".RemoteProcess.RemoteProcessService2"
android:process=":remote" />
进程名以":"开头的进程是属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而进程名不以“:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
小知识点:Android系统会为每一个应用分配一个唯一的UID,具有相同UID的应用才能共享数据。这里需要说明的是,两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以。在这种情况下,它们可以相互访问对方的私有数据,比如data目录,组件信息等,不管它们是否跑在同一个进程中。当然如果它们跑在同一个进程中,那么除了能共享data目录、组件信息,还可以共享内存数据,或者说它们看起来就像一个应用的两个部分。
多进程模式下注意事项
Android 会为每一个应用分配一个独立的虚拟机,或者说为每一个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间。
public class UserManager {
public static int userId = 1;
}
如上代码,我们在MainActivity中将userId赋值为2,在SecondActivity(通过android:process运行在单独的进程中)中打印userId,会发现userId的值是1,而不是2。
一般来说,使用多进程会造成如下几个方面的问题:
- 静态成员和单例模式完全失效;
- 线程的同步机制完全失效;
- SP的可靠性下降;
- Application会创建多次;
第一个问题和第二个问题原因类似。
第三个问题是因为SP不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,因为SP底层是通过读/写XML文件来实现的,并发写显然是可能出问题的,甚至并发读/写都有可能出问题。
第四个问题也是显而易见的,由于系统要在创建新的进程的同时分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程。因此,相当于系统又把这个应用重新启动了一遍,既然重新启动了,那么自然就会创建新的Application。即运行在同一个进程中的组件是属于同一个虚拟机和同一个Application的,同理,运行在不同进程中的组件是属于两个不同的虚拟机和Application的。
小结:以上问题产生的原因是多进程模式中,不同的进程拥有独立的虚拟机、Application、内存空间。