❶ 進程保活
一 、問:什麼是進程保活?
答:進程保活就是進程永遠存在內存中,是殺不死的,就算殺死了也會有辦法重新啟動起來,其實這些並不是流氓手段,很多情況下,如果你想給你的用戶提供服務,就必須有一個進程常駐著,便於在特定的時候做一些特定的事情,比如廣播接受者,他就不支持靜態注冊,也就是說如果我們想接受屏幕開關啟動的廣播,必須要在進程中動態注冊,這個時候如果沒有一個常駐的進程,鎖屏業務就無法正常的為用戶展開服務。
二、問:進程是怎麼死掉的呢?
答:其實進程被殺死的原因,一方面是人為的,二、可能被第三方應用殺死,如殺敵軟體等。
三、問:android進程的優先順序?
答:
1、前台進程 (Foreground process):用戶當前操作所在的進程,當內存不足以承擔前台進程的使用,才有可能回收
2、可見進程(Visible process):沒有任何前台組件,但是仍然會影響屏幕上所見內容,他是一種極為重要的進程,除非為了維持前台進程,因內存不足,有可能會回收掉可見進程,否則系統是不會回收可見進程。
3、服務進程(Service process):他與用戶所見的內容是沒有直接關聯,但是他們通常執行一些用戶關心的操作,比如說在後台獲取網路數據,後台播放音樂,後台進行一些數據計算等。被殺死的原因:也是為了
支持前台進程和可見進程,因內存不足情況下才會被回收。
4、後台進程(BaclGround process):對用戶的體驗沒有直接的影響,用戶可以隨時終止他們,這個進程是為了供給上面三個進程來使用的,通常在後台進程運行著很多操作,他們保存在一個列表當中,為了確保用戶最近查看Activit的進程最後一個被終止,他是一個LRU演算法,
5、空進程(Empty process) :保存這個進程的唯一目的就是用來做緩存,以縮短下次在運行組件所需的啟動時間,為了使系統總體的資源在進程緩存和內存底層之間保持平衡。它是不包括任何組件的進程.
四、問:Android進程的回收策略?
答:Android進程的回收策略主要是通過Low memory killer機制來完成的。
Low memory killer:通過一些比較復雜的評分機制,對進程進行打分,然後講分數的進程判定為bad進程,殺死並釋放內存。Low memory killer是定時進行檢查的,它主要是通過進程的OOM_ODJ來判斷進程的優先順序。當OOM_ODJ的值越小,進程的優先順序越高,而OOM_ODJ越不會去回收。反之就會被回收。
注意:Low memory killer和out memory不一樣的地方:out memory機制只有當系統內存不足的時候才會啟動檢查,而Low memory killer是定時進行檢查的,它主要是通過進程的OOM_ODJ來判斷進程的優先順序。
五、問:進程保活方案?
答:Android進程的回收策略主要是通過Low memory killer機制來完成的。
1、利用系統廣播拉活,在發生系統事件的時候,系統會發出相應的廣播,
詳情查看:http://blog.csdn.NET/sunshinetan/article/details/53126857
2、利用系統Service機制拉活,在Service有一個onStartCommand
推薦博客:http://blog.csdn.net/wulianghuan/article/details/8596467
Android開發的過程中,每次調用startService(Intent)的時候,都會調用該Service對象的onStartCommand(Intent,int,int)方法,然後在onStartCommand方法中做一些處理。然後我們注意到這個函數有一個int的返回值,這篇文章就是簡單地講講int返回值的作用。從Android官方文檔中,我們知道onStartCommand有4種返回值:
START_STICKY:如果service進程被kill掉,保留service的狀態為開始狀態,但不保留遞送的intent對象。隨後系統會嘗試重新創建service,由於服務狀態為開始狀態,所以創建服務後一定會調用onStartCommand
(Intent,int,int)方法。如果在此期間沒有任何啟動命令被傳遞到service,那麼參數Intent將為null。(service因內存不足的情況下,殺死的進程才可以拉活,這里要特別注意,不是所有情況都可以拉活。第一次server被殺死後,會在5秒後拉活,第二次會在10秒後,第三次會在20秒後。之後就不會在拉活。第二種情況是獲得root許可權通過stop停止的,也是無法通過server拉活)
START_NOT_STICKY:「非粘性的」。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統將會把它置為started狀態,系統不會自動重啟該服務,直到startService(Intent intent)方法再次被用;。
START_REDELIVER_INTENT:重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啟該服務,並將Intent的值傳入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill後一定能重啟。
3、利用Native進程拉活,
4、利用JobScheler機制拉活:Android5.0之後提供的一個機制,他會監聽主進程的存活,如果死掉就會激活拉活進程。
5、利用賬號同步機制拉活:android系統有一個賬戶系統,設置一個自己的賬戶,android會定期喚醒賬戶更新服務。我們可以自己設定同步的事件間隔,且發起更新的是系統,不會受到任何限制。需要在 AndroidManifest 中定義賬號授權與同步服務。
Android 版本(Android N)中系統對賬戶同步這里做了變動,該方法不再有效。
缺點:
a.用戶會在系統設置的賬戶列表裡面看到一個不認識的賬戶;
b.同步的事件間隔是有限制的,最短1分鍾,見源碼,如果小雨60秒,置為60秒;
c.用戶可以卸載賬戶;
d.必須聯網!google提供這個組件是讓你同步賬戶信息,不聯網就不能保活!
❷ Android後台進程保活方案
思想: 使用 Linux 中的 fork 機制創建 Native 進程,在 Native 進程中監控主進程的存活,當主進程掛掉後,在 Native 進程中立即對主進程進行拉活。
原理: 在 Android 中所有進程和系統組件的生命周期受 ActivityManagerService 的統一管理。Android5.0以下通過 Linux 的 fork 機制創建的進程為純 Linux 進程,其生命周期不受 Android 的管理。
該方案主要適用於 Android5.0 以下版本手機。
該方案不受 forceclose 影響,被強制停止的應用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好。
詳情
對於 Android5.0 以上手機,系統雖然會將native進程內的所有進程都殺死,這里其實就是系統「依次」殺死進程時間與拉活邏輯執行時間賽跑的問題,如果可以跑的比系統邏輯快,依然可以有效拉起。在 某些 Android 5.0 以上機型有效。
詳情
https://github.com/Marswin/MarsDaemon
作者5.0以下系統用一個java進程和一個fork出來的純native進程雙管道互鎖監聽對方的狀態,無論哪個被殺後都拉起第三個進程,第三個進程來拉活常駐進程,實現拉活。
5.0以上同一進程組的進程會被同時殺死,所以5.0以上使用雙java進程在native層互鎖文件實現監聽,但任務管理器會在短時間內殺死所有進程,只能用反射提前初始化pacel,在進程被殺的時候和系統搶那幾十毫秒的時間發送一個拉活的廣播。用4個文件來讓兩個進程實現互鎖來做監聽,但實際效果很一般,測試了幾個5.0以上的國產機型都不行,效果是根本監聽不到進程被殺,目測原因是當任務管理器查殺進程的時候將所有的進程都掛起了,隨後全部殺掉,並在一段時間內禁止進程啟動。
PersistedJobService.java
BootReceiver.java靜態注冊BroadcastReceiver
注冊,開機,網路切換、拍照、拍視頻時候,利用系統產生的廣播也能喚醒app,不過Android N已經將這三種廣播取消了
常用的拉活許可權
BackgroundService.java
WakeLock
作為前台應用運行,提高應用存活幾率
service被關掉後自動啟動
START_STICKY
如果系統在onStartCommand返回後被銷毀,系統將會重新創建服務並依次調用onCreate和onStartCommand(注意:根據測試Android2.3.3以下版本只會調用onCreate根本不會調用onStartCommand,Android4.0可以辦到),這種相當於服務又重新啟動恢復到之前的狀態了)。
START_NOT_STICKY
如果系統在onStartCommand返回後被銷毀,如果返回該值,則在執行完onStartCommand方法後如果Service被殺掉系統將不會重啟該服務。
START_REDELIVER_INTENT
START_STICKY的兼容版本,不同的是其不保證服務被殺後一定能重啟。
service注冊,許可權設置為高優先順序
KeepAliveService.java
注冊,在新的獨立進程內啟動,適用5.0以下的原生系統,5.0以上同樣會被殺死
他的局限性在於:
第一,用戶會在系統設置的賬戶列表裡面看到一個不認識的賬戶;
第二,同步的事件間隔是有限制的,最短1分鍾,見源碼,如果小雨60秒,置為60秒。而且各種國產機怎麼改的源碼我們未可知,是不是都能用仍然未可知;
第三,很致命,某些手機比如note3需要手動設置賬戶,你如何騙你的用戶給你手動設置賬戶完了之後不卸載你;
第四,也很致命,必須聯網!google提供這個組件是讓你同步賬戶信息,不聯網你同步個鬼,我們要保活,可以不聯網不做事,但是不能不聯網就死
集成三方推送平台sdk,友盟極光等
❸ android後台服務保持,不被殺死
作者:閉關寫代碼
鏈接:https://www.hu.com/question/29826231/answer/71207109
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。
強烈建議不要這么做,不僅僅從用戶角度考慮,作為Android開發者也有責任去維護Android的生態環境。現在很多Android開發工程師,主力機居然是iPhone而不是Android設備,感到相當悲哀。
從技術角度概括一下現在普遍的防殺方法
Service設置成START_STICKY,kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣
通過 startForeground將進程設置為前台進程,做前台服務,優先順序和前台應用一個級別,除非在系統內存非常缺,否則此進程不會被 kill
雙進程Service:讓2個進程互相保護,其中一個Service被清理後,另外沒被清理的進程可以立即重啟進程
QQ黑科技:在應用退到後台後,另起一個只有 1 像素的頁面停留在桌面上,讓自己保持前台狀態,保護自己不被後台清理工具殺死
在已經root的設備下,修改相應的許可權文件,將App偽裝成系統級的應用(Android4.0系列的一個漏洞,已經確認可行)
Android系統中當前進程(Process)fork出來的子進程,被系統認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,並不受影響。鑒於目前提到的在Android-Service層做雙守護都會失敗,我們可以fork出c進程,多進程守護。死循環在那檢查是否還存在,具體的思路如下(Android5.0以下可行)
用C編寫守護進程(即子進程),守護進程做的事情就是循環檢查目標進程是否存在,不存在則啟動它。
在NDK環境中將1中編寫的C代碼編譯打包成可執行文件(BUILD_EXECUTABLE)。
主進程啟動時將守護進程放入私有目錄下,賦予可執行許可權,啟動它即可。
聯系廠商,加入白名單
------------------------------------------------------
TIP: 面對各種流氓軟體後台常駐問題,建議使用「綠色守護」來解決,可是殺掉那些第三方清理工具難以清除的後台程序
❹ android push 推送服務 如何做到app進程被清理掉還能收到推送 我看有少部分應用做到了
在國內 Android 生態中,推送通道都是由終端與雲端之間的長鏈接來維持,嚴重依賴於應用進程的存活狀態,軟體推出後台運行後會接受不到消息推送。 針對這個問題,如今一些手機廠家會在自家 rom 中做系統級別的推送通道,再由系統分發給各個 app,以此提高在自家 rom 上的推送送達率 極光推送率先和國內包括華為,小米,OPPO,VIVO,魅族等7大主流手機廠商打通通道,大大提高消息送達率❺ 想讓android應用常駐後台,不被殺死,各位大神有什麼高招
方法: 對於一個service,可以首先把它設為在前台運行: public void MyService.onCreate() { super.onCreate(); Notification notification = new Notification(android.R.drawable.my_service_icon, "my_service_name", System.currentTimeMillis()); PendingIntent p_intent = PendingIntent.getActivity(this, 0, new Intent(this, MyMainActivity.class), 0); notification.setLatestEventInfo(this, "MyServiceNotification, "MyServiceNotification is Running!", p_intent); Log.d(TAG, String.format("notification = %s", notification)); startForeground(0x1982, notification); // notification ID: 0x1982, you can name it as you will. } 重要設置------------------------------- 相較於/data/app下的應用,放在/system/app下的應用享受更多的特權,比如若在其Manifest.xml文件中設置persistent屬性為true,則可使其免受out-of-memory killer的影響。如應用程序'Phone'的AndroidManifest.xml文件: <application android:name="PhoneApp" android:persistent="true" android:label="@string/dialerIconLabel" android:icon="@drawable/ic_launcher_phone"> ... </application> 設置後app提升為系統核心級別,任何情況下不會被kill掉, settings->applications裡面也會屏蔽掉stop操作。 這樣設置前的log: Proc #19: adj=svc /B 4067b028 255:com.xxx.xxx/10001 (started-services) # cat /proc/255/oom_adj 設置後的log: PERS #19: adj=core /F 406291f0 155:com.xxx.xxx/10001 (fixed) # cat /proc/155/oom_adj -12 # 這是CORE_SERVER_ADJ 註:init進程的oom_adj為-16(即SYSTEM_ADJ): cat /proc/1/oom_adj Android相關部分分析: 在文件frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中有以下的代碼: final ProcessRecord addAppLocked(ApplicationInfo info) { ProcessRecord app = getProcessRecordLocked(info.processName, info.uid); if (app == null) { app = newProcessRecordLocked(null, info, null); mProcessNames.put(info.processName, info.uid, app); updateLruProcessLocked(app, true, true); } if ((info.flags&(ApplicationInfo.FLAG_SYSTEMApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEMApplicationInfo.FLAG_PERSISTENT)) { app.persistent = true; app.maxAdj = CORE_SERVER_ADJ; // 這個常數值為-12。 } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); startProcessLocked(app, "added application", app.processName); } return app; } 可見要想成為core service (即app.maxAdj = CORE_SERVER_ADJ(-12)),應用程序需要FLAG_SYSTEM和FLAG_PERSISTENT兩個標志,FLAG_SYSTEM指的是應用位於/system/app下,FLAG_PERSISTENT就是指persistent屬性。 而對於frameworks/base/services/java/com/android/server/SystemServer.java,則調用 ActivityManagerService.setSystemProcess(); 把自己的 app.maxAdj 設置成SYSTEM_ADJ,即-16。 原理: Android中的進程是託管的,當系統進程空間緊張的時候,會依照優先順序自動進行進程的回收。由此帶來三個問題: 1) 回收規則: 什麼時候回收與回收哪一個? 2) 避免誤殺: 如何阻止被回收? 3) 數據恢復與保存: 被回收了怎麼辦? Android將進程分為6個等級,它們按優先順序順序由高到低依次是: 1.前台進程( FOREGROUND_APP) 2.可視進程(VISIBLE_APP ) 3. 次要服務進程(SECONDARY_SERVER ) 4.後台進程 (HIDDEN_APP) 5.內容供應節點(CONTENT_PROVIDER) 6.空進程(EMPTY_APP) 特徵: 1.如果一個進程裡面同時包含service和可視的activity,那麼這個進程應該歸於可視進程,而不是service進程。 2.另外,如果其他進程依賴於它的話,一個進程的等級可以提高。例如,一個A進程里的service被綁定到B進程里的組件上,進程A將總被認為至少和B進程一樣重要。 3.系統中的phone服務被劃分到前台進程而不是次要服務進程. 在android中,進程的oom_adj值也就代表了它的優先順序。oom_adj值越高代表該進程優先順序越低。文件/init.rc中有以下屬性設置: setprop ro.FOREGROUND_APP_ADJ 0 setprop ro.VISIBLE_APP_ADJ 1 setprop ro.SECONDARY_SERVER_ADJ 2 setprop ro.HIDDEN_APP_MIN_ADJ 7 setprop ro.CONTENT_PROVIDER_ADJ 14 setprop ro.EMPTY_APP_ADJ 15 /init.rc中,將PID為1的進程(init進程)的oom_adj設置為SYSTEM_ADJ(-16): # Set init its forked children's oom_adj. write /proc/1/oom_adj -16 查看本機設置: cat /sys/mole/lowmemorykiller/parameters/adj 0,1,2,7,14,15 回收時機: 文件/init.rc中: setprop ro.FOREGROUND_APP_MEM 1536 // 6M setprop ro.VISIBLE_APP_MEM 2048 // 8M setprop ro.SECONDARY_SERVER_MEM 4096 // 16M setprop ro.HIDDEN_APP_MEM 5120 // 20M setprop ro.CONTENT_PROVIDER_MEM 5632 // 22.4M setprop ro.EMPTY_APP_MEM 6144 // 24M 這些數字也就是對應的內存閾值,一旦低於該值,Android便開始按順序關閉相應等級的進程。 注意這些數字的單位是page: 1 page = 4 kB。所以上面的六個數字對應的就是(MB): 6,8,16,20,22,24。 查看現在的內存閾值設置: cat /sys/mole/lowmemorykiller/parameters/minfree 要想重新設置該值(對應不同的需求): echo "1536,2048,4096,5120,15360,23040">/sys/mole/lowmemorykiller/parameters/minfree 這樣當可用內存低於90MB的時候便開始殺死"空進程",而當可用內存低於60MB的時候才開始殺死"內容供應節點"類進程。 具體的回收實現在ActivityManagerService.java中的函數trimApplications(): 1.首先移除package已被卸載的無用進程; 2.基於進程當前狀態,更新oom_adj值,然後進行以下操作: 1) 移除沒有activity在運行的進程; 2) 如果AP已經保存了所有的activity狀態,結束這個AP。 3. 最後,如果目前還是有很多activities 在運行,那麼移除那些activity狀態已經保存好的activity。 更新oom_adj的值: 在ActivityManagerService.java文件的ComputeOomAdjLocked() 中計算出進程的oom_adj,例如: if (app == TOP_APP) { // The last app on the list is the foreground app. adj = FOREGROUND_APP_ADJ; app.adjType = "top-activity"; } Android kernel中的low memory killer Android的Low Memory Killer根據需要(當系統內存短缺時)殺死進程釋放其內存,源代碼在kernel/drivers/misc/lowmemorykiller.c中。簡單說,就是尋找一個最合適的進程殺死,從而釋放它佔用的內存。 最合適的進程是: • oom_adj越大 • 佔用物理內存越多 一旦一個進程被選中,內核會發送SIGKILL信號將之殺死: for_each_process(p) { …… if(selected == NULL p->oomkilladj > selected->oomkilladj (p->oomkilladj == selected->oomkilladj && tasksize > selected_tasksize)) { selected = p; } } if(selected != NULL) { force_sig(SIGKILL, selected); } 查看LRU列表:adb shell mpsys activity 當activitydemo在前台時: 包含Service的進程的優先順序比較高,在computeOomAdjLocked中將其分為了兩小類: static final int MAX_SERVICE_INACTIVITY = 30*60*1000; if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { if (adj > SECONDARY_SERVER_ADJ) { adj = SECONDARY_SERVER_ADJ; app.adjType = "started-services"; app.hidden = false; } } if (adj > SECONDARY_SERVER_ADJ) { app.adjType = "started-bg-services"; } 完全讓進程不被kill是不可能的,我們可以通過一些操作,使進程被kill的幾率變小: 1) 提高進程的優先順序: * 後台操作採用運行於前台的Service形式,因為一個運行著service的進程比一個運行著後台activity的等級高; * 按back鍵使得進程中的activity在後台運行而不是destory,需重載back按鍵(沒有任何activity在運行的進程優先被殺). * 依賴於其他優先順序高的進程; 2) 強制修改進程屬性: * 在進程中設置:setPersistent(true); * 在Manifest文件中設置(如上)。