在Android中,进程(process)的概念被弱化,传统的进程是程序执行的载体,进程退出意味着应用的关闭。但是在Android中进程知识一个运行组件的容器,当系统需要运行一个组件时,启动包含它的进程,当组件不在使用时,进程也会被关闭。例如一个APK文件中的两个service,可以运行在一个进程中,也可以运行在各自的进程中。
虽然在Android的应用开发中,不再强调进程的概念,但是在AMS中,还必须管理和调度进程,AMS对进程的管理,主要体现在两方面:一是动态的调整进程在mLruProcesss列表的位置,二是调整进程oom_adj的值,这两项调整和系统进行自动内存回收有关。当内存不足时,系统会关闭一些进程来释放内存。
系统主要根据进程的oom_adj值来挑选要杀死的进程,oom_adj值越大表示进程越可能被杀死。

1. 启动进程
AMS中启动一个进程调用的是addAppLocked()方法,代码如下:

final ProcessResord addAppLocked(ApplicationInfo info, boolean isolated){  ProcessRecord app;   //isolated为true表示要启动一个新进程  if(!isolated){      app=getProcessResordLocked(info.processName,info.uid,true);                                                                                          }else{     app=null;   }   if(app=null){       //创建一个ProcessRecord对象       app=newProcessRecordLocked(info,null,0);       mProcessNames.put(info.processName,app.uid,app);       if(isolated){           mIsolatedProcesses.put(app.uid,app);       }       updateLruProcessLocked(app,false,null);       updateOomAdjLocked();   }   .....  if(app.thred==null&&mPersistentStartingProcesses.indexOf(app)<0){          mPersistentStartingProcesses.add(app);       //启动进程       startProcessLocked(app,"added application",app.processName           abiOverride,null /*entryPoint */,null /*entryPointArgs */);  }  return app;}

addAppLocked()方法会根据参数参数isolated来决定是否启动一个新进程,如果isoated为true,即使系统中可能已经有一个同名的进程存在,也会再创建一个新锦成。getProcessRecordLocked()方法用来当前运行的进程列表查找进程。newProcessRecordLocked()方法用来创建一个ProcessRecord的数据结构。updateLruProcessLocked方法用来更新运行进程的状态,updateOomAdjLocked()方法用来更新进程的优先级,这两个方法是Process的管理核心。
首先看看startProcessLocked()是启动进程的方法,看看它的代码:

private final void startProcessLocked(ProcessRecord app,String hostingType,String abiOverride){    if(app.pid>0&&app.pid!=MY_PID){         synchronized(mpidSelfLocked){         mPidSelfLocked.remove(app.pid);//把进程id先移除,防止重复         //把消息PROC_START_TIMEOUT_MSG也清除         mHandler.removeMessages(PROC_START_TIMEOUT_MSG,app);         }         app.setpid(0);    }    mProcessOnHold.remove(app);    ......    try{        final int uid=app.uid;        int[] gids=null;        intmountExternal=zygote.MOUNT_EXTERNAL_NONE;        if(!app.isolate){            int [] permGids=null;            try{                 final PackageManager                          pm=mContext.getPackagesManager();                 //检查进程权限,确定它是否能看见所有用户的存储空间                 if(Enviroment.isExternalStorageEmulated()){                    if(pm.checkPermission(.....)){             mountExternal=Zygote.MOUNTEXTERNAL_MULTIUSER_ALL;                    else{                      mountExternal=Zygote.MOUNTEXTERNAL_MULTIUSER;                    }                              }                 }catch (PackageManager.NameNotFountException e){.}            }            ......            //启动应用            Process.ProcessStartResult startResult=Process.start(                app.processName,uid,uid,gids,debugFlags,                mountExternal,app.info.targetSdkVersion,                app.info.seinfo,requiredAbi,instructionSet,                app.infodataDir,entryPointArgs)                .....            synchornized(mPidSelfLocked){               //发送一个定时消息,时间到应用还没启动完成就会出现ANR               this.mPidSelfLocked.put(startResult.pid,app);               if(isActivityProcess){                  Message msg=mHandler.obtainMessage(                  PROC_START_TIME_OUT_MSG);                  msg.obj=app;                  mHandler.sendMessageDelayed(msg,startResult                  .usingWrapper?PROC_START_WITH_WRAPPER:                  PROC_STRAT_TIMEOUT);               }            }          }catch(RuntimeException e){            app.setpid(0);            mBatteryStatsService.noteProcessFinish(            app.processName,app.info.uid);            if(app.isolated){                mBatteryStatsService.removeIsolatedUid(                app.uid,app.info.uid);            }        }    }}

startProcessLocked()方法的流程是,准备好启动应用的参数,调用Process类的start来启动进程,启动进程后AMS给自己发送了一个PROC_START_TIMEOUT_MSG的消息,来防止进程启动超时。如果start()函数返回的结果中usingWrapper的值为true,超时时间设为1200秒。
static final int PROC_START_TIMEOUT_WITH_WRAPPER=1200*1000;
否则超时时间设为10秒。
static final int PROC_START_TIMEOUT=10*1000;
如果时间到了,但是进程还没启动完成,AMS将弹出发生ANR的对话框。

2. 调整进程的位置
AMS的代码中经常调用updateLruProcessLocked()方法来调整某个进程在mLruProcesses列表的位置,mLruProcess是最近使用进程列表(List Of Recent Using的缩写)。每当进程的Activity或者Service发生变化时,意味着进程活动发生了活动,因此,调用这个方法将调整到尽可能最高的位置,同时还要更新关联进程的位置。在mLruProcesses列表中,最近活动的进程总是位于最高位置。同时拥有Activity的进程的位置总是高于只有Service的进程位置。
AMS的成员变量mLruProcessActivityStart和mLruProcessServiceStart分别指向位置最高的、带有Activity进程和没有Activity进程。
updateLruProcessLocked()方法的代码如下:

final void updateLruProcessLocked(ProcessRecord app,boolean activityChange, ProcessRecord client){    //app.activities.size()大于0,表示本进程有活动的Activity。    //app.hasClientActivities的值为true,表示绑定了本进程的Service的    //客户进程有活动的Activity    //treatLikeActivity表示Service启动时带有标记BIND_TREAT_LIKE_ACTVITY    final boolean hasActivity=app.activities.size()>0    ||app.hasClientActivities||treatLikeActivity;    final boolean hasService=false;    if(!activityChange&&hasActivity){        //如果ProcessRecord对象已经有了Activity        //再调用本方法,除非是Activity发生变化了才要        return;    }    mLruSeq++;    final long now=SystenClock.uptimeMillis();    app.lastActivityTime=now;//更新lastActivityTime中的时间    if(hasActivity){       //如果进程已经初始化,而且在mLruProcesses列表位置也是最后一项       //这样也没什么可做的,退出       final int N=mLruProcesses.size();       if(N>0&&mLruProcesses.get(N-1)==app){           return ;       }     }else{        //如果进程中没有Activity,而且应景位于mLruProcesses列表的合适位置,退出        if(mLruProcessServiceStart>0&&mLruProcesses.get(mLruProcessServiceStart-1)==app){            return ;        }   }   int lrui=mLruProcess.lastIndexOf(app);   if(app.persistent&&lrui>=0){       return;//带有persistent标志的进程不需要调整,退出   }   if(lrui>=0){      //如果进程已经存在,先从mLruProceses列表中移除,同时调整mLruProcessActivityStart和mLruProcessServiceStart指向的位置      if(lruiif(lruiint nextIndex;   if(hasActivity){       final int N=mLruProcess.size();       if(app.activities.size()==0&&mLruProcessActivityStart1)){       //进程中没有Activity,但是它的Service客户进程中有Activity       mLruProcesses.add(N-1,app);//将进程插入到最后一项       final int uid=app.info.uid;       //如果从倒数第三项开始连续有进程的uid和插入的进程uid相同,把他们的        位置向上移动       for(int i=N-2;i>mLruProcessActivityStart;i--){         processRecord subProc =mPruProcess.get(i);         if(subProc.info.uid==uid){            if(mLruProcesses.get(i).info.uid!=uid){            mLruProcesses.set(i,mLruProcesses.get(i-1));            mLruProcesses.set(i-1,temp);            i--;            }         }else{            break;         }       }   }  else{          mLruProcesses.add(app);//进程有Activity,加入到最后一项       }      nextIndex=mLruProcessesServiceStart;//关联进程将要插入的位置    }else if(hasService){      .....//hasService总是为False,这段不会执行   }else{      //如果进程中只有Service,将进程插入到mLruProcessServiceStart指向的位置      int index=mLruProcessServiceStart;      if(client!=null){          ......//基本上为null      }      mLruProcess.add(index,app);      nextIndex=index-1;  //关联进程插入的位置      mLruProcessActivityStart++;      mLruProcessServiceStart++;   }   //将和本进程的Service关联的客户进程的位置调整到本进程之后   for(int j=app.connections.size()-1;j>=0;j--){       ConnectionRecord cr=app.connections.valueAt(j);      if(cr.binding!=null&&!crserviceDead          &&cr.binding.service!=null&&cr.binding.service.app        !=null &&cr.binding.service.app.lruSeq!=mLruq        &&!cr.binding.service.app.persistent){         nextIndex=updateLruProcessInternalLocked(         cr.binding.service.app,now,nextIntext,         "service connection",cr,app);        }   }  //将和本进程ContentProvider关联的客户进程的位置调整到本进程之后   for(int j=app.conProviders.size()-1;j>=0;j--){    ContentProviderRecord cpr=app.conProviders.get(j).provider;    if(cpr.proc!=null&&cpr.proc.lruSeq!=mLruSeq    &&!cpr.proc.persistent){       nextIndex=updateLruProcessInternalLocked(         cpr.proc,now,nextIntext,         "provider reference",cpr,app);    }   }}

updateLruProcessLocked()方法中调整进程很重要的一个依据是进程中有没有活动的Activity。除了本身进程存在Activity对象之外,如果和进程中运行的Service相关联的客户进程有Activity,也算进程拥有Activity,这里调整位置的目的是为了将来杀死进程释放内存做准备,如果一个进程关联进程Activity对象存在,那么它的重要性也和真正的和拥有Activity对象的进程相当,如果杀死它,将导致另一个进程出现严重错误,Activity用来显示UI,关系着用户体验,因此尽量不关闭运行Activity组件的进程。
如果一个进程“拥有”Activity,通常会把它插到队列的最高位置,否则,只会把它放到所有没有Activity进程的前面,这个位置正是变量mLruProcessServiceStart所指向的。
调整某个进程的位置之后,还要调整和该进程的关联的位置。进程的关联进程有两种类型:一种是绑定了本进程服务的进程,另一种是连接了本进程的ContentProvider的进程。如果这些进程本身有Activity是不会调整的,需要调整的是那些没有Activity的进程,在updateLruProcessInternalLocked()方法中会执行这种调整,但是,能调整到最高位置也就是mLruProcessServiceStart指向的位置。
updateLruProcessInternalLocked()方法代码如下:

private final int updateLruProcessInternalLocked(ProcessRecord    app,long now,int index,String what,Object obj,ProcessRecord    srcApp){   app.lastActivityTime=now;   if(app.activities.size()>0){       return index;//如果有Activity,不用调整位置。   }   int lrui=mLruProcesses.lastIndexOf(app);   if(lrui<0){      return index;//如果进程不在mLruProcesses中,退出          }   if(lrui>=index){       return index;//如果进程目前的位置高于要调整的位置,退出   }   if(lrui>=mLruProcessActivityStart){      return index; //如果进程目前的位置比有Activity的进程还高,退出   }   //把进程调整到参数index-1的位置   mLruProcesses.remove(this);   if(index>0){   index--;   }   mLruProcesses.add(index,app);   return index;//返回进程的位置}

3. ProcessList的常量
在ProcessList中定义了大量AMS中用到的常量,看看他们的定义

final class ProcessList{   //定义发生crash最小时间间隔,如果进程小于这个时间内发生crash,会被认为坏进程   static final int MIN_CRASH_INTERVAL=60*1000;   //处于某种不可知状态进程的oom_adj值   static final int UNKOWN_ADJ=16;   //cahhed进程的的oom_adj最大和最小值定义   static final int CACHE_APP_MAX_ADJ=15;   static final int CHCHE_APP_MIN_ADJ=9;   //位于B列表的服务进程oom_adj值,位于B列表的都是一些旧的、过时的服务进程   static final int SERVICE_B_ADJ=8;   //当前Activity的前一个Activity所处进程的oom_adj值   static final int PREVIOUS_APP_ADJ=7;   //Home进程oom_adj值   static final int HOME_APP_ADJ=6;   //包含组件Service的进程oom_adj   static final int SERVICE_ADJ=5;   //heavy-weight进程的oom_adj值   static final int HEAVY_WEIGH_APP_ADJ=4;   //正在执行的backup的进程oom_adj值   static final int BACKUP_APP_adj=3;   //不在前台但是包含有用户可感知组件的进程的oom_adj值(例如播放音乐的后台进程)   static final int PERCEPTIBLE_APP_ADJ=2;   //仅包含Activity的可见进程的oom_adj的值   static final int VISIBLE_APP_ADJ=1;   //前台进程的oom_adj值   static final int FOREGROUND_APP_ADJ=0;   //带有PERSISTENT标记而且还有组件Service的进程的oom_adj值   static final int PERSISTENT_SERVICE_ADJ=-11;   //死亡后会重启的PERSISTENT进程oom_adj值   static final int PERSISTENT_PROC_ADJ=-12;   //系统进程oom_adj   static final int SYSTEM_ADJ=-16;   //包含native层代码进程的oom_adj   static final int NATIVE_adj=-17;   //定义内存页面大小为4KB   static final int PACKAGE_SIZE=4*1024;   //系统最少处于cached状态的进程数量   static final int MIN_CACHED_APPS=2;   //系统最大处于cached状态的进程数量   static final int MAX_CACHED_APPS=32;   //定义空进程最大保存时间为30分钟   static final int MAX_EMPTY_TIME=30*60*1000;   //定义最大的空进程数量。它的值为MAX_CACHED_APPS的2/3   static final int MAX_EMPTY_APPS=           computeEmptyProcessLimit(MAX_CACHED_APPS);   //开始内存回收空进程的阈值。系统空进程进程数量低于这个值不会执行内存回收。   static final int TRIM_EMPTY_APPS=MAX_EMPTY_APPS/2;   //开始内存回收cached的阈值。系统cached进程数量低于这个值不会执行内存回收。   static final int TRIM_CACHED_APPS=(MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;    //定义内存回收的oom_adj阈值   private final int mOomAdj=new init[]{      FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ,PERCEPTIBLE_APP_ADJ,      BACKUP_APP_adj,CHCHE_APP_MIN_ADJ,CACHE_APP_MAX_ADJ   };   //定义用于低配置(HVGA或者更低,内存小于512M)设备内存回收阈值   private final int mOomMinFreeLow=new int[]{       12288,18432,24576,       36864,43008,49152   };   //定义高分辨率内存回收阈值   private final int mOonMinFreeHigh=new int []{       73728.92160,110592,       129024,147456,184320   };   ......}

这里先解释空进程和cached进程的概念,如果一个进程不包含任何组件,该进程可以认为是空进程,例如,一个进程只包含一个Activity,当这个Activity销毁后变成一个”空”进程。
当Android结束一个进程时,并不会将一个进程立即从系统删除,而是把它标记为cached进程,当再次启动新进程时,优先会使用cached进程吧,这样会加快启动速度。
4. 调整进程的oom_adj值
AMS中调整进程的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 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);        }        // 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();        }        mStackSupervisor.rankTaskLayersIfNeeded();        mAdjSeq++;        mNewNumServiceProcs = 0;        mNewNumAServiceProcs = 0;        final int emptyProcessLimit;        final int cachedProcessLimit;        if (mProcessLimit <= 0) {            emptyProcessLimit = cachedProcessLimit = 0;        } else if (mProcessLimit == 1) {            emptyProcessLimit = 1;            cachedProcessLimit = 0;        } else {            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.        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;        ProcessRecord selectedAppRecord = null;        long serviceLastActivity = 0;        int numBServices = 0;        for (int i=N-1; i>=0; i--) {            ProcessRecord app = mLruProcesses.get(i);            if (app == null) {                continue;            }            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 && app != TOP_APP) {                        serviceLastActivity = sr.lastActivity;                        selectedAppRecord = app;                    } else if (sr.lastActivity < serviceLastActivity && app !=  TOP_APP) {                        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;                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++;                }            }        }        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");        }        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!");            }        }        if (memFactor != mLastMemoryLevel) {            EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);        }        mLastMemoryLevel = memFactor;        mLastNumProcesses = mLruProcesses.size();        boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), 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);                /* yulong begin add */                /* FEATURE_APP_FREEZE_BACKGROUND */                /* add for app freeze, liuyaxin, 20170519*/                if(ZSFeature.ZEUSIS_FEATURE_APP_FREEZE_BACKGROUND){                    if(app.frozenRemoved){                        Slog.d(TAG, app.info.packageName + " is frozen and no need to scheduleTrimMemory[updateOomAdjLocked memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL]");                        continue;                    }                }                /* yulong end */                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);                /* yulong begin add */                /* FEATURE_APP_FREEZE_BACKGROUND */                /* add for app freeze, liuyaxin, 20170519*/                if(ZSFeature.ZEUSIS_FEATURE_APP_FREEZE_BACKGROUND){                    if(app.frozenRemoved){                        Slog.d(TAG, app.info.packageName + " is frozen and no need to scheduleTrimMemory[updateOomAdjLocked memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL]");                        continue;                    }                }                /* yulong end */                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);            int uidChange = UidRecord.CHANGE_PROCSTATE;            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);                if (ActivityManager.isProcStateBackground(uidRec.curProcState)) {                    if (!ActivityManager.isProcStateBackground(uidRec.setProcState)) {                        uidRec.lastBackgroundTime = nowElapsed;                        if (!mHandler.hasMessages(IDLE_UIDS_MSG)) {                            // Note: the background settle time is in elapsed realtime, while                            // the handler time base is uptime.  All this means is that we may                            // stop background uids later than we had intended, but that only                            // happens because the device was sleeping so we are okay anyway.                            mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, BACKGROUND_SETTLE_TIME);                        }                    }                } else {                    if (uidRec.idle) {                        uidChange = UidRecord.CHANGE_ACTIVE;                        uidRec.idle = false;                    }                    uidRec.lastBackgroundTime = 0;                }                uidRec.setProcState = uidRec.curProcState;                enqueueUidChangeLocked(uidRec, -1, uidChange);                noteUidProcessState(uidRec.uid, uidRec.curProcState);            }        }        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");            }        }    }

updateOomAdjLocked()方法通过调用computeOomAdjLocked()方法来计算进程的oom_adj的值。如果进程的curAdj变量的值仍然大于等于系统预定义的最大oom_adj值(UNKNOW_ADJ),则表明该进程属于“cached”进程或者空进程,updateOomAdjLocked()方法将会为该进程分配oom_adj值。如果用来表示进程状态的变量curProcState的值为PROCESS_STATE_CACHED_ACTIVITY或者PROCESS_STATE_CACHED_ACTIVITY_CLIENT,这说明进程是cached进程,否则为空进程。
updateOomAdjLocked()方法中根据系统定义的cached进程的最大和最小oom_adj的值,先计算出slot的数量,后计算每个slot需要容纳的cached进程的数量cachedFactor和空进程的数量emptyFactor,这样做的目的为了将系统中cached进程和空进程分成不同的级别,每个级别有相同的oom_adj值,级别和级别之间的oom_adj值为2.因此,updateOomAdjLocked()方法区分某个进程是cached进程还是空进程后,会按照从低到高的原则把进程放到某个级别中,如果该几倍进程满了,就进入下一个级别。

更多相关文章

  1. Android开发指南 ──应用程序基础
  2. Android进程管理机制及优化(HTC&其它可参考)
  3. Android中的线程处理
  4. Android线程模型解析(包括UI的更新)
  5. Android内核详解之Low memory killer
  6. Android初学的学习笔记
  7. Android最全面试题71道题 详解
  8. Android(安卓)应用程序基础(Application Fundamentals)
  9. Android(安卓)进程保活招式大全(转)

随机推荐

  1. android之Task和Back Stack(回退栈)
  2. android获取web服务器端session并验证登
  3. Android(安卓)如何优雅的hook私有方法
  4. Android系统显示原理
  5. Activity 启动模式和 taskAffinity 属性
  6. android试手——通讯录(附源码)
  7. Android(OPhone) 学习笔记 - 记事本实例
  8. Android(安卓)项目实践(五)——基础类和工
  9. Xamarin android 使用RecyclerView结合Sw
  10. Android实现手机游戏隐藏虚拟按键