第十二章 進程保活

(一)Android回收策略

Android 中對於內存的回收,主要依靠 Lowmemorykiller 來完成,是一種根據 OOM_ADJ 閾值級別觸發相應力度的內存回收的機制。

系統出於體驗和性能上的考慮,app在退到後臺時系統並不會真正的kill掉這個進程,而是將其緩存起來。打開的應用越多,後臺緩存的進程也越多。在系統內存不足的情況下,系統開始依據自身的一套進程回收機制來判斷要kill掉哪些進程,以騰出內存來供給需要的app。這套殺進程回收內存的機制就叫 Low Memory Killer ,它是基於Linux內核的 OOM Killer(Out-Of-Memory killer)機制誕生。oom_adj是linux內核分配給每個系統進程的一個值,代表進程的優先級,進程回收機制就是根據這個優先級來決定是否進行回收。對於oom_adj的作用,你只需要記住以下幾點即可:
1、進程的oom_adj越大,表示此進程優先級越低,越容易被殺回收;越小,表示進程優先級越高,越不容易被殺回收
2、普通app進程的oom_adj>=0,系統進程的oom_adj纔可能<0

通過shell命令可以查看進程的oom_adj

grep PackageName //獲取你指定的進程信息

1.1)進程優先級

Android 系統將盡量長時間地保持應用進程,但爲了新建進程或運行更重要的進程,最終需要清除舊進程來回收內存。 爲了確定保留或終止哪些進程,系統會根據進程中正在運行的組件以及這些組件的狀態,將每個進程放入“重要性層次結構”中。 必要時,系統會首先消除重要性最低的進程,然後是清除重要性稍低一級的進程,依此類推,以回收系統資源。
在這裏插入圖片描述
前臺進程的重要性最高,依次遞減,空進程的重要性最低,下面分別來闡述每種級別的進程:

1、前臺進程 —— Foreground process

用戶當前操作所必需的進程。通常在任意給定時間前臺進程都爲數不多。只有在內存不足以支持它們同時繼續運行這一萬不得已的情況下,系統纔會終止它們。

2、可見進程 —— Visible process

沒有任何前臺組件、但仍會影響用戶在屏幕上所見內容的進程。可見進程被視爲是極其重要的進程,除非爲了維持所有前臺進程同時運行而必須終止,否則系統不會終止這些進程。

3、服務進程 —— Service process

儘管服務進程與用戶所見內容沒有直接關聯,但是它們通常在執行一些用戶關心的操作(例如,在後臺播放音樂或從網絡下載數據)。因此,除非內存不足以維持所有前臺進程和可見進程同時運行,否則系統會讓服務進程保持運行狀態。

4、後臺進程 —— Background process

後臺進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供前臺進程、可見進程或服務進程使用。 通常會有很多後臺進程在運行,因此它們會保存在 LRU 列表中,以確保包含用戶最近查看的 Activity 的進程最後一個被終止。如果某個 Activity 正確實現了生命週期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,因爲當用戶導航回該 Activity 時,Activity 會恢復其所有可見狀態。

5、空進程 —— Empty process

保留這種進程的的唯一目的是用作緩存,以縮短下次在其中運行組件所需的啓動時間。 爲使總體系統資源在進程緩存和底層內核緩存之間保持平衡,系統往往會終止這些進程。

1.2)OOM_ADJ

在這裏插入圖片描述
其中紅色部分代表比較容易被殺死的 Android 進程(OOM_ADJ>=4),綠色部分表示不容易被殺死的 Android 進程,其他表示非 Android 進程(純 Linux 進程)。在 Lowmemorykiller 回收內存時會根據進程的級別優先殺死 OOM_ADJ 比較大的進程,對於優先級相同的進程則進一步受到進程所佔內存和進程存活時間的影響。

1.3)進程被殺死場景

在這裏插入圖片描述

(二)進程保活方案

根據前文,得出減少進程被殺死概率無非就是想辦法提高進程優先級,減少進程在內存不足等情況下被殺死的概率。

2.1)提升進程優先級,降低進程被殺死的概率

1、利用 Activity 提升權限

(1)設計思想
監控手機鎖屏解鎖事件,在屏幕鎖屏時啓動1個像素的 Activity,在用戶解鎖時將 Activity 銷燬掉。注意該 Activity 需設計成用戶無感知。
通過該方案,可以使進程的優先級在屏幕鎖屏時間由4提升爲最高優先級1。
(2)適用場景
本方案主要解決第三方應用及系統管理工具在檢測到鎖屏事件後一段時間(一般爲5分鐘以內)內會殺死後臺進程,已達到省電的目的問題。
(3)具體實現
步驟1:首先定義 Activity,並設置 Activity 的大小爲1像素
在這裏插入圖片描述
步驟2:從 AndroidManifest 中通過如下屬性,排除 Activity 在 RecentTask 中的顯示
在這裏插入圖片描述
步驟3:控制Activity爲透明
在這裏插入圖片描述
步驟4:Activity啓動與銷燬時機的控制
在這裏插入圖片描述

2、利用Notification提升權限

(1)設計思想
Android 中 Service 的優先級爲4,通過 setForeground 接口可以將後臺 Service 設置爲前臺 Service,使進程的優先級由4提升爲2,從而使進程的優先級僅僅低於用戶當前正在交互的進程,與可見進程優先級一致,使進程被殺死的概率大大降低。
(2)實現挑戰
從 Android2.3 開始調用 setForeground 將後臺 Service 設置爲前臺 Service 時,必須在系統的通知欄發送一條通知,也就是前臺 Service 與一條可見的通知時綁定在一起的。
對於不需要常駐通知欄的應用來說,該方案雖好,但卻是用戶感知的,無法直接使用。
方案挑戰應對措施:通過實現一個內部 Service,在 LiveService 和其內部 Service 中同時發送具有相同 ID 的 Notification,然後將內部 Service 結束掉。隨着內部 Service 的結束,Notification 將會消失,但系統優先級依然保持爲2。
(3)具體實現
在這裏插入圖片描述
在這裏插入圖片描述

2.2)進程被殺死後,進行拉活

1、利用系統廣播拉活

(1)設計思想
在發生特定系統事件時,系統會發出響應的廣播,通過在 AndroidManifest 中“靜態”註冊對應的廣播監聽器,即可在發生響應事件時拉活。
常用的用於拉活的廣播事件包括:
在這裏插入圖片描述
(2)適用範圍
1、廣播接收器被管理軟件、系統軟件通過“自啓管理”等功能禁用的場景無法接收到廣播,從而無法自啓。
2、系統廣播事件不可控,只能保證發生事件時拉活進程,但無法保證進程掛掉後立即拉活。
因此,該方案主要作爲備用手段。

2、利用第三方應用廣播拉活

(1)設計思想
該方案總的設計思想與接收系統廣播類似,不同的是該方案爲接收第三方 Top 應用廣播。接入第三方SDK也會喚醒相應的app進程,如微信sdk會喚醒微信,支付寶sdk會喚醒支付寶。
通過反編譯第三方 Top 應用,如:手機QQ、微信、支付寶、UC瀏覽器等,以及友盟、信鴿、個推等 SDK,找出它們外發的廣播,在應用中進行監聽,這樣當這些應用發出廣播時,就會將我們的應用拉活。
(2)適用範圍
1、與系統廣播一樣不可控
2、受反編譯分析過的第三方應用的程度的限制
3、第三方應用的廣播屬於應用私有,當前版本中有效的廣播,在後續版本隨時就可能被移除或被改爲不外發。

3、利用系統Service機制拉活

(1)設計思想
將 Service 設置爲 START_STICKY,利用系統機制在 Service 掛掉後自動拉活
在這裏插入圖片描述
(2)使用範圍:以下兩種情況無法拉活
1、Service 第一次被異常殺死後會在5秒內重啓,第二次被殺死會在10秒內重啓,第三次會在20秒內重啓,一旦在短時間內 Service 被殺死達到5次,則系統不再拉起。
2、進程被取得 Root 權限的管理工具或系統工具通過 forestop 停止掉,無法重啓。

4、利用Native進程拉活

在 Android 中所有進程和系統組件的生命週期受 ActivityManagerService 的統一管理。而且,通過 Linux 的 fork 機制創建的進程爲純 Linux 進程,其生命週期不受 Android 的管理。
利用 Linux 中的 fork 機制創建 Native 進程,在 Native 進程中監控主進程的存活,當主進程掛掉後,在 Native 進程中立即對主進程進行拉活。

5、利用 JobScheduler 機制拉活

Android5.0 以後系統對 Native 進程等加強了管理,Native 拉活方式失效。系統在 Android5.0 以上版本提供了 JobScheduler 接口,系統會定時調用該進程以使應用進行一些邏輯操作。

6、利用賬號同步機制拉活

Android 系統的賬號同步機制會定期同步賬號進行,該方案目的在於利用同步機制進行進程的拉活。添加賬號和設置同步週期的代碼如下:
在這裏插入圖片描述
該方案需要在 AndroidManifest 中定義賬號授權與同步服務。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章