這個(gè)文章只是Android歷史保活方案總結(jié),沒(méi)有什么特別的參考意義,Android 已經(jīng)到10了,100%保活本身就已經(jīng)不復(fù)存在,文章中所有的方案,都是有可能有用,畢竟4.4還有人用,至于要不用可以自己參考,畢竟當(dāng)PM就是讓你應(yīng)用不死,你能不寫(xiě)代碼嗎?
保活通常分為2種方案,一種為提高進(jìn)程優(yōu)先級(jí),防止被殺,另一種為進(jìn)程被殺死拉活
1. 進(jìn)程優(yōu)先級(jí)
Android系統(tǒng)會(huì)盡可能的保持應(yīng)用進(jìn)程,但是當(dāng)需要建立新的進(jìn)程或者運(yùn)行更重要的進(jìn)程,便會(huì)回收優(yōu)先級(jí)低一些的進(jìn)程,這個(gè)就是lowmemorykiller的工作。而進(jìn)程的優(yōu)先級(jí)其實(shí)就是 /proc/pid/oom_adj
進(jìn)程的優(yōu)先級(jí)排序
- 前臺(tái)進(jìn)程(Foreground Process)
- 可見(jiàn)進(jìn)程(Visible Process)
- 服務(wù)進(jìn)程(Service Process)
- 后臺(tái)進(jìn)程(Background Process)
- 空進(jìn)程(Empty Process)
前臺(tái)進(jìn)程
- 擁有 用戶(hù)正在交互的 Activity(正處于 onResume中)
- 擁有 Service綁定到正處于 onResume的 Activity
- 擁有 Service 調(diào)用 startForeground 成為前臺(tái)服務(wù)
- 擁有 Service 正在執(zhí)行生命周期回調(diào)(onCreate、onStart、onDestroy)
- 擁有 BroadcastReceiver 正在執(zhí)行 onReceive
可見(jiàn)進(jìn)程
- 擁有 Activity 處于 onPause ,此時(shí)可見(jiàn)但是不可操作
- 擁有 Service 綁定到正處于 onPause的 Activity
服務(wù)進(jìn)程
- 僅通過(guò) startService 啟動(dòng)的 Service
后臺(tái)進(jìn)程
- 擁有 Activity 處于 onStop
空進(jìn)程
- 不擁有任何活動(dòng)的組件進(jìn)程
2. 回收策略
從Zygote fork出來(lái)的進(jìn)程都會(huì)被儲(chǔ)存在 ActivityManagerService.mLruProcesses 列表中,由ActivityManagerService進(jìn)行統(tǒng)一管理。ActivityManagerService會(huì)根據(jù)進(jìn)程狀態(tài)去更新進(jìn)程所對(duì)應(yīng)的 oom_adj 的值,當(dāng)內(nèi)存達(dá)到一定的閾值會(huì)觸發(fā)清理 oom_adj 高的進(jìn)程。

3. 保活方案
3.1 提高進(jìn)程優(yōu)先級(jí)
3.1.1 利用Activity
1像素Activy,監(jiān)控手機(jī)解鎖屏事件,解鎖時(shí)將Activity銷(xiāo)毀,鎖屏?xí)r啟動(dòng),并且要無(wú)感知,在RecentTask里移除
3.1.2 前臺(tái)服務(wù)+Notification
Service 通過(guò) startForegroundService 啟動(dòng) ,低版本時(shí)可以通過(guò)特殊方式對(duì) Notification 進(jìn)行隱藏,高版本無(wú)法規(guī)避,此方案為通過(guò)需求正向解決
3.1.3 引導(dǎo)用戶(hù)打開(kāi)電池管理,允許應(yīng)用后臺(tái)運(yùn)行
目前市面上的手機(jī),或多或少都有對(duì)進(jìn)程管理有優(yōu)化,可能會(huì)有允許應(yīng)用后臺(tái)允許的功能,但是每款手機(jī)的入口均不相同,而且相同廠(chǎng)商的不同版本也會(huì)不同
具體做法,找到手機(jī)的電池管理或者系統(tǒng)的后臺(tái)管理,針對(duì)不同的手機(jī)做文字書(shū)面的提醒,提醒用戶(hù)開(kāi)啟此功能,暴力一點(diǎn)可以想辦法拿到此Activity的具體類(lèi)名 包名等信息,進(jìn)行反射調(diào)用。
此方案一般應(yīng)用不要使用,工作量巨大,而且僅僅針對(duì)提醒類(lèi)應(yīng)用使用,比如吃藥提醒,起床鬧鐘,這些對(duì)保活要求非常高的應(yīng)用才適合
3.2 進(jìn)程死后拉活
3.2.1 監(jiān)聽(tīng)系統(tǒng)靜態(tài)廣播
低版本時(shí),靜態(tài)廣播可以喚醒應(yīng)用進(jìn)程,所以監(jiān)聽(tīng)系統(tǒng)廣播,例如開(kāi)機(jī),鎖屏,解鎖等可以做到,但是高版本不能通過(guò)靜態(tài)廣播監(jiān)聽(tīng)系統(tǒng)廣播了
3.2.2 監(jiān)聽(tīng)三方靜態(tài)廣播
與上個(gè)方案類(lèi)似,都是運(yùn)用靜態(tài)廣播可以拉活應(yīng)用為基礎(chǔ),只是發(fā)送方不是系統(tǒng),而且三方應(yīng)用。所以此方案可行,但是很不穩(wěn)定,海外和國(guó)內(nèi)用戶(hù)群體不同,手機(jī)使用的APK也會(huì)不同,而且需要大量反編譯三方應(yīng)用,投成本也很高
3.2.3 利用系統(tǒng)Service機(jī)制拉活
Service 的 onStartCommand 返回值,當(dāng)返回值為 START_STICKY 和 START_REDELIVER_INTENT 時(shí),服務(wù)會(huì)自動(dòng)重啟,但是 Service 在短時(shí)間內(nèi)被殺死5次,則不再拉起
3.2.4 利用 JobScheduler
JobScheduler 為Android 5.0之后引入的,本質(zhì)是系統(tǒng)定時(shí)任務(wù),如果進(jìn)程被殺,任務(wù)仍然會(huì)被執(zhí)行,在7.0后 JobScheduler 添加了限制,最低間隔為15分鐘。但是還是有概率出現(xiàn)存在進(jìn)程死亡后,不觸發(fā)的情況。
3.2.5 利用 AlarmManager
本質(zhì)上也是通過(guò)設(shè)置定時(shí)任務(wù),如果進(jìn)程被殺,任務(wù)也仍然會(huì)被執(zhí)行,此時(shí)就可以拉活進(jìn)程。Doze模式會(huì)影響 AlarmManager 不被觸發(fā),此時(shí)要用setAlarmClock來(lái)設(shè)置。同樣有概率出現(xiàn)存在進(jìn)程死亡后,不觸發(fā)的情況。
而且Android 9.0的谷歌原生手機(jī),多了一個(gè)功能,就是顯示手機(jī)下一個(gè)的鬧鐘時(shí)間是幾點(diǎn),如果用到了這種保活方式,用戶(hù)也注意到了這個(gè)功能,那么鬧鐘上的時(shí)間會(huì)暴露有應(yīng)用在明目張膽的保活
3.2.6 利用賬號(hào)同步機(jī)制
Android 系統(tǒng)的賬號(hào)同步機(jī)制會(huì)定期同步賬號(hào)進(jìn)行,該方案目的在于利用同步機(jī)制進(jìn)行進(jìn)程的拉活。添加賬號(hào)和設(shè)置同步周期的代碼即可,谷歌商店會(huì)查這種保活方案,后果不知,建議慎用
3.2.7 利用Native進(jìn)程拉活
利用 linux 中的 fork 機(jī)制創(chuàng)建 Native 進(jìn)程,在 Native 進(jìn)程中監(jiān)控主進(jìn)程的存活,當(dāng)主進(jìn)程掛掉后,在 Native 進(jìn)程中立即對(duì)主進(jìn)程進(jìn)行拉活。
感知主進(jìn)程死亡:在主進(jìn)程中創(chuàng)建一個(gè)監(jiān)控文件,并且在主進(jìn)程中持有文件鎖。在拉活進(jìn)程啟動(dòng)后申請(qǐng)文件鎖將會(huì)被堵塞,一旦可以成功獲取到鎖,說(shuō)明主進(jìn)程掛掉,即可進(jìn)行拉活。
拉活主進(jìn)程:通過(guò) Native 進(jìn)程拉活主進(jìn)程的部分代碼如下,即通過(guò) am 命令進(jìn)行拉活。通過(guò)指定“–include-stopped-packages”參數(shù)來(lái)拉活主進(jìn)程處于 forestop 狀態(tài)的情況。
但是 Android5.0 以上手機(jī) 會(huì)依次殺死所有進(jìn)程,也會(huì)將 Native 進(jìn)程殺死
3.2.8 利用雙進(jìn)程拉活
啟動(dòng)兩個(gè)Service A和B,處于不同進(jìn)程,然后在A(yíng)的 onStartCommand 中綁定 B,B也在A(yíng)的 onStartCommand 中綁定A,通過(guò) ServiceConnection 的回調(diào) onServiceDisconnected ,當(dāng)綁定斷開(kāi)時(shí),說(shuō)明另一個(gè)進(jìn)程死亡,于是重新啟動(dòng)死亡的進(jìn)程(Service),6.0之后保活效果也開(kāi)始有限,與Natvie進(jìn)程遇到的問(wèn)題相似,只有在依次殺死進(jìn)程的間隔中,有幾率拉活
3.3 其他拉活方式
3.3.1 利用系統(tǒng)官方的服務(wù),或者三方服務(wù)
- 國(guó)外可以使用 Firebase 的云端推送
- 國(guó)內(nèi)可以使用極光推送等服務(wù)
主要還是依靠,自己應(yīng)用與其他應(yīng)用使用相同SDK,然后相同的SDK里面內(nèi)置了相互喚醒功能,具體保活的效果也是依賴(lài)三方SDK的能力