Android应用程序保活

Android应用程序保活

Android进程

Android在内存较低的情况下,会关闭一些优先级较低的进程以增大内存运行更重要的进程,而在这个进程中的所有线程,也会被同时销毁。

Android中,进程的生命周期都是由系统控制的。即使用户在界面上关掉一个应用,切换到了别的应用,那个应用的进程依然是存在于内存之中的。这样设计的目的是为了下次启动应用能更加快速。当然,随着系统运行时间的增长,内存中的进程可能会越来越多,而可用的内存则将会越来越少。Android Kernel会定时执行一次检查,杀死一些进程,释放掉内存。

Android一般的进程优先级划分:
1.前台进程 (Foreground process)
2.可见进程 (Visible process)
3.服务进程 (Service process)
4.后台进程 (Background process)
5.空进程 (Empty process)

进程其实有一种具体的数值,称作oom_adj,注意:数值越大优先级越低

进程

系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app。这套杀进程回收内存的机制就叫 Low Memory Killer ,它是基于Linux内核的 OOM Killer(Out-Of-Memory killer)机制诞生。

扫描二维码关注公众号,回复: 7546568 查看本文章

Android 的 low memory killer 是基于 linux 的OOM(out of memory)规则改进而来的。OOM 通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为 bad进程,杀死进程并释放内存。OOM 只有当系统内存不足的时候才会启动检查,而 low memory killer 则不仅是在应用程序分配内存发现内存不足时启动检查,它也会定时地进行检查。

Low memory killer 主要是通过进程的 oom_adj 来判定进程的重要程度的。oom_adj 的大小和进程的类型以及进程被调度的次序有关

在 linux 中,存在一个名为 kswapd 的内核线程,当linux回收存放分页的时候,kswapd 线程将会遍历一张 shrinker 链表,并执行回调,或者某个app分配内存,发现可用内存不足时,则内核会阻塞请求分配内存的进程分配内存的过程,并在该进程中去执行lowmemorykiller来释放内存

进程被kill的场景

点击home键使app长时间停留在后台,内存不足被kill
在大多数国产手机下,进入锁屏状态一段时间,省电机制会kill后台进程

进程的优先级

什么是oom_adj?它是linux内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。对于oom_adj的作用,你只需要记住以下几点即可:
进程的oom_adj越大,表示此进程优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收
普通app进程的oom_adj>=0,系统进程的oom_adj才可能<0
一般前台的进程优先级oom_adj = 0 ,只有系统进程的oom_adj才会小于0
ps | grep PackageName (com.ypcang.android.shop) //查看此app全部进程
cat /proc/进程号(19848)/oom_adj //查看某一进程的优先级

当app在前台时 oom_adj = 0,对应上面的表格是前台进程。
当app退到后台时,oom_adj = 6,对应后台进程。
app退到后台时,其所有的进程优先级都会降低。但是UI进程是降低最为明显的,因为它占用的内存资源最多,系统内存不足的时候肯定优先杀这些占用内存高的进程来腾出资源。所以,为了尽量避免后台UI进程被杀,需要尽可能的释放一些不用的资源,尤其是图片、音视频之类的。

提升优先级的方案

利用Activity提升进行优先级

方案设计:

监控手机的锁屏和解锁事件,在屏幕锁屏时启动1个像素的Activity,在解锁时将Activity销毁。该Activity要设计成用户无感知。
这里有个前提是APP进程需要在后台。如果APP进程在前台,那么进程已经是前台进程了,那么上面的做法就没有任何意义了。

通过该方案,进程的优先级可以在锁屏时由oom_adj为9(不同手机系统的值可能不一样)提升到0(前台进程)。这样我们的APP就不容易在锁屏时间内被第三方应用给杀死。

适用范围:

场景:该方案主要解决的痛点是第三方应用或者系统管理工具会在检测到锁屏事件一段时间后杀死后台进程,以达到省电的目的。

版本:适用于所有的Android版本。

利用Notification提升进程优先级

方案设计:

通过将Android中的Service的setForeground接口可以将后台Service设置为前台Service,这样进程的优先级就被提升到了2,从而使进程的优先级仅仅次于用户当前正在交互的进程,与可见进程的优先级一致,使进程被杀死的概率大大降低。

在Android 2.3开始调用setForeground将后台Service设置为前台Service时,必须在系统的通知栏发送一条通知,这意味着前台Service与一条可见的通知是绑定在一起的。但是对于不需要使用常驻通知栏的应用来说,该方案是用户感知的,没有办法直接使用。

我们可以通过实现一个内部Service,在LiveService和其内部Service中同时发送具有相同ID的Notification,然后将内部Service结束掉,同时也将Notification结束掉,随着Notification的消失,用户就无感知了,同时也实现了将系统优先级提升到2的操作。

适用范围:

版本:适用于所有的Android版本。

进程保活方案

利用系统广播拉活

方案设计

在发生特定系统事件时,系统会发出响应的广播,如果我们在AndroidManifest中"静态"注册对应的广播监听器,就可以在发生响应事件时进行拉活。
常用的用于拉活的广播事件包括:

适用范围

适用于全部的Android平台。但是存在着以下几个缺点:
1、广播接收器被管理软件或者系统软件通过"自启动"等功能禁用的场景无法接收到广播,从而无法自启。
2、系统广播事件是不可控制的,只能在保证发生广播事件时拉活进程,但是无法做到进程挂掉后立即拉活。

因此,该方案只是作为一个备选方案。

利用第三方应用广播拉活

方案设计

该方案的设计思想和接收系统广播的类似,不同的是该方案接收的是第三方Top应用的广播。

通过反编译第三方Top应用,如:手机QQ、微信、支付宝、UC浏览器等,以及友盟、信鸽、个推等SDK,找出它们外发的广播,在应用中进行监听,当这些应用发出广播时,就会将我们的应用进行拉活。

适用范围

该方案的缺点和上面所说的系统广播的方案一样之外,还有下面几个缺点:
1、进程拉活的效果取决于反编译分析过的第三方应用的多少。
2、第三方应用的广播属于应用私有的,所以有可能存在当前版本有效的广播在后续的版本中随时有可能被移除或者被改为不外发。

因此,该方案也只是作为一个备选方案。

利用系统Service机制拉活

方案设计

该方案将Service的onStartCommand方法的返回值设置为START_STICKY,利用系统机制在Service挂掉后自动拉活。

适用范围

下面这两种情况无法进行拉活:
1、Service在第一次被异常杀死后会在5秒内重启,第二次被杀死后会在10秒重启,第三次杀死后会在20秒重启,但是一旦在短时间内Service被杀死的次数达到5次,则系统不再拉起。
2、进程被取得Root权限的管理工具或系统工具通过foreStop停止掉,则无法重启。

利用JobScheduler机制拉活

方案设计

Android 5.0以后的版本提供了JobScheduler接口,系统会定时调用该进程以使应用进行一些逻辑操作。

适用范围

主要适用于Android 5.0以上的版本。在Android 5.0以上版本中不受forcestop影响,被强制停止的应用依然可以被拉起,在Android 5.0以上版本拉活效果是非常好的。(但是在小米手机上可能会偶尔出现无法拉活的问题。)

利用账号同步机制拉活

方案设计

Android系统的账号同步机制会定期同步账号,该方案的目的在于利用同步机制进行进程的拉活。

适用范围

适用于所有的Android版本,包括forestop掉的进程也可以进行拉活。但是在最新Android版本(Android N)中系统好像对账户同步做了改动,所以该方法是否能够再用还需要进行一定的实验。

参考文章

https://www.jianshu.com/p/df766d5573a5

https://www.jianshu.com/p/16fb9e5cc6cc

猜你喜欢

转载自www.cnblogs.com/kexinxin/p/11723454.html