天天看點

Android應用程式保活

Android應用程式保活

Android程序

Android在記憶體較低的情況下,會關閉一些優先級較低的程序以增大記憶體運作更重要的程序,而在這個程序中的所有線程,也會被同時銷毀。

Android中,程序的生命周期都是由系統控制的。即使使用者在界面上關掉一個應用,切換到了别的應用,那個應用的程序依然是存在于記憶體之中的。這樣設計的目的是為了下次啟動應用能更加快速。當然,随着系統運作時間的增長,記憶體中的程序可能會越來越多,而可用的記憶體則将會越來越少。Android Kernel會定時執行一次檢查,殺死一些程序,釋放掉記憶體。

Android一般的程序優先級劃分:

1.前台程序 (Foreground process)

2.可見程序 (Visible process)

3.服務程序 (Service process)

4.背景程序 (Background process)

5.空程序 (Empty process)

程序其實有一種具體的數值,稱作oom_adj,注意:數值越大優先級越低

程序

系統出于體驗和性能上的考慮,app在退到背景時系統并不會真正的kill掉這個程序,而是将其緩存起來。打開的應用越多,背景緩存的程序也越多。在系統記憶體不足的情況下,系統開始依據自身的一套程序回收機制來判斷要kill掉哪些程序,以騰出記憶體來供給需要的app。這套殺程序回收記憶體的機制就叫 Low Memory Killer ,它是基于Linux核心的 OOM Killer(Out-Of-Memory killer)機制誕生。

Android 的 low memory killer 是基于 linux 的OOM(out of memory)規則改進而來的。OOM 通過一些比較複雜的評分機制,對程序進行打分,然後将分數高的程序判定為 bad程序,殺死程序并釋放記憶體。OOM 隻有當系統記憶體不足的時候才會啟動檢查,而 low memory killer 則不僅是在應用程式配置設定記憶體發現記憶體不足時啟動檢查,它也會定時地進行檢查。

Low memory killer 主要是通過程序的 oom_adj 來判定程序的重要程度的。oom_adj 的大小和程序的類型以及程序被排程的次序有關

在 linux 中,存在一個名為 kswapd 的核心線程,當linux回收存放分頁的時候,kswapd 線程将會周遊一張 shrinker 連結清單,并執行回調,或者某個app配置設定記憶體,發現可用記憶體不足時,則核心會阻塞請求配置設定記憶體的程序配置設定記憶體的過程,并在該程序中去執行lowmemorykiller來釋放記憶體

程序被kill的場景

點選home鍵使app長時間停留在背景,記憶體不足被kill

在大多數國産手機下,進入鎖屏狀态一段時間,省電機制會kill背景程序

程序的優先級

什麼是oom_adj?它是linux核心配置設定給每個系統程序的一個值,代表程序的優先級,程序回收機制就是根據這個優先級來決定是否進行回收。對于oom_adj的作用,你隻需要記住以下幾點即可:

程序的oom_adj越大,表示此程序優先級越低,越容易被殺回收;越小,表示程序優先級越高,越不容易被殺回收

普通app程序的oom_adj>=0,系統程序的oom_adj才可能<0

一般前台的程序優先級oom_adj = 0 ,隻有系統程序的oom_adj才會小于0

ps | grep PackageName (com.ypcang.android.shop) //檢視此app全部程序

cat /proc/程序号(19848)/oom_adj //檢視某一程序的優先級

Android應用程式保活

當app在前台時 oom_adj = 0,對應上面的表格是前台程序。

當app退到背景時,oom_adj = 6,對應背景程序。

app退到背景時,其所有的程序優先級都會降低。但是UI程序是降低最為明顯的,因為它占用的記憶體資源最多,系統記憶體不足的時候肯定優先殺這些占用記憶體高的程序來騰出資源。是以,為了盡量避免背景UI程序被殺,需要盡可能的釋放一些不用的資源,尤其是圖檔、音視訊之類的。

提升優先級的方案

利用Activity提升進行優先級

方案設計:

監控手機的鎖屏和解鎖事件,在螢幕鎖屏時啟動1個像素的Activity,在解鎖時将Activity銷毀。該Activity要設計成使用者無感覺。

這裡有個前提是APP程序需要在背景。如果APP程序在前台,那麼程序已經是前台程序了,那麼上面的做法就沒有任何意義了。

通過該方案,程序的優先級可以在鎖屏時由oom_adj為9(不同手機系統的值可能不一樣)提升到0(前台程序)。這樣我們的APP就不容易在鎖屏時間内被第三方應用給殺死。

适用範圍:

場景:該方案主要解決的痛點是第三方應用或者系統管理工具會在檢測到鎖屏事件一段時間後殺死背景程序,以達到省電的目的。

版本:适用于所有的Android版本。

利用Notification提升程序優先級

通過将Android中的Service的setForeground接口可以将背景Service設定為前台Service,這樣程序的優先級就被提升到了2,進而使程序的優先級僅僅次于使用者目前正在互動的程序,與可見程序的優先級一緻,使程序被殺死的機率大大降低。

在Android 2.3開始調用setForeground将背景Service設定為前台Service時,必須在系統的通知欄發送一條通知,這意味着前台Service與一條可見的通知是綁定在一起的。但是對于不需要使用常駐通知欄的應用來說,該方案是使用者感覺的,沒有辦法直接使用。

我們可以通過實作一個内部Service,在LiveService和其内部Service中同時發送具有相同ID的Notification,然後将内部Service結束掉,同時也将Notification結束掉,随着Notification的消失,使用者就無感覺了,同時也實作了将系統優先級提升到2的操作。

程序保活方案

利用系統廣播拉活

方案設計

在發生特定系統事件時,系統會發出響應的廣播,如果我們在AndroidManifest中"靜态"注冊對應的廣播監聽器,就可以在發生響應事件時進行拉活。

常用的用于拉活的廣播事件包括:

Android應用程式保活

适用範圍

适用于全部的Android平台。但是存在着以下幾個缺點:

1、廣播接收器被管理軟體或者系統軟體通過"自啟動"等功能禁用的場景無法接收到廣播,進而無法自啟。

2、系統廣播事件是不可控制的,隻能在保證發生廣播事件時拉活程序,但是無法做到程序挂掉後立即拉活。

是以,該方案隻是作為一個備選方案。

利用第三方應用廣播拉活

該方案的設計思想和接收系統廣播的類似,不同的是該方案接收的是第三方Top應用的廣播。

通過反編譯第三方Top應用,如:手機QQ、微信、支付寶、UC浏覽器等,以及友盟、信鴿、個推等SDK,找出它們外發的廣播,在應用中進行監聽,當這些應用發出廣播時,就會将我們的應用進行拉活。

該方案的缺點和上面所說的系統廣播的方案一樣之外,還有下面幾個缺點:

1、程序拉活的效果取決于反編譯分析過的第三方應用的多少。

2、第三方應用的廣播屬于應用私有的,是以有可能存在目前版本有效的廣播在後續的版本中随時有可能被移除或者被改為不外發。

是以,該方案也隻是作為一個備選方案。

利用系統Service機制拉活

該方案将Service的onStartCommand方法的傳回值設定為START_STICKY,利用系統機制在Service挂掉後自動拉活。

下面這兩種情況無法進行拉活:

1、Service在第一次被異常殺死後會在5秒内重新開機,第二次被殺死後會在10秒重新開機,第三次殺死後會在20秒重新開機,但是一旦在短時間内Service被殺死的次數達到5次,則系統不再拉起。

2、程序被取得Root權限的管理工具或系統工具通過foreStop停止掉,則無法重新開機。

利用JobScheduler機制拉活

Android 5.0以後的版本提供了JobScheduler接口,系統會定時調用該程序以使應用進行一些邏輯操作。

主要适用于Android 5.0以上的版本。在Android 5.0以上版本中不受forcestop影響,被強制停止的應用依然可以被拉起,在Android 5.0以上版本拉活效果是非常好的。(但是在小米手機上可能會偶爾出現無法拉活的問題。)

利用賬号同步機制拉活

Android系統的賬号同步機制會定期同步賬号,該方案的目的在于利用同步機制進行程序的拉活。

适用于所有的Android版本,包括forestop掉的程序也可以進行拉活。但是在最新Android版本(Android N)中系統好像對賬戶同步做了改動,是以該方法是否能夠再用還需要進行一定的實驗。