Android Gems — Android的LowMemoryKiller杀进程策略

Posted threepigs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Gems — Android的LowMemoryKiller杀进程策略相关的知识,希望对你有一定的参考价值。

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,通过进程间通信写入。

作者简介:

田力,网易彩票Android端创始人,小米视频创始人,现任roobo技术经理、视频云技术总监

欢迎关注微信公众号 磨剑石,定期推送技术心得以及源码分析等文章,谢谢


以上是关于Android Gems — Android的LowMemoryKiller杀进程策略的主要内容,如果未能解决你的问题,请参考以下文章

Android Gems — AMS的Service生命周期管理

Android Gems — AMS的Service生命周期管理

Android Gems — Fragment本质之生命周期管理

Android Gems — Fragment本质之生命周期管理

Android Gems — Fragment本质之View管理

Android Gems — Fragment本质之View管理