Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Gems — Android的LowMemoryKiller殺進程策略

Android Gems — Android的LowMemoryKiller殺進程策略

編輯:關於Android編程

Anroid的殺進程策略是基於kernel裡的LowMemoryKiller模塊,LMK的實現在這裡不展開分析,大致的原理就是LMK注冊了內核的shrinker(lowmem_shrinker),內核線程kswapd,在linux回收內存分頁的時候,通過shrinker回調回來給LMK。LMK根據每個進程的oom_adj值,將大於某個阈值的進程都發送SIGKILL信號殺掉。oom_adj的阈值因內存情況不同而不同,具體的對應關系可以查看/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree這兩個文件。oom_adj的值從-17到16,值越小,代表越重要,越晚被殺,比如一個應用如果在前台的時候,oom_adj的值就會減到0。也就是說設為負值的那些應用,會比前台應用還晚被殺。於是,系統殺進程的策略就可以通過調整每個進程的oom_adj的值來實現。

oom_adj的值有如下類:

// 不可見的Activity  
static final int CACHED_APP_MAX_ADJ = 15;  
static final int CACHED_APP_MIN_ADJ = 9;  
  
/ 比較老的Service  
static final int SERVICE_B_ADJ = 8;  
  
// 上一個應用,這樣在做任務切換,或者返回的時候,能夠快速載入  
static final int PREVIOUS_APP_ADJ = 7;  
  
/ 桌面 App  
static final int HOME_APP_ADJ = 6;  
  
/ Service  
static final int SERVICE_ADJ = 5;  
  
// 重量級應用,早期版本可以在manifest裡加cantSaveState來聲明,新版已經注釋了,目前沒看到哪裡可以設置  
static final int HEAVY_WEIGHT_APP_ADJ = 4;  
  
// 備份代理應用,manifest裡Application標簽裡可以聲明backAgent  
static final int BACKUP_APP_ADJ = 3;  
  
// 可感知的App,比如有Pause狀態的Activity,Stopping狀態的Activity,被一個可見的進程BindService的進程等  
static final int PERCEPTIBLE_APP_ADJ = 2;  
  
// 前台可見的Activity,  
static final int VISIBLE_APP_ADJ = 1;  
  
/ 前台App,包括Top App,Instrumentation Test App,正在接收broadcast的App,正在執行的Service等  
static final int FOREGROUND_APP_ADJ = 0;  
  
/  被Persist App BindService的進程  
static final int PERSISTENT_SERVICE_ADJ = -11;  
  
/  聲明了persist的進程  
static final int PERSISTENT_PROC_ADJ = -12;  
  
// 系統進程,比如system server  
static final int SYSTEM_ADJ = -16;  
  
// 不被系統管的Native進程,比如/system/bin下運行的那些服務(surfaceflinger etc)  
static final int NATIVE_ADJ = -17;  

oom_adj的值受很多因素影響:應用是否有activity,activity是否可見,是否有service,service是否被bind的其他進程的oom_adj等等。在Framework裡oom_adj的調整主要由ActivityManagerService這個類負責,任何可能會影響到進程oom_adj的值的情況,就會調用updateOomAdjLocked來更新各進程的oom_adj值,比如:

1,Activity切換

2,Service start/stop/bind

3,Broadcast分發處理

updateOomAdjLocked會遍歷當前進程列表,對每個進程ProcessRecord都調用computeOomAdjLocked來重新計算oom_adj,最後applyOomAdjLocked來使oom_adj生效。

我們看看updateOomAdjLocked的實現:

final void updateOomAdjLocked() {  
        final ActivityRecord TOP_ACT = resumedAppLocked();  
        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;  
        final long now = SystemClock.uptimeMillis();  
        final long oldTime = now - ProcessList.MAX_EMPTY_TIME;  
        final int N = mLruProcesses.size();  
  
        ......  
        ......  
          
        for (int i=N-1; i>=0; i--) {  
            ProcessRecord app = mLruProcesses.get(i);  
            // 找到最早的一次service活動時間  
            if (mEnableBServicePropagation && app.serviceb  
                    && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {  
                numBServices++;  
                for (int s = app.services.size() - 1; s >= 0; s--) {  
                    ServiceRecord sr = app.services.valueAt(s);  
                    if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName  
                            + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "  
                            + sr.lastActivity + " packageName = " + sr.packageName  
                            + " processName = " + sr.processName);  
                    if (SystemClock.uptimeMillis() - sr.lastActivity  
                            < mMinBServiceAgingTime) {  
                        if (DEBUG_OOM_ADJ) {  
                            Slog.d(TAG,"Not aged enough!!!");  
                        }  
                        continue;  
                    }  
                    if (serviceLastActivity == 0) {  
                        serviceLastActivity = sr.lastActivity;  
                        selectedAppRecord = app;  
                    } else if (sr.lastActivity < serviceLastActivity) {  
                        serviceLastActivity = sr.lastActivity;  
                        selectedAppRecord = app;  
                    }  
                }  
            }  
            if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,  
                    "Identified app.processName = " + selectedAppRecord.processName  
                    + " app.pid = " + selectedAppRecord.pid);  
            if (!app.killedByAm && app.thread != null) {  
                app.procStateChanged = false;  
               // 重新計算進程app的oom_adj  
                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);  
  
                // If we haven't yet assigned the final cached adj  
                // to the process, do that now.  
                // 如果沒找到對應的oom_adj,那麼根據app的進程狀態,如果有activity存在,那麼oom_adj設為curCachedAdj,  
                // 否則就是empty進程,講oom_adj設為curEmptyAdj  
                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {  
                    switch (app.curProcState) {  
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:  
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:  
                            // This process is a cached process holding activities...  
                            // assign it the next cached value for that type, and then  
                            // step that cached level.  
                            app.curRawAdj = curCachedAdj;  
                            app.curAdj = app.modifyRawOomAdj(curCachedAdj);  
                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i  
                                    + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj  
                                    + ")");  
                            if (curCachedAdj != nextCachedAdj) {  
                                stepCached++;  
                                if (stepCached >= cachedFactor) {  
                                    stepCached = 0;  
                                    curCachedAdj = nextCachedAdj;  
                                    nextCachedAdj += 2;  
                                    if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {  
                                        nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;  
                                    }  
                                }  
                            }  
                            break;  
                        default:  
                            // For everything else, assign next empty cached process  
                            // level and bump that up.  Note that this means that  
                            // long-running services that have dropped down to the  
                            // cached level will be treated as empty (since their process  
                            // state is still as a service), which is what we want.  
                            app.curRawAdj = curEmptyAdj;  
                            app.curAdj = app.modifyRawOomAdj(curEmptyAdj);  
                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i  
                                    + " adj: " + app.curAdj + " (curEmptyAdj=" + 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;  
                    }  
                }  
                // 調用applyOomAdjLocked使新的oom_adj生效  
                applyOomAdjLocked(app, true, now);  
                 
                // Count the number of process types.  
                switch (app.curProcState) {  
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:  
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:  
                        mNumCachedHiddenProcs++;  
                        numCached++;  
                       // 計算Cached進程個數,超過cachedProcessLimit即直接kill  
                        if (numCached > cachedProcessLimit) {  
                            app.kill("cached #" + numCached, true);  
                        }  
                        break;  
                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:  
                        //  計算empty進程個數,超過上限即kill  
                        if (numEmpty > ProcessList.TRIM_EMPTY_APPS  
                                && app.lastActivityTime < oldTime) {  
                            app.kill("empty for "  
                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)  
                                    / 1000) + "s", true);  
                        } else {  
                            numEmpty++;  
                            if (numEmpty > emptyProcessLimit) {  
                                app.kill("empty #" + numEmpty, true);  
                            }  
                        }  
                        break;  
                    default:  
                        mNumNonCachedProcs++;  
                        break;  
                }  
                ......  
                ......  
            }  
        }  
       // 在低內存的情況下,把過老的service的oom_adj的值調大到CACHED_APP_MAX_ADJ,以便可以被優先殺死  
        if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel)  
                && (selectedAppRecord != null)) {  
            ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,  
                    ProcessList.CACHED_APP_MAX_ADJ);  
            selectedAppRecord.setAdj = selectedAppRecord.curAdj;  
            if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName  
                        + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");  
        }  
         
        // finish所有後台的activity,這個有系統開關可以控制,Settings.Global.ALWAYS_FINISH_ACTIVITIES,也就是開發者選項裡的“不保留活動”,  
       // 也可以通過ActivityManagerNative的setAlwaysFinish來設置,這需要聲明權限android.Manifest.permission.SET_ALWAYS_FINISH  
        if (mAlwaysFinishActivities) {  
            // Need to do this on its own message because the stack may not  
            // be in a consistent state at this point.  
            mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");  
        }  
        ......  
        ......  
  
    }  

系統將進程分三類:

一, empty process,沒有service,也沒有activity,空進程沒有執行邏輯,可以優先被殺,empty process有數量限制,超過限制之後就馬上被kill。

二, cached process,只有不可見的activity,這類進程優先級比empty高些,但也同樣可以被殺,用戶不會有太明顯的感知,表現就是返回到他的activity之後,

進程被重新被創建,Activity也會重新onCreate。

empty和cached進程的上限是ProcessList.MAX_CACHED_APPS=32個,而empty的上限是ProcessList.computeEmptyProcessLimit(ProcessList.MAX_CACHED_APPS),默認是16。

三,其他是第三類,包括有前台可見的Activity的進程,有前台Service的進程等。

三類進程數之和就等於LruProcesses隊列的大小。

private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,  
            boolean doingAll, long now) {  
        if (mAdjSeq == app.adjSeq) {  
            // This adjustment has already been computed.  
            return app.curRawAdj;  
        }  
  
        if (app.thread == null) {  
            app.adjSeq = mAdjSeq;  
            app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;  
            app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;  
            return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);  
        }  
  
        app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;  
        app.adjSource = null;  
        app.adjTarget = null;  
        app.empty = false;  
        app.cached = false;  
  
        final int activitiesSize = app.activities.size();  
  
        // app最大的adj和前台app的adj一樣,說明是系統進程,adj就設為maxAdj  
        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {  
            // The max adjustment doesn't allow this app to be anything  
            // below foreground, so it is not worth doing work for it.  
            app.adjType = "fixed";  
            app.adjSeq = mAdjSeq;  
            app.curRawAdj = app.maxAdj;  
            app.foregroundActivities = false;  
            app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;  
            app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;  
            // System processes can do UI, and when they do we want to have  
            // them trim their memory after the user leaves the UI.  To  
            // facilitate this, here we need to determine whether or not it  
            // is currently showing UI.  
            app.systemNoUi = true;  
            if (app == TOP_APP) {  
                app.systemNoUi = false;  
            } else if (activitiesSize > 0) {  
                for (int j = 0; j < activitiesSize; j++) {  
                    final ActivityRecord r = app.activities.get(j);  
                    if (r.visible) {  
                        app.systemNoUi = false;  
                    }  
                }  
            }  
            if (!app.systemNoUi) {  
                app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;  
            }  
            return (app.curAdj=app.maxAdj);  
        }  
  
        app.systemNoUi = false;  
  
        final int PROCESS_STATE_TOP = mTopProcessState;  
  
        // Determine the importance of the process, starting with most  
        // important to least, and assign an appropriate OOM adjustment.  
        int adj;  
        int schedGroup;  
        int procState;  
        boolean foregroundActivities = false;  
        BroadcastQueue queue;  
        if (app == TOP_APP) {   // App正在系統頂層,adj設為FOREGROUND_APP_ADJ  
            // The last app on the list is the foreground app.  
            adj = ProcessList.FOREGROUND_APP_ADJ;  
            schedGroup = Process.THREAD_GROUP_DEFAULT;  
            app.adjType = "top-activity";  
            foregroundActivities = true;  
            procState = PROCESS_STATE_TOP;  
            if(app == mHomeProcess) {  
                mHomeKilled = false;  
                mHomeProcessName = mHomeProcess.processName;  
            }  
        } else if (app.instrumentationClass != null) {  // App正執行Instrumentation,adj設為FOREGROUND_APP_ADJ  
            // Don't want to kill running instrumentation.  
            adj = ProcessList.FOREGROUND_APP_ADJ;  
            schedGroup = Process.THREAD_GROUP_DEFAULT;  
            app.adjType = "instrumentation";  
            procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;  
        } else if ((queue = isReceivingBroadcast(app)) != null) { // App正在接收broadcast,adj設為FOREGROUND_APP_ADJ  
            // An app that is currently receiving a broadcast also  
            // counts as being in the foreground for OOM killer purposes.  
            // It's placed in a sched group based on the nature of the  
            // broadcast as reflected by which queue it's active in.  
            adj = ProcessList.FOREGROUND_APP_ADJ;  
            schedGroup = (queue == mFgBroadcastQueue)  
                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;  
            app.adjType = "broadcast";  
            procState = ActivityManager.PROCESS_STATE_RECEIVER;  
        } else if (app.executingServices.size() > 0) {   // App的Service正在執行,adj設為FOREGROUND_APP_ADJ  
            // An app that is currently executing a service callback also  
            // counts as being in the foreground.  
            adj = ProcessList.FOREGROUND_APP_ADJ;  
            schedGroup = app.execServicesFg ?  
                    Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;  
            app.adjType = "exec-service";  
            procState = ActivityManager.PROCESS_STATE_SERVICE;  
            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);  
        } else {  
            // As far as we know the process is empty.  We may change our mind later.  
            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;  
            // At this point we don't actually know the adjustment.  Use the cached adj  
            // value that the caller wants us to.  
            adj = cachedAdj;  
            procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;  
           //  初始狀態cached和empty都設為true,根據進程的執行狀態再改  
            app.cached = true;  
            app.empty = true;  
            app.adjType = "cch-empty";  
              
            // 桌面App,既不是empty也不是cached,adj設為PERSISTENT_PROC_ADJ  
            if (mHomeKilled && app.processName.equals(mHomeProcessName)) {  
                adj = ProcessList.PERSISTENT_PROC_ADJ;  
                schedGroup = Process.THREAD_GROUP_DEFAULT;  
                app.cached = false;  
                app.empty = false;  
                app.adjType = "top-activity";  
            }  
        }  
       
        // Examine all activities if not already foreground.  
        if (!foregroundActivities && activitiesSize > 0) {  
            // 遍歷非前台的activity  
            for (int j = 0; j < activitiesSize; j++) {  
                final ActivityRecord r = app.activities.get(j);  
                if (r.app != app) {  
                    Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "  
                            + app + "?!? Using " + r.app + " instead.");  
                    continue;  
                }  
                if (r.visible) {                 
                     // 可見的Activity,如果Activity不在最頂層,而且被頂層完全擋住的時候visible狀態會被設為false,  
                    // 如果是可見的,那麼adj設為VISIBLE_APP_ADJ,cached和empty也設為false  
                    // App has a visible activity; only upgrade adjustment.  
                    if (adj > ProcessList.VISIBLE_APP_ADJ) {  
                        adj = ProcessList.VISIBLE_APP_ADJ;  
                        app.adjType = "visible";  
                    }  
                    if (procState > PROCESS_STATE_TOP) {  
                        procState = PROCESS_STATE_TOP;  
                    }  
                    schedGroup = Process.THREAD_GROUP_DEFAULT;  
                    app.cached = false;  
                    app.empty = false;  
                    foregroundActivities = true;  
                    break;  
                } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {  
                    // Pause狀態的Activity,adj設為PERCEPTIBLE_APP_ADJ,cached和empty也設為false  
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;  
                        app.adjType = "pausing";  
                    }  
                    if (procState > PROCESS_STATE_TOP) {  
                        procState = PROCESS_STATE_TOP;  
                    }  
                    schedGroup = Process.THREAD_GROUP_DEFAULT;  
                    app.cached = false;  
                    app.empty = false;  
                    foregroundActivities = true;  
                } else if (r.state == ActivityState.STOPPING) {  
                    // Stopping狀態的app,adj設為PERCEPTIBLE_APP_ADJ,cached和empty也設為false                     
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;  
                        app.adjType = "stopping";  
                    }  
                    // For the process state, we will at this point consider the  
                    // process to be cached.  It will be cached either as an activity  
                    // or empty depending on whether the activity is finishing.  We do  
                    // this so that we can treat the process as cached for purposes of  
                    // memory trimming (determing current memory level, trim command to  
                    // send to process) since there can be an arbitrary number of stopping  
                    // processes and they should soon all go into the cached state.  
                    if (!r.finishing) {  
                        if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {  
                            procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;  
                        }  
                    }  
                    app.cached = false;  
                    app.empty = false;  
                    foregroundActivities = true;  
                } else {     
                    // 進這個分支說明進程有不可見的Activity,adj會設為CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ之間的數  
                    if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {  
                        procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;  
                        app.adjType = "cch-act";  
                    }  
                }  
            }  
        }  
  
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
              // 如果有前台的Service,adj設為PERCEPTIBLE_APP_ADJ,可通過ActivityManagerNative將Service設為foreground  
            if (app.foregroundServices) {  
               // The user is aware of this app, so make it visible.  
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;  
                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;  
                app.cached = false;  
                app.adjType = "fg-service";  
                schedGroup = Process.THREAD_GROUP_DEFAULT;  
            } else if (app.forcingToForeground != null) {  
                // The user is aware of this app, so make it visible.  
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;  
                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;  
                app.cached = false;  
                app.adjType = "force-fg";  
                app.adjSource = app.forcingToForeground;  
                schedGroup = Process.THREAD_GROUP_DEFAULT;  
            }  
        }  
  
        if (app == mHeavyWeightProcess) {  
            if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {  
                // We don't want to kill the current heavy-weight process.  
                adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;  
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;  
                app.cached = false;  
                app.adjType = "heavy";  
            }  
            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {  
                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;  
            }  
        }  
  
        if (app == mHomeProcess) {  
             // 如果桌面App,adj設為HOME_APP_ADJ  
            if (adj > ProcessList.HOME_APP_ADJ) {  
                // This process is hosting what we currently consider to be the  
                // home app, so we don't want to let it go into the background.  
                adj = ProcessList.HOME_APP_ADJ;  
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;  
                app.cached = false;  
                app.adjType = "home";  
            }  
            if (procState > ActivityManager.PROCESS_STATE_HOME) {  
                procState = ActivityManager.PROCESS_STATE_HOME;  
            }  
        }  
  
        // 如果是剛剛切換出去的App,adj設為PREVIOUS_APP_ADJ  
        if (app == mPreviousProcess && app.activities.size() > 0) {  
            if (adj > ProcessList.PREVIOUS_APP_ADJ) {  
                // This was the previous process that showed UI to the user.  
                // We want to try to keep it around more aggressively, to give  
                // a good experience around switching between two apps.  
                adj = ProcessList.PREVIOUS_APP_ADJ;  
                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;  
                app.cached = false;  
                app.adjType = "previous";  
            }  
            if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {  
                procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;  
            }  
        }  
  
        if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj  
                + " reason=" + app.adjType);  
  
        // By default, we use the computed adjustment.  It may be changed if  
        // there are applications dependent on our services or providers, but  
        // this gives us a baseline and makes sure we don't get into an  
        // infinite recursion.  
        app.adjSeq = mAdjSeq;  
        app.curRawAdj = adj;  
        app.hasStartedServices = false;  
  
        // Backup App,adj設為BACKUP_APP_ADJ  
        if (mBackupTarget != null && app == mBackupTarget.app) {  
            // If possible we want to avoid killing apps while they're being backed up  
            if (adj > ProcessList.BACKUP_APP_ADJ) {  
                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);  
                adj = ProcessList.BACKUP_APP_ADJ;  
                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {  
                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;  
                }  
                app.adjType = "backup";  
                app.cached = false;  
            }  
            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {  
                procState = ActivityManager.PROCESS_STATE_BACKUP;  
            }  
        }  
  
        boolean mayBeTop = false;  
  
           // 如果App有Service,adj設為SERVICE_ADJ  
        for (int is = app.services.size()-1;  
                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ  
                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE  
                        || procState > ActivityManager.PROCESS_STATE_TOP);  
                is--) {  
            ServiceRecord s = app.services.valueAt(is);  
            if (s.startRequested) {  
                app.hasStartedServices = true;  
                if (procState > ActivityManager.PROCESS_STATE_SERVICE) {  
                    procState = ActivityManager.PROCESS_STATE_SERVICE;  
                }  
                if (app.hasShownUi && app != mHomeProcess) {  
                    // If this process has shown some UI, let it immediately  
                    // go to the LRU list because it may be pretty heavy with  
                    // UI stuff.  We'll tag it with a label just to help  
                    // debug and understand what is going on.  
                    if (adj > ProcessList.SERVICE_ADJ) {  
                        app.adjType = "cch-started-ui-services";  
                    }  
                } else {  
                    if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {  
                        // This service has seen some activity within  
                        // recent memory, so we will keep its process ahead  
                        // of the background processes.  
                        if (adj > ProcessList.SERVICE_ADJ) {  
                            adj = ProcessList.SERVICE_ADJ;  
                            app.adjType = "started-services";  
                            app.cached = false;  
                        }  
                    }  
                    // If we have let the service slide into the background  
                    // state, still have some text describing what it is doing  
                    // even though the service no longer has an impact.  
                    if (adj > ProcessList.SERVICE_ADJ) {  
                        app.adjType = "cch-started-services";  
                    }  
                }  
            }  
            //  如果App有Service,那麼需要檢查是否有外部的App在Bind它,如果一個高優先級的App,bind了你的Service,那麼你的優先級也會同樣有提升  
            for (int conni = s.connections.size()-1;  
                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ  
                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE  
                            || procState > ActivityManager.PROCESS_STATE_TOP);  
                    conni--) {  
                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);  
                for (int i = 0;  
                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ  
                                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE  
                                || procState > ActivityManager.PROCESS_STATE_TOP);  
                        i++) {  
                    // XXX should compute this based on the max of  
                    // all connected clients.  
                    ConnectionRecord cr = clist.get(i);  
                    if (cr.binding.client == app) {  
                        // Binding to ourself is not interesting.  
                        continue;  
                    }  
                    // 只有bind的時候不加BIND_WAIVE_PRIORITY這個flag才會影響對方的adj  
                    if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {  
                        ProcessRecord client = cr.binding.client;  
                        int clientAdj = computeOomAdjLocked(client, cachedAdj,  
                                TOP_APP, doingAll, now);  
                        int clientProcState = client.curProcState;  
                        if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {  
                            // If the other app is cached for any reason, for purposes here  
                            // we are going to consider it empty.  The specific cached state  
                            // doesn't propagate except under certain conditions.  
                            clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;  
                        }  
                        String adjType = null;  
                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {  
                            // Not doing bind OOM management, so treat  
                            // this guy more like a started service.  
                            if (app.hasShownUi && app != mHomeProcess) {  
                                // If this process has shown some UI, let it immediately  
                                // go to the LRU list because it may be pretty heavy with  
                                // UI stuff.  We'll tag it with a label just to help  
                                // debug and understand what is going on.  
                                if (adj > clientAdj) {  
                                    adjType = "cch-bound-ui-services";  
                                }  
                                app.cached = false;  
                                clientAdj = adj;  
                                clientProcState = procState;  
                            } else {  
                                if (now >= (s.lastActivity  
                                        + ActiveServices.MAX_SERVICE_INACTIVITY)) {  
                                    // This service has not seen activity within  
                                    // recent memory, so allow it to drop to the  
                                    // LRU list if there is no other reason to keep  
                                    // it around.  We'll also tag it with a label just  
                                    // to help debug and undertand what is going on.  
                                    if (adj > clientAdj) {  
                                        adjType = "cch-bound-services";  
                                    }  
                                    clientAdj = adj;  
                                }  
                            }  
                        }  
                        if (adj > clientAdj) {  
                            // If this process has recently shown UI, and  
                            // the process that is binding to it is less  
                            // important than being visible, then we don't  
                            // care about the binding as much as we care  
                            // about letting this process get into the LRU  
                            // list to be killed and restarted if needed for  
                            // memory.  
                            if (app.hasShownUi && app != mHomeProcess  
                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
                                adjType = "cch-bound-ui-services";  
                            } else {  
                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT  
                                        |Context.BIND_IMPORTANT)) != 0) {  
                                    // 如果Client Bind的時候加了BIND_ABOVE_CLIENT和BIND_IMPORTANT,那麼講client的adj值給Service,最低不小於PERSISTENT_SERVICE_ADJ  
                                    adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ  
                                            ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;  
                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0  
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ  
                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
                                    // 如果Client Bind的時候加了BIND_NOT_VISIBLE,並且client的adj比PERCEPTIBLE_APP_ADJ小的時候,將PERCEPTIBLE_APP_ADJ給adj  
                                    adj = ProcessList.PERCEPTIBLE_APP_ADJ;  
                                } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {  
                                    // 把Client的adj給adj,因為adj是> clientAdj的,所以Service的adj還是得到了提升  
                                    adj = clientAdj;  
                                } else {  
                                    // 這裡client的adj是要小於等於VISIBLE_APP_ADJ的,所以adj將會提升至VISIBLE_APP_ADJ  
                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {  
                                        adj = ProcessList.VISIBLE_APP_ADJ;  
                                    }  
                                }  
                                if (!client.cached) {  
                                    app.cached = false;  
                                }  
                                adjType = "service";  
                            }  
                        }  
                        ......  
                        ......  
                        ......  
        }  
        // ContentProvider的連接也同樣會影響到app的adj  
        for (int provi = app.pubProviders.size()-1;  
                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ  
                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE  
                        || procState > ActivityManager.PROCESS_STATE_TOP);  
                provi--) {  
            ContentProviderRecord cpr = app.pubProviders.valueAt(provi);  
            for (int i = cpr.connections.size()-1;  
                    i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ  
                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE  
                            || procState > ActivityManager.PROCESS_STATE_TOP);  
                    i--) {  
                ContentProviderConnection conn = cpr.connections.get(i);  
                ProcessRecord client = conn.client;  
                if (client == app) {  
                    // Being our own client is not interesting.  
                    continue;  
                }  
                int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);  
                int clientProcState = client.curProcState;  
                if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {  
                    // If the other app is cached for any reason, for purposes here  
                    // we are going to consider it empty.  
                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;  
                }  
                if (adj > clientAdj) {  
                    if (app.hasShownUi && app != mHomeProcess  
                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {  
                        app.adjType = "cch-ui-provider";  
                    } else {  
                        adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ  
                                ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;  
                        app.adjType = "provider";  
                    }  
                    app.cached &= client.cached;  
                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo  
                            .REASON_PROVIDER_IN_USE;  
                    app.adjSource = client;  
                    app.adjSourceProcState = clientProcState;  
                    app.adjTarget = cpr.name;  
                }  
                ......  
                ......  
            }  
            // If the provider has external (non-framework) process  
            // dependencies, ensure that its adjustment is at least  
            // FOREGROUND_APP_ADJ.  
            if (cpr.hasExternalProcessHandles()) {  
                if (adj > ProcessList.FOREGROUND_APP_ADJ) {  
                    adj = ProcessList.FOREGROUND_APP_ADJ;  
                    schedGroup = Process.THREAD_GROUP_DEFAULT;  
                    app.cached = false;  
                    app.adjType = "provider";  
                    app.adjTarget = cpr.name;  
                }  
                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {  
                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;  
                }  
            }  
        }  
        ......  
        ......  
        app.curAdj = app.modifyRawOomAdj(adj);  
        app.curSchedGroup = schedGroup;  
        app.curProcState = procState;  
        app.foregroundActivities = foregroundActivities;  
        return app.curRawAdj;  
        }  

computeOomAdjLocked計算完oom_adj之後,就調用applyOomAdjLocked使之生效,applyOomAdjLocked比較簡單,調用ProcessList的setOomAdj,通過LocalSocket連接到

lmkd,通過進程間通信寫入。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved