1. 程式人生 > >【android 】程序、守護程序的實現及程序拉活

【android 】程序、守護程序的實現及程序拉活

1,概念

1)守護程序(Daemon)

是一種執行在後臺的特殊程序,它獨立於控制終端並且週期性的執行某些任務。android中守護程序的實現主要由Service來完成。Android繼承了Linux的lowmemorykiller,為了實現程序常駐,需要應用到守護程序。

2)程序拉活

android程序拉活包括2個層面:

①提高程序優先順序,降低程序被殺死的概率。

②程序被殺死後,進行拉活。(守護程序主要做的事)

3)android記憶體管理機制:

當記憶體不足時,為了新建程序或執行更重要的程序,根據程序優先順序,清除舊程序來回收系統資源。

2,實現思想

1)提升程序優先順序

可通過提升程序優先順序來保活程序。相關方案:檢視3-(1)。程序重要性逐漸降低為:

①前臺程序(Foreground process)

使用者當前操作所必需的程序。記憶體不足以支援前臺程序執行時,系統才終止該程序。

a.擁有使用者正在互動的 Activity(已呼叫 onResume())

b.擁有繫結到使用者正在互動的Activity的Service

c.擁有正在“前臺”執行的 Service(服務已呼叫startForeground())

d.擁有正執行一個生命週期回撥的 Service(onCreate()、onStart() 或 onDestroy())

e.擁有正執行其onReceive() 方法的 BroadcastReceiver

②可見程序(Visible process)

沒有任何前臺元件、但仍會影響使用者在螢幕上所見內容的程序。只有前臺程序執行記憶體不足才終止。

a.擁有不在前臺、但仍對使用者可見的 Activity(已呼叫 onPause(),比如輸入法程序)。

b.擁有繫結到可見(或前臺)Activity的 Service

 ③服務程序(Service process)

通常執行一些使用者關心的操作(例如,在後臺播放音樂或從網路下載資料)。只有前臺程序、可見程序記憶體不足才終止。

a. 正在執行startService() 方法啟動的服務,且不屬於上述兩個更高類別程序的程序。

④後臺程序(Background process)

後臺程序對使用者體驗沒有直接影響,系統可能隨時終止它們。

a.對使用者不可見的Activity 的程序(已呼叫 Activity的onStop() 方法)

⑤空程序(Empty process)

保留這種程序的的唯一目的是用作快取,以縮短下次在其中執行元件所需的啟動時間。為使總體系統資源在程序快取和底層核心快取之間保持平衡,系統往往會終止這些程序。

a.不含任何活動應用元件的程序

3.實現demo

1)提升程序優先順序:

利用activity提升許可權(放一個畫素在前臺

a.實現:

監控手機鎖屏解鎖事件,在螢幕鎖屏時啟動1個畫素的 Activity,在使用者解鎖時將Activity 銷燬掉。注意該 Activity 需設計成使用者無感知。QQ黑科技之一。
通過該方案,可以使程序的優先順序在螢幕鎖屏時間由4提升為最高優先順序1。

b.場景:

本方案主要解決第三方應用及系統管理工具在檢測到鎖屏事件後一段時間(一般為5分鐘以內)內會殺死後臺程序,已達到省電的目的問題。     

新增Manifest檔案屬性值為android:persistent=“true”

大神說,如果用系統shareuid+系統簽名,就可以保證即使前臺activity黑屏,該程序都死不掉。。。。反正我沒機會試( TNT)

2)程序拉活

①利用廣播拉活

註冊廣播監聽器,在發生響應事件時拉活。

i>常用系統廣播:

       a.開機廣播

         詳情檢視:http://blog.csdn.net/sunshinetan/article/details/53126857

       b.網路變化廣播

       c.檔案掛載廣播

       d.螢幕亮滅廣播

       e.鎖屏解鎖廣播

       f.應用安裝解除安裝廣播

缺點:

        a.廣播接收器被管理軟體、系統軟體通過“自啟管理”等功能禁用的場景無法接收到廣播,從而無法自啟。

        b.系統廣播事件不可控,只能保證發生事件時拉活程序,但無法保證程序掛掉後立即拉活。

ii>第三方應用廣播

通過反編譯第三方 Top 應用,如:手機QQ、微信、支付寶、UC瀏覽器等,以及友盟、信鴿、個推等 SDK,找出它們外發的廣播,在應用中進行監聽,這樣當這些應用發出廣播時,進行應用拉活。

缺點:

        第三方應用的廣播屬於應用私有,當前版本中有效的廣播,在後續版本隨時就可能被移除或被改為不外發。

②利用Service拉活(如何保證Service的存活)

i>START_STICKY狀態

       程式碼如下,將Service 設定為 START_STICKY,利用系統機制在 Service 掛掉後自動拉活。kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣。

 注意:

        a.Service 第一次被異常殺死後會在5秒內重啟,第二次被殺死會在10秒內重啟,第三次會在20秒內重啟,一旦在短時間內 Service 被殺死達到5次,則系統不再拉起。

        b.程序被取得 Root 許可權的管理工具或系統工具通過 forestop 停止掉,無法重啟。

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

    	return Service.START_STICKY;
    }

ii>提升Service優先順序、Service程序優先順序:將Service設定為前臺服務

       將後臺Service設定為前臺Service,將程序優先順序由4提升為2。前臺Service是使用者可感知的,對於不需要常駐通知欄的應用,採用Notification來實現:

       實現一個內部 Service,在 LiveService 和其內部 Service 中同時傳送具有相同 ID 的 Notification,然後將內部 Service 結束掉。隨著內部 Service 的結束,Notification 將會消失,但系統優先順序依然保持為2。  

        可以使用startForeground()將service放到前臺狀態。

        如果在極度極度低記憶體的壓力下,該service還是會被kill掉,並且不一定會restart()

        另外也可以放一個畫素在前臺(手機QQ)來實現。

iii>服務互相繫結

        跨程序bind一個service之後,如果被bind的service掛掉,bind他的service會把他拉起來。

iv>onDestroy方法裡重啟service

      service +broadcast 方式,就是當service走onDestory()的時候,傳送一個自定義的廣播,當收到廣播的時候,重新啟動service,或者直接在onDestroy()裡startService。

       當使用類似口口管家等第三方應用或是在setting裡-應用-強制停止時,APP程序可能就直接被幹掉了,onDestroy方法都進不來,所以還是無法保證。

v>在JNI層,用C程式碼fork一個程序出來

        這樣產生的程序,會被系統認為是兩個不同的程序.但是Android5.0之後可能不行.

vi>root之後放到system/app變成系統級應用

③利用Native程序拉活(守護執行緒)

i>實現:

       利用Linux 中的 fork 機制建立 Native 程序,在 Native 程序中監控主程序的存活,當主程序掛掉後,在 Native 程序中立即對主程序進行拉活。

a.在Native程序中感知主執行緒存活,當主程序不存活時進行拉活。

方法一:

         在Native程序中,通過死迴圈或定時器,輪訓判斷主程序是否存活。缺點:不停的輪詢執行判斷邏輯,非常耗電。

方法二(推薦):

         在主程序中建立一個監控檔案,在主程序中持有檔案鎖。拉活程序啟動後,申請檔案鎖將會被堵塞,一旦可以成功獲取到鎖,說明主程序掛掉,即可進行拉活。

         原理:不論windows還是linux都會有一套檔案的程序同步機制,為了各個程序間檔案的同步問題,一個程序可以給一個檔案上鎖,操作完了之後再解鎖,其他程序如果擔心同步問題,會首先檢查一下檔案是否有鎖,如果有鎖,代表別人正在操作,就會延遲對檔案的操作。那麼當一個程序掛掉,他給檔案加的鎖也自然會消失。

          為了實現雙向守護程序,程序a給檔案1加鎖,阻塞讀取檔案2的鎖。程序b給檔案2加鎖,阻塞讀取檔案1的鎖。如果對方程序掛掉,即可讀取到對方所持有檔案鎖的檔案,即可監聽到對方掛掉。

b.在Native程序中拉活主程序。

       方法一:通過am命令進行拉活。通過指定“—include-stopped-packages”引數來拉活主程序處於 forestop 狀態的情況。

c.保證Native程序唯一性。

      方法一:將 Native 程序設計成 C/S 結構模式,主程序與 Native 程序通過 Localsocket 進行通訊。在Native程序中利用 Localsocket 保證 Native 程序的唯一性,不至於出現建立多個 Native 程序以及 Native 程序變成殭屍程序等問題。

ii>主要原理:

      在 Android 中所有程序和系統元件的生命週期受 ActivityManagerService 的統一管理。而且,通過 Linux 的 fork 機制建立的程序為純 Linux 程序,其生命週期不受 Android 的管理。

iii>適用範圍:

      適用於android5.0以下版本。

      對於 Android5.0 以上手機,系統雖然會將native程序內的所有程序都殺死,這裡其實就是系統“依次”殺死程序時間與拉活邏輯執行時間賽跑的問題,如果可以跑的比系統邏輯快,依然可以有效拉起,故在某些 Android 5.0 以上機型有效。 

      適用Android以上機型demo(征服android 5.1無問題):http://download.csdn.net/detail/sunshinetan/9709469

④利用賬戶同步機制拉活

     android系統有一個賬戶系統,設定一個自己的賬戶,android會定期喚醒賬戶更新服務。我們可以自己設定同步的事件間隔,且發起更新的是系統,不會受到任何限制。需要在 AndroidManifest 中定義賬號授權與同步服務。

     Android 版本(Android N)中系統對賬戶同步這裡做了變動,該方法不再有效。

缺點:

       a.使用者會在系統設定的賬戶列表裡面看到一個不認識的賬戶;

b.同步的事件間隔是有限制的,最短1分鐘,見原始碼,如果小雨60秒,置為60秒;

c.使用者可以解除安裝賬戶;

d.必須聯網!google提供這個元件是讓你同步賬戶資訊,不聯網就不能保活!

4,用途

 守護程序,與程序常駐、程序拉活做的是同一類事情。

 1)鎖屏應用正常為使用者服務。

 2)IM類應用,需要在後臺維護一個長連結,以便於及時將資訊傳遞給yoghurt。

 3)一些專用裝置,在工作的時候需要實現軟體常駐介面。

5,如何判斷應用被強殺

在Application中定義一個static常量,賦值為-1,在歡迎介面改為0,如果被強殺,application重新初始化,在父類Activity判斷該常量的值。