深刻Android系統(十一)AMS-1-應用組成與服務的啓動

牛年犇犇犇,剛剛完成AMS一半的學習進度,篇幅確實有點大,不過先更上兩篇吧java

咱們不止一次提到Android一直想弱化進程的存在,可是,Android畢竟是創建在Linux系統之上,基礎的運行環境仍是由進程組成。android

咱們前面已經介紹,全部的Android的應用程序都是由Zygote進程fork而來,所以,構成應用進程的底層基礎,像虛擬機、動態庫等都是相同的。web

有了從Zygote中繼承來的通用基礎環境,Android還在Java層創建一套框架來管理運行的組件來進一步弱化進程的存在感。算法

不過因爲每一個應用的上層配置都不相同,所以,這個框架不能提早在Zygote中徹底創建好後繼承,只能在應用啓動時建立。數據庫

而這套框架就構成了Android應用開發的基礎,而這套框架的核心就是大名鼎鼎的ActivityManagerServie設計模式

應用進程的組成

學習ActivityManagerServie前咱們先簡單瞭解下Android應用進程的組成數組

組成Android應用進程的核心是ActivityThread類,這個類包含了應用框架中其餘重要的類。相關類變量聲明以下:緩存

public final class ActivityThread extends ClientTransactionHandler {
    ...
    // 一個Binder實體對象,AMS 經過它來調用應用的接口
    final ApplicationThread mAppThread = new ApplicationThread();
    Application mInitialApplication;
    // 用來保存應用中的 Activity 對象
    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
    // 用來保存應用中的 Service 對象
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
    // 用來保存應用中的 ContentProvider 對象
    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey, ProviderClientRecord>();
    // 用來保存包含代碼的的應用
    final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
    // 用來保存只包含資源文件的應用
    final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<>();
    // 應用資源管理對象
    private final ResourcesManager mResourcesManager;
    // 上下文對象
    private ContextImpl mSystemContext;
    private ContextImpl mSystemUiContext;
}
複製代碼

咱們先來看下ApplicationThreadmarkdown

ApplicationThread的做用

ApplicationThreadActivityThread的一個內部類,它和ActivityThread同樣,雖然名字中都包含了Thread,可是它們並非繼承自線程類Thread數據結構

ApplicationThread是一個Binder服務類,AndroidActivityManagerService操做應用就是經過ApplicationThread來完成的。

咱們先看下AIDL文件內容,路徑frameworks/base/core/java/android/app/IApplicationThread.aidl,片斷以下:

oneway interface IApplicationThread {
    ......
    void scheduleSleeping(IBinder token, boolean sleeping);
    ......
}
複製代碼

請留意AIDL中的oneway關鍵字,修飾interface意味着修飾接口中的全部方法

oneway修飾表示一個異步過程,調用時不須要等待返回值

ApplicationThread類的片斷以下:

private class ApplicationThread extends IApplicationThread.Stub {
    ......
    public final void scheduleSleeping(IBinder token, boolean sleeping) {
        sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
    }
    ......// 省略大量接口
}
複製代碼
  • ApplicationThread中接口的實現都是把Binder調用轉換成消息來排隊處理。
  • 以上面的scheduleSleeping()爲例,只是發送了一個SLEEPING的消息
  • 全部消息的處理都集中在Handler對象mHhandleMessage()方法中集中處理。處理部分以下:
    public void handleMessage(Message msg) {
        switch (msg.what) {
            ...
            case SLEEPING:
                handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
                break;
            ...
        }
    }
    複製代碼
    • 最後經過ActivityThreadhandleSleeping()來執行

在源碼中,ApplicationThread中的接口一般都是以schedule*開頭,而真正處理的方法以handle*開頭,很容易分辨。

爲何要這樣設計呢?

主要是避免方法在調用和執行時出現耗時過長影響整個系統的運行:

  • 對於調用端:還記得IApplicationThread.aidl中的oneway
    • oneway修飾就代表客戶端進行Binder調用時不會等待服務端結果的返回(這部分能夠去看以前的Binder-3-原理部分
  • 對於服務端:經過sendMessage的方式將Binder調用轉化爲消息的異步處理
    • 消息處理部分交給了H mH這個Handler
    • ActivityThread的靜態main()方法中,會經過Looper.loop()進入消息的循環處理

理解應用的Context

Context的字面含義是上下文環境。應用的上層代碼經過Context類提供的接口來操做Android的組件和資源。在Android的應用程序中,Context無處不在,不少接口都要求使用Context對象做爲參數。

Android的應用本質上是一系列組件加上資源文件的容器,可是,這些組件的使用方式各不相同,並且比較複雜,Context類的做用就是把這些細節封裝起來,這樣,即便開發人員不瞭解組件的運行原理也能使用它們。從某種意義上將,Context包含了整個應用框架的操做接口。

對於應用開發者來講,大部分代碼都在Activity或者Service的繼承類中實現。爲了方便應用使用,這兩個類的父類也是Context

Context是一個抽象類,Android相關類的繼承關係設計以下:
image AndroidContext有兩個實現類

  • ContextImplContext真正的實現類
    • 目前Android中惟一的業務實現類
    • 集成了應用框架的一些核心對象,如ActivityThread對象
  • ContextWrapper:方法的實現只是轉調成員變量mBase的方法
    • mBase自己也是Context類型對象,它的具體類型是ContextImpl

上面這種設計模式稱爲proxy模式或者wrapper模式,它的好處就是將接口和實現分離,能夠動態的切換多種實現。

Activity類有些特殊(畢竟承載了應用的顯示部分),Android又爲它抽象出來了一個ContextThemeWrapper

  • 這樣的目的是爲了實現Activity中單獨的Theme
  • 一個應用中能夠有一套全局的Theme,同時每一個Activity還能夠有本身的Theme

Application

Application類也是繼承ContextWrapper

Application類能夠看作是應用自己的抽象,一個應用進程只有一個Application對象,在應用啓動時由框架建立。

Application自己沒有實現太多功能,它的主要做用是提供一些回調接口來通知應用進程狀態的變化。相關的方法以下:

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    // 在應用建立時調用
    public void onCreate();
    // 在應用銷燬時調用
    public void onTerminate();
    // 在系統配置發生變化時調用
    public void onConfigurationChanged(Configuration newConfig);
    // 在系統內存不足時調用
    public void onLowMemory();
    // 在系統要求應用釋放多餘內存時調用
    public void onTrimMemory(int level);
}
複製代碼

應用中能夠定義Application的子類。子類必須在AndroidManifest.xml<application/>標籤中定義,這樣系統才能在生成應用對象時使用子類來替換Application類。

<application/>標籤在Android SDK文檔中有詳細的介紹,能夠先簡單閱讀標籤的屬性描述,否則到後面理解ActivityManagerService的業務邏輯時可能會有障礙。

allowTaskReparenting爲例,它的描述是這樣的:

  • 當下一次將啓動 Activity 的任務轉至前臺時,Activity 是否能從該任務轉移至與其有類似性的任務
    • 「true」表示能夠轉移,「false」表示仍須留在啓動它的任務處。
    • 默認值爲「false」。
  • 對於<activity> 標籤有其本身的 allowTaskReparenting 屬性,該屬性能夠替換此處設置的值。

剩下的屬性你們能夠參考官方說明。傳送門:<application/>標籤

Android 框架的核心-AMS服務

ActivityManagerServiceAndroid Framework的核心,它管理着Android系統的4大組件:ActivityServiceContentProviderBroadcast

前面已經介紹了,Android但願模糊進程的做用,取而代之以組件的概念,ActivityManagerService正是這一理念的實現。ActivityManagerService除了管理組件外,同時也管理和調度全部的用戶進程

爲了方便,ActivityManagerService後面就用AMS來表示了哈

AMSSystemServer中的啓動流程

咱們已經知道AMS服務運行在SystemServer進程中。

AMSSystemServer的主要流程以下:

private void startBootstrapServices() {
    // 建立 AMS 服務
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    ......
    // 調用 AMS 的 setSystemProcess
    mActivityManagerService.setSystemProcess();
}
private void startOtherServices() {
    // 調用 AMS 的 systemReady
    mActivityManagerService.systemReady(...);
}
複製代碼

上面的代碼重點分爲三部分:

  • 經過SystemServiceManager.startService方法進行AMS建立
    • 方法會根據傳入的Class對象來建立對應類的實例對象
    • 這裏傳入的ActivityManagerService.Lifecycle類,類結構以下:
    public static final class Lifecycle extends SystemService {
        private final ActivityManagerService mService;
        public Lifecycle(Context context) {
            super(context);
            // 建立 ActivityManagerService 實例對象
            mService = new  ActivityManagerService(context);
        }
        ......
    }
    複製代碼
    • 能夠看到,在Lifecycle的構造方法中初始化了AMS對象
  • 調用AMSsetSystemProcess方法
  • 調用AMSsystemReady方法

這三部分咱們詳細來看下

AMS的初始化

AMS的構造方法以下:

public ActivityManagerService(Context systemContext) {
    ......
    mContext = systemContext;
    mFactoryTest = FactoryTest.getMode();
    // 獲取運行在 SystemServer 中的 ActivityThread 對象
    mSystemThread = ActivityThread.currentActivityThread();
    mUiContext = mSystemThread.getSystemUiContext();
    ......
    // 建立用於處理消息的線程和Handler對象
    // 這裏建立了兩個消息處理線程:mHandlerThread 和 mProcStartHandlerThread
    mHandlerThread = new ServiceThread(TAG,
            THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());
    mUiHandler = mInjector.getUiHandler(this);

    mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
            THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
    mProcStartHandlerThread.start();
    mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
    ......
    // 建立管理廣播的數據結構
    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;
    // 建立管理組件 Service 的對象
    mServices = new ActiveServices(this);
    // 建立管理組件 Provider 的對象
    mProviderMap = new ProviderMap(this);
    mAppErrors = new AppErrors(mUiContext, this);
    // 獲取系統的 system 和 data 目錄
    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    systemDir.mkdirs();
    // 建立 BatteryStatsService 服務
    mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
    ......
    // 建立 ProcessStatsService 服務
    mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
    // 建立 AppOpsService 服務
    mAppOpsService = mInjector.getAppOpsService(new File(systemDir, "appops.xml"), mHandler);
    // 打開 urigrants.xml 文件
    mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
    // 建立 UserController ,UserController 對應的構造方法中會設置 USER_SYSTEM 用戶做爲第一個用戶
    mUserController = new UserController(this);
    // 建立 VrController ,用來進行部分 VR 狀態的監聽和切換工做
    mVrController = new VrController(this);
    // 獲取 opengles 的版本
    GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
        ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
    ......
    // 建立 Activity 管理對象
    mStackSupervisor = createStackSupervisor();
    ......
    // 建立 Intent 防火牆
    mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
    ......
    // 建立 CPU 使用狀況的統計線程
    mProcessCpuThread = new Thread("CpuTracker") {
        ...
    };
    ......
    // 將服務添加到 WatchDog 進行監聽
    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
    ......
}
複製代碼

AMS構造方法的主要做用是建立出了4大組件ActivityServiceContentProviderBroadcast的管理對象和一些輔助服務,沒有很複雜的邏輯,註釋很詳細啦

AMSsetSystemProcess方法

SystemServer中建立完AMS對象後,會調用它的setSystemProcess方法,代碼以下:

public void setSystemProcess() {
    try {
        // =============== 將一些監測服務添加到 ServiceManager ===============
        // AMS 服務
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
                DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
        // ProcessStats 是能夠用來dump每一個進程內存使用狀況的服務
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
        // MemBinder 是能夠用來dump每一個進程內存信息的服務
        ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
                DUMP_FLAG_PRIORITY_HIGH);
        // GraphicsBinder 是能夠用來dump每一個進程圖形加速狀態的服務
        ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
        // DbBinder 是能夠用來dump每一個進程數據庫狀態的服務
        ServiceManager.addService("dbinfo", new DbBinder(this));
        if (MONITOR_CPU_USAGE) {
            // CPU 信息
            ServiceManager.addService("cpuinfo", new CpuBinder(this),
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
        }
        // PermissionController 是用來檢查 Binder 調用權限的服務
        ServiceManager.addService("permission", new PermissionController(this));
        // ProcessInfoService 是能夠用來獲取進程相關信息的服務
        ServiceManager.addService("processinfo", new ProcessInfoService(this));
        // 獲取 framework-res.apk 的 ApplicationInfo 對象
        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
        synchronized (this) {
            // 將 SystemServer 進程自己添加到 AMS process 的管理中
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
    } catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException("Unable to find android system package", e);
    }
    // 啓動應用操做監聽
    mAppOpsService.startWatchingMode(......);
}
複製代碼

SystemServer調用setSystemProcess方法的主要工做是向ServiceManager註冊一些服務。須要注意的是:

  • 經過getApplicationInfo方法獲取了framework-res.apkApplicationInfo對象
  • 而後使用newProcessRecordLocked()方法將ApplicationInfo對象轉化爲ProcessRecord對象,並將其添加到AMS的進程管理體系中

AMSsystemReady方法

SystemServer在啓動完全部服務以後,將調用AMSsystemReady方法。這個方法時Android進入用戶交互階段前最後進行的準備工做。

systemReady方法比較長,咱們一點一點來分析

AMS相關服務的準備階段

相關代碼以下:

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
    synchronized(this) {
        if (mSystemReady) {
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }
        ......
        // 通知 VrController 註冊 VrModeStateListener
        mVrController.onSystemReady();
        // 通知 UserController 裝載用戶的 Profile 信息
        mUserController.onSystemReady();
        // 通知 RecentTasks 重建帶有 persisitent 標記的 Task
        mRecentTasks.onSystemReadyLocked();
        // 通知 AppOpsService 啓動 APP 權限監聽
        mAppOpsService.systemReady();
        // 系統相關服務準備完成
        mSystemReady = true;
    }
    ......
    // 查找待清理進程
    ArrayList<ProcessRecord> procsToKill = null;
    synchronized(mPidsSelfLocked) {
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);
            // 此處判斷進程是否有 FLAG_PERSISTENT 標誌
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList<ProcessRecord>();
                }
                // 將沒有 FLAG_PERSISTENT 標誌的進程添加到清理集合中
                procsToKill.add(proc);
            }
        }
    }
    // 清理集合中的進程
    synchronized(this) {
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                removeProcessLocked(proc, true, false, "system update done");
            }
        }
        // 進程清理完成
        mProcessesReady = true;
    }
    Slog.i(TAG, "System now ready");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());
    ......
}
複製代碼

上面註釋比較詳細,簡單總結主要流程以下:

  • 調用VrControllerUserControllerRecentTasksAppOpsService服務的*SystemReady()方法進行對應服務的初始化工做
    • 對於上面的4個服務,任何一個的知識點均可以單獨寫一篇博文了,這裏咱們先略過哈,大局爲重
  • mPidsSelfLocked集合中查找非FLAG_PERSISTENT標記的進程,並將其清理
    • mPidsSelfLocked集合存放的是已經運行了的進程
    • 這些基本都是經過ActivityThread.attach()加入mPidsSelfLocked集合的
    • FLAG_PERSISTENT標記的進程說明後面很快還會啓動,沒有必要清理

SystemServer啓動的過程會執行PMSupdatePackagesIfNeeded()方法,這個方法會發送一個ACTION_PRE_BOOT_COMPLETED的廣播。

因此,若是咱們的應用響應這個ACTION_PRE_BOOT_COMPLETED而且加入FLAG_PERSISTENT標誌,那麼就能夠存活下來

FactoryMode檢測階段

相關代碼以下

synchronized(this) {
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        // 處於工廠模式,則查找對應的應用程序
        ResolveInfo ri = mContext.getPackageManager()
                .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
                        STOCK_PM_FLAGS);
        CharSequence errorMsg = null;
        if (ri != null) {
            ActivityInfo ai = ri.activityInfo;
            ApplicationInfo app = ai.applicationInfo;
            // 判斷找到的程序是否爲系統應用
            if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                mTopAction = Intent.ACTION_FACTORY_TEST;
                mTopData = null;
                mTopComponent = new ComponentName(app.packageName,
                        ai.name);
            } else {
                errorMsg = mContext.getResources().getText(
                        com.android.internal.R.string.factorytest_not_system);
            }
        } else {
            errorMsg = mContext.getResources().getText(
                    com.android.internal.R.string.factorytest_no_action);
        }
        if (errorMsg != null) {
            ......
            // 錯誤消息不爲空,發送對應的信息
            Message msg = Message.obtain();
            msg.what = SHOW_FACTORY_ERROR_UI_MSG;
            msg.getData().putCharSequence("msg", errorMsg);
            mUiHandler.sendMessage(msg);
        }
    }
}
複製代碼

對於Android產品,如手機、電視等,須要進入工廠模式來執行檢測程序,工廠模式下運行的程序須要響應Intent.ACTION_FACTORY_TEST

所以,當檢測處處於工廠模式時,會去查找響應該Intent的程序,並放置到mTopComponent中,這樣將會啓動對應的測試應用。若是找不到,則發送異常Message

應用啓動階段

相關代碼以下:

// 更新設置信息,包括是否支持畫中畫、多窗口等屬性
retrieveSettings();
final int currentUserId = mUserController.getCurrentUserId();
synchronized (this) {
    readGrantedUriPermissionsLocked();
}
......
// 執行回調參數
if (goingCallback != null) goingCallback.run();
// 通知其餘服務,當前用戶開始運行
mSystemServiceManager.startUser(currentUserId);
synchronized (this) {
    // 啓動帶有 FLAG_PERSISTENT 標記的應用
    startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
    mBooting = true;
    ......
    // 啓動 Home 應用
    startHomeActivityLocked(currentUserId, "systemReady");
    ......
    long ident = Binder.clearCallingIdentity();
    try {
        // 發送 ACTION_USER_STARTED 廣播
        Intent intent = new Intent(Intent.ACTION_USER_STARTED);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                | Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
        broadcastIntentLocked(null, null, intent,...);
        // 發送 ACTION_USER_STARTING 廣播
        intent = new Intent(Intent.ACTION_USER_STARTING);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
        broadcastIntentLocked(null, null, intent,...);
    } catch (Throwable t) {
        Slog.wtf(TAG, "Failed sending first user broadcasts", t);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
    mStackSupervisor.resumeFocusedStackTopActivityLocked();
    mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
    ......
}
複製代碼

這一段的代碼主要做用是

  • 更新設置,判斷是否支持畫中畫、多窗口等信息
  • 執行systemReady方法參數goingCallback的回調方法run()
    • 回調方法是在SystemServer中定義的
  • 啓動帶有FLAG_PERSISTENT標記的應用
    • 具體啓動應用是經過addAppLocked()方法,後面詳細介紹
  • 啓動Home應用
    • 查找並啓動可以響應android.intent.action.MAINActivity

Process管理

雖然Android在應用開發中能夠弱化進程的概念,可是在AMS中,還必須管理和調度進程。AMS對進程的管理,主要體如今兩個方面:

  • 動態調整進程在mLruProcesses列表的位置
    • 核心方法:updateLruProcessLocked
  • 調整進程的oom_adj的值
    • 核心方法:updateOomAdjLocked

這兩項調整和Android的內存回收機制有關。當內存不足時,系統會關閉一些進程來釋放內存。

進程的啓動

前面介紹了,AMS中啓動帶有FLAG_PERSISTENT標記的應用是經過addAppLocked()方法,代碼以下:

final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, boolean disableHiddenApiChecks, String abiOverride) {
    ProcessRecord app;
    // isolated 爲 true 表示要啓動一個新的進程
    if (!isolated) {
        // 在已經啓動的進程列表中查找
        app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
                info.uid, true);
    } else {
        app = null;
    }
    if (app == null) {
        // 新建一個 ProcessRecord 對象
        app = newProcessRecordLocked(info, customProcess, isolated, 0);
        updateLruProcessLocked(app, false, null);
        updateOomAdjLocked();
    }
    try {
        // 將包的stopped狀態設置爲false
        // 若是爲ture那麼全部廣播都沒法接收,除非帶有標記FLAG_INCLUDE_STOPPED_PACKAGES的廣播
        // 正經的廣播都不會帶有這個標記
        AppGlobals.getPackageManager().setPackageStoppedState(info.packageName, false, UserHandle.getUserId(app.uid));
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        ......
    }
    if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        // 設置 persistent 標記
        app.persistent = true;
        app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    }
    if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
        mPersistentStartingProcesses.add(app);
        // 啓動進程
        startProcessLocked(app, "added application",
                customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
                abiOverride);
    }
    return app;
}
複製代碼

addAppLocked()方法流程以下:

  • 先根據參數isolated來決定是否啓動一個新進程
    • 若是isolatedtrue,即便系統中可能已經有一個同名的進程存在,也會經過newProcessRecordLocked()再新建一個進程
      • 經過updateLruProcessLocked()方法更新運行中的進程的狀態
      • 經過updateOomAdjLocked()方法來更新進程的優先級
    • 若是isolatedfalse,會經過getProcessRecordLocked()方法在當前運行的進程列表中查找
  • 接着檢查應用是否具備persistent標記
    • 若是有,設置persistentmaxAdj屬性
  • 最後,經過startProcessLocked()來啓動進程

updateLruProcessLocked()updateOomAdjLocked()這兩個方法是進程管理的核心,等下細聊。

咱們先看下startProcessLocked()的啓動邏輯:

private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
    ......
    long startTime = SystemClock.elapsedRealtime();
    if (app.pid > 0 && app.pid != MY_PID) {
        synchronized (mPidsSelfLocked) {
            // 移除集合中的進程ID,避免重複
            mPidsSelfLocked.remove(app.pid);
            // 移除消息隊列中的 PROC_START_TIMEOUT_MSG 消息,避免干擾
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
    }
    ......
    mProcessesOnHold.remove(app);
    ...//省略大量的啓動參數準備過程
    final String entryPoint = "android.app.ActivityThread";
    return startProcessLocked(hostingType, hostingNameStr, entryPoint, ...);
}
private boolean startProcessLocked(hostingType, hostingNameStr, entryPoint,...) {
    ......
    if (mConstants.FLAG_PROCESS_START_ASYNC) {
        // 異步啓動的狀況,經過 mProcStartHandler 來處理
        mProcStartHandler.post(() -> {
            ......
            // 啓動應用
            final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, ...);
            synchronized (ActivityManagerService.this) {
                // 發送一個延時消息用來監聽應用啓動
                handleProcessStartedLocked(app, startResult, startSeq);
            }
            ......
        });
        return true;
    } else {
        // 啓動應用
        final ProcessStartResult startResult = startProcess(hostingType, entryPoint, ...);
        // 發送一個延時消息用來監聽應用啓動
        handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
        startSeq, false);
        return app.pid > 0;
    }
}
private ProcessStartResult startProcess(String hostingType, String entryPoint, ...) {
    ......
    final ProcessStartResult startResult;
    if (hostingType.equals("webview_service")) {
        // startWebView 是 Process 的靜態方法
        // 啓動的是 WebViewZygote,應該是爲了和本地應用有所區分,不先管它。
        startResult = startWebView(entryPoint,...);
    } else {
        // 經過 Process.start() 函數啓動應用
        startResult = Process.start(entryPoint, ...);
    }
    ...
    return startResult;
}
複製代碼

註釋比較清楚。對於startProcessLocked()方法,主要作了兩件事:

  • 經過startProcess()方法來啓動應用進程

    • startProcess()方法最後是經過Process.start()方法來完成。執行結果就是建立了一個新進程,並在其中執行ActivityThreadmain()方法
    • 關於Process.start()方法在深刻Android系統(七)Zygote進程中已經介紹過了,這裏就不展開啦
  • 而後經過handleProcessStartedLocked()方法來檢測應用啓動是否超時

handleProcessStartedLocked()方法以下:

static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
    static final int PROC_START_TIMEOUT = 10*1000;
    private boolean handleProcessStartedLocked(...) {
        ......
        synchronized (mPidsSelfLocked) {
            this.mPidsSelfLocked.put(pid, app);
            if (!procAttached) {
                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
                // 發送一個延時消息
                mHandler.sendMessageDelayed(msg, usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
        return true;
    }
複製代碼

handleProcessStartedLocked()方法主要是發送了一個延時消息PROC_START_TIMEOUT_MSG

Android的想法應該是:當應用啓動後去移除這個消息,若是消息在延時結束前沒有被移除,就認爲應用的啓動出了問題。

那麼,在哪裏移除的呢??

咱們已經知道,應用的啓動入口在ActivityThreadmain()方法。而在main()方法的執行邏輯中會執行一個attach()方法(這個方法也很重要),方法以下:

private void attach(boolean system, long startSeq) {
        ......
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        ......
    }
複製代碼

attach()方法中會調用AMSattachApplication() 方法,而在attachApplication()中執行了 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

666,把Handler使用的是淋漓盡致啊

進程列表的調整-LRU

LRULeast Recently Used的縮寫,即最近最少使用,是一種經常使用的頁面置換算法,選擇最近最久未使用的頁面予以淘汰。

Android中進程啓動後都會在AMS的成員變量mLruProcesses中保存其ProcessRecord信息。mLruProcessesLRU順序存儲了當前運行的應用程序進程信息,mLruProcesses中的第一個元素就是最近最少使用的進程對應的ProcessRecord

AMS中會經過updateLruProcessLocked()來調整進程在mLruProcesses列表中的位置,代碼以下:

final void updateLruProcessLocked(ProcessRecord app, boolean activityChange, ProcessRecord client) {
    // app.activities.size() > 0 說明本進程中有活動的 Activity。app.activities 元素的類型是 ActivityRecord
    // app.hasClientActivities 爲 true 表示綁定了本進程Service的客戶進程中有活動的 Activity
    // app.treatLikeActivity 爲 true 表示 Service 啓動時帶有 BIND_TREAT_LIKE_ACTIVITY 標記,這個屬性和鍵盤邏輯關係比較大
    // app.recentTasks.size() > 0 說明本進程中有活動的任務棧。app.recentTasks 元素的類型是 TaskRecord
    final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
            || app.treatLikeActivity || app.recentTasks.size() > 0;
    final boolean hasService = false; // not impl yet. app.services.size() > 0;
    if (!activityChange && hasActivity) {
        // 若是當前進程中存在 Activity 而且 Activity 的狀態沒有發生過變化
        // 不作處理,直接返回
        return;
    }
    mLruSeq++; // 執行次數 +1
    final long now = SystemClock.uptimeMillis();
    app.lastActivityTime = now; // 更新 lastActivityTime 時間
    if (hasActivity) {
        // 若是 hasActivity 爲 true 而且在 mLruProcesses 列表的最後一個位置
        // 不須要再進行額外的操做,直接退出
        final int N = mLruProcesses.size();
        if (N > 0 && mLruProcesses.get(N-1) == app) {
            return;
        }
    } else {
        // hasActivity 爲 false,說明進程中沒有 Activity
        // 若是位置位於 mLruProcessServiceStart-1 說明沒有問題
        if (mLruProcessServiceStart > 0
                && mLruProcesses.get(mLruProcessServiceStart-1) == app) {
            return;
        }
    }
    // 獲取當前應用在集合中的位置
    int lrui = mLruProcesses.lastIndexOf(app);
    if (app.persistent && lrui >= 0) {
        // 若是集合中已經存在而且應用屬於 persistent 類型,則不須要作優化處理,直接返回
        return;
    }
    if (lrui >= 0) {
        // 若是 mLruProcesses 集合中已經存在,而且不是 persistent 類型,先將其從集合中移除
        // 並同時調整 mLruProcessActivityStart 和 mLruProcessServiceStart 的位置
        if (lrui < mLruProcessActivityStart) {
            mLruProcessActivityStart--;
        }
        if (lrui < mLruProcessServiceStart) {
            mLruProcessServiceStart--;
        }
        mLruProcesses.remove(lrui);
    }
    int nextIndex;
    if (hasActivity) {
        // 當前集合中全部的進程數量,請注意此時 app 已經不在集合中了
        final int N = mLruProcesses.size();
        if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
                && mLruProcessActivityStart < (N - 1)) {
            // 進程中沒有 Activity,可是它的 Service 客戶進程有 Activity
            // 將進程插入到集合的尾部
            mLruProcesses.add(N - 1, app);
            // 檢查集合中進程的uid,將與 app 相同uid的進程位置調整到一塊兒
            final int uid = app.info.uid;
            for (int i = N - 2; i > mLruProcessActivityStart; i--) {
                ProcessRecord subProc = mLruProcesses.get(i);
                if (subProc.info.uid == uid) {
                    // 若是app的前一個進程的uid與其相同,檢繼續查前一個進程
                    if (mLruProcesses.get(i - 1).info.uid != uid) {
                        // 兩個進程uid不一致進行位置互換,這裏不太清楚目的
                        ProcessRecord tmp = mLruProcesses.get(i);
                        mLruProcesses.set(i, mLruProcesses.get(i - 1));
                        mLruProcesses.set(i - 1, tmp);
                        i--;
                    }
                } else {
                    // A gap, we can stop here.
                    break;
                }
            }
        } else {
            // 若是包含 Activity 直接添加到集合的尾部
            mLruProcesses.add(app);
        }
        nextIndex = mLruProcessServiceStart;
    } else if (hasService) {
        mLruProcesses.add(mLruProcessActivityStart, app);
        nextIndex = mLruProcessServiceStart;
        mLruProcessActivityStart++;
    } else  {
        // 沒有 Service 的狀況
        int index = mLruProcessServiceStart;
        ......
        mLruProcesses.add(index, app);
        nextIndex = index-1;
        mLruProcessActivityStart++;
        mLruProcessServiceStart++;
    }
    // 將和本進程 Service 關聯的客戶進程的位置調整到本進程以後
    for (int j=app.connections.size()-1; j>=0; j--) {
        ConnectionRecord cr = app.connections.valueAt(j);
        if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
                && cr.binding.service.app != null
                && cr.binding.service.app.lruSeq != mLruSeq
                && !cr.binding.service.app.persistent) {
            nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
                    "service connection", cr, app);
        }
    }
    // 將和本進程 ContentProvider 關聯的客戶進程的位置調整到本進程以後
    for (int j=app.conProviders.size()-1; j>=0; j--) {
        ContentProviderRecord cpr = app.conProviders.get(j).provider;
        if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {
            nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
                    "provider reference", cpr, app);
        }
    }
}
複製代碼

updateLruProcessLocked()方法中調整進程很重要的一個依據是進程中有沒有活動的Activity
Activity用來顯示UI,關係着用戶體驗,所以Android儘可能不關閉運行Activity組件的進程。除了進程自己存在Activity對象外,若是和進程中運行的Service相關聯的客戶進程中有Activity,也算本進程擁有Activity

  • 這樣作的目的是爲了未來殺死進程釋放內存作準備。
  • 若是一個進程的關聯進程有Activity對象存在,那麼它的重要性也和真正擁有Activity對象的進程至關。
  • 若是殺死它,將可能致使另外一個進程出現異常

若是一個進程擁有Activity,一般會把它放入隊列的最高端的位置(也就是集合索引值大的方向)
不然,只會把它放到全部沒有Activity的進程的前面,也就是mLruProcessActivityStart所表示的位置。

調整完某個進程的位置以後,還須要調整和該進程相關聯進程的位置
進程的關聯進程有兩種類型:

  • 一種是綁定了本進程Service的進程
  • 一種是鏈接了本進程的ContentProvider的進程

若是關聯進程自己有Activity是不會調整的,須要調整的是那些沒有Activity的進程,在updateLruProcessInternalLocked()方法中會進行這種調整,咱們簡單看下:

private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index, String what, Object obj, ProcessRecord srcApp) {
    app.lastActivityTime = now;
    if (app.activities.size() > 0 || app.recentTasks.size() > 0) {
        // 若是待調整進程包含 Activity ,不作調整,直接返回
        return index;
    }
    int lrui = mLruProcesses.lastIndexOf(app);
    if (lrui < 0) {
        // 若是進程不在 mLruProcesses 集合中,直接返回
        return index;
    }
    if (lrui >= index) {
        // 若是進程當前位置高於要調整的位置,不做調整,直接返回
        return index;
    }
    if (lrui >= mLruProcessActivityStart) {
        // 若是進程當前位置比 Activity 進程的其實位置還要高,不作調整,直接返回
        return index;
    }
    // 把進程調整到 index-1 的位置
    mLruProcesses.remove(lrui);
    if (index > 0) {
        index--;
    }
    mLruProcesses.add(index, app);
    return index;
}
複製代碼

註釋比較詳細,很少解釋了哈。

ProcessList

前面介紹了進程列表的調整邏輯,在學習oom_adj調整前咱們先看下ProcessList類的內容

ProcessList類中定義了大量AMS中用到的常量,部分定義以下:

public final class ProcessList {
    // 定義進程發生 crash 的最小時間間隔,若是進程在小於這個時間內發生 crash,會被認爲是異常進程
    static final int MIN_CRASH_INTERVAL = 60*1000;
    ......
    // 處於某種不可知狀態的進程的 oom_adj 值
    static final int UNKNOWN_ADJ = 1001;
    // cached 進程的 oom_adj 的最大值和最小值定義
    static final int CACHED_APP_MAX_ADJ = 906;
    static final int CACHED_APP_MIN_ADJ = 900;
    // 位於 B 列表的服務進程的 oom_adj 值。位於 B 列表的都是一些舊的、過期的服務進程
    static final int SERVICE_B_ADJ = 800;
    // 當前 Activity 的前一個 Activity 所處進程的 oom_adj 值
    static final int PREVIOUS_APP_ADJ = 700;
    // Home 進程的 oom_adj 值
    static final int HOME_APP_ADJ = 600;
    // 只包含組件 Service 的進程的 oom_adj 值
    static final int SERVICE_ADJ = 500;
    // heavy-weight 進程的 oom_adj 值
    static final int HEAVY_WEIGHT_APP_ADJ = 400;
    // 正在執行 backup 任務進程的 oom_adj 值
    static final int BACKUP_APP_ADJ = 300;
    // 不在前臺可是包含有用戶可感知組件的進程的 oom_adj 值(例如播放音樂的後臺進程)
    static final int PERCEPTIBLE_APP_ADJ = 200;
    // 僅包含 Activity 的可見進程的 oom_adj 值
    static final int VISIBLE_APP_ADJ = 100;
    ......
    // 定義用於內存回收的 oom_adj 閾值
    private final int[] mOomAdj = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
    };
    // 定義用於低配置(HVGA或更低,或內存小於512MB)設備內存回收的內存閾值,單位:KB
    private final int[] mOomMinFreeLow = new int[] {
            12288, 18432, 24576,
            36864, 43008, 49152
    };
    // 用於定義高配置(高分辨率或內存1GB左右)設備內存回收的內存閾值,單位:KB
    private final int[] mOomMinFreeHigh = new int[] {
            73728, 92160, 110592,
            129024, 147456, 184320
    };
    ......
}
複製代碼

ProcessList中定義的常量有不少和進程類型相關的,像cached進程service進程等。關於Android進程的分類官方將其分爲了4類,簡要以下:

  • foreground process:前臺進程,是用戶目前執行操做所需的進程。在不一樣的狀況下,進程可能會由於其所包含的各類應用組件而被視爲前臺進程
  • visible process:可見進程,正在進行用戶當前知曉的任務,所以終止該進程會對用戶體驗形成明顯的負面影響
  • service process:服務進程,包含一個已使用startService()方法啓動的Service
  • cached process:緩存進程,是目前不須要的進程,所以,若是其餘地方須要內存,系統能夠根據須要自由地終止該進程

進程具體的類型描述及終止規則就不詳細介紹了,具體你們能夠參考官網:進程和應用生命週期,很詳細喲

ProcessList中一樣也定義了一個和oom_adj相關的方法,用來將oom_adj的數值發送給lmkd,以下:

public static final void setOomAdj(int pid, int uid, int amt) {
        if (pid <= 0) {
            return;
        }
        if (amt == UNKNOWN_ADJ)
            return;
        long start = SystemClock.elapsedRealtime();
        ByteBuffer buf = ByteBuffer.allocate(4 * 4);
        buf.putInt(LMK_PROCPRIO);
        buf.putInt(pid);
        buf.putInt(uid);
        buf.putInt(amt);
        writeLmkd(buf);
    }
複製代碼

調整進程的oom_adj

Android基於各個應用進程四大組件的狀態對應用進程進行重要性評估,也就是計算更新oom_adj值。並在系統內存緊張時根據重要性由低到高來選擇殺死應用進程,以達到釋放內存的目的

AMS中調整進程oom_adj值的方法是updateOomAdjLocked()方法,簡要代碼以下:

final void updateOomAdjLocked() {
    // 獲取位於前臺的 Activity 和它所在的進程
    final ActivityRecord TOP_ACT = resumedAppLocked();
    final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
    final long now = SystemClock.uptimeMillis();
    final long nowElapsed = SystemClock.elapsedRealtime();
    final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
    final int N = mLruProcesses.size();
    ......
    // 計算 slot 數值。這裏就用到了 ProcessList 類中的一些常量
    // 根據常量數值,計算結果爲:(906-900+1)/2=3
    int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
            - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
    // 計算 empty進程 的數量
    int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
    if (numEmptyProcs > cachedProcessLimit) {
        // 若是空進程的數量超過了 cache進程 的限制值,更新爲限制值
        numEmptyProcs = cachedProcessLimit;
    }
    // 計算一個 slot 能夠存放的empty進程數
    int emptyFactor = numEmptyProcs/numSlots;
    if (emptyFactor < 1) emptyFactor = 1;
    // 計算一個 slot 能夠存放的cache進程數
    int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
    if (cachedFactor < 1) cachedFactor = 1;
    ......
    // 初始化 adj 數值
    int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
    int nextCachedAdj = curCachedAdj+1;
    int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
    int nextEmptyAdj = curEmptyAdj+2;
    ......
    // 從 mLruProcesses 集合的後面向前處理
    for (int i=N-1; i>=0; i--) {
        ProcessRecord app = mLruProcesses.get(i);
        if (!app.killedByAm && app.thread != null) {
            app.procStateChanged = false;
            // 計算進程的 oom_adj 值
            computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
            ......
            if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
                // 計算出的 oom_adj 值大於 ProcessList.UNKNOWN_ADJ(系統定義的最大值)的狀況
                switch (app.curProcState) {
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                    case ActivityManager.PROCESS_STATE_CACHED_RECENT:
                        // 上面三種進程狀態按照cached進程的參數進行調整
                        app.curRawAdj = curCachedAdj;
                        // 修正 adj 數值
                        app.curAdj = app.modifyRawOomAdj(curCachedAdj);
                        if (curCachedAdj != nextCachedAdj) {
                            stepCached++;
                            if (stepCached >= cachedFactor) { // 一個 slot 中放不下了
                                stepCached = 0;
                                curCachedAdj = nextCachedAdj;
                                nextCachedAdj += 2; // 使用一個新的 slot,即將 adj 值增長 2
                                if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                                    nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
                                }
                            }
                        }
                        break;
                    default:
                        // 其餘進程狀態按照empty進程的參數進行設置
                        app.curRawAdj = curEmptyAdj;
                        app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
                        if (curEmptyAdj != nextEmptyAdj) {
                            stepEmpty++;
                            if (stepEmpty >= emptyFactor) {
                                stepEmpty = 0;
                                curEmptyAdj = nextEmptyAdj;
                                nextEmptyAdj += 2;
                                if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                                    nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
                                }
                            }
                        }
                        break;
                }
            }
        }
    }
    ......
    for (int i=N-1; i>=0; i--) {
        ProcessRecord app = mLruProcesses.get(i);
        if (!app.killedByAm && app.thread != null) {
            // 更新進程的 oom_adj 值
            applyOomAdjLocked(app, true, now, nowElapsed);
            ......
        }
    }
    ......
}
複製代碼

updateOomAdjLocked()方法中

  • 先計算出了slot和每一個slot須要容納的進程數量,包括:cached進程empty進程
    • 這樣作的目的是爲了將系統中的cached進程empty進程分紅不一樣的級別
    • 每一個級別擁有相同的oom_adj
    • 級別和級別間隔的oom_adj值爲2
  • 而後經過調用computeOomAdjLocked()方法來計算進程的oom_adj的值
    • oom_adj值的計算過程這裏也就先簡單略過啦,感興趣的同窗能夠前去學習一下
  • 若是計算後該進程的curAdj仍然大於系統定義的最大oom_adj值(ProcessList.UNKNOWN_ADJ),代表該進程屬於cached進程或者empty進程
    • 根據進程狀態變量curProcState來區分進程類型
    • 確認進程類型後,會按照從低到高的原則把進程放到某個slot級別中
    • 若是該級別的進程數滿了,就進入下一個級別(oom_adj數值+2)

咱們須要注意的是,計算oom_adj值的時候是從mLruProcesses列表的尾部開始計算的
這就意味着排在後面(數組索引值大的)的進程若是變成了cahced進程empty進程,將會比它前面的同類型進程有更小的oom_adj
oom_adj值越大越可能被關閉,這也就是爲何要常常調整進程在mLruProcesses列表的位置

而對於applyOomAdjLocked()方法,最核心的地方在於執行了ProcessList.setOomAdj()方法,跟蹤方法調用會發現

  • 最終是往名爲lmkdSocket發送數據,數據內容爲piduid及對應的adj
  • lmkdlmkd進程建立,因此後面的事情就由lmkd來處理

關於lmkd咱們就不深刻了,你們能夠前去官網瞭解:低內存終止守護程序

官方簡介:Android 低內存終止守護程序 (lmkd) 進程可監控運行中的 Android 系統的內存狀態,並經過終止最沒必要要的進程來應對內存壓力大的問題,使系統以可接受的性能水平運行

相關文章
相關標籤/搜索