這個文章只是Android歷史保活方案總結,沒有什么特別的參考意義,Android 已經到10了,100%保活本身就已經不復存在,文章中所有的方案,都是有可能有用,畢竟4.4還有人用,至于要不用可以自己參考,畢竟當PM就是讓你應用不死,你能不寫代碼嗎?
這個文章只是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)
前臺進程(Foreground Process)
可見進程(Visible Process)
服務進程(Service Process)
后臺進程(Background Process)
空進程(Empty Process)
擁有 用戶正在交互的 Activity(正處于 onResume中)
擁有 Service綁定到正處于 onResume的 Activity
擁有 Service 調用 startForeground 成為前臺服務
擁有 Service 正在執行生命周期回調(onCreate、onStart、onDestroy)
擁有 BroadcastReceiver 正在執行 onReceive
擁有 用戶正在交互的 Activity(正處于 onResume中)
擁有 Service綁定到正處于 onResume的 Activity
擁有 Service 調用 startForeground 成為前臺服務
擁有 Service 正在執行生命周期回調(onCreate、onStart、onDestroy)
擁有 BroadcastReceiver 正在執行 onReceive
擁有 Activity 處于 onPause ,此時可見但是不可操作
擁有 Service 綁定到正處于 onPause的 Activity
擁有 Activity 處于 onPause ,此時可見但是不可操作
擁有 Service 綁定到正處于 onPause的 Activity
僅通過 startService 啟動的 Service
僅通過 startService 啟動的 Service
擁有 Activity 處于 onStop
擁有 Activity 處于 onStop
不擁有任何活動的組件進程
不擁有任何活動的組件進程
從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 的云端推送
國內可以使用極光推送等服務
國外可以使用 Firebase 的云端推送
國內可以使用極光推送等服務
主要還是依靠,自己應用與其他應用使用相同SDK,然后相同的SDK里面內置了相互喚醒功能,具體保活的效果也是依賴三方SDK的能力
作者:Cloud_lys
鏈接:https://juejin.im/post/5df24da36fb9a0165c711807
作者:Cloud_lys
鏈接:https://juejin.im/post/5df24da36fb9a0165c711807


