一種提高Android應用程式存活率新方法

skyseraph發表於2016-12-19

基礎知識

Android 程式優先順序

1 程式優先順序等級一般分法

  • Activte process
  • Visible Process
  • Service process
  • Background process
  • Empty process

2 Service技巧

  • onStartCommand返回START_STICKY
  • onDestroy中startself
  • Service後臺變前置,setForground(true)
  • android:persistent = “true”

3 程式優先順序號

ProcessList.java

Android Low Memory Killer

Android系統記憶體不足時,系統會殺掉一部分程式以釋放空間,誰生誰死的這個生死大權就是由LMK所決定的,這就是Android系統中的Low Memory Killer,其基於Linux的OOM機制,其閾值定義如下面所示的lowmemorykiller檔案中,當然也可以通過系統的init.rc實現自定義。
lowmemorykiller.c

在Low Memory Killer中通過程式的oom_adj與佔用記憶體的大小決定要殺死的程式,oom_adj值越小越不容易被殺死。其中,lowmem_minfree是殺程式的時機,誰被殺,則取決於lowmem_adj,具體值得含義參考上面 Android程式優先順序 所述.

在init.rc中定義了init程式(系統程式)的oom_adj為-16,其不可能會被殺死(init的PID是1),而前臺程式是0(這裡的前臺程式是指使用者正在使用的Activity所在的程式),使用者按Home鍵回到桌面時的優先順序是6,普通的Service的程式是8.
init.rc

關於Low Memory Killer的具體實現原理可參考Ref-2.

檢視某個App的程式

步驟(手機與PC連線)

  1. adb shell
  2. ps | grep 程式名
  3. cat /proc/pid/oom_adj //其中pid是上述grep得到的程式號

ps-grep

Linux AM命令

am命令:在Android系統中通過adb shell 啟動某個Activity、Service、撥打電話、啟動瀏覽器等操作Android的命令.其原始碼在Am.java中,在shell環境下執行am命令實際是啟動一個執行緒執行Am.java中的主函式(main方法),am命令後跟的引數都會當做執行時引數傳遞到主函式中,主要實現在Am.java的run方法中。

撥打電話
命令:am start -a android.intent.action.CALL -d tel:電話號碼
示例:am start -a android.intent.action.CALL -d tel:10086

開啟一個網頁
命令:am start -a android.intent.action.VIEW -d 網址
示例:am start -a android.intent.action.VIEW -d http://www.skyseraph.com

啟動一個服務
命令:am startservice <服務名稱>
示例:am startservice -n com.android.music/ com.android.music.MediaPlaybackService

NotificationListenerService

“A service that receives calls from the system when new notifications are posted or removed, or their ranking changed.” From Google

用來監聽到通知的傳送以及移除和排名位置變化,如果我們註冊了這個服務,當系統任何一條通知到來或者被移除掉,我們都能通過這個service來監聽到,甚至可以做一些管理工作。

Android賬號和同步機制

屬於Android中較偏冷的知識,具體參考 Ref 3 /4 /5

Android多程式

  • 實現:android:process
  • 好處:一個獨立的程式可以充分利用自己的RAM預算,使其主程式擁有更多的空間處理資源。此外,作業系統對待執行在不同元件中的程式是不一樣的。這意味著,當系統執行在低可用記憶體的條件時,並不是所有的程式都會被殺死
  • 大坑:每一個程式將有自己的Dalvik VM例項,意味著你不能通過這些例項共享資料,至少不是傳統意義上的。例如,靜態欄位在每個程式都有自己的值,而不是你傾向於相信的只有一個值。
  • 更多詳細請參考Ref 9

現有方法

網路連線保活方法

A. GCM
B. 公共的第三方push通道(信鴿等)
C. 自身跟伺服器通過輪詢,或者長連線
具體實現請參考 微信架構師楊幹榮的”微信Android客戶端後臺保活經驗分享” (Ref-1).

雙service(通知欄) 提高程式優先順序

思路:(API level > 18 )

  • 應用啟動時啟動一個假的Service(FakeService), startForeground(),傳一個空的Notification
  • 啟動真正的Service(AlwaysLiveService),startForeground(),注意必須相同Notification ID
  • FakeService stopForeground()

效果:通過adb檢視,執行在後臺的服務其程式號變成了1(優先順序僅次於前臺程式)

風險:Android系統前臺service的一個漏洞,可能在6.0以上系統中修復

實現:核心程式碼如下

  • AlwaysLiveService 常駐記憶體服務

  • FakeService 臨時服務

Service及時拉起

AlarmReceiver, ConnectReceiver,BootReceiver等

  • Service設定(見上面基礎部分)
  • 通過監聽系統廣播,如開機,鎖屏,亮屏等重新啟動服務
  • 通過alarm定時器,啟動服務

守護程式/程式互拉

在分析360手機助手app時,發現其擁有N多個程式,一個程式kill後會被其它未kill的程式拉起,這也是一種思路吧,雖然有點流氓~
守護程式一般有這樣兩種方式:

  • 多個java程式守護互拉
  • 底層C守護程式拉起App上層/java程式

Linux Am命令開啟後臺程式

一種底層實現讓程式不被殺死的方法,在Android4.4以上可能有相容性問題,具體參考Ref-7

NotificationListenerService通知

一種需要使用者允許特定許可權的系統拉起方式,4.3以上系統

前臺浮窗

有朋友提出一種應用退出後啟動一個不可互動的浮窗,個人覺得這種方法是無效的,讀者有興趣可以一試

新方法(AccountSync)

思路

利用Android系統提供的賬號和同步機制實現

效果

  • 通過adb檢視,執行在後臺的服務其程式號變成了1(優先順序僅次於前臺程式),能提高程式優先順序,對比如下圖

ps-grep2

正常情況

ps-grep1

採用AccountSyncAdapter方法後

  • 程式被系統kill後,可以由syn拉起

風險

  • SyncAdapter時間進度不高,往往會因為手機處於休眠狀態,而時間往後調整,同步間隔最低為1分鐘
  • 使用者可以單獨停止或者刪除,有些手機賬號預設是不同步的,需要手動開啟

實現 (核心程式碼)

1 建立資料同步系統(ContentProvider)

通過一個ContentProvider用來作資料同步,由於並沒有實際資料同步,所以此處就直接建立一個空的ContentProvider即可

然後再Manifest中宣告

2 建立Sync系統 (SyncAdapter)

通過實現SyncAdapter這個系統服務後, 利用系統的定時器對程式資料ContentProvider進行更新,具體步驟為:

  • 建立Sync服務

  • 宣告Sync服務

其中sync_adapter為:

引數說明:

android:contentAuthority 指定要同步的ContentProvider在其AndroidManifest.xml檔案中有個android:authorities屬性。
android:accountType 表示進行同步的賬號的型別。
android:userVisible 設定是否在“設定”中顯示
android:supportsUploading 設定是否必須notifyChange通知才能同步
android:allowParallelSyncs 是否支援多賬號同時同步
android:isAlwaysSyncable 設定所有賬號的isSyncable為1
android:syncAdapterSettingsAction 指定一個可以設定同步的activity的Action。

  • 賬戶呼叫Sync服務
    首先配置好Account(第三步),然後再通過ContentProvider實現
    手動更新

新增賬號

同步週期設定

3 建立賬號系統 (Account Authenticator)

通過建立Account賬號,並關聯SyncAdapter服務實現同步

  • 建立Account服務

  • 宣告Account服務

其中authenticator為:

Refs

  1. 微信Android客戶端後臺保活經驗分享
  2. Android Low Memory Killer原理
  3. stackOverflow 上介紹的雙Service方法
  4. Write your own Android Sync Adapter
  5. Write your own Android Authenticator
  6. Android developer
  7. Android篇從底層實現讓程式不被殺死(失效Closed)
  8. Android 4.3+ NotificationListenerService 的使用
  9. Going multiprocess on Android687474703a2f2f377869386b6a2e636f6d312e7a302e676c622e636c6f7564646e2e636f6d2f696d6730312e676966

相關文章