Android保活机制

市面上没有100%的保活机制,除非手机厂商将该应用设置成为系统白名单(比如微信等)。我们要做的尽可能的提高APP的优先级,尽量避免其被杀死,以及被杀死后如何“复活”。

如何查看app在系统中的优先级

1
2
# 这里的11572要改为对应进程的id
adb shell cat /proc/11572/oom_adj

获取到的值参考下图:(数字越小,优先级越高)

image-20210123231047923

保活法-提高优先级

目的:尽力去提升进程优先级。

1像素法

在监听到手机关闭屏幕时,偷偷创建一个只有1像素的、透明的Activity,让应用成为前台进程,然后再打开屏幕时,关掉这个Activity。

针对锁屏状态下优先级降低的情况。

前台服务保活

在启动应用的同时,创建一个前台服务(前台服务的优先级远高于普通服务),然后在该服务中又创建一个前台服务,共用同一个SERVICE_ID,然后马上销毁这个前台服务【stopSelf()】,这样一来前台就不会出现通知栏,而前台服务(第一个service)依旧存在。如此实现了优先级的提升。

第二个service

这个方法实际上是利用了Google的一个漏洞,传入同一个id创建两个前台服务可以创建成功。但是在Android 8.0以后,Google工程师修补了这个bug,所以该方法只适用于7.0及以下的手机。

拉活法-起死回生

目的:app被杀死后把他给救活。

广播拉活

在发生特定的系统事件时,系统会发出广播。此时可以通过静态注册特定的广播监听器,在收到响应事件时进行拉活。

但是自Android 7.0起,对广播进行了限制,在8.0后变得更加严格,所以该方法已逐渐被弃用。

“全家桶”拉活

如果有多个自家的app在用户设备上安装,只要开启一个就可以将其他的app唤醒。比如在一个app中发广播,另一个app中收到广播进行拉活。

service系统机制拉活

在service的onStartCommand方法执行完以后,会返回一个int类型的值。这个值有START_STICKY、START_NOT_STICKY、START_REDELIVER_INTENT 和 START_STICKY_COMPATIBILITY四种可能。

START_STICKY:粘性。如果service进程被kill掉,保留service状态为开始状态,但不保留传达的intent对象。随后系统会尝试重新创建该service。由于service为开始状态,所以服务创建后一定会调用到onStartCommand方法。 如果此期间内没有任何启动命令被传递到service,那么intent参数为null。

START_NOT_STICKY:”非粘性“。执行完onStartCommand后,服务器被异常kill,系统不会自动重启该服务。

START_REDELIVER_INTENT:重传Intent。 执行完onStartCommand后,服务器被异常kill,系统会自动重启该服务,并传入Intent。

START_STICKY_COMPATIBILITYSTART_STICKY的兼容版,但不保证被kill后一定执行。

所以,只要将onStartCommand方法最后返回START_STICKY即可。

1
2
3
4
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
...
return Service.START_STICKY
}

某些ROM不会拉活。并且经测试,service第一次被杀死很快被重启,第二次比第一次慢,第三次又比前一次慢,一旦在短时间内被杀死4~5次,则系统不再拉起。

账户同步拉活

官方允许的保活做法!

image-20210124111011415

通过代码的方式,将app列入系统的账户【Account】名单,系统会每15分钟左右进行一次检索,从而将你的app拉活。优点:系统唤醒,比较稳定;缺点:拉活时间不能把控。

JobScheduler拉活

JobScheduler允许在特定状态与特定时间间隔周期性执行任务。我们利用其这个特性开一个定时器即可完成保活,与普通定时器不同的是其调度是由系统完成的。

缺点:比较耗费内存。因为比较流氓,所以被某些ROM禁用了。【不推荐使用】

双进程保活

原理:两个进程协同,一个进程死了,另外一个将其拉活。用到了AIDL在进程间进行交互。