IPC在android主要是利用了binder
android中的多进程模式
利用android:process在AndroidManifest指定(常用方法)
(默认是包名,“:”的含义是指要在当前的进程名前面附加上当前的包名,这是一种简写方法。 其次,进程名以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而进程名不以“:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。)
通过JNI在native层去fork一个新的进程(非常规方法)
android系统会为每个应用分配一个唯一的UID,具有相同的UID的应用可以共享应用数据(data目录,组件信息),如果它们不仅ShareUID相同并且具有相同的签名,这两个应用可以跑在同一个进程,那它们可以共享内存数据。
多进程模式的运行机制
多进程会造成如下几方面的问题
(1)静态成员和单例模式完全失效
(2)线程同步机制完全失效
(3)SharePreference的可靠性下降
(4)Application会多次创建
前面1、2问题,因为多个应用会有多个虚拟机环境,不同虚拟机环境,对于同一个类,有不同的副本,锁也是一样,第三个问题SharePreference底层是通过读写XML来实现的,并发读写会使数据变得不可靠。第4个问题跟前面的一样,多进程模式中,不同进程的组件会拥有独立的虚拟机,Application以及内存空间。
IPC基础概念介绍
Serializable接口
serialVersionUID是用来辅助序列化和反序列化过程的,序列化的时候系统会把当前类的serialVersionUID写入序列化文件中,当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致说明序列化的类的版本和当前版本相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变换,比如成员变量的恶数量、类型可能发生了改变。
Parcelable接口
writeToParcel,序列化
CREATOR,反序列化
Binder
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file:
*/
package com.ryg.chapter_2.aidl;
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.ryg.chapter_2.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager interface,
* generating a proxy if needed.
*/
public static com.ryg.chapter_2.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.ryg.chapter_2.aidl.IBookManager))) {
return ((com.ryg.chapter_2.aidl.IBookManager) iin);
}
return new com.ryg.chapter_2.aidl.IBookManager.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_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ryg.chapter_2.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.ryg.chapter_2.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.ryg.chapter_2.aidl.IBookManager {
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 java.util.List<com.ryg.chapter_2.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.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException;
public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
}
DESCRIPTOR
Binder的唯一标识,一般用类名表示
asBinder
返回当前Binder对象
onTransact
运行在服务端的Binder线程池,返回值Boolean可以用作权限验证
Proxy#getBookList
客户端调用,_data写入参数,接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起,然后服务端的 onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果:最后返回_reply中的数据。
linkToDeath和unlinkToDeath
如果服务端进程由于某种原因异常终止,,这个时候我们到服务端的Binder连接断裂。这样可以设置死亡代理DeathRecipient
可在回调方法binderDied中unlinkToDeath并且尝试重新绑定service.
然后在连接成功时linkToDeath,当Binder死亡的时候我们就可以收到通知拉。
Android中的IPC方式
Bundle(支持Intent传输,只支持bundle支持的数据类型)
使用文件共享(适合对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读和写问题)
使用Messenger(基于AIDL,跨进进程串行的进行消息传递,不支持高并发场合)
使用AIDL(适用于跨进程调用服务端的方法,支持高并发)
注意几点:
1.AIDL中除了基本数据类型,其他类型的参数必须标上方向(in,out,inout)
2.应该把所有和AIDL相关的类和文件全部放入同一个包里面,方便以后同步服务端和客户端的项目结构。
3.为了支持服务端高并发的需求,应该使用支持高并发的集合类,比如CopyOnWriteArrayList和CocurrentHashMap,binder会按照相应集合的规范访问数据并形成一个新的集合对象返回给客户端。
4.RemoteCallbackList是系统专门提供的用于删除跨进程listener的接口。原理是,虽然注册和解注册的时候listeners不同,它可以记录和管理binder相同的listeners,所以注册和解注册的时候就可以得心应手了。遍历RemoteCallbackList时需要配套使用beginBroadcast和finishBroadcast。
5.在客户端调用服务端远程方法时,需要处理线程挂起问题,避免ANR。服务端回调客户端方法的时候也要同样注意ANR问题。
6.DeathRecipient.binderDied方法是在客户端的Binder线程池中被回调。
7.权限验证机制。可以在onbind的时候进行权限验证,也可以在onTransact中进行包名验证和权限验证。
使用ContentProvider
(底层是实现是Binder,系统提供CRUD,四大方法运行在binder线程池,回调方法运行在UI线程)
使用socket
(TCP和UDP)
Binder连接池
一个Service可以完成多个AIDL接口的工作