目錄:
1、方案
2、進(jìn)程
3、參考資料大集合
4、額外收獲

這周因?yàn)楣窘邮值囊粋€(gè)項(xiàng)目涉及到進(jìn)程保活問題,小野貓?jiān)诰W(wǎng)上翻翻炒炒各種方案,著實(shí)費(fèi)勁掙扎了一番。真真是從入門到放棄,當(dāng)然跟各路大神的從入門到放棄在深度上還是有很大的差別的。無論如何,在此記錄一番以留下鄙人在進(jìn)程?;钸@條路上走過的痕跡。
路過且想直接翻更優(yōu)良資料的小伙伴,請(qǐng)繞路到本文的第三部分:<a>3. 資料大集合</a>
1. 方案
有人說:
進(jìn)程永生不死終究是個(gè)徹頭徹尾的偽命題!
<a>服服帖帖地相信著。</a>
這些天瞧見的幾種?;罘桨福?/p>
- 提升進(jìn)程/服務(wù)優(yōu)先級(jí),降低被殺死的幾率
- 利用系統(tǒng)廣播喚醒
- 雙進(jìn)程守護(hù),你被殺掉我來救
- 第三方SDK或其他APP,相互喚醒
- 傳說中與廠商合作,添加白名單
方案很多,然而,沒有添加白名單,怎么都不能完全做到的。
可參考資料:Android保證service不被殺掉-增強(qiáng)版: 進(jìn)程?;?根據(jù)用戶需求慎用)
我曾掙扎過的,大家都懂:
- 在Application,Service,Receiver標(biāo)簽內(nèi)添加:
android : persistent = true - 將Service設(shè)置為前臺(tái)服務(wù):在
onCreate()方法中調(diào)用startForeground(),在onDestroy()中調(diào)用stopForeground()。 - 在Service的
onDestroy()中發(fā)送廣播通知啟動(dòng)Service自己。 - 在Service的
onStartCommand()方法設(shè)置返回值為START_STICKY - 監(jiān)聽系統(tǒng)廣播,時(shí)刻喚醒自己
其中ACTION_TIME_TICK每分鐘發(fā)送一次,不過似乎不支持靜態(tài)廣播監(jiān)聽 - NDK做雙進(jìn)程守護(hù)
- 上面這些是代碼層面上的做法,另外針對(duì)不同的廠商,指導(dǎo)用戶在手機(jī)管家、i管家應(yīng)用里做一些用戶可操作的信任操作也是有必要的。
當(dāng)然,并不是說掙扎后發(fā)現(xiàn)這些做法都沒有用,而是無法保證進(jìn)程一定不死。各個(gè)廠商有自己的一套內(nèi)存管理機(jī)制,不在白名單內(nèi)很難做到,要加入白名單也很難。
2. 進(jìn)程
2.1. 進(jìn)程分類
進(jìn)程分為以下五個(gè)類別,對(duì)應(yīng)五個(gè)級(jí)別,排列順序按優(yōu)先級(jí)從最高到最低。
傳送門,咱去看看官方完整說明 ???
-
前臺(tái)進(jìn)程(Foreground Process)
用戶當(dāng)前操作所必須的進(jìn)程。 -
可見進(jìn)程(Visible Process)
沒有任何前臺(tái)組件,但仍會(huì)影響用戶在屏幕上所見內(nèi)容的進(jìn)程。 -
服務(wù)進(jìn)程(Service Process)
正在運(yùn)行已使用startService()方法啟動(dòng)的服務(wù)的進(jìn)程,而且該進(jìn)程不屬于“前臺(tái)進(jìn)程”和“可見進(jìn)程”。 -
后臺(tái)進(jìn)程(Background Process)
包含了目前對(duì)用戶不可見的Activity的進(jìn)程(這個(gè)Activity已經(jīng)調(diào)用了onStop()方法)。 -
空進(jìn)程(Empty Process)
不含任何活動(dòng)應(yīng)用組件的進(jìn)程。之所以存在空進(jìn)程的目的是做“緩存”。
如果要通過提高進(jìn)程優(yōu)先級(jí)來降低進(jìn)程被殺死的可能性,首先我們得知道有哪些進(jìn)程是前臺(tái)進(jìn)程。那么問題來了,什么進(jìn)程會(huì)被定為前臺(tái)進(jìn)程呢?
下圖就是官方正解了:

2.2. 進(jìn)程被殺死的情況有哪些???
-
觸發(fā)系統(tǒng)進(jìn)程管理機(jī)制(調(diào)的接口是:
Lowmemorykiller)
根據(jù)重要性的值,由大到小依次殺掉 -
沒有root,被第三方應(yīng)用殺死(調(diào)的接口是:
killBackgroundProcess)
只會(huì)殺死OOM_ADJ值為4以上的進(jìn)程 -
有root,被第三方應(yīng)用殺死(調(diào)的接口是:
force-stop或kill)
理論上可殺掉所有進(jìn)程,一般只殺非系統(tǒng)關(guān)鍵進(jìn)程和非前臺(tái)和可見進(jìn)程 -
各廠商提供的殺進(jìn)程的功能(調(diào)的接口是:
force-stop或kill)
理論上可以殺掉包括Native進(jìn)程在內(nèi)的所有進(jìn)程 -
用戶主動(dòng)強(qiáng)行停止進(jìn)程(調(diào)的接口是:
force-stop)
只能停止第三方和非system/phone進(jìn)程應(yīng)用。
2.3. 進(jìn)程回收機(jī)制:(LowMemoryKiller)
在2.2中我們提到,觸發(fā)系統(tǒng)進(jìn)程管理機(jī)制來殺死進(jìn)程所調(diào)用的接口就是:LowMemoryKiller,那么這個(gè)LowMemoryKiller究竟是啥呢?
安卓開發(fā)過程中稍不注意很可能就出現(xiàn)OOM,這個(gè)大家都是知道的,不就是內(nèi)存溢出么。LowMemoryKiller正是安卓系統(tǒng)對(duì)Linux內(nèi)核的內(nèi)存管理機(jī)制的一個(gè)增強(qiáng)。要說起來這個(gè)低內(nèi)存管理機(jī)制跟內(nèi)存溢出機(jī)制還帶了幾分血緣關(guān)系咧!
2.3.1. LowMemoryKiller原理:
Low Memory Killer在用戶空間中指定了一組內(nèi)存臨界值,當(dāng)其中的某個(gè)值與進(jìn)程描述中的oom_adj值在同一范圍時(shí),該進(jìn)程將被Kill掉。
LowMemoryKiller在系統(tǒng)啟動(dòng)的時(shí)候就已經(jīng)由init進(jìn)程一并啟動(dòng)了。LowMemoryKiller啟動(dòng)就是,就會(huì)不斷監(jiān)測(cè)系統(tǒng)的運(yùn)行情況和內(nèi)存情況,當(dāng)內(nèi)存少于minfree文件中限定的閥值的時(shí)候,lowMemoryKiller遍歷當(dāng)前進(jìn)程的oom_score_adj,把大于對(duì)應(yīng)閥值的進(jìn)程進(jìn)行kill操作。

2.3.2. AMS計(jì)算進(jìn)程的優(yōu)先級(jí)值
每個(gè)進(jìn)程都有自己的oom_adj和oom_score_adj兩個(gè)值,這兩個(gè)值是由位于應(yīng)用框架層中ActivityManager的AMS(ActivityManagerService)計(jì)算出來的。
oom_adj代表進(jìn)程的優(yōu)先級(jí),數(shù)值越高,優(yōu)先級(jí)越低,越容易被殺死;對(duì)應(yīng)每個(gè)oom_adj都可以有一個(gè)空閑進(jìn)程的閥值。Android Kernel每隔一段時(shí)間會(huì)檢測(cè)當(dāng)前空閑內(nèi)存是否低于某個(gè)閥值。假如是,則殺死oom_adj最大的不必要的進(jìn)程,如果有多個(gè),就根據(jù)oom_score_adj去殺死進(jìn)程,,直到內(nèi)存恢復(fù)低于閥值的狀態(tài)。
2.3.3. 設(shè)定LowMemoryKiller對(duì)照值的兩個(gè)文件
- adj文件:
/sys/module/lowmemorykiller/parameters/adj
保存著當(dāng)前系統(tǒng)殺進(jìn)程的等級(jí) - minfree文件:
/sys/module/lowmemorykiller/parameters/minfree。
保存對(duì)應(yīng)的閥值。
下圖是oom_adj的級(jí)別對(duì)照說明:
紅色部分 代表比較容易被殺死的 Android 進(jìn)程
綠色部分 表示不容易被殺死的 Android 進(jìn)程
其他 表示非 Android 進(jìn)程

下圖是Android6.0中設(shè)定的16個(gè)adj值及其對(duì)應(yīng)的說明:

有關(guān)AMS的參考資料:Android核心分析之AMS
有關(guān)LowMemoryKiller的參考資料:Android 6.0的lowmemorykiller機(jī)制
開發(fā)不死軟件,從系統(tǒng)性能方面來說是很不利的,當(dāng)手機(jī)上這樣的應(yīng)用多了,系統(tǒng)就危險(xiǎn)了。但是另一方面,有些應(yīng)用為了保證用戶體驗(yàn)不得不讓自己的進(jìn)程保持不死狀態(tài),比如說來電秀、即時(shí)通訊等類型的APP。無論是出于學(xué)習(xí)還是出于工作需要,了解下無妨。
3. 參考資料大集合
傳說中大冰哥的系列文章(這家伙人長(zhǎng)得帥,文寫得好,知乎上的問答也棒棒的!如我這般生活在安卓開發(fā)最底層的貧下中農(nóng)就該多看看多學(xué)習(xí)):
關(guān)于 Android 進(jìn)程?;睿闼枰赖囊磺?/a>
Android后臺(tái)殺死系列之一:FragmentActivity及PhoneWindow后臺(tái)殺死處理機(jī)制
Android后臺(tái)殺死系列之二:ActivityManagerService與App現(xiàn)場(chǎng)恢復(fù)機(jī)制
Android后臺(tái)殺死系列之三:LowMemoryKiller原理(4.3-6.0)
Android后臺(tái)殺死系列之四:Binder訃告原理
此外更有好文:
Android 進(jìn)程?;钫惺酱笕?/a>
論Android應(yīng)用進(jìn)程長(zhǎng)存的可行性
微信Android客戶端后臺(tái)保活經(jīng)驗(yàn)分享
Android進(jìn)程?;畹囊话闾茁?/a>
Android進(jìn)程?;?自“裁”或者耍流氓
關(guān)于進(jìn)程保活的兩三事——新手升級(jí)經(jīng)驗(yàn)卡
Android 進(jìn)程?;疃荚谶@里
Hello-Daemon【github】
4. 額外收獲
搜集資料過程中發(fā)現(xiàn),有些程序開發(fā)小伙伴在接到需求后會(huì)先針對(duì)需求進(jìn)行深入思考再開始投入實(shí)際的工作,是個(gè)很不錯(cuò)的工作方式,避免了在工作過程中陷入“搜索資料-思考-實(shí)踐-再搜集資料-再思考-再實(shí)踐”的不良循環(huán)中。大概方向先把控好無形之中能很大地提高工作效率。