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来决定是否启动一个新的进程,如果isolated为true,即使系统中有一个同名的进程存在,也会再创建一个新的进程。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
- Android的组件管理(Android N)--Process管理(一)
- Android的组件管理(Android N)--Process管理(二)
- Android的组件管理(Android N)--ActivityManagerService服务
- Android线程管理(一)
- Android 组件 — Activity (生命周期管理)
- Android图片管理组件
- Android N Telecom对Audio的管理
- Android 启动栈管理方式 (一)
- Android热点连接管理(一)
- Android AccountManager帐号管理(一)
- (android文档原创翻译)管理Activity的生命周期<一>
- Android 网络管理类的使用(一)
- Android开发通过GitHub管理你的项目(一)
- Android图片管理组件(双缓存+异步加载)
- Android图片管理组件(双缓存+异步加载)
- Android图片管理组件(双缓存+异步加载)
- Android图片管理组件(双缓存+异步加载)
- Android图片管理组件(双缓存、异步加载)
- Java常用设计模式
- Android Spinner选择同一个选项时触发onItemSelected事件
- Linux基金会宣布成立OpenSDS组织,应对存储云化转型
- 手把手教你画AndroidK线分时图及指标
- gson 解析 date 数据
- Android的组件管理(Android N)--Process管理(一)
- 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结
- Android中自动跳转到系统设置界面
- Jquery的html方法里包含特殊字符的处理,类似双引号之类的
- GB28181注册流程讲解
- 误删除Oracle家目录的恢复方法
- rawNAND、ClearNAND、eMMC的区别
- Phalcon ajax防 csrf 提交方法
- java synchronized详解