Android 中的多进程
- 扩大应用使用内存
adb shell getprop dalvik.vm.heapsize查看当前应用内存上限
- 可以将容易出错的代码丢进特定进程, 这样,在特定进程崩掉,不至于引起应用所有进程崩掉。
- 推送
推送需要通过跨进程的方式,完成消息传递。 极光推送,本质是集成了各家运营商的推送服务。极光内部做了分发。
多进程的实现
- binder
- socket
- 共享内存
Android 从安全性、性能方面,最终选择了综合考虑选择了 binder. 其中的 性能通过 mmp 保证。
mmp: memory map. 将客户端进程的内存信息拷贝至 内核后, 通过 mmp 将 客户端的内存地址和服务端的内存地址放在了同一逻辑地址中。
Binader 如何用
AIDL, binder 的使用是很复杂了, 为了让开发者逃离琐碎复杂语法, Android 提供了 AIDL 简化了整个跨进程的流程。
应用场景
- 在 Service 中,维持一个列表,并暴露方法
addBook往列表中添加数据。 - Client 想展示 Service 中列表个数。
现象
如果 service 与 client 在统一进程, 那么 onConnect 中 binder 就是 service 中 onBind 中返回的 binder。
onBind()) binder: com.aidldemo.MyService$1@27bd08d currentThread:Thread[main,5,main]
onServiceConnected: binder: com.aidldemo.MyService$1@27bd08d currentThread:Thread[main,5,main]
如果 service 设置在 remote Process, client 中 onConnect 中 binder 和 service 中 onBind 中 binder 是不一样的对象。 client 中的是一个 proxy.
onBind()) binder: com.aidldemo.MyService$1@f3115ed currentThread:Thread[main,5,main]
onServiceConnected: binder: android.os.BinderProxy@7537253 currentThread:Thread[main,5,main]
分析
以上现象表明,如果服务和绑定者在同一个进程,那么Client的onServiceConnected(ComponentName name, IBinder binder)的 binder 就是服务端的 binder. 否则就返回android.os.BinderProxy。
很明显,BinderProxy 中就有跨进程的能力。
接着执行 IBookManager.Stub.asInterface(binder) 如果是同一个进程逻辑,就直接通过 binder 执行服务端的 binder 逻辑。 如果非一个进程, 就要将 BinderProxy 丢进 IBookManager.Stub.Proxy, 在 Proxy 中, 就利用 BinderProxy的跨进程能力,进行跨进程操作。即此时我在 client 端调用 addBook 的逻辑已经流转至 IBookManager.Stub.Proxy , 具体我们可以来看看源码:
private static class Proxy implements com.aidldemo.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 void addBook(com.aidldemo.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);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBook(book);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
上面的流程, 就帮我们将 addBook 的流程从客户端流转到了服务端。