Android进程保活实践:上篇 | 08_carmelo

前言

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

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

进程优先级

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

  • 红色部分是容易被回收的进程,属于android进程
  • 绿色部分是较难被回收的进程,属于android进程
  • 其他部分则不是android进程,也不会被系统回收,一般是ROM自带的app和服务才能拥有

如何查看某个进程的oom_adj数值呢?
oom_adj 存储在proc/PID/oom_adj文件中,其中PID是进程的id,直接 adb shell进入手机根目录查看这个文件即可。

演示一下:以我自己的项目为例,app中有两个进程,一个是主进程,另一个是运行service的进程取名为:remote。首先用android studio查看每个进程的PID:

然后分别查看app在前台,app退到后台,这2中场景主进程的oom_adj数值:

可见,当app在前台时 oom_adj = 0,对应上面的表格是前台进程。
当app退到后台时,oom_adj = 6,对应后台进程。然后查看运行着service的进程:

ok,知道了进程优先级的概念以及如何查看优先级,我们就可以对app进程优化,然后通过查看这个数值判断我们的优化是否有效果。

进程被kill的场景

1.点击home键使app长时间停留在后台,内存不足被kill

处理这种情况前提是你的app至少运行了一个service,然后通过Service.startForeground() 设置为前台服务,可以将oom_adj的数值由4降低到1,大大提高存活率。

  • 要注意的是android4.3之后Service.startForeground() 会强制弹出通知栏,解决办法是再启动一个service和推送共用一个通知栏,然后stop这个service使得通知栏消失。
  • Android 7.1之后google修复这个bug,目前没有解决办法
    下面的代码放到你的service的onStartCommand方法中:

<

经过改进之后,再来看下这个后台service进程的oom_adj,发现被提升为前台进程。

2.在大多数国产手机下,进入锁屏状态一段时间,省电机制会kill后台进程

这种情况和上面不太一样,是很过国产手机rom自带的优化,当锁屏一段时间之后,即使手机内存够用为了省电,也会释放掉一部分内存。

策略:注册广播监听锁屏和解锁事件, 锁屏后启动一个1像素的透明Activity,这样直接把进程的oom_adj数值降低到0,0是android进程的最高优先级。 解锁后销毁这个透明Activity。这里我把这个Activity放到:remote进程也就是我那个后台服务进程,当然你也可以放到主进程,看你打算保活哪个进程。

我们可以写一个KeepLiveManager来负责接收广播,维护这个Activity的常见和销毁,注意锁屏广播和解锁分别是:ACTION_SCREEN_OOF和ACTION_USER_PRESENT,并且只能通过动态注册来绑定,并且是绑定到你的后台service里面,onCreate绑定,onDestroy里面解绑

配好之后把手机锁屏,看下:remote进程的oom_adj:

3. 用户手动释放内存:包括手机自带清理工具,和第三方app(360,猎豹清理大师等)

清理内存软件会把 优先级低于 前台进程(oom_adj = 0)的所有进程放入清理列表,而当我们打开了清理软件就意味着其他app不可能处于前台。所以说理论上可以kill任何app。
以360安全卫士为例,打开内存清理:

因此这类场景唯一的处理办法就是加入 手机rom 白名单,比如你打开小米,魅族的权限管理 -> 自启动管理可以看到 QQ,微信,天猫默认被勾选,这就是厂商合作。那我们普通app可以这么做:在app的设置界面加一个选项,提示用户自己去勾选自启动,我封装了一个工具类给出国内各厂商的自启动的Intent跳转方法:

补充几点:

  • 额外说下 自启动是什么意思? 网上都是小米开启自启动就是加入白名单,其实根本不是这样的,经过实测就算app勾选自启动也会被内存优化加速清理掉,只不过进程会在半分钟后复活。
  • 除了还有自启动还有一个设置就是电池管理,比如小米的神隐模式,这部分和自启动不同的是它是管理app在锁屏之后被省电机制杀死的场景,当然每家厂商也有对应的Intent跳转路径。
  • 如何查找不同厂商的设置界面跳转Intent,比如上面的国内手机厂商白名单,给个方法:(前提是你有N多个不同手机,像我这样。。。)

在酷安应用市场下载一个叫 当前Activity 的app,打开后可以看到当前界面的className,例如:

就找到了魅族MX4 pro 后台权限的Activity。

进程唤醒

分两种情况,一是主进程(含有Activity没有service),这种进程由于内存不足被kill之后,用户再次打开app系统会恢复到上次的Activity,这个不在本文话题之内。另一种是service的后台进程被kill,可以通过service自有api来重启service:

配好START_STICKY后,通过android studio 释放进程的工具测试下,可以发现:remote进程被kill之后马上重启了:

但它不是100%保证重启成功,比如下面2种情况:(本人经过测试,这里就不放效果图了)

  • Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。
  • 进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。

总结

本文通过两种 提高进程优先级的方法,针对锁屏 和非锁屏模式下进程在后台被kill的场景处理,把后台进程优先级提升到可见级别,基本可以保证绝大多数场景不会被kill。另外,针对含有service的进程被kill给出了可唤醒的办法。

最后,我将进程保活的代码上传到了Github,地址:
https://github.com/08carmelo/android-keeplive


韩小告

14楼 · 2018.07.29 14:35

app退到后台时,oom_adj = 6,对应后台进程。

adj=6是home进程, app退入后台理论上应该进adj_previous 很明显你得到的结果应该是在厂商客制化过的设备上得出来的。

四喜汤圆
13楼 · 2018.04.21 00:04

楼主我的问题是:寻找跳转到不同手机厂商设置界面的方法时,如果没有你这么多真机,该用什么方法去获得?

刷机,刷各家的rom。。。
2018.04.30 22:09
@四喜汤圆 直接使用adb shell 打印当前的act 就可以看到了

2018.08.03 07:54
广陵墨玉刀

12楼 · 2018.04.12 16:37

一像素保活,STAT_STICKY,申请自启权限,前台进程等,在华为手机7.0的系统上都不好用,我有个需求是获取用户轨迹,只要不强制退出,就常驻后台,但是华为手机7.0可以活半个小时8.0就20s就死了,请问下楼主有什么其他的方法吗?

Android7.0之后是无效的,文中也有说明,暂时没有解决办法(除了引导用户加入白名单)
2018.04.13 16:50
@广陵墨玉刀 楼主这篇的些地方有问题,在安卓6.0 上, 系统锁屏后,并不会回收你的进程,系统会让你的应用进程进入 挂起状态,也就是阻塞状态, 进程仍然存在,只是进程暂停运行了,这种模式叫 doze mode, 官网有介绍。

另外,你反应的华为手机 前台进程保活无效,给你推荐个方案: 锁屏后循环播放无声音乐,解释后停止播放,实测在华为能永久保活,我们项目中就有用到。

2018.08.16 22:56
@安卓猿 我后面也用到了,也是这种多媒体锁的方式。

2018.08.17 14:13
@安卓猿 在不考虑耗电的情况下,这种方案可能是现在最有可能保活的方案了,类似QQ音乐,你在后台听歌能听到没电

2018.09.28 15:18
@贺岗 对,只要你的应用播放了无声音乐,锁屏后你的进程仍然能正常运行,也就你是的进程中的各种线程都能正常执行, 但是在安卓8.0后,系统的一些传感器如 gps模块、方向传感器 等 会被系统禁用,这些传感器所对应的回调将不会再回调,你的业务代码也就得不到响应
2018.09.28 15:23
萬物並作吾以觀復

11楼 · 2018.04.11 11:18

进程保活是一个伪命题

飞奔的小马
10楼 · 2018.04.10 11:47

楼主,在华为手机7.0系统上进程退到后台过一会还是会被杀了,自启动都启不起来,有啥好办法没

L_栗子
9楼 · 2018.04.10 09:56

进程唤醒
分两种情况,一是主进程(含有Activity没有service),这种进程由于内存不足被kill之后,用户再次打开app系统会恢复到上次的Activity,关于这种方法,楼主有什么好的文章链接或者思路给分享一下,一直比较困惑,感谢了!

c459beb59113
8楼 · 2018.04.09 10:42

美团用了进程保活的,7.1的手机每次都要点开通知强行杀死进程,这样真的很烦...

神奇的小蘑菇
6楼 · 2018.03.13 11:23

在中国安卓环境下除非进入c层编写代码,进行进程保活,否则其他的手段几乎没有作用。

我爱丽
5楼 · 2018.03.07 23:22

这些都用过,用了好多测试机,只有oppo一款活着?

怎么测试的
2018.03.08 15:44
东冬_6ac5
4楼 · 2018.03.07 11:23

现在还有一像素的处理?

@东冬_6ac5 有什么问题?
2018.03.07 11:27

这个算是黑科技,很早很早的了,现在又有几个手机会这样用

2018.03.08 10:02

@东冬_6ac5 嗯,进程保活的手段就这老几样。 我只是把认为还不错的三条测试下,并用到项目

2018.03.08 10:05
LeonXtp

3楼 · 2018.03.06 01:28

很多国产机用户一清理内存,应用就死掉了,博主还有一种双进程互相唤醒的办法没有提到,但是那个方法,在小米华为等系统里还是没用

清理内存会同时kill双进程,N进程也没用。很多国产机用户一清理内存这个场景,唯一办法就是加入白名单
2018.03.07 00:25
@08_carmelo :flushed: 现在国内基本是小米,华为,OPPO,VIVO的天下,进程保活太难了,估计也就只能加入厂商的白名单才能保活,但是我们又不是微信或者QQ这种应用,想让厂商把我们加入白名单太难了

感谢分享,我最近也是一直在研究这个保活问题

2018.04.10 15:37
@wo叫天然呆 先优化,总比不做处理强。其次,考虑在设置界面引导用户加白名单
2018.04.11 11:50
@LeonXtp 安卓在5.0 及后续的源码中,关闭进程时 会 关联 这个进程所在的进程组, 因此才会出现 多进程守护 保活 无效
2018.08.16 22:58

作者: RESSRC

个人资源站

《Android进程保活实践:上篇 | 08_carmelo》有一个想法

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据