0. what is IPC
Inter-Process commonication 进程间通信,跨进程通信
ps:注意区分跨线程和跨进程
1. android 跨进程通信形式
- intent-bundle
- broadcast
- content provider(*)
- messagener(*)
- AIDL(*)
- file
画*的为比较难的,其中难度系数 AIDL>Messagener>ContentProvider,具体的使用方法请自行搜索,说一下AIDL的流程和各自的特性。
先说下特性吧 messagener 是串行处理的 AIDL支持并发处理,所以根据自己需要 AIDL 使用过程不再阐述,自行百度,下面说下跨进程发生了啥
调用过程看起来是在客户端直接调用binder然后强转调用方法即可,但是,但是,说下隐藏点。
onserviceconnected
参数 IBinder 有两种类型 Binder 和 BinderProxy(没见过吧) ,其中Binder 类型是非跨进程的时候拿到的,BinderProxy 是跨进程的,然后看各自的asInterface方法(这里asinterface 需要转成你定义的接口才能调用)
onserviceConnected IBookManager manager = IBookManager.Stub.asInterface(service) //service 可能是Binder 类型或者是 BinderProxy,为什么是这两种类型自行百度,因为我也没看明白
Binder
/** * Use information supplied to attachInterface() to return the * associated IInterface if it matches the requested * descriptor. */ public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { //这个owner 在构造函数里调用attch 方法设置了,所以会返回自己 return mOwner; } return null; }
BinderProxy
public IInterface queryLocalInterface(String descriptor) { return null; }
调用方
/** * Cast an IBinder object into an com.test.aidl.IBookManager interface, * generating a proxy if needed. */ public static com.test.aidl.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } //这里,看到了,如果是Binder那么能查询到就会直接返回,然后调用,如果返回null(binderproxy)那么创建一个代理类回去 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.test.aidl.IBookManager))) { return ((com.test.aidl.IBookManager) iin); } return new com.test.aidl.IBookManager.Stub.Proxy(obj); }
看了上边的几段代码应该能明确了如果 是跨进程调用的话,会返回给客户端一个服务端Binder的代理对象,这个代理对象继承自stub(binder)的实现,所以具有同样的方法,至于调用参照2.
binder 代理类的调用 客户端拿到binder (实际是个代理,客户端不知道也不care)之后,看是调用了,调用到代理的各种方法,举个栗子
@Override public java.util.List<com.test.aidl.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.test.aidl.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.test.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; }
首先看到了一大堆序列化的东西,为啥需要序列化???想想intent是怎么传递数据的?为啥intent 那么传递?因为支持跨进程啊,可以看到,实际的调用是mRemote 对象,mRemote对象是啥? 上边的asInterface 里边的最后一句
return new com.test.aidl.IBookManager.Stub.Proxy(obj);
就是它了 ,所以mRemote 是obj 也就是一个BinderProxy 对象,敲黑板重点来了:
- 这个obj(BinderProxy 对象) 是remote 进程的binder 的代理
- 跨进程调用的实际是 transcat 方法
Stub.TRANSACTION_getBookList 这是个id,标识了要真正调用的方法 所以过程为,客户端拿到了一个代理A,这个代理A包装了一个B 的代理B+,客户端调用 A->B+ ->驱动跨进程->B->真正的方法
remote进程 的解析,并回写结果 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.test.aidl.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); }
全是代理。大概是这样 client <——> Binder驱动 <——> remote,只是Binder 驱动那层我们感知不到,所以看起来是两个进程直接通信的。 另外还有messagener 通信,据说是调用优化版,没有细看代码。以上基本就是AIDL 的整个过程了,至于绑定服务相关和驱动层还没看估计短时间也不会看了。
名称 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
bundle | 简单易用 | 只能传输bundle支持的数据类型 | 四大组件间的进程间通信 |
文件 | 简单易用 | 不适合高并发,无法即时通信 | 无并发需求,交换简单数据 |
AIDL | 支持一对多并发,实时通信 | 使用复杂,需要处理线程同步 | 一对多通信,RPC需求 |
Messagener | 功能一般,支持一对多串行实时通信 | 不能很好的处理高并发,不支持rpc(个人理解是因为单向通信,不支持返回),只能传递bundle支持的数据类型 | 低并发一对多计时通信无rpc,或者不需要的返回值的rpc请求 |
contentprovider | 在数据源访问方向功能强大,支持一对多并发数据共享,可通过call扩展操作 | 受约束的AIDL,提供CRUD操作 | 一对度进程间的数据共享 |