進(jìn)程贬妫活

前言

進(jìn)程保活的關(guān)鍵點(diǎn)有兩個(gè)搭独,一個(gè)是進(jìn)程優(yōu)先級(jí)的理解婴削,優(yōu)先級(jí)越高存活幾率越大。二是弄清楚哪些場(chǎng)景會(huì)導(dǎo)致進(jìn)程會(huì)kill牙肝,然后采取下面的策略對(duì)各種場(chǎng)景進(jìn)行優(yōu)化:

  1. 提高進(jìn)程的優(yōu)先級(jí)
  2. 在進(jìn)程被kill之后能夠喚醒

一. 進(jìn)程優(yōu)先級(jí)

Android一般的進(jìn)程優(yōu)先級(jí)劃分: 1.前臺(tái)進(jìn)程 (Foreground process) 2.可見進(jìn)程 (Visible process) 3.服務(wù)進(jìn)程 (Service process) 4.后臺(tái)進(jìn)程 (Background process) 5.空進(jìn)程 (Empty process) 這是一種粗略的劃分唉俗,進(jìn)程其實(shí)有一種具體的數(shù)值嗤朴,稱作oom_adj,注意:數(shù)值越大優(yōu)先級(jí)越低:

image
  • 紅色部分是容易被回收的進(jìn)程虫溜,屬于android進(jìn)程
  • 綠色部分是較難被回收的進(jìn)程雹姊,屬于android進(jìn)程
  • 其他部分則不是android進(jìn)程,也不會(huì)被系統(tǒng)回收衡楞,一般是ROM自帶的app和服務(wù)才能擁有

如何查看某個(gè)進(jìn)程的oom_adj數(shù)值呢容为? oom_adj 存儲(chǔ)在proc/PID/oom_adj文件中,其中PID是進(jìn)程的id寺酪,直接 adb shell進(jìn)入手機(jī)根目錄查看這個(gè)文件即可。

演示一下:以我自己的項(xiàng)目為例替劈,app中有兩個(gè)進(jìn)程寄雀,一個(gè)是主進(jìn)程,另一個(gè)是運(yùn)行service的進(jìn)程取名為:remote陨献。首先用android studio查看每個(gè)進(jìn)程的PID:

image

然后分別查看app在前臺(tái)盒犹,app退到后臺(tái),這2中場(chǎng)景主進(jìn)程的oom_adj數(shù)值:

image

可見眨业,當(dāng)app在前臺(tái)時(shí) oom_adj = 0急膀,對(duì)應(yīng)上面的表格是前臺(tái)進(jìn)程。
當(dāng)app退到后臺(tái)時(shí)龄捡,oom_adj = 6卓嫂,對(duì)應(yīng)后臺(tái)進(jìn)程。

然后查看運(yùn)行著service的進(jìn)程:

image

ok聘殖,知道了進(jìn)程優(yōu)先級(jí)的概念以及如何查看優(yōu)先級(jí)晨雳,我們就可以對(duì)app進(jìn)程優(yōu)化,然后通過查看這個(gè)數(shù)值判斷我們的優(yōu)化是否有效果奸腺。

二.進(jìn)程被kill的場(chǎng)景

1.點(diǎn)擊home鍵使app長(zhǎng)時(shí)間停留在后臺(tái)餐禁,內(nèi)存不足被kill

處理這種情況前提是你的app至少運(yùn)行了一個(gè)service,然后通過Service.startForeground() 設(shè)置為前臺(tái)服務(wù)突照,可以將oom_adj的數(shù)值由4降低到1帮非,大大提高存活率。

  • 要注意的是android4.3之后Service.startForeground() 會(huì)強(qiáng)制彈出通知欄讹蘑,解決辦法是再啟動(dòng)一個(gè)service和推送共用一個(gè)通知欄末盔,然后stop這個(gè)service使得通知欄消失。

  • Android 7.1之后google修復(fù)這個(gè)bug衔肢,目前沒有解決辦法 下面的代碼放到你的service的onStartCommand方法中:

   //設(shè)置service為前臺(tái)服務(wù)庄岖,提高優(yōu)先級(jí)
        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啟動(dòng)后通知欄會(huì)出現(xiàn)一條"正在運(yùn)行"的通知消息)
            service.startForeground(GRAY_SERVICE_ID, new Notification());
        }

經(jīng)過改進(jìn)之后心剥,再來看下這個(gè)后臺(tái)service進(jìn)程的oom_adj,發(fā)現(xiàn)被提升為前臺(tái)進(jìn)程背桐。

image
image

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

這種情況和上面不太一樣链峭,是很過國(guó)產(chǎn)手機(jī)rom自帶的優(yōu)化畦娄,當(dāng)鎖屏一段時(shí)間之后,即使手機(jī)內(nèi)存夠用為了省電弊仪,也會(huì)釋放掉一部分內(nèi)存熙卡。

策略:注冊(cè)廣播監(jiān)聽鎖屏和解鎖事件, 鎖屏后啟動(dòng)一個(gè)1像素的透明Activity励饵,這樣直接把進(jìn)程的oom_adj數(shù)值降低到0驳癌,0是android進(jìn)程的最高優(yōu)先級(jí)。 解鎖后銷毀這個(gè)透明Activity役听。這里我把這個(gè)Activity放到:remote進(jìn)程也就是我那個(gè)后臺(tái)服務(wù)進(jìn)程颓鲜,當(dāng)然你也可以放到主進(jìn)程,看你打算钡溆瑁活哪個(gè)進(jìn)程甜滨。

image

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

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

image

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

清理內(nèi)存軟件會(huì)把 優(yōu)先級(jí)低于 前臺(tái)進(jìn)程(oom_adj = 0)的所有進(jìn)程放入清理列表黍匾,而當(dāng)我們打開了清理軟件就意味著其他app不可能處于前臺(tái)栏渺。所以說理論上可以kill任何app。 以360安全衛(wèi)士為例锐涯,打開內(nèi)存清理:

image

因此這類場(chǎng)景唯一的處理辦法就是加入 手機(jī)rom 白名單磕诊,比如你打開小米,魅族的權(quán)限管理 -> 自啟動(dòng)管理可以看到 QQ纹腌,微信霎终,天貓默認(rèn)被勾選,這就是廠商合作升薯。那我們普通app可以這么做:在app的設(shè)置界面加一個(gè)選項(xiàng)莱褒,提示用戶自己去勾選自啟動(dòng),我封裝了一個(gè)工具類給出國(guó)內(nèi)各廠商的自啟動(dòng)的Intent跳轉(zhuǎn)方法:

/**
 * Created by carmelo on 2018/3/17.
 * 國(guó)內(nèi)手機(jī)廠商白名單跳轉(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;
    }
}

補(bǔ)充幾點(diǎn):

  • 額外說下 自啟動(dòng)是什么意思涎劈? 網(wǎng)上都是小米開啟自啟動(dòng)就是加入白名單广凸,其實(shí)根本不是這樣的阅茶,經(jīng)過實(shí)測(cè)就算app勾選自啟動(dòng)也會(huì)被內(nèi)存優(yōu)化加速清理掉,只不過進(jìn)程會(huì)在半分鐘后復(fù)活谅海。

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

  • 如何查找不同廠商的設(shè)置界面跳轉(zhuǎn)Intent,比如上面的國(guó)內(nèi)手機(jī)廠商白名單侥袜,給個(gè)方法:(前提是你有N多個(gè)不同手機(jī)蝌诡,像我這樣。枫吧。送漠。)

    image

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

image

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

三.進(jìn)程喚醒

分兩種情況代兵,一是主進(jìn)程(含有Activity沒有service)尼酿,這種進(jìn)程由于內(nèi)存不足被kill之后,用戶再次打開app系統(tǒng)會(huì)恢復(fù)到上次的Activity植影,這個(gè)不在本文話題之內(nèi)裳擎。另一種是service的后臺(tái)進(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)程的工具測(cè)試下谷饿,可以發(fā)現(xiàn):remote進(jìn)程被kill之后馬上重啟了:

image

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

  • Service 第一次被異常殺死后會(huì)在5秒內(nèi)重啟博投,第二次被殺死會(huì)在10秒內(nèi)重啟绸贡,第三次會(huì)在20秒內(nèi)重啟,一旦在短時(shí)間內(nèi) Service 被殺死達(dá)到5次毅哗,則系統(tǒng)不再拉起听怕。
  • 進(jìn)程被取得 Root 權(quán)限的管理工具或系統(tǒng)工具通過 forestop 停止掉,無法重啟虑绵。

總結(jié)

本文通過兩種 提高進(jìn)程優(yōu)先級(jí)的方法尿瞭,針對(duì)鎖屏 和非鎖屏模式下進(jìn)程在后臺(tái)被kill的場(chǎng)景處理,把后臺(tái)進(jìn)程優(yōu)先級(jí)提升到可見級(jí)別翅睛,基本可以保證絕大多數(shù)場(chǎng)景不會(huì)被kill声搁。另外黑竞,針對(duì)含有service的進(jìn)程被kill給出了可喚醒的辦法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酥艳,一起剝皮案震驚了整個(gè)濱河市摊溶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌充石,老刑警劉巖莫换,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異骤铃,居然都是意外死亡拉岁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門惰爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喊暖,“玉大人,你說我怎么就攤上這事撕瞧×赀矗” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵丛版,是天一觀的道長(zhǎng)巩掺。 經(jīng)常有香客問我,道長(zhǎng)页畦,這世上最難降的妖魔是什么胖替? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮豫缨,結(jié)果婚禮上独令,老公的妹妹穿的比我還像新娘。我一直安慰自己好芭,他們只是感情好燃箭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舍败,像睡著了一般遍膜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓤湘,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天瓢颅,我揣著相機(jī)與錄音,去河邊找鬼弛说。 笑死挽懦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的木人。 我是一名探鬼主播信柿,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼冀偶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了渔嚷?” 一聲冷哼從身側(cè)響起进鸠,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎形病,沒想到半個(gè)月后客年,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡漠吻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年量瓜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片途乃。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绍傲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耍共,到底是詐尸還是另有隱情烫饼,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布试读,位于F島的核電站枫弟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鹏往。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一骇塘、第九天 我趴在偏房一處隱蔽的房頂上張望伊履。 院中可真熱鬧,春花似錦款违、人聲如沸唐瀑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哄辣。三九已至,卻和暖如春赠尾,著一層夾襖步出監(jiān)牢的瞬間力穗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工气嫁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留当窗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓寸宵,卻偏偏與公主長(zhǎng)得像崖面,于是被迫代替她去往敵國(guó)和親元咙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

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