一、跨进程通信方式
跨进程通信主要有以下几类:管道、Socket、共享内存、信号。
1. 管道
管道的特点是半双工&单向的,管道里面的数据只能往一个方向流动。一般情况下管道是在父子进程之间使用的。
2.socket
socket的特点是全双工,即可读也可写。可以用在两个无亲缘关系的进程之间,但需要公开路径。
例子:
在Android的Framework机制中,zygote就是通过socket来接受AMS的请求,然后启动应用进程的。
3.共享内存
共享内存的特点:速度快,且不需要多次拷贝,且进程之间不需要存在亲缘关系,只需要拿到文件描述符即可。
这里补充一下:管道和socket的问题在于数据不能太大,否则性能会非常糟糕,相比较共享内存不存在这个问题。
4.信号
信号的特点是:
a).单向的,发送出去后不管其他人接受者是如何处理的;
b).只能带信号,不能带其他参数。
c).知道进程的pid就可以发信号,而且一次可以一群进程发信号(需 root权限 或 同uid 才行)。
例子:
Android的Process#killProcess方法,就是发送的 SIGNAL_KILL 信号。
5. Binder
Binder机制是Android特有的进程间通信的机制,特点为:采用C/S的通信模式、有更好的传输性能,最重要的特点是安全。
下面我们就着重讲一下Android的Binder机制。
二、Binder的通信架构
Binder的通信架构示例如下图(示例的是系统服务,因为只有系统服务才能注册到ServiceManager):
1. 进程如何启动Binder机制
- 首先打开binder驱动,binder驱动会给进程创立一套档案。
- 然后将返回的描述符进行内存映射,分配缓存区。
- 最后启动binder线程,binder线程会注册到binder驱动,同时线程进入loop循环,不断的跟binder驱动交互。
2. Binder机制的分层架构
Binder机制的分层架构如下图所示:
三、Binder机制的同步与异步
一般我们声明AIDL的时候,都是类似如下的方式,此方法是同步方法:
interface IPlayer { int getVolume();// 同步,假设执行1秒 }
其实我们也可以使用oneway来修饰AIDL内部的方法,修饰完成后就表示此方法是异步调用的。例如:
interface IPlayer { oneway void start();//异步,假设执行2秒 oneway void stop();//异步,假设执行2秒 int getVolume();// 同步,假设执行1秒 }
在上面的代码中,Client端调用IPlayer.start(),Server端的start需要执行2秒,由于定义的接口是异步的,Client端可以快速的执行IPlayer.start(),不会被Server端block住2秒。但是当Client端调用IPlayer. getVolume(),Server端的getVolume需要执行1秒,由于定义的接口是同步的,Client端在执行IPlayer. getVolume()的时候,会被Server端block住1秒。
为什么Android的Binder机制会提供同步/异步的调用机制呢?答:异步调用在不需要Server端的返回值或者状态的时候,能有效的提高Client的效率。