Android 進(jìn)程優(yōu)先級(jí)和 LowMemoryKiller 機(jī)制 - 2

接上篇

二 Framework OOM Adjustment 機(jī)制

Android 系統(tǒng)(以6.0 AOSP 代碼為例),和 LMK 相關(guān)的源碼主要有:

platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
platform/system/core/lmkd/lmkd.c
kernel/common/drivers/staging/Android/lowmemorykiller.c

2.1 OOM Adjustment

ADJ 定義在 ProcessList

ADJ Value Note
UNKNOWN_ADJ 16 一般指將要會(huì)緩存進(jìn)程擂错,無(wú)法獲取確定值
CACHED_APP_MAX_ADJ 15 不可見(jiàn)進(jìn)程的adj最大值
CACHED_APP_MIN_ADJ 9 不可見(jiàn)進(jìn)程的adj最小值
SERVICE_B_AD 8 B List中的Service(較老的味滞、使用可能性更小)
PREVIOUS_APP_ADJ 7 上一個(gè)App的進(jìn)程(往往通過(guò)按返回鍵)
HOME_APP_ADJ 6 Home進(jìn)程
SERVICE_ADJ 5 服務(wù)進(jìn)程(Service process)
HEAVY_WEIGHT_APP_ADJ 4 后臺(tái)的重量級(jí)進(jìn)程,system/rootdir/init.rc文件中設(shè)置
BACKUP_APP_ADJ 3 備份進(jìn)程
PERCEPTIBLE_APP_ADJ 2 可感知進(jìn)程剑鞍,比如后臺(tái)音樂(lè)播放
VISIBLE_APP_ADJ 1 可見(jiàn)進(jìn)程(Visible process)
FOREGROUND_APP_ADJ 0 前臺(tái)進(jìn)程(Foreground process
PERSISTENT_SERVICE_ADJ -11 關(guān)聯(lián)著系統(tǒng)或persistent進(jìn)程
PERSISTENT_PROC_ADJ -12 系統(tǒng)persistent進(jìn)程刹悴,比如telephony
SYSTEM_ADJ -16 系統(tǒng)進(jìn)程
NATIVE_ADJ -17 native進(jìn)程(不被系統(tǒng)管理)
    // OOM adjustments for processes in various states:
    
    // Adjustment used in certain places where we don't know it yet.
    // (Generally this is something that is going to be cached, but we
    // don't know the exact value in the cached range to assign yet.)
    static final int UNKNOWN_ADJ = 16;
    
    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption.
    static final int CACHED_APP_MAX_ADJ = 15;
    static final int CACHED_APP_MIN_ADJ = 9;
    
    // The B list of SERVICE_ADJ -- these are the old and decrepit
    // services that aren't as shiny and interesting as the ones in the A list.
    static final int SERVICE_B_ADJ = 8;
    
    // This is the process of the previous application that the user was in.
    // This process is kept above other things, because it is very common to
    // switch back to the previous app.  This is important both for recent
    // task switch (toggling between the two top recent apps) as well as normal
    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
    // and then pressing back to return to e-mail.
    static final int PREVIOUS_APP_ADJ = 7;
    
    // This is a process holding the home application -- we want to try
    // avoiding killing it, even if it would normally be in the background,
    // because the user interacts with it so much.
    static final int HOME_APP_ADJ = 6;
    
    // This is a process holding an application service -- killing it will not
    // have much of an impact as far as the user is concerned.
    static final int SERVICE_ADJ = 5;
    
    // This is a process with a heavy-weight application.  It is in the
    // background, but we want to try to avoid killing it.  Value set in
    // system/rootdir/init.rc on startup.
    static final int HEAVY_WEIGHT_APP_ADJ = 4;
    
    // This is a process currently hosting a backup operation.  Killing it
    // is not entirely fatal but is generally a bad idea.
    static final int BACKUP_APP_ADJ = 3;
    
    // This is a process only hosting components that are perceptible to the
    // user, and we really want to avoid killing them, but they are not
    // immediately visible. An example is background music playback.
    static final int PERCEPTIBLE_APP_ADJ = 2;
    
    // This is a process only hosting activities that are visible to the
    // user, so we'd prefer they don't disappear.
    static final int VISIBLE_APP_ADJ = 1;
    
    // This is the process running the current foreground app.  We'd really
    // rather not kill it!
    static final int FOREGROUND_APP_ADJ = 0;
    
    // This is a process that the system or a persistent process has bound to,
    // and indicated it is important.
    static final int PERSISTENT_SERVICE_ADJ = -11;
    
    // This is a system persistent process, such as telephony.  Definitely
    // don't want to kill it, but doing so is not completely fatal.
    static final int PERSISTENT_PROC_ADJ = -12;
    
    // The system process runs at the default adjustment.
    static final int SYSTEM_ADJ = -16;
    
    // Special code for native processes that are not being managed by the system (so
    // don't have an oom adj assigned by the system).
    static final int NATIVE_ADJ = -17;

2.2 Process State

在 ActivityManager 中定義了從-1到16共18種進(jìn)程狀態(tài):

PROCESS_STATE 取值 解釋
PROCESS_STATE_CACHED_EMPTY 16 進(jìn)程處于cached狀態(tài),且為空進(jìn)程
PROCESS_STATE_CACHED_ACTIVITY_CLIENT 15 進(jìn)程處于cached狀態(tài)攒暇,且為另一個(gè)cached進(jìn)程(內(nèi)含Activity)的client進(jìn)程
PROCESS_STATE_CACHED_ACTIVITY 14 進(jìn)程處于cached狀態(tài),且內(nèi)含Activity
PROCESS_STATE_LAST_ACTIVITY 13 后臺(tái)進(jìn)程子房,且擁有上一次顯示的Activity
PROCESS_STATE_HOME 12 后臺(tái)進(jìn)程形用,且擁有home Activity
PROCESS_STATE_RECEIVER 11 后臺(tái)進(jìn)程,且正在運(yùn)行receiver
PROCESS_STATE_SERVICE 10 后臺(tái)進(jìn)程证杭,且正在運(yùn)行service
PROCESS_STATE_HEAVY_WEIGHT 9 后臺(tái)進(jìn)程田度,但無(wú)法執(zhí)行restore,因此盡量避免kill該進(jìn)程
PROCESS_STATE_BACKUP 8 后臺(tái)進(jìn)程解愤,正在運(yùn)行backup/restore操作
PROCESS_STATE_IMPORTANT_BACKGROUND 7 對(duì)用戶很重要的進(jìn)程镇饺,用戶不可感知其存在
PROCESS_STATE_IMPORTANT_FOREGROUND 6 對(duì)用戶很重要的進(jìn)程,用戶可感知其存在
PROCESS_STATE_TOP_SLEEPING 5 與PROCESS_STATE_TOP一樣送讲,但此時(shí)設(shè)備正處于休眠狀態(tài)
PROCESS_STATE_FOREGROUND_SERVICE 4 擁有一個(gè)前臺(tái)Service
PROCESS_STATE_BOUND_FOREGROUND_SERVICE 3 擁有一個(gè)前臺(tái)Service奸笤,且由系統(tǒng)綁定
PROCESS_STATE_TOP 2 擁有當(dāng)前用戶可見(jiàn)的top Activity
PROCESS_STATE_PERSISTENT_UI 1 persistent系統(tǒng)進(jìn)程,并正在執(zhí)行UI操作
PROCESS_STATE_PERSISTENT 0 persistent系統(tǒng)進(jìn)程
PROCESS_STATE_NONEXISTENT -1 不存在的進(jìn)程

在 ActivityManager 中的 RunningAppProcessInfo 類中定義了進(jìn)程的優(yōu)先級(jí) IMPORTANCE 值:

        /**
         * Constant for {@link #importance}: This process is running the
         * foreground UI; that is, it is the thing currently at the top of the screen
         * that the user is interacting with.
         */
        public static final int IMPORTANCE_FOREGROUND = 100;
        /**
         * Constant for {@link #importance}: This process is running a foreground
         * service, for example to perform music playback even while the user is
         * not immediately in the app.  This generally indicates that the process
         * is doing something the user actively cares about.
         */
        public static final int IMPORTANCE_FOREGROUND_SERVICE = 125;
        /**
         * Constant for {@link #importance}: This process is running the foreground
         * UI, but the device is asleep so it is not visible to the user.  This means
         * the user is not really aware of the process, because they can not see or
         * interact with it, but it is quite important because it what they expect to
         * return to once unlocking the device.
         */
        public static final int IMPORTANCE_TOP_SLEEPING = 150;
        /**
         * Constant for {@link #importance}: This process is running something
         * that is actively visible to the user, though not in the immediate
         * foreground.  This may be running a window that is behind the current
         * foreground (so paused and with its state saved, not interacting with
         * the user, but visible to them to some degree); it may also be running
         * other services under the system's control that it inconsiders important.
         */
        public static final int IMPORTANCE_VISIBLE = 200;
        /**
         * Constant for {@link #importance}: This process is not something the user
         * is directly aware of, but is otherwise perceptable to them to some degree.
         */
        public static final int IMPORTANCE_PERCEPTIBLE = 130;
        /**
         * Constant for {@link #importance}: This process is running an
         * application that can not save its state, and thus can't be killed
         * while in the background.
         * @hide
         */
        public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
        /**
         * Constant for {@link #importance}: This process is contains services
         * that should remain running.  These are background services apps have
         * started, not something the user is aware of, so they may be killed by
         * the system relatively freely (though it is generally desired that they
         * stay running as long as they want to).
         */
        public static final int IMPORTANCE_SERVICE = 300;
        /**
         * Constant for {@link #importance}: This process process contains
         * background code that is expendable.
         */
        public static final int IMPORTANCE_BACKGROUND = 400;
        /**
         * Constant for {@link #importance}: This process is empty of any
         * actively running code.
         */
        public static final int IMPORTANCE_EMPTY = 500;
        /**
         * Constant for {@link #importance}: This process does not exist.
         */
        public static final int IMPORTANCE_GONE = 1000;
        /** @hide */
        public static int procStateToImportance(int procState) {
            if (procState == PROCESS_STATE_NONEXISTENT) {
                return IMPORTANCE_GONE;
            } else if (procState >= PROCESS_STATE_HOME) {
                return IMPORTANCE_BACKGROUND;
            } else if (procState >= PROCESS_STATE_SERVICE) {
                return IMPORTANCE_SERVICE;
            } else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
                return IMPORTANCE_CANT_SAVE_STATE;
            } else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
                return IMPORTANCE_PERCEPTIBLE;
            } else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
                return IMPORTANCE_VISIBLE;
            } else if (procState >= PROCESS_STATE_TOP_SLEEPING) {
                return IMPORTANCE_TOP_SLEEPING;
            } else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
                return IMPORTANCE_FOREGROUND_SERVICE;
            } else {
                return IMPORTANCE_FOREGROUND;
            }
        }

2.3 Framework ADJ 調(diào)整算法

ActivityManagerService 中三個(gè)核心方法:

  • updateOomAdjLocked:更新adj哼鬓,當(dāng)目標(biāo)進(jìn)程為空监右,或者被殺則返回false;否則返回true;
  • computeOomAdjLocked:計(jì)算adj异希,返回計(jì)算后RawAdj值;
  • applyOomAdjLocked:應(yīng)用adj健盒,當(dāng)需要?dú)⒌裟繕?biāo)進(jìn)程則返回false口注;否則返回true嗜暴。

updateOomAdjLocked 中會(huì)調(diào)用 computeOomAdjLockedapplyOomAdjLocked

ADJ 的更新時(shí)機(jī)

  1. Activity

    • ASS.realStartActivityLocked: 啟動(dòng)Activity
    • AS.resumeTopActivityInnerLocked: 恢復(fù)棧頂Activity
    • AS.finishCurrentActivityLocked: 結(jié)束當(dāng)前Activity
    • AS.destroyActivityLocked: 摧毀當(dāng)前Activity
  2. Service

    • realStartServiceLocked: 啟動(dòng)服務(wù)
    • bindServiceLocked: 綁定服務(wù)(只更新當(dāng)前app)
    • unbindServiceLocked: 解綁服務(wù) (只更新當(dāng)前app)
    • bringDownServiceLocked: 結(jié)束服務(wù) (只更新當(dāng)前app)
    • sendServiceArgsLocked: 在bringup或則cleanup服務(wù)過(guò)程調(diào)用 (只更新當(dāng)前app)
  3. Broadcast

    • BQ.processNextBroadcast: 處理下一個(gè)廣播
    • BQ.processCurBroadcastLocked: 處理當(dāng)前廣播
    • BQ.deliverToRegisteredReceiverLocked: 分發(fā)已注冊(cè)的廣播 (只更新當(dāng)前app)
  4. ContentProvider

    • AMS.removeContentProvider: 移除provider
    • AMS.publishContentProviders: 發(fā)布provider (只更新當(dāng)前app)
    • AMS.getContentProviderImpl: 獲取provider (只更新當(dāng)前app)
  5. Process

    • AMS.setSystemProcess: 創(chuàng)建并設(shè)置系統(tǒng)進(jìn)程
    • AMS.addAppLocked: 創(chuàng)建persistent進(jìn)程
    • AMS.attachApplicationLocked: 進(jìn)程創(chuàng)建后attach到system_server的過(guò)程;
    • AMS.trimApplications: 清除沒(méi)有使用app
    • AMS.appDiedLocked: 進(jìn)程死亡
    • AMS.killAllBackgroundProcesses: 殺死所有后臺(tái)進(jìn)程.即(ADJ>9或removed=true的普通進(jìn)程)
    • AMS.killPackageProcessesLocked: 以包名的形式 殺掉相關(guān)進(jìn)程;

updateOomAdjLocked

ActivityManagerService 會(huì)在每次需要更新 app oom_adj 的時(shí)候調(diào)用updateOomAdjLocked 方法更新每個(gè)進(jìn)程的 oom_adj橡淆。

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();
        if (false) {
            RuntimeException e = new RuntimeException();
            e.fillInStackTrace();
            Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
        }
        // 重置所有uid記錄憨降,把curProcState設(shè)置成16(空進(jìn)程)
        // Reset state in all uid records.
        for (int i=mActiveUids.size()-1; i>=0; i--) {
            final UidRecord uidRec = mActiveUids.valueAt(i);
            if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                    "Starting update of " + uidRec);
            uidRec.reset();
        }
        mAdjSeq++;
        mNewNumServiceProcs = 0;
        mNewNumAServiceProcs = 0;
        final int emptyProcessLimit;
        final int cachedProcessLimit;
        
        // mProcessLimit默認(rèn)值等于32父虑,通過(guò)開(kāi)發(fā)者選擇可設(shè)置,或者廠商會(huì)自行調(diào)整
        if (mProcessLimit <= 0) {
            emptyProcessLimit = cachedProcessLimit = 0;
        } else if (mProcessLimit == 1) {
            emptyProcessLimit = 1;
            cachedProcessLimit = 0;
        } else {
            // emptyProcessLimit = 16券册, cachedProcessLimit = 16
            emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
            cachedProcessLimit = mProcessLimit - emptyProcessLimit;
        }
        // Let's determine how many processes we have running vs.
        // how many slots we have for background processes; we may want
        // to put multiple processes in a slot of there are enough of
        // them.
        // numSlots = 3
        int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
                - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
        int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
        if (numEmptyProcs > cachedProcessLimit) {
            // If there are more empty processes than our limit on cached
            // processes, then use the cached process limit for the factor.
            // This ensures that the really old empty processes get pushed
            // down to the bottom, so if we are running low on memory we will
            // have a better chance at keeping around more cached processes
            // instead of a gazillion empty processes.
            numEmptyProcs = cachedProcessLimit;
        }
        int emptyFactor = numEmptyProcs/numSlots;
        if (emptyFactor < 1) emptyFactor = 1;
        int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots;
        if (cachedFactor < 1) cachedFactor = 1;
        int stepCached = 0;
        int stepEmpty = 0;
        int numCached = 0;
        int numEmpty = 0;
        int numTrimming = 0;
        mNumNonCachedProcs = 0;
        mNumCachedHiddenProcs = 0;
        // First update the OOM adjustment for each of the
        // application processes based on their current state.
        int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
        int nextCachedAdj = curCachedAdj+1;
        int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
        int nextEmptyAdj = curEmptyAdj+2;
        for (int i=N-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            if (!app.killedByAm && app.thread != null) {
                app.procStateChanged = false;
                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.
                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(app, true, now, nowElapsed);
                // Count the number of process types.
                switch (app.curProcState) {
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                        mNumCachedHiddenProcs++;
                        numCached++;
                        if (numCached > cachedProcessLimit) {
                            app.kill("cached #" + numCached, true);
                        }
                        break;
                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
                        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;
                }
                if (app.isolated && app.services.size() <= 0) {
                    // If this is an isolated process, and there are no
                    // services running in it, then the process is no longer
                    // needed.  We agressively kill these because we can by
                    // definition not re-use the same process again, and it is
                    // good to avoid having whatever code was running in them
                    // left sitting around after no longer needed.
                    app.kill("isolated not needed", true);
                } else {
                    // Keeping this process, update its uid.
                    final UidRecord uidRec = app.uidRecord;
                    if (uidRec != null && uidRec.curProcState > app.curProcState) {
                        uidRec.curProcState = app.curProcState;
                    }
                }
                if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
                        && !app.killedByAm) {
                    numTrimming++;
                }
            }
        }
        mNumServiceProcs = mNewNumServiceProcs;
        // Now determine the memory trimming level of background processes.
        // Unfortunately we need to start at the back of the list to do this
        // properly.  We only do this if the number of background apps we
        // are managing to keep around is less than half the maximum we desire;
        // if we are keeping a good number around, we'll let them use whatever
        // memory they want.
        final int numCachedAndEmpty = numCached + numEmpty;
        int memFactor;
        if (numCached <= ProcessList.TRIM_CACHED_APPS
                && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
            if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
                memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
            } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
                memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
            } else {
                memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
            }
        } else {
            memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
        }
        // We always allow the memory level to go up (better).  We only allow it to go
        // down if we are in a state where that is allowed, *and* the total number of processes
        // has gone down since last time.
        if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
                + " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
                + " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
        if (memFactor > mLastMemoryLevel) {
            if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
                memFactor = mLastMemoryLevel;
                if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
            }
        }
        mLastMemoryLevel = memFactor;
        mLastNumProcesses = mLruProcesses.size();
        boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now);
        final int trackerMemFactor = mProcessStats.getMemFactorLocked();
        if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
            if (mLowRamStartTime == 0) {
                mLowRamStartTime = now;
            }
            int step = 0;
            int fgTrimLevel;
            switch (memFactor) {
                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
                    break;
                case ProcessStats.ADJ_MEM_FACTOR_LOW:
                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
                    break;
                default:
                    fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
                    break;
            }
            int factor = numTrimming/3;
            int minFactor = 2;
            if (mHomeProcess != null) minFactor++;
            if (mPreviousProcess != null) minFactor++;
            if (factor < minFactor) factor = minFactor;
            int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
            for (int i=N-1; i>=0; i--) {
                ProcessRecord app = mLruProcesses.get(i);
                if (allChanged || app.procStateChanged) {
                    setProcessTrackerStateLocked(app, trackerMemFactor, now);
                    app.procStateChanged = false;
                }
                if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
                        && !app.killedByAm) {
                    if (app.trimMemoryLevel < curLevel && app.thread != null) {
                        try {
                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                                    "Trimming memory of " + app.processName + " to " + curLevel);
                            app.thread.scheduleTrimMemory(curLevel);
                        } catch (RemoteException e) {
                        }
                        if (false) {
                            // For now we won't do this; our memory trimming seems
                            // to be good enough at this point that destroying
                            // activities causes more harm than good.
                            if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
                                    && app != mHomeProcess && app != mPreviousProcess) {
                                // Need to do this on its own message because the stack may not
                                // be in a consistent state at this point.
                                // For these apps we will also finish their activities
                                // to help them free memory.
                                mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
                            }
                        }
                    }
                    app.trimMemoryLevel = curLevel;
                    step++;
                    if (step >= factor) {
                        step = 0;
                        switch (curLevel) {
                            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                                curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
                                break;
                            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                                curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                                break;
                        }
                    }
                } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                    if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                            && app.thread != null) {
                        try {
                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                                    "Trimming memory of heavy-weight " + app.processName
                                    + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                            app.thread.scheduleTrimMemory(
                                    ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                        } catch (RemoteException e) {
                        }
                    }
                    app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                } else {
                    if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                            || app.systemNoUi) && app.pendingUiClean) {
                        // If this application is now in the background and it
                        // had done UI, then give it the special trim level to
                        // have it free UI resources.
                        final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
                        if (app.trimMemoryLevel < level && app.thread != null) {
                            try {
                                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                                        "Trimming memory of bg-ui " + app.processName
                                        + " to " + level);
                                app.thread.scheduleTrimMemory(level);
                            } catch (RemoteException e) {
                            }
                        }
                        app.pendingUiClean = false;
                    }
                    if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
                        try {
                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                                    "Trimming memory of fg " + app.processName
                                    + " to " + fgTrimLevel);
                            app.thread.scheduleTrimMemory(fgTrimLevel);
                        } catch (RemoteException e) {
                        }
                    }
                    app.trimMemoryLevel = fgTrimLevel;
                }
            }
        } else {
            if (mLowRamStartTime != 0) {
                mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
                mLowRamStartTime = 0;
            }
            for (int i=N-1; i>=0; i--) {
                ProcessRecord app = mLruProcesses.get(i);
                if (allChanged || app.procStateChanged) {
                    setProcessTrackerStateLocked(app, trackerMemFactor, now);
                    app.procStateChanged = false;
                }
                if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                        || app.systemNoUi) && app.pendingUiClean) {
                    if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                            && app.thread != null) {
                        try {
                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                                    "Trimming memory of ui hidden " + app.processName
                                    + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                            app.thread.scheduleTrimMemory(
                                    ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                        } catch (RemoteException e) {
                        }
                    }
                    app.pendingUiClean = false;
                }
                app.trimMemoryLevel = 0;
            }
        }
        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");
        }
        if (allChanged) {
            requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
        }
        // Update from any uid changes.
        for (int i=mActiveUids.size()-1; i>=0; i--) {
            final UidRecord uidRec = mActiveUids.valueAt(i);
            if (uidRec.setProcState != uidRec.curProcState) {
                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                        "Changes in " + uidRec + ": proc state from " + uidRec.setProcState
                        + " to " + uidRec.curProcState);
                uidRec.setProcState = uidRec.curProcState;
                enqueueUidChangeLocked(uidRec, false);
            }
        }
        if (mProcessStats.shouldWriteNowLocked(now)) {
            mHandler.post(new Runnable() {
                @Override public void run() {
                    synchronized (ActivityManagerService.this) {
                        mProcessStats.writeStateAsyncLocked();
                    }
                }
            });
        }
        if (DEBUG_OOM_ADJ) {
            final long duration = SystemClock.uptimeMillis() - now;
            if (false) {
                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
                        new RuntimeException("here").fillInStackTrace());
            } else {
                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
            }
        }
    }

NEXT:http://www.reibang.com/p/04901127fd18

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末频轿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子烁焙,更是在濱河造成了極大的恐慌航邢,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骄蝇,死亡現(xiàn)場(chǎng)離奇詭異膳殷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)赚窃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)册招,“玉大人,你說(shuō)我怎么就攤上這事勒极∈顷” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵辱匿,是天一觀的道長(zhǎng)键痛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)匾七,這世上最難降的妖魔是什么絮短? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮昨忆,結(jié)果婚禮上丁频,老公的妹妹穿的比我還像新娘。我一直安慰自己邑贴,他們只是感情好席里,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拢驾,像睡著了一般胁勺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上独旷,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天署穗,我揣著相機(jī)與錄音,去河邊找鬼嵌洼。 笑死案疲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的麻养。 我是一名探鬼主播褐啡,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鳖昌!你這毒婦竟也來(lái)了备畦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤许昨,失蹤者是張志新(化名)和其女友劉穎懂盐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體糕档,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莉恼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俐银。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尿背,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捶惜,到底是詐尸還是另有隱情田藐,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布吱七,位于F島的核電站坞淮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陪捷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一诺擅、第九天 我趴在偏房一處隱蔽的房頂上張望市袖。 院中可真熱鬧,春花似錦烁涌、人聲如沸苍碟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)微峰。三九已至,卻和暖如春抒钱,著一層夾襖步出監(jiān)牢的瞬間蜓肆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工谋币, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仗扬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓蕾额,卻偏偏與公主長(zhǎng)得像早芭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诅蝶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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