双进程保活思路学习总结

本文探讨了Android进程间通讯(IPC)的原理,特别是AIDL的使用,以及如何通过双进程保活策略使应用在后台保持活跃,类似于QQ和微信。详细介绍了Android进程的生命周期、内存管理机制LowMemoryKiller,以及针对系统、手动清理和Rom/第三方软件清理的保活解决方案,如Service之间的相互启动唤醒和使用JobService + JobScheduler进行系统级监控。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

鸣谢:
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。这种机制是系统记得唤醒机制,能每隔多长时间监控服务是否还活着

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值