Android多进程保活

1 简介

   在Android 4.4及以后的系统中,应用能否常驻内存,一直以来都是相当头疼的事情,尤其移动端IM、消息推送这类应用,为了保证“全时在线”的概念,真是费尽了心思。虽然APP常驻内存对于用户来说比较”恶心”,但是在诸如IM和消息推送这类场景来说,APP的常驻内存却尤其重要。
  此次将对Android的进程保活方案进行调研,避免android程序因系统资源紧张或用户主动去清理应用而导致的程序被系统杀死,导致“行啊”无法实时的接收最新的消息推送和通知。通过调研,了解系统为什么会杀掉进程,杀的为什么是我的进程,这是按照什么标准来选择的,是一次性干掉多个进程,还是一个接着一个杀,保活套路一堆,如何进行进程保活才是比较恰当以及实现思路。


2 Android进程

2.1 概述

  Android应用启动后至少对应一个进程,有的是多个进程,而且主流应用中多个进程的应用比例较大。

2.2 进程分类

2.2.1 前台进程

  用户正在使用的程序,一般系统是不会杀死前台进程的,除非用户强制停止应用或者系统内存不足等极端情况会杀死。

场景
  • 某个进程持有一个正在与用户交互的Activity并且该Activity正处于resume的状态。
  • 某个进程持有一个Service,并且该Service与用户正在交互的Activity绑定。
  • 某个进程持有一个Service,并且该Service调用startForeground()方法使之位于前台运行。
  • 某个进程持有一个Service,并且该Service正在执行它的某个生命周期回调方法,比如onCreate()、 onStart()或onDestroy()。
  • 某个进程持有一个BroadcastReceiver,并且该BroadcastReceiver正在执行其onReceive()方法。

2.2.2 可见进程

  • 我们的Activity处在onPause()(没有进入onStop())
  • 绑定到前台Activity的Service。

2.2.3 服务进程

  简单的startService()启动。

2.2.4 后台进程

  • 对用户没有直接影响的进程—-Activity出于onStop()的时候。
  • android:process=”:xxx”

2.2.5 空进程

  不含有任何的活动的组件。(android设计的,为了第二次启动更快,采取的一个权衡)

2.3 内存阈值

  系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app, 这套杀进程回收内存的机制就叫 Low Memory Killer。那这个不足怎么来规定呢,那就是内存阈值。内存阈值在不同的手机上不一样,一旦低于该值,Android便开始按顺序关闭进程.

2.4 进程被杀死的优先级

  现在要杀后台进程,但是手机中后台进程很多,难道要一次性全部都清理掉?当然不是的,进程是有它的优先级的,这个优先级通过进程的adj值来反映,它是linux内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。
  adj越大,占用物理内存越多会被最先kill掉。那么现在对于进程保活这个问题就转化成如何降低adj的值,以及如何使得我们应用占的内存最少。

3 进程保活方案

当前业界的Android进程保活手段主要分为 黑、白、灰 三种,其大致的实现思路如下
  • 黑色保活:不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
  • 白色保活:启动前台Service
  • 灰色保活:利用系统的漏洞启动前台Service

3.1 黑色保活

  所谓黑色保活,就是利用不同的app进程使用广播来进行相互唤醒。

常见的应用场景如下
  • 监控系统的广播,如开机,网络切换等,唤醒进程
  • 利用App自身,发出广播或者启动服务。比如打开阿里系的任意一款APP,都可能会激活其他阿里系App的进程

  针对第一种方案,谷歌已经做了部分处理,禁止监控系统级别的某些广播,比如网络切换;第二种方案的使用范围相对更广,更实用。

3.2 白色保活

  白色保活手段非常简单,就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台。常见的音乐播放器都是采用该方案。
  粘性服务这个是系统自带的,onStartCommand方法必须具有一个整形的返回值,这个整形的返回值用来告诉系统在服务启动完毕后。Service的onStartCommand方法里返回 STATR_STICK,onDestory中start自启(准确的将算不上进程拉活,只能算service自启,force_stop后不能正常拉活)。

3.3 灰色保活

  灰色保活,这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大致的实现思路如下:

  • API < 18,启动前台Service时直接传入new Notification();
  • API >= 18,同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理;

  当某一天 API >= 18 的方案也失效的时候,我们就又要另谋出路了。需要注意的是,使用灰色保活并不代表着你的Service就永生不死了,只能说是提高了进程的优先级。如果你的app进程占用了大量的内存,按照回收进程的策略,同样会干掉你的app。

  另外一种灰色保活方案是开启一个像素Activity。在锁屏的时候在本进程开启一个Activity,为了欺骗用户,让这个Activity的大小是1像素,并且透明无切换动画,在开屏幕的时候,把这个Activity关闭掉,所以这个就需要监听系统锁屏广播。我们的应用就始终和前台进程是一样的优先级了,为了省电,系统检测到锁屏事件后一段时间内会杀死后台进程,如果采取这种方案,就可以避免了这个问题,但是还是有被杀掉的可能。

4 APP进程不死的秘密

  许多大厂的APP,比如微信,QQ,支付宝等,你在使用的时候会发觉,他们的进程是不会被系统杀死,而且在启动一系列内存清理工具进行强制清理,也只是暂时杀死进程或者根本不能杀死。那么他们拥有什么秘密武器,可以保证进程不死呢?答案就是白名单。有些手机厂商把这些知名的app放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、QQ、陌陌都在小米的白名单中)。如果从白名单中移除,他们终究还是和普通app一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧。

5 总结

  从保活这一点来说,黑色保活和白色保活方案相对较好;灰色保活方案可行性虽然很高,可以但是对用户来说太流氓了,不推荐。 对于有硬性需求的,可以引导用户加入白名单。至于推送, 可以尝试集成多个推送方案,小米,华为等都有推送sdk,在对应手机上可以确保收到消息, 然后像百度这种是多app公用通道的,也就是手机中有一个使用百度推送的app被允许后台启动,就能让其他app收到推送。随着Android版本的不断更新及国内厂商对ROM的不断优化,如何最大可能的对进程保活,是Android一道需要长期钻研的学问,也是Android开发者不得不面对的问题。进程保活的根本方案终究还是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!

6 参考

https://www.jianshu.com/p/1c353edf73ba
https://segmentfault.com/a/1190000006251859
https://www.jianshu.com/p/63aafe3c12af

猜你喜欢

转载自blog.csdn.net/weixin_40876113/article/details/80830795