Android 進程常駐(2)----細數利用android系統機制的保活手段

年前就開篇了android進程常駐,但是一直瑣事不斷,也一直沒有靜下心來整理,只是把項目傳到的github,有好多朋友會來問我其中實現原理,其實也是一點一點推演過來的。我的想法就是按照我當時的推演過程,按順序寫完這幾篇博客,也算是對那一個月努力的一個交代。


上一篇講了系統管理進程和強殺進程的過程原理,今天就開始想一下,在此基礎上,如何實現保活,當然作爲一個android開發,最先想到的肯定是在framework層有沒有什麼機制可以利用實現保活,當時整理了以下幾點(是對照自己當時寫的ppt整理的,有些細節已經忘記):


1、將Service設置爲前臺進程

2、在service的onstart方法裏返回 STATR_STICK

3、添加Manifest文件屬性值爲android:persistent=“true”

4、覆寫Service的onDestroy方法

5、添加廣播監聽android.intent.action.USER_PRESENT事件以及其他一些可以允許的事件

6、服務互相綁定

7、設置鬧鐘,定時喚醒

8、賬戶同步,定時喚醒

9、native層保活






好的,然後我們一個一個的來說



1、將Service設置爲前臺進程。

本質是修改了Service所在進程的進程優先級,詳情請參照Android 進程常駐(1)----開篇。有了前臺進程的優先級,在android系統清理內存的時候,他被殺死的優先級僅高於前臺的activity,也就是正在和用戶交互的頁面,而且使用ddms殺進程他也可以自己啓動起來。

但是,然,並,卵!

首先ddms殺進程和在系統設置的正在運行中殺進程本身就不具威脅,在系統設置的所有應用中選擇強行停止,仍然可以強停掉,360,cm等軟殺更是能輕而易舉殺死他。而且他還有一個缺點,在api 17以上,設置了一個前臺服務,他會以一個無法消除的notification的樣式出現在用戶的手機狀態欄裏,大大降低了用戶體驗。看源碼




所以一般這麼用







2、在service的onstart方法裏返回 STATR_STICK

沒多大用,放在常規應用裏的service ok,但保活的話還是差些。。。這裏不多說了直接看源碼註釋




其他幾個返回值分別代表了

START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill後一定能重啓。 

START_STICKY:系統就會重新創建這個服務並且調用onStartCommand()方法,但是它不會重新傳遞最後的Intent對象,這適用於不執行命令的媒體播放器(或類似的服務),它只是無限期的運行着並等待工作的到來。

START_NOT_STICKY:直到接受到新的Intent對象,纔會被重新創建。這是最安全的,用來避免在不需要的時候運行你的服務。

START_REDELIVER_INTENT:系統就會重新創建了這個服務,並且用最後的Intent對象調。等待中的Intent對象會依次被髮送。這適用於如下載文件。






3、添加Manifest文件屬性值爲android:persistent=“true”

如果你的應用能設置這個屬性,可以全文跳過我這個系列所有文章。因爲他真的可以殺不死,像系統的keyguard進程,media進程,且這些進程的adj都是負數,代表了前臺activity黑屏了他們也不會死。但是這個屬性需要系統shareuid,然後編譯不過,因爲需要系統簽名,什麼?你用系統簽名?請忽略我全部

所以然並卵。





4、覆寫Service的onDestroy方法

你會說這麼low也行?爲了把我知道的所有方式都列舉出來,所以這裏也說一下,在設置裏面的正在運行,注意是正在運行裏面,點擊關閉,會走onDestroy回調方法,你在這裏可以把自己啓動起來。

但是仍然然並卵,設置裏面的force close纔是真正的勁敵,還有root了的360,cm這些boos纔是我們要解決的對象。




5、添加廣播監聽android.intent.action.USER_PRESENT事件以及其他一些可以允許的事件

這個有必要說一下,這個廣播相信可能有的朋友不是很清楚,這是一個android解鎖的廣播事件。

注意:

1.這不是SCREEN_ON\SCREEN_OFF廣播,,這不是SCREEN_ON\SCREEN_OFF廣播,這不是SCREEN_ON\SCREEN_OFF廣播。

2.這是一個可以靜態註冊的廣播,這是一個可以靜態註冊的廣播,這是一個可以靜態註冊的廣播。


所以在manifest裏面註冊之後不需要任何前提,理論上用戶每次開屏解鎖都會觸發我們的onReceive事件,在這裏我們可以檢查進程服務是否在,不在就拉起來。

但是,這個事件只有解鎖纔有,如果用戶的沒有設置鎖屏,那麼這個事件就是沒有的,而且我們的目標是保證進程一直存活,而不是儘可能多的活起來。所以這個當作一個補充的手段也不錯,另外所有那些可以靜態註冊的廣播都可以這樣搞,前提是你不怕用戶看到你申請了好多權限,當然這個USER_PRESENT事件是不需要權限的。

以下是幾個常見可以靜態註冊的廣播,另外android7取消了wifi的靜態廣播註冊,沒有證實

android.intent.action.USER_PRESENT
android.net.conn.CONNECTIVITY_CHANGE
android.intent.action.MEDIA_MOUNTED
android.intent.action.MEDIA_UNMOUNTED
android.net.wifi.RSSI_CHANGED
android.net.wifi.STATE_CHANGE
android.net.wifi.WIFI_STATE_CHANGED




6、服務互相綁定

這個是android裏面一個特性,跨進程bind一個service之後,如果被bind的service掛掉,bind他的service會把他拉起來。依然然並卵,具體爲什麼以後再說。



7、設置鬧鐘,定時喚醒

市面上瞭解到的大部分應用是用這種保活方式,使用系統鬧鐘定時發通知過來喚醒進程。

但是,

且先不說高頻的喚醒和手機廠商對於wakelock的控制上造成的耗電問題。單單保活效果上就很難過關,force close直接殺掉,沒有掙扎的機會,360、cm更是隨便殺。說下alarm的幾個參數


AlarmManager.RTC,硬件鬧鐘,不喚醒手機(也可能是其它設備)休眠;當手機休眠時不發射鬧鐘。

AlarmManager.RTC_WAKEUP,硬件鬧鐘,當鬧鐘發躰時喚醒手機休眠;

AlarmManager.ELAPSED_REALTIME,真實時間流逝鬧鐘,不喚醒手機休眠;當手機休眠時不發射鬧鐘。

AlarmManager.ELAPSED_REALTIME_WAKEUP,真實時間流逝鬧鐘,當鬧鐘發躰時喚醒手機休眠;

 

嗯,RTC鬧鐘和ELAPSED_REALTIME最大的差別就是前者可以通過修改手機時間觸發鬧鐘事件,後者要通過真實時間的流逝,即使在休眠狀態,時間也會被計算。






8、賬戶同步,定時喚醒

這個估計也是好多人不知道一點,android系統裏有一個賬戶系統,設置一個自己的賬戶,android會定期喚醒賬戶更新服務,我們可以自己設定同步的事件間隔。且發起更新的是系統,不會受到任何限制。看下效果,晚上下班到第二天早晨,開着cm後臺自動清理




 log上來看喚醒時間一直正常,且在睡眠中是不會產生喚醒的。

使用方法也很簡單:









那麼,這就是我們想要的?


還不行!!!


他的侷限性在於:

第一,用戶會在系統設置的賬戶列表裏面看到一個不認識的賬戶;

第二,同步的事件間隔是有限制的,最短1分鐘,見源碼,如果小雨60秒,置爲60秒。而且各種國產機怎麼改的源碼我們未可知,是不是都能用仍然未可知;

第三,很致命,某些手機比如note3需要手動設置賬戶,你如何騙你的用戶給你手動設置賬戶完了之後不卸載你;

第四,也很致命,必須聯網!google提供這個組件是讓你同步賬戶信息,不聯網你同步個鬼,我們要保活,可以不聯網不做事,但是不能不聯網就死


但是,把他放在最後,仍然是一個很好的保活補充手段

9、native層保活

終於要到正文了。下一篇開啓native保活的篇章,首先上一個github上別人的native保活方案,也是絕大多數公司採用的native方案,筆者所在公司亦是北京知名互聯網公司,之前也採取的類似方案,但是,其實只是開了一個native進程定期發intent而已,缺陷是:只能簡單保活,360、cm碾壓其無壓力,但仍有可借鑑之處,下一篇分析,然後開始我的native之旅

https://github.com/Coolerfall/Android-AppDaemon


發佈了42 篇原創文章 · 獲贊 44 · 訪問量 85萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章