美文网首页
进程保活

进程保活

作者: Coder_Sven | 来源:发表于2019-12-18 11:38 被阅读0次

    进程保活的关键点有两个,一个是进程优先级的理解,优先级越高存活几率越大。二是弄清楚哪些场景会导致进程会kill,然后采取下面的策略对各种场景进行优化:

    1. 提高进程的优先级
    2. 在进程被kill之后能够唤醒

    进程优先级

    Android一般的进程优先级划分:
    ​ 1.前台进程 (Foreground process)
    ​ 2.可见进程 (Visible process)
    ​ 3.服务进程 (Service process)
    ​ 4.后台进程 (Background process)
    ​ 5.空进程 (Empty process)
    ​ 这是一种粗略的划分,进程其实有一种具体的数值,称作oom_adj,注意:数值越大优先级越低:

    1,Activity提权

    原理:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素透明的 Activity,在用户解锁时将 Activity 销毁掉,从而达到提高进程优先级的作用。

    造一个一个像素的Activity

    public class KeepActivity extends Activity {
        private static final String TAG = "KeepActivity";
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.e(TAG,"启动Keep");
            Window window = getWindow();
            //设置这个activity在左上角
            window.setGravity(Gravity.START | Gravity.TOP);
            WindowManager.LayoutParams attributes = window.getAttributes();
            //宽高为1
            attributes.width = 1;
            attributes.height = 1;
            //起始位置左上角
            attributes.x = 0;
            attributes.y = 0;
            window.setAttributes(attributes);
    
            KeepManager.getInstance().setKeepActivity(this);
        }
    }
    

    监听系统开屏或者息屏的广播

    public class KeepReceiver extends BroadcastReceiver {
        private static final String TAG = "KeepReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.e(TAG, "receive:" + action);
            if (TextUtils.equals(action, Intent.ACTION_SCREEN_OFF)) {
                //灭屏 开启1px activity
                KeepManager.getInstance().startKeep(context);
            } else if (TextUtils.equals(action, Intent.ACTION_SCREEN_ON)) {
                //亮屏 关闭
                KeepManager.getInstance().finishKeep();
            }
        }
    }
    
    public class KeepManager {
        private static final KeepManager ourInstance = new KeepManager();
    
        public static KeepManager getInstance() {
            return ourInstance;
        }
    
        private KeepManager() {
        }
        private KeepReceiver keepReceiver;
        private WeakReference<Activity> mKeepActivity;
        /**
         * 注册
         * @param context
         */
        public void registerKeepReceiver(Context context){
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            filter.addAction(Intent.ACTION_SCREEN_ON);
            keepReceiver = new KeepReceiver();
            context.registerReceiver(keepReceiver, filter);
        }
    
        /**
         * 反注册
         * @param context
         */
        public void unRegisterKeepReceiver(Context context){
            if (null != keepReceiver) {
                context.unregisterReceiver(keepReceiver);
            }
        }
    
        /**
         * 启动1个像素的KeepActivity
         * @param context
         */
        public void startKeep(Context context) {
            Intent intent = new Intent(context, KeepActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    
        /**
         * finish1个像素的KeepActivity
         */
        public void finishKeep() {
            if (null != mKeepActivity) {
                Activity activity = mKeepActivity.get();
                if (null != activity) {
                    activity.finish();
                }
                mKeepActivity = null;
            }
        }
    
        public void setKeepActivity(KeepActivity mKeepActivity) {
            this.mKeepActivity = new WeakReference<Activity>(mKeepActivity);
        }
    }
    

    2,Service提权

    创建一个前台服务用于提高app在按下home键之后的进程优先级

    startForeground(ID,Notification):使Service成为前台Service。 前台服务需要在通知栏显示一条通知

    public class ForegroundService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel("sven", "sven",
                        NotificationManager.IMPORTANCE_LOW);
                NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                if (manager == null)
                    return;
                manager.createNotificationChannel(channel);
    
                Notification notification = new NotificationCompat.Builder(this, "sven").setAutoCancel(true).setCategory(
                        Notification.CATEGORY_SERVICE).setOngoing(true).setPriority(
                        NotificationManager.IMPORTANCE_LOW).build();
                startForeground(10, notification);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                //如果 18 以上的设备 启动一个Service startForeground给相同的id
                //然后结束那个Service
                startForeground(10, new Notification());
                startService(new Intent(this, InnnerService.class));
            } else {
                startForeground(10, new Notification());
            }
        }
    
        public static class InnnerService extends Service {
    
            @Override
            public void onCreate() {
                super.onCreate();
    
                //发送相同的Notification,然后将其取消并取消自己的前台显示
                Notification.Builder builder = new Notification.Builder(this);
                startForeground(10, new Notification());
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        stopForeground(true);
                        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                        manager.cancel(10);
                        stopSelf();
                    }
                },100);
            }
    
            @Nullable
            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
        }
    }
    
    

    3,广播拉活

    在发生特定系统事件时,系统会发出广播,通过在 AndroidManifest 中静态注册对应的广播监听器,即可在发生响应事件时拉活。但是从android 7.0开始,对广播进行了限制,而且在8.0更加严格

    4,全家桶拉活

    有多个app在用户设备上安装,只要开启其中一个就可以将其他的app也拉活。比如手机里装了手Q、QQ空间、兴趣部落等等,那么打开任意一个app后,其他的app也都会被唤醒。

    5,Service机制(Sticky)拉活

    将 Service 设置为 START_STICKY,利用系统机制在 Service 挂掉后自动拉活

    只要 targetSdkVersion 不小于5,就默认是 START_STICKY。
    但是某些ROM 系统不会拉活。并且经过测试,Service 第一次被异常杀死后很快被重启,第二次会比第一次慢,第三次又会比前一次慢,一旦在短时间内 Service 被杀死4-5次,则系统不再拉起。

    6,JobScheduler拉活

    JobScheduler允许在特定状态与特定时间间隔周期执行任务。可以利用它的这个特点完成保活的功能,效果即开启一个定时器,与普通定时器不同的是其调度由系统完成。

    @SuppressLint("NewApi")
    public class MyJobService extends JobService {
        private static final String TAG = "MyJobService";
    
        public static void startJob(Context context) {
            JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
                    Context.JOB_SCHEDULER_SERVICE);
            JobInfo.Builder builder = new JobInfo.Builder(10,
                    new ComponentName(context.getPackageName(),
                            MyJobService.class.getName())).setPersisted(true);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                //7.0以上延迟1s执行
                builder.setMinimumLatency(1000);
            }else{
                //每隔1s执行一次job
                builder.setPeriodic(1000);
            }
            jobScheduler.schedule(builder.build());
        }
    
        @Override
        public boolean onStartJob(JobParameters jobParameters) {
            Log.e(TAG,"开启job");
            //7.0以上轮询
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                startJob(this);
            }
    
            return false;
        }
    
        @Override
        public boolean onStopJob(JobParameters jobParameters) {
            return false;
        }
    }
    

    7,推送拉活

    根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送。

    8,Native拉活

    Native fork子进程用于观察当前app主进程的存亡状态。对于5.0以上成功率极低。

    9,双进程守护

    两个进程共同运行,如果有其中一个进程被杀,那么另外一个进程就会将被杀的进程重新拉起

    参考代码:

    [https://github.com/games2sven/ProcessLiving]:

    相关文章

      网友评论

          本文标题:进程保活

          本文链接:https://www.haomeiwen.com/subject/pqnxjctx.html