目录:
1、方案
2、进程
3、参考资料大集合
4、额外收获
这周因为公司接手的一个项目涉及到进程保活问题,小野猫在网上翻翻炒炒各种方案,着实费劲挣扎了一番。真真是从入门到放弃,当然跟各路大神的从入门到放弃在深度上还是有很大的差别的。无论如何,在此记录一番以留下鄙人在进程保活这条路上走过的痕迹。
路过且想直接翻更优良资料的小伙伴,请绕路到本文的第三部分:3. 资料大集合
1. 方案
有人说:
进程永生不死终究是个彻头彻尾的伪命题!
这些天瞧见的几种保活方案:
- 提升进程/服务优先级,降低被杀死的几率
- 利用系统广播唤醒
- 双进程守护,你被杀掉我来救
- 第三方SDK或其他APP,相互唤醒
- 传说中与厂商合作,添加白名单
方案很多,然而,没有添加白名单,怎么都不能完全做到的。
可参考资料:Android保证service不被杀掉-增强版: 进程保活(根据用户需求慎用)
我曾挣扎过的,大家都懂:
- 在Application,Service,Receiver标签内添加:
android : persistent = true
- 将Service设置为前台服务:在
onCreate()
方法中调用startForeground()
,在onDestroy()
中调用stopForeground()
。 - 在Service的
onDestroy()
中发送广播通知启动Service自己。 - 在Service的
onStartCommand()
方法设置返回值为START_STICKY
- 监听系统广播,时刻唤醒自己
其中ACTION_TIME_TICK每分钟发送一次,不过似乎不支持静态广播监听 - NDK做双进程守护
- 上面这些是代码层面上的做法,另外针对不同的厂商,指导用户在手机管家、i管家应用里做一些用户可操作的信任操作也是有必要的。
当然,并不是说挣扎后发现这些做法都没有用,而是无法保证进程一定不死。各个厂商有自己的一套内存管理机制,不在白名单内很难做到,要加入白名单也很难。
2. 进程
2.1. 进程分类
进程分为以下五个类别,对应五个级别,排列顺序按优先级从最高到最低。
传送门,咱去看看官方完整说明 ✈✈✈
- 前台进程(Foreground Process)
用户当前操作所必须的进程。 - 可见进程(Visible Process)
没有任何前台组件,但仍会影响用户在屏幕上所见内容的进程。 - 服务进程(Service Process)
正在运行已使用startService()
方法启动的服务的进程,而且该进程不属于“前台进程”和“可见进程”。 - 后台进程(Background Process)
包含了目前对用户不可见的Activity的进程(这个Activity已经调用了onStop()
方法)。 - 空进程(Empty Process)
不含任何活动应用组件的进程。之所以存在空进程的目的是做“缓存”。
如果要通过提高进程优先级来降低进程被杀死的可能性,首先我们得知道有哪些进程是前台进程。那么问题来了,什么进程会被定为前台进程呢?
下图就是官方正解了:
2.2. 进程被杀死的情况有哪些???
- 触发系统进程管理机制(调的接口是:
Lowmemorykiller
)
根据重要性的值,由大到小依次杀掉
- 没有root,被第三方应用杀死(调的接口是:
killBackgroundProcess
)
只会杀死OOM_ADJ值为4以上的进程
- 有root,被第三方应用杀死(调的接口是:
force-stop
或kill
)
理论上可杀掉所有进程,一般只杀非系统关键进程和非前台和可见进程
- 各厂商提供的杀进程的功能(调的接口是:
force-stop
或kill
)
理论上可以杀掉包括Native进程在内的所有进程
- 用户主动强行停止进程(调的接口是:
force-stop
)
只能停止第三方和非system/phone进程应用。
2.3. 进程回收机制:(LowMemoryKiller)
在2.2中我们提到,触发系统进程管理机制来杀死进程所调用的接口就是:LowMemoryKiller
,那么这个LowMemoryKiller
究竟是啥呢?
安卓开发过程中稍不注意很可能就出现OOM,这个大家都是知道的,不就是内存溢出么。LowMemoryKiller正是安卓系统对Linux内核的内存管理机制的一个增强。要说起来这个低内存管理机制跟内存溢出机制还带了几分血缘关系咧!
2.3.1. LowMemoryKiller原理:
Low Memory Killer在用户空间中指定了一组内存临界值,当其中的某个值与进程描述中的oom_adj
值在同一范围时,该进程将被Kill掉。
LowMemoryKiller在系统启动的时候就已经由init进程一并启动了。LowMemoryKiller启动就是,就会不断监测系统的运行情况和内存情况,当内存少于minfree文件中限定的阀值的时候,lowMemoryKiller遍历当前进程的oom_score_adj
,把大于对应阀值的进程进行kill操作。
2.3.2. AMS计算进程的优先级值
每个进程都有自己的oom_adj
和oom_score_adj
两个值,这两个值是由位于应用框架层中ActivityManager的AMS(ActivityManagerService)计算出来的。
oom_adj
代表进程的优先级,数值越高,优先级越低,越容易被杀死;对应每个oom_adj都可以有一个空闲进程的阀值。Android Kernel每隔一段时间会检测当前空闲内存是否低于某个阀值。假如是,则杀死oom_adj最大的不必要的进程,如果有多个,就根据oom_score_adj
去杀死进程,,直到内存恢复低于阀值的状态。
2.3.3. 设定LowMemoryKiller对照值的两个文件
- adj文件:
/sys/module/lowmemorykiller/parameters/adj
保存着当前系统杀进程的等级 - minfree文件:
/sys/module/lowmemorykiller/parameters/minfree
。
保存对应的阀值。
下图是oom_adj的级别对照说明:
红色部分 代表比较容易被杀死的 Android 进程
绿色部分 表示不容易被杀死的 Android 进程
其他 表示非 Android 进程
下图是Android6.0中设定的16个adj值及其对应的说明:
有关AMS的参考资料:Android核心分析之AMS
有关LowMemoryKiller的参考资料:Android 6.0的lowmemorykiller机制
开发不死软件,从系统性能方面来说是很不利的,当手机上这样的应用多了,系统就危险了。但是另一方面,有些应用为了保证用户体验不得不让自己的进程保持不死状态,比如说来电秀、即时通讯等类型的APP。无论是出于学习还是出于工作需要,了解下无妨。
3. 参考资料大集合
传说中大冰哥的系列文章(这家伙人长得帅,文写得好,知乎上的问答也棒棒的!如我这般生活在安卓开发最底层的贫下中农就该多看看多学习):
关于 Android 进程保活,你所需要知道的一切
Android后台杀死系列之一:FragmentActivity及PhoneWindow后台杀死处理机制
Android后台杀死系列之二:ActivityManagerService与App现场恢复机制
Android后台杀死系列之三:LowMemoryKiller原理(4.3-6.0)
Android后台杀死系列之四:Binder讣告原理
此外更有好文:
Android 进程保活招式大全
论Android应用进程长存的可行性
微信Android客户端后台保活经验分享
Android进程保活的一般套路
Android进程保活-自“裁”或者耍流氓
关于进程保活的两三事——新手升级经验卡
Android 进程保活都在这里
Hello-Daemon【github】
4. 额外收获
搜集资料过程中发现,有些程序开发小伙伴在接到需求后会先针对需求进行深入思考再开始投入实际的工作,是个很不错的工作方式,避免了在工作过程中陷入“搜索资料-思考-实践-再搜集资料-再思考-再实践”的不良循环中。大概方向先把控好无形之中能很大地提高工作效率。