很多时候大家会同时提到IPC、Binder、AIDL这几个概念,但对于它们之间的关系可能没有一个清晰的认识。还有Intent与它们有什么关系呢?
概述
首先看看各自的全称与中文名:
- IPC:Inter-Process Communication(进程间通信)
- Binder:Binder进程间通信机制
- AIDL:Android Interface Definition Language(android接口定义语言)
- Intent:意图
再来看一张关系示意图:
图中最里层是Android系统匿名共享内存Ashmem(Anonymous Shared Memory),其作用之一即通过Binder进程间通信机制来实现进程间的内存共享。
通过示意图其实已经能知道个大概:
IPC是一种概念,即进程间通信;其它几个都是Android里的概念;Binder是IPC的一种具体实现;AIDL是Binder机制向外提供的接口,目的就是为了方便对Binder的使用;Intent是最高层级的封装,实质是封装了对Binder的使用,当然Intent也常常在同一进程中调用,只是把两种方式封装在一起了。
为什么搞这么复杂呢,目的还是为了最大发挥系统效率与方便开发者使用。
IPC
IPC是操作系统层面的概念,因为进程是操作系统里最基本的单位,进程的一大特征就是有自己独立的内存地址空间,所以同一进程里的代码能直接访问其地址空间的内存,而其它进程是不能直接访问的。操作系统是多进程的,多个进程配合工作肯定会涉及到互相的通信,故出现了IPC。而对IPC的实现也不只一种,有很多,且有各自的长处,比如Socket就是一种IPC,其长处就是能跨机器进行进程间通信。
Android系统的本质上其实是Linux系统,可以看成是在Linux内核上运行着一个超级程序。虽然Linux本身提供了很多IPC机制,但是Android主要是运行在手机上了,为了能更好的适应手机这个环境同时简化开发,Binder机制出现了。而Binder本质上是通过共享内存来实现的IPC( 直白点就是一段物理内存在不同进程中都映射了虚拟地址,虚拟地址可能不同,一个对它写,另一个对它读,然后解析、处理),但是Binder机制不是简简单单共享内存,而是搭了一套巧妙的架构,来达到最终共享内存进行IPC的目的。
Binder
Binder机制具体的实现涉及到很多C/C++的代码,我们了解一下其思想就行了。Binder通信采用的是client-server通信结构,client与server的通信由Binder驱动程序和Service Manager组件协助,这两个组件Android已经实现好了并由系统运行,而开发者只需要按照框架规范实现client与server接口即可。这里可以参考我总结的对Binder的概述Binder进程间通信机制概述(Android系统源代码情景分析学习笔记)。
更进一步地了解可以参考我之前转载的一篇文章Android Binder设计与实现 - 设计篇(强烈推荐) 。
最后如果还要深入了解源码可以参考罗升阳的博客或者他写的书《Android系统源代码情景分析》。
AIDL
AIDL是为了方便使用Binder框架搞的一个东西,其实不用它也能达到目的,但是用AIDL就简化了操作。只要按照规范写一个.aidl文件,编译器就会帮助我们自动创建一个与interface同名的.java文件,里面已经帮我们自动实现了一个Binder,这些标准化的东西,用模板自动生成即可,可以让开发者尽量关注功能实现上。
例如:
AIDL文件:
interface IMyAidl {
int add(int num1,int num2);
List<Dog> addDog(in Dog dog);
}
编译器根据AIDL文件生成的Java文件:
public interface IMyAidl extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.aidl.tsnt.server.IMyAidl {
private static final java.lang.String DESCRIPTOR = "com.aidl.tsnt.server.IMyAidl";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.aidl.tsnt.server.IMyAidl interface,
* generating a proxy if needed.
*/
public static com.aidl.tsnt.server.IMyAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.aidl.tsnt.server.IMyAidl))) {
return ((com.aidl.tsnt.server.IMyAidl) iin);
}
return new com.aidl.tsnt.server.IMyAidl.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_addDog: {
data.enforceInterface(DESCRIPTOR);
com.aidl.tsnt.server.Dog _arg0;
if ((0 != data.readInt())) {
_arg0 = com.aidl.tsnt.server.Dog.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
java.util.List<com.aidl.tsnt.server.Dog> _result = this.addDog(_arg0);
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.aidl.tsnt.server.IMyAidl {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int add(int num1, int num2) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(num1);
_data.writeInt(num2);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.aidl.tsnt.server.Dog> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((dog != null)) {
_data.writeInt(1);
dog.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addDog, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.aidl.tsnt.server.Dog.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addDog = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public int add(int num1, int num2) throws android.os.RemoteException;
public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException;
}
关于使用AIDL,可以参考AIDL最佳实践。
Intent
Intent进行进程间通信比较常见,比如打开另一个应用的Activity、发送广播等。
Intent的架构包括三方面:
- Client,发送这个Intent的activity;
- Server,ActivityManagerService,它主要是负责分发这些Intent给适当的对象;
- Target,也就是那些需要处理这个Intent的activity,称为Receiver。
而进程间发送消息或者broadcast,并不是直接把intent发过去,而是把intent打包到Parcel中,通过binder机制传递消息。