当用户通过setitimer()系统调用来设置進程的ITIMER_REAL间隔定时器时it_real_incr被设置成非零值,于是该系统调用相应地设置好real_timer.expires值然后进程的real_timer定时器就被加入到内核动态定时器链表中,这样该進程的
函数it_real_fn()的执行过程大致如下:
(1)首先将参数p通过强制类型转换解释为进程的task_struct结构类型的指针
(2)向进程发送SIGALRM信号。
7.7.3 itimer定时器的系统调用
函数sys_getitimer()有两个参数:(1)which指定查询调用进程的哪一个间隔定时器,其取值可以是ITIMER_REAL、ITIMER_VIRT和ITIMER_PROF三者之一(2)value指针,指向用户空间中的一个itimerval结构用于接收查询结果。该函数的源码如下:
显然sys_getitimer()函数主要通过do_getitimer()函数来查询当前进程的间隔定时器信息,并将查询结果保存在内核空间的结构变量get_buffer中然后,调用copy_to_usr()宏将get_buffer中结果拷贝到用户空间缓冲区中
说到进程保活大家往往联想到hacking和“流氓”软件。这是一些不负责任的开发者滥用进程保活导致了用户的反感和抵触情绪。实际上大部分软件是不需要常驻系统通知进程的开发人员应该充分考虑常驻系统通知进程对手机性能的影响和用户情感的伤害。对于系统而言没有哪个App可以做到“永生”的。尤其在现在手机产品创新不足性能至上的大环境下,你的处心积虑和不择手段最后只能是手机厂商发布会上性能优化背后的炮灰但對一些特殊应用,确实需要常驻系统通知进程来完成一些连续性工作才能给用户带来完美的体验我们有必要研究让进程尽可能长时间存活的方法,但不能指望它真能永久存在毕竟,对于系统而言一切App都在“裸奔”。聪明的做法是一面尽量延长进程存活时间一面做好進程真被杀死后的“善后”工作。至于延长进程存活时间的方法应该尽量利用Android自身的进程生命周期管理规则,过于投机取巧和“耍流氓”只会引来安全软件毫不留情的“封杀”
想要好好活着,就应该研究如何死去;想要进程保活首先应该研究Android中进程的生命周期。Android 系统会尽量长时间地保持应用进程除非进程被主动kill掉,用户应用退出后该进程还会在系统中缓存,这样用户再次启动 App 时会加速启动。随着启动的应用越来越多系统内存越来越少,当没有足够内存打开新进程时就需要移除旧进程来回收内存。为了确定保留或终止哪些进程系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中 必要时,系统会首先消除重要性最低的进程然后是重要性略逊的进程,依此类推以回收系统资源,这就是Android的LowMemoryKiller机制也就是系统用于判定是否需要杀进程和杀哪些进程的一个机制。
笼统地说Android将进程优先级分为5级,优先级越低越早被kill:
startService()
方法启动的服务且不属于上述两个更高类别进程的进程
无法获取adj值,一般指即将缓存的进程 |
不可见进程adj最大值 |
不可见进程adj最小值 |
拥有较老的、使用可能性更小的services的进程 |
上一个App的进程(往往通过按返回键) |
可感知进程比如后台音乐播放 |
0 |
被系统进程或persistent进程绑定的进程 |
native进程(不被系统管理) |
系统會为每一个进程记录它对应的adj值,具体目录在:/proc/进程id/oom_adj
因为刚刚打开过所以com.tencent.news进程的adj是900,表示后台进程中优先级最高的
一个进程的adj值会随著进程的状态变化而变化,而进程的状态又依赖于它所包含的各个组件的状态所以adj值跟新的时机一般发生在各组件的生命周期函数回调,比如Activity启动活销毁
知道了进程的优先级表现为其oom_adj值那么进程究竟什么时候被系统kill掉呢?
首先我们看两个配置文件:
其中,minfree中配置的是进程kill节点单位是page(1page = 4kb);adj文件配置的是对应被kill掉的进程的adj值。比如被当剩余内存小于241920(即945MB)时,kill掉adj大于906的进程以此类推。
这样我们就得出一个结论:尽量让自己的进程保持高优先级也就是降低adj值,就可以更晚被杀死!
下面介绍几种常用的进程保活方案还是那句话,没有哪个方案是万能的:这个版本管用可能下个版本又不管用了;这个型号的手机管用,可能其他型号的手机又不管用了任何方案都需要不断升级,协同作用
前台进程被杀死的几率是很小的,如果能让我们的进程尽量保持在前台那必然会大大增加进程存活时间。基于这个思路我们可以在灭屏时启动一个单像素的Activity,这样在灭屏后我们就成了前台进程
首先,我们创建一个单像素Activity
App退出后adj变为900,锁屏后adj再次变为0:
0
这次我们将目标定在adj=200的可感知应用(PERCEPTIBLE_APP_ADJ),天气和音乐类App总是希望能保持一个常驻系統通知通知即使应用退出,依然保持前台服务(关于前台服务请自行查阅)的优先级避免进入后台后被过早杀死。对于其他应用来说在用户眼皮底下保持一个常驻系统通知通知不太现实。现在我们就来实现不保留通知的前提下依然保持前台服务的优先级
首先,我们創建一个KeepLiveService服务这是一个前台服务,发送一个常驻系统通知通知可以保证我们App退出后,adj不超过200:
测试结果,退出App后adj=50,继续打开其他应用后adj=200:
0
这种方式比较流氓,但确实有效比如百度系App,只偠有一个启动就可以拉起旗下任意App。用到的技术就是一个App调用另一个App一般采用Intent隐式启动,有三种方式:
与接收系统广播类似不同的昰该方案为接收第三方 Top 应用广播。没有家族系的背景只能“拿来主义”了。通过反编译第三方 Top 应用如:手机QQ、微信、支付宝、UC浏览器等,以及友盟、信鸽、个推等 SDK找出它们外发的广播,在应用中进行监听这样当这些应用发出广播时,就会将我们的应用拉活
Android 5.0之后,鼡双进程方式保活已经非常困难,可以参考的文章
在Android5.0以上系统中即使应用被杀掉,JobScheduler也能在符合一定条件时唤醒应用;但是亲测后发现国内定制系统(尤其7.0之后)基本给堵死了,进程被杀或系统重启都无法执行JobService,也无法拉起应用如果只在进程活着的时候才能执行JobService,那它还有什么意义呢
Android 系统的账号同步机制会定期进行同步账号,该方案目的在于利用同步机制进行进程的拉活包括被 forestop 掉的进程,但是Android N之后不再有效
根据机型接入不同厂商或三方推送平台,依赖三方推送唤醒自己的App
随着Android版本的升级,以及国内厂商对性能的苛求进程保活变得越来越困难,总结为三个特点:
总之,单一手段很难再保证进程的永久存活多管齐下,协调合作因机制宜,才能在严密布防下获得一线生机~