双进程保活思路学习总结

来源:互联网 发布:忠邦的梦 知乎 编辑:程序博客网 时间: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。这种机制是系统记得唤醒机制,能每隔多长时间监控服务是否还活着

原创粉丝点击