阿里巴巴面試 :進程保活如何作到,大家保活率有多高

本專欄專一分享大型Bat面試知識,後續會持續更新,喜歡的話麻煩點擊一個關注

前言

進程保活的關鍵點有兩個,一個是進程優先級的理解,優先級越高存活概率越大。二是弄清楚哪些場景會致使進程會kill,而後採起下面的策略對各類場景進行優化:android

  1. 提升進程的優先級
  2. 在進程被kill以後可以喚醒

廢話很少說先上面試資料目錄
圖片描述面試

一. 進程優先級

Android通常的進程優先級劃分: 1.前臺進程 (Foreground process) 2.可見進程 (Visible process) 3.服務進程 (Service process) 4.後臺進程 (Background process) 5.空進程 (Empty process) 這是一種粗略的劃分,進程其實有一種具體的數值,稱做oom_adj,注意:數值越大優先級越低:
shell

  • 紅色部分是容易被回收的進程,屬於android進程
  • 綠色部分是較難被回收的進程,屬於android進程
  • 其餘部分則不是android進程,也不會被系統回收,通常是ROM自帶的app和服務才能擁有

如何查看某個進程的oom_adj數值呢? oom_adj 存儲在proc/PID/oom_adj文件中,其中PID是進程的id,直接 adb shell進入手機根目錄查看這個文件便可。api

演示一下:以我本身的項目爲例,app中有兩個進程,一個是主進程,另外一個是運行service的進程取名爲:remote。首先用android studio查看每一個進程的PID:

而後分別查看app在前臺,app退到後臺,這2中場景主進程的oom_adj數值:

可見,當app在前臺時 oom_adj = 0,對應上面的表格是前臺進程。安全

當app退到後臺時,oom_adj = 6,對應後臺進程。微信

而後查看運行着service的進程:

ok,知道了進程優先級的概念以及如何查看優先級,咱們就能夠對app進程優化,而後經過查看這個數值判斷咱們的優化是否有效果。app

二.進程被kill的場景

1.點擊home鍵使app長時間停留在後臺,內存不足被killide

處理這種狀況前提是你的app至少運行了一個service,而後經過Service.startForeground() 設置爲前臺服務,能夠將oom_adj的數值由4下降到1,大大提升存活率。工具

  • 要注意的是android4.3以後Service.startForeground() 會強制彈出通知欄,解決辦法是再啓動一個service和推送共用一個通知欄,而後stop這個service使得通知欄消失。
  • Android 7.1以後google修復這個bug,目前沒有解決辦法 下面的代碼放到你的service的onStartCommand方法中:
//設置service爲前臺服務,提升優先級
        if (Build.VERSION.SDK_INT < 18) {
            //Android4.3如下 ,此方法能有效隱藏Notification上的圖標
            service.startForeground(GRAY_SERVICE_ID, new Notification());
        } else if(Build.VERSION.SDK_INT>18 && Build.VERSION.SDK_INT<25){
            //Android4.3 - Android7.0,此方法能有效隱藏Notification上的圖標
            Intent innerIntent = new Intent(service, GrayInnerService.class);
            service.startService(innerIntent);
            service.startForeground(GRAY_SERVICE_ID, new Notification());
        }else{
            //Android7.1 google修復了此漏洞,暫無解決方法(現狀:Android7.1以上app啓動後通知欄會出現一條"正在運行"的通知消息)
            service.startForeground(GRAY_SERVICE_ID, new Notification());
        }

通過改進以後,再來看下這個後臺service進程的oom_adj,發現被提高爲前臺進程。

測試

2.在大多數國產手機下,進入鎖屏狀態一段時間,省電機制會kill後臺進程

這種狀況和上面不太同樣,是很過國產手機rom自帶的優化,當鎖屏一段時間以後,即便手機內存夠用爲了省電,也會釋放掉一部份內存。

策略:註冊廣播監聽鎖屏和解鎖事件, 鎖屏後啓動一個1像素的透明Activity,這樣直接把進程的oom_adj數值下降到0,0是android進程的最高優先級。 解鎖後銷燬這個透明Activity。這裏我把這個Activity放到:remote進程也就是我那個後臺服務進程,固然你也能夠放到主進程,看你打算保活哪一個進程。

咱們能夠寫一個KeepLiveManager來負責接收廣播,維護這個Activity的常見和銷燬,注意鎖屏廣播和解鎖分別是:ACTION_SCREEN_OOF和ACTION_USER_PRESENT,而且只能經過動態註冊來綁定,而且是綁定到你的後臺service裏面,onCreate綁定,onDestroy裏面解綁

配好以後把手機鎖屏,看下:remote進程的oom_adj:

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

清理內存軟件會把 優先級低於 前臺進程(oom_adj = 0)的全部進程放入清理列表,而當咱們打開了清理軟件就意味着其餘app不可能處於前臺。因此說理論上能夠kill任何app。 以360安全衛士爲例,打開內存清理:

所以這類場景惟一的處理辦法就是加入 手機rom 白名單,好比你打開小米,魅族的權限管理 -> 自啓動管理能夠看到 QQ,微信,天貓默認被勾選,這就是廠商合做。那咱們普通app能夠這麼作:在app的設置界面加一個選項,提示用戶本身去勾選自啓動,我封裝了一個工具類給出國內各廠商的自啓動的Intent跳轉方法:

/**
 * Created by carmelo on 2018/3/17.
 * 國內手機廠商白名單跳轉工具類
 */

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;
    }
}

補充幾點:

  • 額外說下 自啓動是什麼意思? 網上都是小米開啓自啓動就是加入白名單,其實根本不是這樣的,通過實測就算app勾選自啓動也會被內存優化加速清理掉,只不過進程會在半分鐘後復活。
  • 除了還有自啓動還有一個設置就是電池管理,好比小米的神隱模式,這部分和自啓動不一樣的是它是管理app在鎖屏以後被省電機制殺死的場景,固然每家廠商也有對應的Intent跳轉路徑。
  • 如何查找不一樣廠商的設置界面跳轉Intent,好比上面的國內手機廠商白名單,給個方法:(前提是你有N多個不一樣手機,像我這樣。。。)


在酷安應用市場下載一個叫 當前Activity 的app,打開後能夠看到當前界面的className,例如:

就找到了魅族MX4 pro 後臺權限的Activity。

三.進程喚醒

分兩種狀況,一是主進程(含有Activity沒有service),這種進程因爲內存不足被kill以後,用戶再次打開app系統會恢復到上次的Activity,這個不在本文話題以內。另外一種是service的後臺進程被kill,能夠經過service自有api來重啓service:

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //.....
        return START_STICKY;    // service被異常中止後,系統嘗試重啓service,不能保證100%重啓成功
    }

配好START_STICKY後,經過android studio 釋放進程的工具測試下,能夠發現:remote進程被kill以後立刻重啓了:

但它不是100%保證重啓成功,好比下面2種狀況:(本人通過測試,這裏就不放效果圖了)

  • Service 第一次被異常殺死後會在5秒內重啓,第二次被殺死會在10秒內重啓,第三次會在20秒內重啓,一旦在短期內 Service 被殺死達到5次,則系統再也不拉起。
  • 進程被取得 Root 權限的管理工具或系統工具經過 forestop 中止掉,沒法重啓。

總結

本文經過兩種 提升進程優先級的方法,針對鎖屏 和非鎖屏模式下進程在後臺被kill的場景處理,把後臺進程優先級提高到可見級別,基本能夠保證絕大多數場景不會被kill。另外,針對含有service的進程被kill給出了可喚醒的辦法。

須要進程保活的代碼+開頭面試資料+以下視頻資料的能夠加
QQ羣:892872246

圖片描述
圖片描述
圖片描述

相關文章
相關標籤/搜索