Android後臺保活實踐總結:即時通信應用沒法根治的「頑疾」

前言

Android進程和Service的保活,是困擾Android開發人員的一大頑疾。因涉及到省電和內存管理策略,各廠商基於自家的理解,在自已ROOM發佈於都對標準Android發行版做爲或多或少的改動,使得應用層程序在處理進程和Service保活問題上變的異常複雜,且很難兼容,由於說不定哪款手機或者哪一個版本的省電策略發生改變,那麼隨之而來的就是進程和Service保活的差別。

在應用場景上,因爲即時通信應用(包括IM聊天應用、消息推送服務等)爲了保證消息的全時、實時送達能力,必需要實現進程或Service的保活。而就這一看似不起眼的問題,實際處理起來,由於衆多Android手機和Android系統版本的差別,讓問題的處理充滿了不肯定性。

本文基於做者的實踐以及相關資料的整理,總結了自已對Android進程和Service保活的理解,但願能爲你的應用開發帶來啓發。php

學習交流

- 更多即時通信技術資料:http://www.52im.net/forum.php?mod=collection&op=allhtml

- 即時通信開發交流羣: 215891622 [推薦]java

概述

近期作了一個Android項目,涉及到了後臺進程和Service保活的問題,網上找了不少資料,基本的保活方法都測試了。結果是:不一樣的手機,不一樣的Android版本保活效果各有差別。最難繞過的是個廠商對「後臺程序保活」管理。

本文主要把相應的實踐結果和保活方法進行總結。然而,因筆者可用的測試真機有限,可能存有不完整的地方,還請及時提出指正並補充,你們共同進步。android

手機QQ、微信這樣的大型IM是如何解決保活問題的?

以小米手機爲例,MIUI的神隱模式讓不少IM和推送開發同行糾結不已:在MIUI深度休眠以後,默認會完全斷開後臺應用的socket。但微信、QQ這樣的應用,MIUI官方的帖子說了:給這2個應用特殊照顧。好吧,特殊照顧,普通的APP只能繼續折騰了。

(關於MIUI的神隱模式的討論,見此貼的回覆:http://www.52im.net/thread-354-1-1.htmlgit

本文實踐涉及到的真機型號和版本

手機:三星9100-4.1.2,三星9300-4.3,華爲G730-4.1.2,華爲TL00H-EMUI3.1(android 5.1.1),魅族MX4-Flyme4.2.8.2c(android 4.4.2)。

手頭能用的測試機就這些了。主要測試的service是一個最基本的service,在相應的生命週期的觸發函數上作了輸出。測試時都沒有添加到後臺保護中,注:三星的機子沒找到有後臺保護設置的地方。github

爲何咱們的後臺進程/Service會被結束掉?

我想到的是有三個方面:微信

  • Android系統內存回收機制;
  • 各廠商對後臺程序的一個管理制度(就是容許程序後臺運行那個);
  • 第三方軟件的清理(360什麼的)。


其中有的後臺程序保護把程序結束的同時會把程序弄成中止狀態,致使沒法接收廣播!app

咱們的保活方案有哪些?

1)控制onStartCommand函數的返回值:

我對這個函數的理解是:當服務被異常終止時,是否重啓服務?有些文章裏面在用這個作保活時,修改的是flag,在我實際測試中是無效。有效的作法是直接返回參數。另外默認的flags值爲0,是START_STICKY_COMPATIBILITY。

具體代碼以下:socket

1
2
3
4
5
6
@Override
publicintonStartCommand(Intent intent,intflags,intstartId) {
     // TODO Auto-generated method stub
     returnSTART_STICKY;
     //return super.onStartCommand(intent, flags, startId);
}


測試結果:
魅族的機子無效,無論默認仍是修改參數,在DDMS裏面直接結束進程後都不會重啓服務。其它三臺機子(9100沒測):默認參數的狀況下就會重啓服務,return START_STICKY 會重啓,return START_NOT_STICKY 不會重啓。

另外:用360一鍵清理,或者360超級ROOT的手機優化,會殺死進程,過會兒仍是會重啓,只是會慢不少,大概是在排隊重啓服務。

ide

2)在service 的onDestory裏面重啓服務:

這個在全部能觸發onDestory的狀況下都是有效的。4臺測試機都測試過。直接startService 或者發送廣播重啓均可以 。

但能觸發onDestory的狀況,我不知道內存回收會不會觸發。另外兩種狀況(2,3)是不觸發的。個人測試方法是在「設置」-> 應用管理-> 正在運行-> 中止服務。(這個是正常中止服務,會觸發onDestory,因此上面的onStartCommand效果不會觸發。)

3)提升服務的優先級:

這個主要是針對第一種kill服務的狀況,內存回收機制。因爲這個測試比較難搭建。360清理什麼把後臺的進程都殺的,體現不出優先級這樣的概念。個人建議是能提升就提升,下面幾個實驗。

[1] 前臺service:
建立一個通知使本身成爲前臺service
測試結果:
360一鍵清理和手機優化,不會把該service結束掉。

[2] 對於後臺保護:
華爲G730不結束service,魅族和華爲TL00H都會結束service。通知欄的保活效果仍是能夠的,通常的應用要求基本能知足了。

[3] 如有root權限:
android:persistent="true",並放入system/app中
測試結果:
效果通常,三星9100上用360等清理工具殺不掉進程,在華爲G730上沒什麼效果.(這個測試跟onStartCommand有點干擾)。

4)守護進程:

雙服務:360會同時殺掉兩個服務,分兩個apk也同樣。
native守護進程:360不會殺掉native的守護進程,但在魅族和華爲TL00H中待機一段時間後仍是會被殺掉。

結論和待續:
1. 通常的應用添加到後臺保護進程後,改個onStartCommand返回值,再加個通知。基本上大部分都能保活了。
2. 雙服務我以爲沒有native守護進程來的好,雖然360,微信什麼的都有幾個進程服務,但若是不添加到後臺保活的話,效果同樣不能保活,也會進入中止狀態。
3. 可是.360手機助手會建立雙natice守護進程作相互的看守。存活的效果會高一點點。「沒添加到後臺保活」通常只會殺一次,(魅族是屏幕關閉後5分鐘,華爲TL00H是屏幕關閉時)。

附個native守護進程:利用socket來判斷服務是否存在,須要在被保活的服務裏建立一個監聽socket。調試信息會在SD卡目錄下建立一個daemon.log。使用方法:NDKFork port包名/.服務名。具體下載連接:
http://download.csdn.net/detail/pvlking/9412815

Android應用實現保活的基本原理總結

都是經過雙進程互拉以及設置進程的重要性,除非你root後,把本身的進程設置成系統進程。

互拉的方式有不少種:

  • 能夠經過監聽系統廣播來把本身拉起來
  • 能夠多個app相互拉
  • 能夠把本身的服務搞成前臺服務
  • 在service的onstart方法裏返回 STATR_STICK
  • 添加Manifest文件屬性值爲android:persistent=「true」
  • 覆寫Service的onDestroy方法
  • 服務互相綁定
  • 設置鬧鐘,定時喚醒
  • 本身的app在native層fork一個子進程來與主進程互拉。


綜上所述,總結下來就是,目前實現Android後臺保活沒有完美實現,只能針對不一樣的機型綜合使用上面列舉的方法,同時祈禱自已APP的用戶不要遇到奇葩機型的保活問題。

推薦一個開源的解決方案 

1)源碼託管地址

源碼託管地址是:https://github.com/52im/MarsDaemon

2)實現原理

原理:使用Jni,在 c端 fork進程,檢測Service是否存活,若Service已被殺死,則進行重啓Service.  至於檢測方式,能夠輪詢獲取子進程Pid,若爲1, 則說明子進程被Init進程所領養,已經成爲了孤兒進程.    可是這種方式比較消耗電量,而且因爲不一樣手機系統定製的改變,當應用被強制中止時,父進程並不必定被真正殺死,所以在一些特定機型上是沒法經過此方式進行判斷. 這裏推薦使用liunx socket的方式進行相似心跳包的檢測,而且當觸發檢測Service是否被殺死以前,須要判斷應用是否已經被卸載,若是應用已經被卸載,則再也不進行檢測Service行爲,直接調用exit(0)退出子進程,避免浪費系統資源和消耗電量.

注意: 目前在Android 5.0系統上會把fork出來的進程放到一個進程組裏, 當程序主進程掛掉後,也會把整個進程組殺掉,所以用fork的方式也沒法在Android5.0及以上系統實現守護進程. 這個是系統層面的限制,固然也是爲了優化整個的系統環境,守護進程給手機帶來的體驗並很差

具體見源碼:
http://androidxref.com/5.0.0_r2/ ... /ProcessRecord.java
Android後臺保活實踐總結:即時通信應用沒法根治的「頑疾」_1809710-8f67dfa36f847c43.png 

好消息:
Android5.0 以上目前已在 https://github.com/52im/MarsDaemon 中被黑科技攻克,部分機型可能沒法起到做用,但思路很值得借鑑,代碼結構也不錯, 具體方案請見源碼哦。

 

(本文同步發佈於:http://www.52im.net/thread-429-1-1.html

相關文章
相關標籤/搜索