這個文章只是Android歷史保活方案總結,沒有什么特別的參考意義,Android 已經到10了,100%保活本身就已經不復存在,文章中所有的方案,都是有可能有用,畢竟4.4還有人用,至于要不用可以自己參考,畢竟當PM就是讓你應用不死,你能不寫代碼嗎?
保活通常分為2種方案,一種為提高進程優先級,防止被殺,另一種為進程被殺死拉活
1. 進程優先級
Android系統會盡可能的保持應用進程,但是當需要建立新的進程或者運行更重要的進程,便會回收優先級低一些的進程,這個就是lowmemorykiller的工作。而進程的優先級其實就是 /proc/pid/oom_adj
進程的優先級排序
- 前臺進程(Foreground Process)
- 可見進程(Visible Process)
- 服務進程(Service Process)
- 后臺進程(Background Process)
- 空進程(Empty Process)
前臺進程
- 擁有 用戶正在交互的 Activity(正處于 onResume中)
- 擁有 Service綁定到正處于 onResume的 Activity
- 擁有 Service 調用 startForeground 成為前臺服務
- 擁有 Service 正在執行生命周期回調(onCreate、onStart、onDestroy)
- 擁有 BroadcastReceiver 正在執行 onReceive
可見進程
- 擁有 Activity 處于 onPause ,此時可見但是不可操作
- 擁有 Service 綁定到正處于 onPause的 Activity
服務進程
- 僅通過 startService 啟動的 Service
后臺進程
- 擁有 Activity 處于 onStop
空進程
- 不擁有任何活動的組件進程
2. 回收策略
從Zygote fork出來的進程都會被儲存在 ActivityManagerService.mLruProcesses 列表中,由ActivityManagerService進行統一管理。ActivityManagerService會根據進程狀態去更新進程所對應的 oom_adj 的值,當內存達到一定的閾值會觸發清理 oom_adj 高的進程。
3. 保活方案
3.1 提高進程優先級
3.1.1 利用Activity
1像素Activy,監控手機解鎖屏事件,解鎖時將Activity銷毀,鎖屏時啟動,并且要無感知,在RecentTask里移除
3.1.2 前臺服務+Notification
Service 通過 startForegroundService 啟動 ,低版本時可以通過特殊方式對 Notification 進行隱藏,高版本無法規避,此方案為通過需求正向解決
3.1.3 引導用戶打開電池管理,允許應用后臺運行
目前市面上的手機,或多或少都有對進程管理有優化,可能會有允許應用后臺允許的功能,但是每款手機的入口均不相同,而且相同廠商的不同版本也會不同
具體做法,找到手機的電池管理或者系統的后臺管理,針對不同的手機做文字書面的提醒,提醒用戶開啟此功能,暴力一點可以想辦法拿到此Activity的具體類名 包名等信息,進行反射調用。
此方案一般應用不要使用,工作量巨大,而且僅僅針對提醒類應用使用,比如吃藥提醒,起床鬧鐘,這些對保活要求非常高的應用才適合
3.2 進程死后拉活
3.2.1 監聽系統靜態廣播
低版本時,靜態廣播可以喚醒應用進程,所以監聽系統廣播,例如開機,鎖屏,解鎖等可以做到,但是高版本不能通過靜態廣播監聽系統廣播了
3.2.2 監聽三方靜態廣播
與上個方案類似,都是運用靜態廣播可以拉活應用為基礎,只是發送方不是系統,而且三方應用。所以此方案可行,但是很不穩定,海外和國內用戶群體不同,手機使用的APK也會不同,而且需要大量反編譯三方應用,投成本也很高
3.2.3 利用系統Service機制拉活
Service 的 onStartCommand 返回值,當返回值為 START_STICKY 和 START_REDELIVER_INTENT 時,服務會自動重啟,但是 Service 在短時間內被殺死5次,則不再拉起
3.2.4 利用 JobScheduler
JobScheduler 為Android 5.0之后引入的,本質是系統定時任務,如果進程被殺,任務仍然會被執行,在7.0后 JobScheduler 添加了限制,最低間隔為15分鐘。但是還是有概率出現存在進程死亡后,不觸發的情況。
3.2.5 利用 AlarmManager
本質上也是通過設置定時任務,如果進程被殺,任務也仍然會被執行,此時就可以拉活進程。Doze模式會影響 AlarmManager 不被觸發,此時要用setAlarmClock來設置。同樣有概率出現存在進程死亡后,不觸發的情況。
而且Android 9.0的谷歌原生手機,多了一個功能,就是顯示手機下一個的鬧鐘時間是幾點,如果用到了這種保活方式,用戶也注意到了這個功能,那么鬧鐘上的時間會暴露有應用在明目張膽的保活
3.2.6 利用賬號同步機制
Android 系統的賬號同步機制會定期同步賬號進行,該方案目的在于利用同步機制進行進程的拉活。添加賬號和設置同步周期的代碼即可,谷歌商店會查這種保活方案,后果不知,建議慎用
3.2.7 利用Native進程拉活
利用 linux 中的 fork 機制創建 Native 進程,在 Native 進程中監控主進程的存活,當主進程掛掉后,在 Native 進程中立即對主進程進行拉活。
感知主進程死亡:在主進程中創建一個監控文件,并且在主進程中持有文件鎖。在拉活進程啟動后申請文件鎖將會被堵塞,一旦可以成功獲取到鎖,說明主進程掛掉,即可進行拉活。
拉活主進程:通過 Native 進程拉活主進程的部分代碼如下,即通過 am 命令進行拉活。通過指定“–include-stopped-packages”參數來拉活主進程處于 forestop 狀態的情況。
但是 Android5.0 以上手機 會依次殺死所有進程,也會將 Native 進程殺死
3.2.8 利用雙進程拉活
啟動兩個Service A和B,處于不同進程,然后在A的 onStartCommand 中綁定 B,B也在A的 onStartCommand 中綁定A,通過 ServiceConnection 的回調 onServiceDisconnected ,當綁定斷開時,說明另一個進程死亡,于是重新啟動死亡的進程(Service),6.0之后保活效果也開始有限,與Natvie進程遇到的問題相似,只有在依次殺死進程的間隔中,有幾率拉活
3.3 其他拉活方式
3.3.1 利用系統官方的服務,或者三方服務
- 國外可以使用 Firebase 的云端推送
- 國內可以使用極光推送等服務
主要還是依靠,自己應用與其他應用使用相同SDK,然后相同的SDK里面內置了相互喚醒功能,具體保活的效果也是依賴三方SDK的能力