【騰訊Bugly干貨分享】Android 進程钡咔活招式大全

雖然這篇文章寫的時間有點遠了,但是很多知識點都是沒變徒探,以前也看過很多蓖吆簦活,但是都說的比較片面测暗,所以轉載這篇文章學習下央串。轉載

還有一篇文章分析市面進程保活的也是挺不錯的(http://www.reibang.com/p/63aafe3c12af

目前市面上的應用碗啄,貌似除了微信和手Q都會比較擔心被用戶或者系統(tǒng)(廠商)殺死問題质和。本文對 Android 進程拉活進行一個總結。

Android 進程拉活包括兩個層面:

  1. 提供進程優(yōu)先級稚字,降低進程被殺死的概率
  2. 在進程被殺死后饲宿,進行拉活

本文下面就從這兩個方面做一下總結。

1. 進程的優(yōu)先級

Android 系統(tǒng)將盡量長時間地保持應用進程胆描,但為了新建進程或運行更重要的進程仆嗦,最終需要清除舊進程來回收內存训唱。 為了確定保留或終止哪些進程便斥,系統(tǒng)會根據進程中正在運行的組件以及這些組件的狀態(tài)米愿,將每個進程放入“重要性層次結構”中。 必要時短绸,系統(tǒng)會首先消除重要性最低的進程车吹,然后是清除重要性稍低一級的進程筹裕,依此類推,以回收系統(tǒng)資源窄驹。

進程的重要性朝卒,劃分5級:

  1. 前臺進程 (Foreground process)
  2. 可見進程 (Visible process)
  3. 服務進程 (Service process)
  4. 后臺進程 (Background process)
  5. 空進程 (Empty process)
圖片.png

前臺進程的重要性最高,依次遞減乐埠,空進程的重要性最低抗斤,下面分別來闡述每種級別的進程

1.1 前臺進程 —— Foreground process
用戶當前操作所必需的進程。通常在任意給定時間前臺進程都為數不多饮戳。只有在內存不足以支持它們同時繼續(xù)運行這一萬不得已的情況下豪治,系統(tǒng)才會終止它們洞拨。

  1. 擁有用戶正在交互的 Activity(已調用 onResume())
  2. 擁有某個 Service扯罐,后者綁定到用戶正在交互的 Activity
  3. 擁有正在“前臺”運行的 Service(服務已調用 startForeground())
  4. 擁有正執(zhí)行一個生命周期回調的 Service(onCreate()、onStart() 或 onDestroy())
  5. 擁有正執(zhí)行其 onReceive() 方法的 BroadcastReceiver

1.2 可見進程 —— Visible process
沒有任何前臺組件烦衣、但仍會影響用戶在屏幕上所見內容的進程歹河。可見進程被視為是極其重要的進程花吟,除非為了維持所有前臺進程同時運行而必須終止秸歧,否則系統(tǒng)不會終止這些進程。

  1. 擁有不在前臺衅澈、但仍對用戶可見的 Activity(已調用 onPause())
  2. 擁有綁定到可見(或前臺)Activity 的 Service

1.3 服務進程 —— Service process
盡管服務進程與用戶所見內容沒有直接關聯(lián)键菱,但是它們通常在執(zhí)行一些用戶關心的操作(例如,在后臺播放音樂或從網絡下載數據)今布。因此经备,除非內存不足以維持所有前臺進程和可見進程同時運行,否則系統(tǒng)會讓服務進程保持運行狀態(tài)部默。

正在運行 startService() 方法啟動的服務侵蒙,且不屬于上述兩個更高類別進程的進程。

1.4 后臺進程 —— Background process

后臺進程對用戶體驗沒有直接影響傅蹂,系統(tǒng)可能隨時終止它們纷闺,以回收內存供前臺進程、可見進程或服務進程使用份蝴。 通常會有很多后臺進程在運行犁功,因此它們會保存在 LRU 列表中,以確保包含用戶最近查看的 Activity 的進程最后一個被終止婚夫。如果某個 Activity 正確實現了生命周期方法浸卦,并保存了其當前狀態(tài),則終止其進程不會對用戶體驗產生明顯影響请敦,因為當用戶導航回該 Activity 時镐躲,Activity 會恢復其所有可見狀態(tài)储玫。

對用戶不可見的 Activity 的進程(已調用 Activity的onStop() 方法)

1.5 空進程 —— Empty process

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

不含任何活動應用組件的進程

2. Android 進程回收策略

Android 中對于內存的回收裆熙,主要依靠 Lowmemorykiller 來完成端礼,是一種根據 OOM_ADJ 閾值級別觸發(fā)相應力度的內存回收的機制。

關于 OOM_ADJ 的說明如下:

圖片.png

其中紅色部分代表比較容易被殺死的 Android 進程(OOM_ADJ>=4),綠色部分表示不容易被殺死的 Android 進程入录,其他表示非 Android 進程(純 Linux 進程)蛤奥。在 Lowmemorykiller 回收內存時會根據進程的級別優(yōu)先殺死 OOM_ADJ 比較大的進程,對于優(yōu)先級相同的進程則進一步受到進程所占內存和進程存活時間的影響僚稿。

Android 手機中進程被殺死可能有如下情況:

圖片.png

綜上凡桥,可以得出減少進程被殺死概率無非就是想辦法提高進程優(yōu)先級,減少進程在內存不足等情況下被殺死的概率蚀同。

3. 提升進程優(yōu)先級的方案

3.1 利用 Activity 提升權限

方案設計思想:監(jiān)控手機鎖屏解鎖事件缅刽,在屏幕鎖屏時啟動1個像素的 Activity,在用戶解鎖時將 Activity 銷毀掉蠢络。注意該 Activity 需設計成用戶無感知衰猛。

通過該方案,可以使進程的優(yōu)先級在屏幕鎖屏時間由4提升為最高優(yōu)先級1刹孔。

方案適用范圍:

  1. 適用場景:本方案主要解決第三方應用及系統(tǒng)管理工具在檢測到鎖屏事件后一段時間(一般為5分鐘以內)內會殺死后臺進程啡省,已達到省電的目的問題。
  2. 適用版本:適用于所有的 Android 版本髓霞。

方案具體實現:首先定義 Activity卦睹,并設置 Activity 的大小為1像素:

圖片.png

其次,從 AndroidManifest 中通過如下屬性酸茴,排除 Activity 在 RecentTask 中的顯示:

圖片.png

最后分预,控制 Activity 為透明:

圖片.png

Activity 啟動與銷毀時機的控制:

圖片.png

3.2 利用 Notification 提升權限

方案設計思想:Android 中 Service 的優(yōu)先級為4,通過 setForeground 接口可以將后臺 Service 設置為前臺 Service薪捍,使進程的優(yōu)先級由4提升為2笼痹,從而使進程的優(yōu)先級僅僅低于用戶當前正在交互的進程,與可見進程優(yōu)先級一致酪穿,使進程被殺死的概率大大降低凳干。

方案實現挑戰(zhàn):從 Android2.3 開始調用 setForeground 將后臺 Service 設置為前臺 Service 時,必須在系統(tǒng)的通知欄發(fā)送一條通知被济,也就是前臺 Service 與一條可見的通知時綁定在一起的救赐。

對于不需要常駐通知欄的應用來說,該方案雖好,但卻是用戶感知的经磅,無法直接使用泌绣。

方案挑戰(zhàn)應對措施:通過實現一個內部 Service,在 LiveService 和其內部 Service 中同時發(fā)送具有相同 ID 的 Notification预厌,然后將內部 Service 結束掉阿迈。隨著內部 Service 的結束,Notification 將會消失轧叽,但系統(tǒng)優(yōu)先級依然保持為2苗沧。

方案適用范圍:適用于目前已知所有版本。

方案具體實現:

圖片.png
圖片.png

4. 進程死后拉活的方案

4.1 利用系統(tǒng)廣播拉活
方案設計思想:在發(fā)生特定系統(tǒng)事件時炭晒,系統(tǒng)會發(fā)出響應的廣播待逞,通過在 AndroidManifest 中“靜態(tài)”注冊對應的廣播監(jiān)聽器,即可在發(fā)生響應事件時拉活网严。

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

圖片.png

方案適用范圍:適用于全部 Android 平臺识樱。但存在如下幾個缺點:

  1. 廣播接收器被管理軟件、系統(tǒng)軟件通過“自啟管理”等功能禁用的場景無法接收到廣播屿笼,從而無法自啟牺荠。
  2. 系統(tǒng)廣播事件不可控翁巍,只能保證發(fā)生事件時拉活進程驴一,但無法保證進程掛掉后立即拉活。

因此灶壶,該方案主要作為備用手段肝断。

4.2 利用第三方應用廣播拉活

方案設計思想:該方案總的設計思想與接收系統(tǒng)廣播類似,不同的是該方案為接收第三方 Top 應用廣播驰凛。

通過反編譯第三方 Top 應用胸懈,如:手機QQ、微信恰响、支付寶趣钱、UC瀏覽器等,以及友盟胚宦、信鴿首有、個推等 SDK,找出它們外發(fā)的廣播枢劝,在應用中進行監(jiān)聽井联,這樣當這些應用發(fā)出廣播時,就會將我們的應用拉活您旁。

方案適用范圍:該方案的有效程度除與系統(tǒng)廣播一樣的因素外烙常,主要受如下因素限制:

  1. 反編譯分析過的第三方應用的多少
  2. 第三方應用的廣播屬于應用私有,當前版本中有效的廣播鹤盒,在后續(xù)版本隨時就可能被移除或被改為不外發(fā)蚕脏。

這些因素都影響了拉活的效果侦副。

4.3 利用系統(tǒng)Service機制拉活

方案設計思想:將 Service 設置為 START_STICKY,利用系統(tǒng)機制在 Service 掛掉后自動拉活:

圖片.png

方案適用范圍:如下兩種情況無法拉活

  1. Service 第一次被異常殺死后會在5秒內重啟驼鞭,第二次被殺死會在10秒內重啟跃洛,第三次會在20秒內重啟,一旦在短時間內 Service 被殺死達到5次终议,則系統(tǒng)不再拉起汇竭。
  2. 進程被取得 Root 權限的管理工具或系統(tǒng)工具通過 forestop 停止掉,無法重啟穴张。

4.4 利用Native進程拉活

方案設計思想:

  • 主要思想:利用 Linux 中的 fork 機制創(chuàng)建 Native 進程细燎,在 Native 進程中監(jiān)控主進程的存活,當主進程掛掉后皂甘,在 Native 進程中立即對主進程進行拉活玻驻。
  • 主要原理:在 Android 中所有進程和系統(tǒng)組件的生命周期受 ActivityManagerService 的統(tǒng)一管理。而且偿枕,通過 Linux 的 fork 機制創(chuàng)建的進程為純 Linux 進程璧瞬,其生命周期不受 Android 的管理。

方案實現挑戰(zhàn):

  • 挑戰(zhàn)一:在 Native 進程中如何感知主進程死亡渐夸。

要在 Native 進程中感知主進程是否存活有兩種實現方式:

  1. 在 Native 進程中通過死循環(huán)或定時器嗤锉,輪訓判斷主進程是否存活,檔主進程不存活時進行拉活墓塌。該方案的很大缺點是不停的輪詢執(zhí)行判斷邏輯瘟忱,非常耗電。
  2. 在主進程中創(chuàng)建一個監(jiān)控文件苫幢,并且在主進程中持有文件鎖访诱。在拉活進程啟動后申請文件鎖將會被堵塞,一旦可以成功獲取到鎖韩肝,說明主進程掛掉触菜,即可進行拉活。由于 Android 中的應用都運行于虛擬機之上哀峻,Java 層的文件鎖與 Linux 層的文件鎖是不同的涡相,要實現該功能需要封裝 Linux 層的文件鎖供上層調用。

封裝 Linux 文件鎖的代碼如下:

圖片.png

Native 層中堵塞申請文件鎖的部分代碼:

圖片.png
  • 挑戰(zhàn)二:在 Native 進程中如何拉活主進程谜诫。

通過 Native 進程拉活主進程的部分代碼如下漾峡,即通過 am 命令進行拉活。通過指定“--include-stopped-packages”參數來拉活主進程處于 forestop 狀態(tài)的情況喻旷。

圖片.png
  • 挑戰(zhàn)三:如何保證 Native 進程的唯一生逸。

從可擴展性和進程唯一等多方面考慮,將 Native 進程設計層 C/S 結構模式,主進程與 Native 進程通過 Localsocket 進行通信槽袄。在Native進程中利用 Localsocket 保證 Native 進程的唯一性烙无,不至于出現創(chuàng)建多個 Native 進程以及 Native 進程變成僵尸進程等問題。

圖片.png

方案適用范圍:該方案主要適用于 Android5.0 以下版本手機遍尺。

該方案不受 forcestop 影響截酷,被強制停止的應用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好乾戏。

對于 Android5.0 以上手機迂苛,系統(tǒng)雖然會將native進程內的所有進程都殺死,這里其實就是系統(tǒng)“依次”殺死進程時間與拉活邏輯執(zhí)行時間賽跑的問題鼓择,如果可以跑的比系統(tǒng)邏輯快三幻,依然可以有效拉起。記得網上有人做過實驗呐能,該結論是成立的念搬,在某些 Android 5.0 以上機型有效。

4.5 利用 JobScheduler 機制拉活

方案設計思想:Android5.0 以后系統(tǒng)對 Native 進程等加強了管理摆出,Native 拉活方式失效朗徊。系統(tǒng)在 Android5.0 以上版本提供了 JobScheduler 接口,系統(tǒng)會定時調用該進程以使應用進行一些邏輯操作偎漫。

在本項目中爷恳,我對 JobScheduler 進行了進一步封裝,兼容 Android5.0 以下版本骑丸。封裝后 JobScheduler 接口的使用如下:

圖片.png
圖片.png

方案適用范圍:該方案主要適用于 Android5.0 以上版本手機舌仍。

該方案在 Android5.0 以上版本中不受 forcestop 影響,被強制停止的應用依然可以被拉活通危,在 Android5.0 以上版本拉活效果非常好。

僅在小米手機可能會出現有時無法拉活的問題灌曙。

4.6 利用賬號同步機制拉活

方案設計思想:Android 系統(tǒng)的賬號同步機制會定期同步賬號進行菊碟,該方案目的在于利用同步機制進行進程的拉活。添加賬號和設置同步周期的代碼如下:

圖片.png

該方案需要在 AndroidManifest 中定義賬號授權與同步服務在刺。

圖片.png

方案適用范圍:該方案適用于所有的 Android 版本逆害,包括被 forestop 掉的進程也可以進行拉活。

最新 Android 版本(Android N)中系統(tǒng)好像對賬戶同步這里做了變動蚣驼,該方法不再有效魄幕。

  1. 其他有效拉活方案

經研究發(fā)現還有其他一些系統(tǒng)拉活措施可以使用,但在使用時需要用戶授權颖杏,用戶感知比較強烈纯陨。

這些方案包括:

  1. 利用系統(tǒng)通知管理權限進行拉活
  2. 利用輔助功能拉活,將應用加入廠商或管理軟件白名單。

這些方案需要結合具體產品特性來搞翼抠。

上面所有解釋這些方案都是考慮的無 Root 的情況咙轩。

其他還有一些技術之外的措施,比如說應用內 Push 通道的選擇:

  1. 國外版應用:接入 Google 的 GCM阴颖。
  2. 國內版應用:根據終端不同活喊,在小米手機(包括 MIUI)接入小米推送、華為手機接入華為推送量愧;其他手機可以考慮接入騰訊信鴿或極光推送與小米推送做 A/B Test钾菊。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市偎肃,隨后出現的幾起案子结缚,更是在濱河造成了極大的恐慌,老刑警劉巖软棺,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件红竭,死亡現場離奇詭異,居然都是意外死亡喘落,警方通過查閱死者的電腦和手機茵宪,發(fā)現死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘦棋,“玉大人稀火,你說我怎么就攤上這事《呐螅” “怎么了凰狞?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沛慢。 經常有香客問我赡若,道長,這世上最難降的妖魔是什么团甲? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任逾冬,我火速辦了婚禮,結果婚禮上躺苦,老公的妹妹穿的比我還像新娘身腻。我一直安慰自己,他們只是感情好匹厘,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布嘀趟。 她就那樣靜靜地躺著,像睡著了一般愈诚。 火紅的嫁衣襯著肌膚如雪她按。 梳的紋絲不亂的頭發(fā)上牛隅,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音尤溜,去河邊找鬼倔叼。 笑死,一個胖子當著我的面吹牛宫莱,可吹牛的內容都是我干的丈攒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼授霸,長吁一口氣:“原來是場噩夢啊……” “哼巡验!你這毒婦竟也來了?” 一聲冷哼從身側響起碘耳,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤显设,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辛辨,有當地人在樹林里發(fā)現了一具尸體捕捂,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年斗搞,在試婚紗的時候發(fā)現自己被綠了指攒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡僻焚,死狀恐怖允悦,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情虑啤,我是刑警寧澤隙弛,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站狞山,受9級特大地震影響全闷,放射性物質發(fā)生泄漏。R本人自食惡果不足惜铣墨,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一室埋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伊约,春花似錦、人聲如沸孕蝉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽降淮。三九已至超埋,卻和暖如春搏讶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背霍殴。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工媒惕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人来庭。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓妒蔚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親月弛。 傳聞我的和親對象是個殘疾皇子肴盏,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評論 25 707
  • 轉載一篇不錯的文章菜皂,解決了我一下關于如何保留android進程的技術。 Android 進程崩髀埽活 目前市面上的應用...
    小帝Ele閱讀 1,021評論 0 6
  • 終于體會到 有些人 在感情面前 恍飘,分開之后 便不愿意在找了 ,那是因為感情徹徹底底的傷了她(他)的心谴垫; 有些人則是...
    淺夢佳人閱讀 212評論 0 1
  • 111.be beyond sb’s comprehension. 超出某人理解范圍的 112.be low of...
    Sharewealorwoel閱讀 138評論 0 0
  • 很多時候自己并非了解自己章母,尤其是關于對一件事情的恐懼,更尤其是對像我這種某些方面敏感性低的人弹渔。自己本身沒有自帶一個...
    Valerie妤閱讀 245評論 0 0