双进程保活思路学习总结
来源:互联网 发布:忠邦的梦 知乎 编辑:程序博客网 时间:2024/05/22 21:18
鸣谢:
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。这种机制是系统记得唤醒机制,能每隔多长时间监控服务是否还活着
- 双进程保活思路学习总结
- android保活进程总结--双进程保活策略
- Android 进程保活总结
- Android进程保活总结
- Android进程保活招式总结
- Android 进程保活技术总结
- 进程保活之双进程守护
- Android双进程保活机制示例
- Android双进程守护service保活
- 应用双进程白色保活
- 进程保活-踩坑篇
- Android进程保活
- 进程保活方法
- Android 进程保活
- Android进程保活
- Android进程保活
- 进程保活大全
- Android 进程保活
- linux防火墙iptables常用规则(屏蔽IP地址、禁用ping、协议设置、NAT与转发、负载平衡、自定义链)
- centos 7 redis远程连接
- 反射_案例2_根据参数类型获取构造器
- jquery checkbox 全部选择或全部取消
- 5 汽水瓶子
- 双进程保活思路学习总结
- 170915_Spring英文文档阅读(九)_2.3 Usage scenarios(一)
- WebView加载速度优化
- 9月14日云栖精选夜读:揭秘IPHONE X刷脸认证的技术奥秘
- 连咸鱼都能学会的Dubbo分布式服务框架入门(附工程)
- 电脑文档背景保护色--豆沙绿
- 《C++ Concurrency in Action》笔记2 线程函数传参(3)类成员函数
- STM32之GPIO原理
- 浅谈HTTP中Get与Post的区别