Android的组件管理(Android N)--Process管理(一)

来源:互联网 发布:计时器软件下载 编辑:程序博客网 时间:2024/06/05 23:43

在Android中,进程的概念被弱化了,传统的进程是程序执行的载体,进程退出也意味着应用关闭。但是在Android中,进程只是一个运行组件的容器,当系统需要运行一个组件时,启动包含它的进程,进程也会被关闭。例如一个apk文件中的两个service,可以运行在一个进程中,也可以运行在各自的进程中。

虽然在Android的应用开发中,不再强调进程的概念,但是在AMS中,还必须管理和调度进程。AMS对进程的管理,主要体现在两个方面:一是动态地调整进程在mLruProcesses列表的位置,二是调整进程的oom_adj的值。这两项调整和系统进行自动内存回收有关,当内存不足时,系统会关闭一些进程来释放内存。

系统主要根据进程的oom_adj值来挑选要杀死的进程,oom_adj值越大表示进程更可能被杀死。

如何启动进程

AMS中启动一个进程调用的是addAppLocked()方法,代码如下:
    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,            String abiOverride) {        ProcessRecord app;        // isolated为true,表示要启动一个新进程。        if (!isolated) {// 在已经启动的进程列表中查询             app = getProcessRecordLocked(info.processName, info.uid, true);        } else {            app = null;        }        // 创建一个ProcessRecord对象。        if (app == null) {            app = newProcessRecordLocked(info, null, isolated, 0);            updateLruProcessLocked(app, false, null);//更新运行中的进程的状态            updateOomAdjLocked();//更新进程的优先级        }        // This package really, really can not be stopped.        // 通过PKMS将package对应的数据结构StoppedState状态设置为false        try {            AppGlobals.getPackageManager().setPackageStoppedState(                    info.packageName, false, UserHandle.getUserId(app.uid));        } catch (RemoteException e) {        } catch (IllegalArgumentException e) {            Slog.w(TAG, "Failed trying to unstop package "                    + info.packageName + ": " + e);        }        if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {            app.persistent = true;            app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;        }        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {            mPersistentStartingProcesses.add(app);            // 启动应用所在的进程,发消息给zygote,zygote会fork出进程            startProcessLocked(app, "added application", app.processName, abiOverride,                    null /* entryPoint */, null /* entryPointArgs */);        }        return app;    }

addAppLocked()会根据参数isolated来决定是否启动一个新的进程,如果isolatedtrue,即使系统中有一个同名的进程存在,也会再创建一个新的进程。getProcessRecordLocked()用来在当前运行的进程列表中查找进程。newProcessRecordLocked()用来创建一个ApplicationInfo对应的ProcessRecord的数据结构。最后调用startProcessLocked()方法来启动进程。startProcessLocked()方法代码如下:

    private final void startProcessLocked(ProcessRecord app, String hostingType,            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {        long startTime = SystemClock.elapsedRealtime();        if (app.pid > 0 && app.pid != MY_PID) {            checkTime(startTime, "startProcess: removing from pids map");            synchronized (mPidsSelfLocked) {                mPidsSelfLocked.remove(app.pid);//把进程id先移除,防止重复;                //把消息PROC_START_TIMEOUT_MSG也移除,下面会利用这条消息来计算启动时间                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);            }            checkTime(startTime, "startProcess: done removing from pids map");            app.setPid(0);        }        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,                "startProcessLocked removing on hold: " + app);        mProcessesOnHold.remove(app);        checkTime(startTime, "startProcess: starting to update cpu stats");        updateCpuStats();        checkTime(startTime, "startProcess: done updating cpu stats");        try {            try {                final int userId = UserHandle.getUserId(app.uid);                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);            } catch (RemoteException e) {                throw e.rethrowAsRuntimeException();            }            int uid = app.uid;            int[] gids = null;            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;            if (!app.isolated) {                int[] permGids = null;                try {                    checkTime(startTime, "startProcess: getting gids from package manager");                    final IPackageManager pm = AppGlobals.getPackageManager();                    permGids = pm.getPackageGids(app.info.packageName,                            MATCH_DEBUG_TRIAGED_MISSING, app.userId);                    MountServiceInternal mountServiceInternal = LocalServices.getService(                            MountServiceInternal.class);                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,                            app.info.packageName);                } catch (RemoteException e) {                    throw e.rethrowAsRuntimeException();                }                /*                 * Add shared application and profile GIDs so applications can share some                 * resources like shared libraries and access user-wide resources                 */                if (ArrayUtils.isEmpty(permGids)) {                    gids = new int[2];                } else {                    gids = new int[permGids.length + 2];                    System.arraycopy(permGids, 0, gids, 2, permGids.length);                }                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));            }            checkTime(startTime, "startProcess: building args");            if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {                if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL                        && mTopComponent != null                        && app.processName.equals(mTopComponent.getPackageName())) {                    uid = 0;                }                if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL                        && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {                    uid = 0;                }            }            int debugFlags = 0;            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;                // Also turn on CheckJNI for debuggable apps. It's quite                // awkward to turn on otherwise.                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;            }            // Run the app in safe mode if its manifest requests so or the            // system is booted in safe mode.            if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||                mSafeMode == true) {                debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;            }            if ("1".equals(SystemProperties.get("debug.checkjni"))) {                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;            }            String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");            if ("true".equals(genDebugInfoProperty)) {                debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;            }            if ("1".equals(SystemProperties.get("debug.jni.logging"))) {                debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;            }            if ("1".equals(SystemProperties.get("debug.assert"))) {                debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;            }            if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {                // Enable all debug flags required by the native debugger.                debugFlags |= Zygote.DEBUG_ALWAYS_JIT;          // Don't interpret anything                debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info                debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;   // Disbale optimizations                mNativeDebuggingApp = null;            }            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;            if (requiredAbi == null) {                requiredAbi = Build.SUPPORTED_ABIS[0];            }            String instructionSet = null;            if (app.info.primaryCpuAbi != null) {                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);            }            app.gids = gids;            app.requiredAbi = requiredAbi;            app.instructionSet = instructionSet;            // Start the process.  It will either succeed and return a result containing            // the PID of the new process, or else throw a RuntimeException.            boolean isActivityProcess = (entryPoint == null);            if (entryPoint == null) entryPoint = "android.app.ActivityThread";            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +                    app.processName);            checkTime(startTime, "startProcess: asking zygote to start proc");            Process.ProcessStartResult startResult = Process.start(entryPoint,                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,                    app.info.dataDir, entryPointArgs);//启动应用            checkTime(startTime, "startProcess: returned from zygote!");            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);            if (app.isolated) {                mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);            }            mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);            checkTime(startTime, "startProcess: done updating battery stats");            EventLog.writeEvent(EventLogTags.AM_PROC_START,                    UserHandle.getUserId(uid), startResult.pid, uid,                    app.processName, hostingType,                    hostingNameStr != null ? hostingNameStr : "");            try {                AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,                        app.info.seinfo, app.info.sourceDir, startResult.pid);            } catch (RemoteException ex) {                // Ignore            }            if (app.persistent) {                Watchdog.getInstance().processStarted(app.processName, startResult.pid);            }            checkTime(startTime, "startProcess: building log message");            StringBuilder buf = mStringBuilder;            buf.setLength(0);            buf.append("Start proc ");            buf.append(startResult.pid);            buf.append(':');            buf.append(app.processName);            buf.append('/');            UserHandle.formatUid(buf, uid);            if (!isActivityProcess) {                buf.append(" [");                buf.append(entryPoint);                buf.append("]");            }            buf.append(" for ");            buf.append(hostingType);            if (hostingNameStr != null) {                buf.append(" ");                buf.append(hostingNameStr);            }            Slog.i(TAG, buf.toString());            if(hostingType.equals("activity")) {                BoostFramework perf = new BoostFramework();                if (perf != null) {                    perf.perfIOPrefetchStart(startResult.pid,app.processName);                }                // Start Freq Aggregation boost                if (mIsFreqAggrEnabled == true && sFreqAggr_init == null                    && sFreqAggr == null) {                   sFreqAggr_init = new BoostFramework();                   sFreqAggr = new BoostFramework();                }                if (sFreqAggr_init != null && sFreqAggr != null) {                   sFreqAggr_init.perfLockAcquire(lFreqAggr_TimeOut, lFreqAggr_Init_ParamVal);                   sIsFreqAggrBoostSet = true;                   // Frequency Aggr perflock can only be passed one opcode-pair                   if (lFreqAggr_ParamVal.length == 2) {                       lFreqAggr_ParamVal[1] = startResult.pid;                       sFreqAggr.perfLockAcquire(lFreqAggr_TimeOut, lFreqAggr_ParamVal);                   } else {                       //Opcodes improperly defined. Disable Perflock FA support.                       sFreqAggr = null;                       sFreqAggr_init.perfLockRelease();                       sIsFreqAggrBoostSet = false;                   }                }                // Start launch boost v2                if (mIsLaunchBoostv2_enabled == true && sPerfBoost_v2 == null) {                    sPerfBoost_v2 = new BoostFramework();                }                if (sPerfBoost_v2 != null) {                   sPerfBoost_v2.perfLockAcquire(lBoost_v2_TimeOut, lBoost_v2_ParamVal);                   sIsLaunchBoostv2_set = true;                }            }            app.setPid(startResult.pid);            app.usingWrapper = startResult.usingWrapper;            app.removed = false;            app.killed = false;            app.killedByAm = false;            checkTime(startTime, "startProcess: starting to update pids map");            synchronized (mPidsSelfLocked) {                //发送一个定时消息,时间到应用还没有启动完成就会出现ANR                this.mPidsSelfLocked.put(startResult.pid, app);                if (isActivityProcess) {                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);                    msg.obj = app;                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);                }            }            checkTime(startTime, "startProcess: done updating pids map");            if ("activity".equals(hostingType) || "service".equals(hostingType)) {                mActivityTrigger.activityStartProcessTrigger(app.processName, startResult.pid);            }        } catch (RuntimeException e) {            Slog.e(TAG, "Failure starting process " + app.processName, e);            // Something went very wrong while trying to start this process; one            // common case is when the package is frozen due to an active            // upgrade. To recover, clean up any active bookkeeping related to            // starting this process. (We already invoked this method once when            // the package was initially frozen through KILL_APPLICATION_MSG, so            // it doesn't hurt to use it again.)            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,                    false, true, false, false, UserHandle.getUserId(app.userId), "start failure");        }    }
startProcessLocked()方法的流程是:准备好启动应用的参数后,调用Process的start()方法来启动进程。启动进程后,AMS会给自己发送一个PROC_START_TIMEOUT_MSG消息,用来防止进程启动时间超时。如果start()函数返回的结果中usingWrapper的值为true,超时时间设为1200秒,否则设为10秒,这两个常量的定义如下:
    // How long we wait for a launched process to attach to the activity manager    // before we decide it's never going to come up for real, when the process was    // started with a wrapper for instrumentation (such as Valgrind) because it    // could take much longer than usual.    static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
    // How long we wait for a launched process to attach to the activity manager    // before we decide it's never going to come up for real.    static final int PROC_START_TIMEOUT = 10*1000;
如果时间到了,但是进程还没有启动完成,AMS将会弹出发生ANR的对话框。

调整进程的位置

AMS的代码中经常用到updateLruProcessLocked()方法来调整某个进程在mLruProcesses列表中的位置,mLruProcesses是最近使用进程列表(List Of Recent Using)。每当进程中的Activity或Service发生变化时,意味着进程发生了活动,因此,调用这个方法将进程调整到尽可能高的位置,同时还要更新关联进程的位置。在mLruProcesses列表中,最近活动过的进程总是位于最高位置,同时拥有Activity的进程的位置总是高于只有Service的进程的位置。
AMS的成员变量mLruProcessesActivityStart和mLruProcessesServiceStart分别指向列表中位置最高的、带有Activity进程和没有Activity的进程。
    final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,            ProcessRecord client) {        // app.activities.size()>0表示本进程中有活动的activity;app.hasClientActivities为true表示某个绑定了本进程中        // 的service的客户进程有活动的activity;app.treatLikeActivity为true表示service启动时带有标记BIND_TREAT_LIKE_ACTIVITY        final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities                || app.treatLikeActivity;        final boolean hasService = false; // not impl yet. app.services.size() > 0;        if (!activityChange && hasActivity) {            // The process has activities, so we are only allowing activity-based adjustments            // to move it.  It should be kept in the front of the list with other            // processes that have activities, and we don't want those to change their            // order except due to activity operations.            // 如果ProcessRecord对象中已经有了Activity再调用本方法,除非是Activity发生变化了才需要            return;        }        mLruSeq++;// 方法每调用一次,这个变量加1;        final long now = SystemClock.uptimeMillis();        app.lastActivityTime = now;//更新lastActivityTime中的时间        // First a quick reject: if the app is already at the position we will        // put it, then there is nothing to do.        if (hasActivity) {            //如果进程已经初始化了,而且在mLruProcesses列表中也是最后一项,直接退出            final int N = mLruProcesses.size();            if (N > 0 && mLruProcesses.get(N-1) == app) {                if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);                return;            }        } else {            //如果进程中没有activity,而且已经位于mLruProcesses列表中合适位置,退出            if (mLruProcessServiceStart > 0                    && mLruProcesses.get(mLruProcessServiceStart-1) == app) {                if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);                return;            }        }        int lrui = mLruProcesses.lastIndexOf(app);        if (app.persistent && lrui >= 0) {//带有persistent标记的进程不需要调整,退出            // We don't care about the position of persistent processes, as long as            // they are in the list.            if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);            return;        }        if (lrui >= 0) {            //如果进程已经存在,先从mLruProcesses列表中移除,同时调整mLruProcessesActivityStart和mLruProcessesServiceStart的值            if (lrui < mLruProcessActivityStart) {                mLruProcessActivityStart--;            }            if (lrui < mLruProcessServiceStart) {                mLruProcessServiceStart--;            }            mLruProcesses.remove(lrui);        }        int nextIndex;        if (hasActivity) {            final int N = mLruProcesses.size();            if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {                // Process doesn't have activities, but has clients with                // activities...  move it up, but one below the top (the top                // should always have a real activity).                //进程中没有activity,但是它的service客户进程中有activity;                if (DEBUG_LRU) Slog.d(TAG_LRU,                        "Adding to second-top of LRU activity list: " + app);                mLruProcesses.add(N - 1, app);//将进程插入到最后一项                // To keep it from spamming the LRU list (by making a bunch of clients),                // we will push down any other entries owned by the app.                final int uid = app.info.uid;                //如果从倒数第三项开始连续有进程的uid和插入的进程的uid相同,把他们的位置向上移动。                for (int i = N - 2; i > mLruProcessActivityStart; i--) {                    ProcessRecord subProc = mLruProcesses.get(i);                    if (subProc.info.uid == uid) {                        // We want to push this one down the list.  If the process after                        // it is for the same uid, however, don't do so, because we don't                        // want them internally to be re-ordered.                        if (mLruProcesses.get(i - 1).info.uid != uid) {                            if (DEBUG_LRU) Slog.d(TAG_LRU,                                    "Pushing uid " + uid + " swapping at " + i + ": "                                    + mLruProcesses.get(i) + " : " + mLruProcesses.get(i - 1));                            ProcessRecord tmp = mLruProcesses.get(i);                            mLruProcesses.set(i, mLruProcesses.get(i - 1));                            mLruProcesses.set(i - 1, tmp);                            i--;                        }                    } else {                        // A gap, we can stop here.                        break;                    }                }            } else {                // Process has activities, put it at the very tipsy-top.                if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);                mLruProcesses.add(app);//进程有activity,加入到最后一项            }            nextIndex = mLruProcessServiceStart;//关联进程将要插入的位置        } else if (hasService) {//hasService为false,这里不会执行            // Process has services, put it at the top of the service list.            if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);            mLruProcesses.add(mLruProcessActivityStart, app);            nextIndex = mLruProcessServiceStart;            mLruProcessActivityStart++;        } else  {            //如果进程中只有service,将进程插入到mLruProcessesServiceStart指向的位置            // Process not otherwise of interest, it goes to the top of the non-service area.            int index = mLruProcessServiceStart;            if (client != null) {//参数client的值,多数情况为null                // If there is a client, don't allow the process to be moved up higher                // in the list than that client.                int clientIndex = mLruProcesses.lastIndexOf(client);                if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG_LRU, "Unknown client " + client                        + " when updating " + app);                if (clientIndex <= lrui) {                    // Don't allow the client index restriction to push it down farther in the                    // list than it already is.                    clientIndex = lrui;                }                if (clientIndex >= 0 && index > clientIndex) {                    index = clientIndex;                }            }            if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);            mLruProcesses.add(index, app);            nextIndex = index-1;//关联进程将要插入的位置            mLruProcessActivityStart++;            mLruProcessServiceStart++;        }        // If the app is currently using a content provider or service,        // bump those processes as well.        //将和本进程的service关联的客户进程的位置调整到本进程之后        for (int j=app.connections.size()-1; j>=0; j--) {            ConnectionRecord cr = app.connections.valueAt(j);            if (cr.binding != null && !cr.serviceDead && cr.binding.service != null                    && cr.binding.service.app != null                    && cr.binding.service.app.lruSeq != mLruSeq                    && !cr.binding.service.app.persistent) {                nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,                        "service connection", cr, app);            }        }      //将和本进程的contentProvider关联的客户进程的位置调整到本进程之后        for (int j=app.conProviders.size()-1; j>=0; j--) {            ContentProviderRecord cpr = app.conProviders.get(j).provider;            if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,                        "provider reference", cpr, app);            }        }    }

updateLruProcessLocked()方法中调整进程很重要的一个依据是进程中有没有活动的activity,除了进程本身存在activity之外,如果和进程中运行的service相关联的客户进程中有activity,也算本进程拥有activity。这里调整位置的目的是为了将来杀死进程释放内存做准备,如果一个进程的关联进程有activity对象存在,如果杀死它,将导致另一个进程出现验证错误。Activity用来显示UI,关系着用户体验,因此,Android尽量不关闭运行activity组件的进程。
如果一个进程拥有activity,通常会把它插入到队列的最高端位置,否则,只会把它放到所有没有activity的进程的前面,这个位置正是变量mLruProcessesServiceStart所指向的。
调整某个进程位置之后,还要调整和该进程的关联进程的位置。进程的管理进程有两种类型:一是绑定了本进程服务的进程;二是连接了本进程ContentProvider的进程。如果这些进程本身有activity是不会调整的,需要调整的是那些没有activity的进程,在updateLruProcessInternalLocked()方法中会执行这种调整,但是,能调整的最高位置也就是mLruProcessesServiceStart指向的位置。
updateLruProcessInternalLocked方法如下:
    private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,            String what, Object obj, ProcessRecord srcApp) {        app.lastActivityTime = now;        if (app.activities.size() > 0) {            // Don't want to touch dependent processes that are hosting activities.            return index;//如果有activity,不用调整位置        }        int lrui = mLruProcesses.lastIndexOf(app);        if (lrui < 0) {            Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "                    + what + " " + obj + " from " + srcApp);            return index;// 如果进程不在mLruProcesses中,退出        }        if (lrui >= index) {            // Don't want to cause this to move dependent processes *back* in the            // list as if they were less frequently used.            return index;//如果进程目前的位置高于要调整的位置,退出        }        if (lrui >= mLruProcessActivityStart) {            // Don't want to touch dependent processes that are hosting activities.            return index;//如果进程目前的位置高于有activity的进程,退出        }        // 把进程调整到参数index-1的位置        mLruProcesses.remove(lrui);        if (index > 0) {            index--;        }        if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index                + " in LRU list: " + app);        mLruProcesses.add(index, app);        return index;//返回进程当前的位置    }

ProcessList的常量

在ProcessList中定义了大量AMS中用到的常量,如下:
/** * Activity manager code dealing with processes. */final class ProcessList {    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;    // The minimum time we allow between crashes, for us to consider this    // application to be bad and stop and its services and reject broadcasts.    // 定义发生crash的最小时间间隔,如果进程在小于这个时间内发生crash,会被认为是“坏”进程。    static final int MIN_CRASH_INTERVAL = 60*1000;    // OOM adjustments for processes in various states:    // Uninitialized value for any major or minor adj fields    static final int INVALID_ADJ = -10000;    // 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.)    // 处于某种不可知状态的进程的oom_adj值    static final int UNKNOWN_ADJ = 1001;    // This is a process only hosting activities that are not visible,    // so it can be killed without any disruption.    // cached进程的oom_adj的最大值和最小值定义    static final int CACHED_APP_MAX_ADJ = 906;    static final int CACHED_APP_MIN_ADJ = 900;    // 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.    // 位于B列表的服务进程的oom_adj值。位于B列表的都是一些旧的、过时的服务进程    static final int SERVICE_B_ADJ = 800;    // 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.    // 当前activity的前一个activity所处进程的oom_adj值。    static final int PREVIOUS_APP_ADJ = 700;    // 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.    // Home进程的oom_adj值。    static final int HOME_APP_ADJ = 600;    // This is a process holding an application service -- killing it will not    // have much of an impact as far as the user is concerned.    // 只包含组件service的进程的oom_adj值。    static final int SERVICE_ADJ = 500;    // 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.    // heavy_weight进程的oom_adj值    static final int HEAVY_WEIGHT_APP_ADJ = 400;    // This is a process currently hosting a backup operation.  Killing it    // is not entirely fatal but is generally a bad idea.    // 正在执行backup的进程的oom_adj值    static final int BACKUP_APP_ADJ = 300;    // 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.    // 不在前台但是包含有用户可感知组件的进程的oom_adj值(例如播放音乐的后台进程)    static final int PERCEPTIBLE_APP_ADJ = 200;    // This is a process only hosting activities that are visible to the    // user, so we'd prefer they don't disappear.    // 进包含activity的可见进程的oom_adj值。    static final int VISIBLE_APP_ADJ = 100;    static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;    // This is the process running the current foreground app.  We'd really    // rather not kill it!前台进程的oom_adj值    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.    // 带有PERSISTENT标记,并且还有组件service的进程的oom_adj值    static final int PERSISTENT_SERVICE_ADJ = -700;    // This is a system persistent process, such as telephony.  Definitely    // don't want to kill it, but doing so is not completely fatal.    // 死亡后会重启的PERSISTENT进程的oom_adj值    static final int PERSISTENT_PROC_ADJ = -800;    // The system process runs at the default adjustment.    // 系统进程的oom_adj值。    static final int SYSTEM_ADJ = -900;    // Special code for native processes that are not being managed by the system (so    // don't have an oom adj assigned by the system).    // 包含native层代码的进程的oom_adj值    static final int NATIVE_ADJ = -1000;    // Memory pages are 4K.定义内存页面大小为4KB    static final int PAGE_SIZE = 4*1024;    // Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE    static final int SCHED_GROUP_BACKGROUND = 0;    // Activity manager's version of Process.THREAD_GROUP_DEFAULT    static final int SCHED_GROUP_DEFAULT = 1;    // Activity manager's version of Process.THREAD_GROUP_TOP_APP    static final int SCHED_GROUP_TOP_APP = 2;    // The minimum number of cached apps we want to be able to keep around,    // without empty apps being able to push them out of memory.    // 系统最少处于cached状态进程的数量    static final int MIN_CACHED_APPS = 2;    // The maximum number of cached processes we will keep around before killing them.    // NOTE: this constant is *only* a control to not let us go too crazy with    // keeping around processes on devices with large amounts of RAM.  For devices that    // are tighter on RAM, the out of memory killer is responsible for killing background    // processes as RAM is needed, and we should *never* be relying on this limit to    // kill them.  Also note that this limit only applies to cached background processes;    // we have no limit on the number of service, visible, foreground, or other such    // processes and the number of those processes does not count against the cached    // process limit.    // 系统最大处于cached状态进程的数量    static final int MAX_CACHED_APPS = SystemProperties.getInt("ro.sys.fw.bg_apps_limit",32);    static final boolean USE_TRIM_SETTINGS =            SystemProperties.getBoolean("ro.sys.fw.use_trim_settings",true);    static final int EMPTY_APP_PERCENT = SystemProperties.getInt("ro.sys.fw.empty_app_percent",50);    static final int TRIM_EMPTY_PERCENT =            SystemProperties.getInt("ro.sys.fw.trim_empty_percent",100);    static final int TRIM_CACHE_PERCENT =            SystemProperties.getInt("ro.sys.fw.trim_cache_percent",100);    static final long TRIM_ENABLE_MEMORY =            SystemProperties.getLong("ro.sys.fw.trim_enable_memory",1073741824);    public static boolean allowTrim() { return Process.getTotalMemory() < TRIM_ENABLE_MEMORY ; }    // We allow empty processes to stick around for at most 30 minutes.    // 定义空进程最大保存时间为30分钟。    static final long MAX_EMPTY_TIME = 30*60*1000;    // The maximum number of empty app processes we will let sit around.    // 系统最大的空进程数量。它的值为MAX_CACHED_APPS的2/3    private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);    // The number of empty apps at which we don't consider it necessary to do    // memory trimming.    public static int computeTrimEmptyApps() {        if (USE_TRIM_SETTINGS && allowTrim()) {            return MAX_EMPTY_APPS*TRIM_EMPTY_PERCENT/100;        } else {            return MAX_EMPTY_APPS/2;        }    }    // 开始内存回收的空进程的阀值。系统中的空进程数量低于这个值不会执行内存回收。    static final int TRIM_EMPTY_APPS = computeTrimEmptyApps();    // The number of cached at which we don't consider it necessary to do    // memory trimming.    public static int computeTrimCachedApps() {        if (USE_TRIM_SETTINGS && allowTrim()) {            return MAX_CACHED_APPS*TRIM_CACHE_PERCENT/100;        } else {            return (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;        }    }    // 开始内存回收的cached进程的阀值。系统中的cached进程数量低于这个值不会执行内存回收。    static final int TRIM_CACHED_APPS = computeTrimCachedApps();    // Threshold of number of cached+empty where we consider memory critical.    static final int TRIM_CRITICAL_THRESHOLD = 3;    // Threshold of number of cached+empty where we consider memory critical.    static final int TRIM_LOW_THRESHOLD = 5;    // Low Memory Killer Daemon command codes.    // These must be kept in sync with the definitions in lmkd.c    //    // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)    // LMK_PROCPRIO <pid> <uid> <prio>    // LMK_PROCREMOVE <pid>    static final byte LMK_TARGET = 0;    static final byte LMK_PROCPRIO = 1;    static final byte LMK_PROCREMOVE = 2;    // These are the various interesting memory levels that we will give to    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we    // can't give it a different value for every possible kind of process.    // 定义用于内存回收的oom_adj阀值    private final int[] mOomAdj = new int[] {            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ    };    // These are the low-end OOM level limits.  This is appropriate for an    // HVGA or smaller phone with less than 512MB.  Values are in KB.    private final int[] mOomMinFreeLow = new int[] {            12288, 18432, 24576,            36864, 43008, 49152    };    // These are the high-end OOM level limits.  This is appropriate for a    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.    private final int[] mOomMinFreeHigh = new int[] {            73728, 92160, 110592,            129024, 147456, 184320    };

如果一个进程中不含有任何组件,这个进程被认为“空”进程。例如,一个进程启动时只含有一个activity,当这个activity销毁后,该进程就变成一个空进程。当Android结束一个进程时,并不会将这个进程立即从系统中删除,而是把它标记为cached进程,再启动新进程时,会优先使用cached进程,这样就能加快应用的启动速度。

调整进程的oom_adj值


AMS中调整进程oom_adj值的方法是updateOomAdjLocked(),这个方法较长,放到下一节分析。

Android的组件管理(Android N)--Process管理(二)


1 0