android進(jìn)程保活實踐

紅色部分是容易被回收的進(jìn)程扶檐,屬于android進(jìn)程

綠色部分是較難被回收的進(jìn)程,屬于android進(jìn)程

其他部分則不是android進(jìn)程胁艰,也不會被系統(tǒng)回收款筑,一般是ROM自帶的app和服務(wù)才能擁有

如何查看某個進(jìn)程的oom_adj數(shù)值呢?

oom_adj 存儲在proc/PID/oom_adj文件中腾么,其中PID是進(jìn)程的id奈梳,直接 adb shell進(jìn)入手機根目錄查看這個文件即可。

演示一下:以我自己的項目為例解虱,app中有兩個進(jìn)程攘须,一個是主進(jìn)程,另一個是運行service的進(jìn)程取名為:remote殴泰。首先用android studio查看每個進(jìn)程的PID:


然后分別查看app在前臺于宙,app退到后臺,這2中場景主進(jìn)程的oom_adj數(shù)值:


可見艰匙,當(dāng)app在前臺時 oom_adj = 0限煞,對應(yīng)上面的表格是前臺進(jìn)程。

當(dāng)app退到后臺時员凝,oom_adj = 6署驻,對應(yīng)后臺進(jìn)程。 然后查看運行著service的進(jìn)程:


ok健霹,知道了進(jìn)程優(yōu)先級的概念以及如何查看優(yōu)先級旺上,我們就可以對app進(jìn)程優(yōu)化,然后通過查看這個數(shù)值判斷我們的優(yōu)化是否有效果糖埋。

進(jìn)程被kill的場景

1.點擊home鍵使app長時間停留在后臺宣吱,內(nèi)存不足被kill

處理這種情況前提是你的app至少運行了一個service,然后通過Service.startForeground() 設(shè)置為前臺服務(wù)瞳别,可以將oom_adj的數(shù)值由4降低到1征候,大大提高存活率杭攻。

要注意的是android4.3之后Service.startForeground() 會強制彈出通知欄,解決辦法是再啟動一個service和推送共用一個通知欄疤坝,然后stop這個service使得通知欄消失兆解。

Android 7.1之后google修復(fù)這個bug,目前沒有解決辦法

下面的代碼放到你的service的onStartCommand方法中:

//設(shè)置service為前臺服務(wù)跑揉,提高優(yōu)先級

? ? ? ? if (Build.VERSION.SDK_INT < 18) {

? ? ? ? ? ? //Android4.3以下 锅睛,此方法能有效隱藏Notification上的圖標(biāo)

? ? ? ? ? ? service.startForeground(GRAY_SERVICE_ID, new Notification());

? ? ? ? } else if(Build.VERSION.SDK_INT>18 && Build.VERSION.SDK_INT<25){

? ? ? ? ? ? //Android4.3 - Android7.0,此方法能有效隱藏Notification上的圖標(biāo)

? ? ? ? ? ? Intent innerIntent = new Intent(service, GrayInnerService.class);

? ? ? ? ? ? service.startService(innerIntent);

? ? ? ? ? ? service.startForeground(GRAY_SERVICE_ID, new Notification());

? ? ? ? }else{

? ? ? ? ? ? //Android7.1 google修復(fù)了此漏洞历谍,暫無解決方法(現(xiàn)狀:Android7.1以上app啟動后通知欄會出現(xiàn)一條"正在運行"的通知消息)

? ? ? ? ? ? service.startForeground(GRAY_SERVICE_ID, new Notification());

? ? ? ? }

經(jīng)過改進(jìn)之后现拒,再來看下這個后臺service進(jìn)程的oom_adj,發(fā)現(xiàn)被提升為前臺進(jìn)程望侈。


2.在大多數(shù)國產(chǎn)手機下印蔬,進(jìn)入鎖屏狀態(tài)一段時間,省電機制會kill后臺進(jìn)程

這種情況和上面不太一樣甜无,是很過國產(chǎn)手機rom自帶的優(yōu)化扛点,當(dāng)鎖屏一段時間之后,即使手機內(nèi)存夠用為了省電岂丘,也會釋放掉一部分內(nèi)存陵究。

策略:注冊廣播監(jiān)聽鎖屏和解鎖事件, 鎖屏后啟動一個1像素的透明Activity奥帘,這樣直接把進(jìn)程的oom_adj數(shù)值降低到0铜邮,0是android進(jìn)程的最高優(yōu)先級。 解鎖后銷毀這個透明Activity寨蹋。這里我把這個Activity放到:remote進(jìn)程也就是我那個后臺服務(wù)進(jìn)程松蒜,當(dāng)然你也可以放到主進(jìn)程,看你打算币丫桑活哪個進(jìn)程秸苗。


我們可以寫一個KeepLiveManager來負(fù)責(zé)接收廣播,維護(hù)這個Activity的常見和銷毀运褪,注意鎖屏廣播和解鎖分別是:ACTION_SCREEN_OOF和ACTION_USER_PRESENT惊楼,并且只能通過動態(tài)注冊來綁定,并且是綁定到你的后臺service里面,onCreate綁定,onDestroy里面解綁

配好之后把手機鎖屏秸讹,看下:remote進(jìn)程的oom_adj:


3. 用戶手動釋放內(nèi)存:包括手機自帶清理工具檀咙,和第三方app(360,獵豹清理大師等)

清理內(nèi)存軟件會把 優(yōu)先級低于 前臺進(jìn)程(oom_adj = 0)的所有進(jìn)程放入清理列表璃诀,而當(dāng)我們打開了清理軟件就意味著其他app不可能處于前臺弧可。所以說理論上可以kill任何app。

以360安全衛(wèi)士為例劣欢,打開內(nèi)存清理:


因此這類場景唯一的處理辦法就是加入 手機rom 白名單棕诵,比如你打開小米裁良,魅族的權(quán)限管理 -> 自啟動管理可以看到 QQ,微信校套,天貓默認(rèn)被勾選趴久,這就是廠商合作。那我們普通app可以這么做:在app的設(shè)置界面加一個選項搔确,提示用戶自己去勾選自啟動,我封裝了一個工具類給出國內(nèi)各廠商的自啟動的Intent跳轉(zhuǎn)方法:

/**

* Created by carmelo on 2018/3/17.

* 國內(nèi)手機廠商白名單跳轉(zhuǎn)工具類

*/

public class SettingUtils {

? ? public static void enterWhiteListSetting(Context context){

? ? ? ? try {

? ? ? ? ? ? context.startActivity(getSettingIntent());

? ? ? ? }catch (Exception e){

? ? ? ? ? ? context.startActivity(new Intent(Settings.ACTION_SETTINGS));

? ? ? ? }

? ? }

? ? private static Intent getSettingIntent(){

? ? ? ? ComponentName componentName = null;

? ? ? ? String brand = android.os.Build.BRAND;

? ? ? ? switch (brand.toLowerCase()){

? ? ? ? ? ? case "samsung":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.samsung.android.sm",

? ? ? ? ? ? ? ? ? ? ? ? "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "huawei":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.huawei.systemmanager",

? ? ? ? ? ? ? ? ? ? ? ? "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "xiaomi":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.miui.securitycenter",

? ? ? ? ? ? ? ? ? ? ? ? "com.miui.permcenter.autostart.AutoStartManagementActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "vivo":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.iqoo.secure",

? ? ? ? ? ? ? ? ? ? ? ? "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "oppo":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.coloros.oppoguardelf",

? ? ? ? ? ? ? ? ? ? ? ? "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "360":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.yulong.android.coolsafe",

? ? ? ? ? ? ? ? ? ? ? ? "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "meizu":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.meizu.safe",

? ? ? ? ? ? ? ? ? ? ? ? "com.meizu.safe.permission.SmartBGActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case "oneplus":

? ? ? ? ? ? ? ? componentName = new ComponentName("com.oneplus.security",

? ? ? ? ? ? ? ? ? ? ? ? "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? default:

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? ? ? Intent intent = new Intent();

? ? ? ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

? ? ? ? if(componentName!=null){

? ? ? ? ? ? intent.setComponent(componentName);

? ? ? ? }else{

? ? ? ? ? ? intent.setAction(Settings.ACTION_SETTINGS);

? ? ? ? }

? ? ? ? return intent;

? ? }

}

補充幾點:

額外說下 自啟動是什么意思灭忠? 網(wǎng)上都是小米開啟自啟動就是加入白名單膳算,其實根本不是這樣的,經(jīng)過實測就算app勾選自啟動也會被內(nèi)存優(yōu)化加速清理掉弛作,只不過進(jìn)程會在半分鐘后復(fù)活涕蜂。

除了還有自啟動還有一個設(shè)置就是電池管理,比如小米的神隱模式映琳,這部分和自啟動不同的是它是管理app在鎖屏之后被省電機制殺死的場景机隙,當(dāng)然每家廠商也有對應(yīng)的Intent跳轉(zhuǎn)路徑。

如何查找不同廠商的設(shè)置界面跳轉(zhuǎn)Intent萨西,比如上面的國內(nèi)手機廠商白名單?

在酷安應(yīng)用市場下載一個叫 當(dāng)前Activity 的app有鹿,打開后可以看到當(dāng)前界面的className,例如:

就找到了魅族MX4 pro 后臺權(quán)限的Activity谎脯。

進(jìn)程喚醒

分兩種情況葱跋,一是主進(jìn)程(含有Activity沒有service),這種進(jìn)程由于內(nèi)存不足被kill之后源梭,用戶再次打開app系統(tǒng)會恢復(fù)到上次的Activity娱俺,這個不在本文話題之內(nèi)。另一種是service的后臺進(jìn)程被kill废麻,可以通過service自有api來重啟service:

@Override

? ? public int onStartCommand(Intent intent, int flags, int startId) {

? ? ? ? //.....

? ? ? ? return START_STICKY;? ? // service被異常停止后荠卷,系統(tǒng)嘗試重啟service,不能保證100%重啟成功

? ? }

配好START_STICKY后烛愧,通過android studio 釋放進(jìn)程的工具測試下油宜,可以發(fā)現(xiàn):remote進(jìn)程被kill之后馬上重啟了:

但它不是100%保證重啟成功,比如下面2種情況:(本人經(jīng)過測試屑彻,這里就不放效果圖了)

Service 第一次被異常殺死后會在5秒內(nèi)重啟验庙,第二次被殺死會在10秒內(nèi)重啟,第三次會在20秒內(nèi)重啟社牲,一旦在短時間內(nèi) Service 被殺死達(dá)到5次粪薛,則系統(tǒng)不再拉起。

進(jìn)程被取得 Root 權(quán)限的管理工具或系統(tǒng)工具通過 forestop 停止掉搏恤,無法重啟违寿。

總結(jié)

本文通過兩種 提高進(jìn)程優(yōu)先級的方法湃交,針對鎖屏 和非鎖屏模式下進(jìn)程在后臺被kill的場景處理,把后臺進(jìn)程優(yōu)先級提升到可見級別藤巢,基本可以保證絕大多數(shù)場景不會被kill搞莺。另外,針對含有service的進(jìn)程被kill給出了可喚醒的辦法掂咒。

后來收到不少留言評論才沧,大多數(shù)都是講這個進(jìn)程保活對很多手機沒有作用绍刮。我一直沒有回復(fù)温圆,因為我們項目在使用這個進(jìn)程保活策略時孩革,同時也加入了進(jìn)程存活時間的Log記錄機制岁歉,目的就是想看下有效果沒。后臺service的啟動就開啟計時器膝蜈,以分鐘為單位不停寫入SharePreference锅移,進(jìn)程被kill這個值就是存活時間(min),同時記錄機型饱搏,Android版本等信息非剃,以Exception的格式封裝上傳到bugly。由于是純手動分析數(shù)據(jù)很麻煩窍帝,最后取了1000條數(shù)據(jù)涵蓋了Android5.0-Android8.0努潘,小米,華為坤学,三星疯坤,oppo/vivo,金立等各種機型。

結(jié)論

和Android版本關(guān)系很大

對于Android6.0以及以下的大部分機型還是有效果的深浮,但是Android7.0和Android8.0基本上所有機型全部陣亡压怠,大部分后臺進(jìn)程在鎖屏后無法存活超過20分鐘。

這個可以從Android 6.0飞苇,7.0和8.0的新特性看出一些端倪菌瘫,google對于內(nèi)存/電量使用越來越嚴(yán)格。

2.和手機廠商關(guān)系比較大布卡,測試結(jié)果顯示雨让,oppo/vivo這兩家廠商進(jìn)程保活最困難忿等,小米和三星比較寬松栖忠。其他的機型居中。

3.綜合結(jié)果是,鑒于目前國內(nèi)大部分手機基本都到7.0了庵寞,進(jìn)程崩晗啵活暫時可以說是宣告失敗了。除了加入廠商白名單之外我不認(rèn)為有真正可行的方案捐川,畢竟google近幾個Android版本不停在系統(tǒng)層面限制脓鹃,我們在app層沒有很大的發(fā)揮空間,so古沥,之前的方案只能作為一個優(yōu)化策略吧瘸右。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市岩齿,隨后出現(xiàn)的幾起案子尊浓,更是在濱河造成了極大的恐慌,老刑警劉巖纯衍,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異苗胀,居然都是意外死亡襟诸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門基协,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歌亲,“玉大人澜驮,你說我怎么就攤上這事陷揪≡忧睿” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵耐量,是天一觀的道長飞蚓。 經(jīng)常有香客問我廊蜒,道長,這世上最難降的妖魔是什么山叮? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任著榴,我火速辦了婚禮,結(jié)果婚禮上屁倔,老公的妹妹穿的比我還像新娘凉驻。我一直安慰自己,他們只是感情好叔壤,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布炼绘。 她就那樣靜靜地躺著妄田,像睡著了一般俺亮。 火紅的嫁衣襯著肌膚如雪疟呐。 梳的紋絲不亂的頭發(fā)上启具,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機與錄音拷沸,去河邊找鬼薯演。 笑死,一個胖子當(dāng)著我的面吹牛跨扮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帝嗡,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼璃氢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了碗降?” 一聲冷哼從身側(cè)響起塘秦,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爪幻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仇轻,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡奶甘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年臭家,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钉赁。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡你踩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出带膜,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布束莫,位于F島的核電站草描,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏饿敲。R本人自食惡果不足惜逛绵,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓢对。 院中可真熱鬧胰苏,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至琉兜,卻和暖如春毙玻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桑滩。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工运准, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胁澳。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓韭畸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胰丁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容