鸣谢:
http://www.jianshu.com/p/810ecb80a96f
http://www.jianshu.com/p/28c5377c77c4
Demo地址:
https://github.com/jigongdajiang/FunDemo/tree/master
IPC
简写:Inter Progress Communication 进程间通讯/跨进程通讯 > Why?: Android 为了保证进程间互补影响,进行了进程隔离,保证每个进程都有一个独立的虚拟空间,但是进程间有时候又不可能没有交流,于是就有了IPC机制
What?: AIDL文件其实就是一种协议文件,一般规定了服务端具备的功能接口
服务端Service中返回IBinder对象为 AIDL文件生成Java文件后的内部类Sub
客户端bindService,在ServiceConnection中的连接成功方法中会返回一个IBinder对象,通过AIDL对应的java类的asInterface方法可以将IBinder转为AIDL对应的java类,通过这个类既可以调用服务端中提供的功能
源码:AIDL对应的Java文件架构
//其本身是个接口,里面有定义的功能方法 和一个 Sub内部抽象类
public interface UserAidl extends android.os.IInterface {
/**
* 内部类继承Binder 且实现了UserAidl 而Binder 实现了IBinder Binder中有一些Native方法
*/
public static abstract class Stub extends android.os.Binder implements gjg.com.fundemo.UserAidl {
//AIDL的唯一标示,用来供底层区分
private static final java.lang.String DESCRIPTOR = "gjg.com.fundemo.UserAidl";
/**
* stub与接口关联
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 这就是客户端连接成功后使用的方法,最终用来返回一个Proxy
*/
public static gjg.com.fundemo.UserAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof gjg.com.fundemo.UserAidl))) {
return ((gjg.com.fundemo.UserAidl) iin);
}
return new gjg.com.fundemo.UserAidl.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 处理,主要讲服务端的数据写入到reply中
*/
@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_getUserName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getUserName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getUserPwd: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getUserPwd();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 客户端得到真正对象
*/
private static class Proxy implements gjg.com.fundemo.UserAidl {
//这个很关键,是IBinder对象,客户端调用服务端的中间桥梁
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.lang.String getUserName() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//最终会通过上面的onTransact 得到有将服务端数据写好了的_reply,从而客户端才能拿到
mRemote.transact(Stub.TRANSACTION_getUserName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public java.lang.String getUserPwd() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getUserPwd, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getUserName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getUserPwd = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* 将在服务端真实的实现,供客户端和服务端的中间的IBinder中onTranst方法使用
*/
public java.lang.String getUserName() throws android.os.RemoteException;
public java.lang.String getUserPwd() throws android.os.RemoteException;
}
android IPC原理源码,也就是为啥bindservice后最终能得到一个IBinder对象,从能通过AIDL协议实现交互
这里就要涉及到源码流程如下
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
//交由方法实现
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
...
// 调用ActivityManagerNative.getDefault().bindService方法
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
// binderService获取的也是一个远程服务的Binder对象,也是跨进程,而ServiceManager就是上面
// 流程图里用来管理这些服务和Binder驱动
IBinder b = ServiceManager.getService("activity");
// 获取到ActivityManager的管理类,最终调用ActivityManagerService是一个典型的跨进程通讯,
IActivityManager am = asInterface(b);
}
private final boolean requestServiceBindingLocked(...){
//ActivityThread的方法
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
}
public final void scheduleBindService(...){
...
handleBindService((BindServiceData)msg.obj);
}
private void handleBindService(BindServiceData data) {
...
Service s = mServices.get(data.token);
...
// 果真调用了service的onBind方法
IBinder binder = s.onBind(data.intent);
// 然后把返回的binder实例公开回调出去
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
}
双进程保活
历史:进程进入后台,被系统干掉,收不到消息了。用户直接把程序拉掉了,毛都不剩了。第三方给强制停止了。现在需求是不能让程序挂掉,要向QQ微信似的打不死
系统对进程的级别判定:
前台进程:用户操作着呢。
Activity已OnResume了
某个Service绑定了正在交互的Activity
Service调了startForeground
Service整执行生命周期呢
正在执行onReceive的BroadcastReceiver可见进程:还有东西可见,但是不交互了
Activity已经onPause了
Service绑定着onPause的Activity服务进程
正在运行使用startService启动的服务,又不属于前两者。这个一般用来在后台播放音乐或者下载任务后台进程
Activity都不可见了也就是onStop了。这时候进程会进入LRU列表中,在内存足够的情况,方便用户能从后台直接切到前台空进程
完全退了了的进程。最容易被干掉。一般也会保留会,目的是为了缓存,方便下次启动的时候能快些其它情况
服务进程要比后台进程高,也就是说Service中执行的要比放到后台的Activity的级别高。因此,一些在Activity理执行时间较长的操作应该交给Service来完成,例如图片上传。
杀进程机制LowMemoryKiller机制:
剩余内存(lowmem_minfree)越小,警戒级别(lowmen_adj)越高,杀的越狠。同级别的先杀占用内存较多的
针对系统的保活方案(这只是针对我们的进程的系统层,但是主要问题针对Rom厂商和第三方软件清理是的保活)
提高进程级别也就是减小警戒级别
减少内存消耗,尤其是当进入后台时要及时释放资源,最大程度的减少内存占用,这样目的就是保证剩余内存尽量多些
后台的Service要轻一些
针对手动或者第三方软件对后台进程的清理的保活方案
建立两个Service,一个是主Service,处理主业务的,另一个是保活Service,这个Service不在主进程,而是单独一个进程。这两个Service通过IPC机制通讯,当启动一个挂掉时互相启动唤醒。这样能保证程序在后台不会被轻易清理,能这样也是因为进程被杀是按顺序杀的。但是这种方案不适用程序被拉掉或者被第三方软件干掉。
针对Rom或者第三方清理软件的保活方案
面对各大厂商其实总有各种草泥马再跑,这对这种情况的保活,这里我们采用JobService + JobScheduler。这种机制是系统记得唤醒机制,能每隔多长时间监控服务是否还活着