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 //查看某一進程的優先級

當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的操作。

適用范圍:

版本:適用於所有的Android版本。

進程保活方案

利用系統廣播拉活

方案設計

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

適用范圍

適用於全部的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)中系統好像對賬戶同步做了改動,所以該方法是否能夠再用還需要進行一定的實驗。

參考文章

https://www.jianshu.com/p/df766d5573a5

https://www.jianshu.com/p/16fb9e5cc6cc


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM