AMS是Android操作系统中的一个核心组件,它的全称:Activity Manager Service,但它不仅管理Activity,更是Android应用程序的管理器。负责管理应用的生命周期、任务栈(Android12后委托给ATMS管理)、进程和活动之间的切换等。
由于AMS的代码量十分庞大,需要有针对性的研究才不会陷入源码的海洋无法自拔。本文将结合源码对AMS的进程管理展开分析。本文基于Android12分析,以前的版本的源码略有差异,比如进程管理优先级的代码,12以前是放到AMS中,12之后,主要委托到了ProcessList类中,但核心思想和算法没有改变。
核心思想
对队列中的进程进行调整,根据hasActivity,hasService条件,将整个队列划分为三个区域。最后根据LRU算法,对进程所在的区域中调整位置。
分析过程已经贴在代码注释中。
ps:由于分析是本人的理解,难免有误差,所以会保存源码中的英文注释。
核心代码
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
final boolean hasActivity = app.hasActivitiesOrRecentTasks() || 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.
//进程中的activity没有改变,就不需要调整
return;
}
//id自增,保证唯一性
mLruSeq++;
final long now = SystemClock.uptimeMillis();
//保存更新调整后的时间
app.lastActivityTime = now;
// First a quick reject: if the app is already at the position we will
// put it, then there is nothing to do.
//快速校验,如果当前有包含activity的进程,并且mLruProcesses的队尾进程已经是当前的,就不需要调整
if (hasActivity) {
final int N = mLruProcesses.size();
if (N > 0 && mLruProcesses.get(N - 1) == app) {
return;
}
} else {//其他类型的进程,包括有service和不含service(other类型)进程
//mLruProcessServiceStart 是mLruProcesses队列的指针,指向service进程队头的位置
if (mLruProcessServiceStart > 0
&& mLruProcesses.get(mLruProcessServiceStart-1) == app) {
//mLruProcesses的队尾已经是当前的(包含service的进程),不需要调整
return;
}
}
//获取当前进程的位置,如果没有的,就是-1
int lrui = mLruProcesses.lastIndexOf(app);
//如果app是系统进程,有做过system应用的同学知道,可以在application下申明是否是isPersistent属性
if (app.isPersistent() && lrui >= 0) {
// We don't care about the position of persistent processes, as long as
// they are in the list.
//系统进程不管
return;
}
//如果已经存在
if (lrui >= 0) {
//不在下面对应队列中,则需要移除后重新调整位置
if (lrui < mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
if (lrui < mLruProcessServiceStart) {
mLruProcessServiceStart--;
}
mLruProcesses.remove(lrui);
}
int nextIndex;
int nextActivityIndex = -1;
if (hasActivity) {
final int N = mLruProcesses.size();
//赋值给调整后(前面已经-1)的指针位置,原位置会让给当前进程
nextIndex = mLruProcessServiceStart;
//当前进程没有activity
if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity
&& mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but below the app that is binding to it.
int pos = N - 1;
//下面的循环目的是将相同进程有很多Client端的进程归并
while (pos > mLruProcessActivityStart) {
final ProcessRecord posproc = mLruProcesses.get(pos);
if (posproc.info.uid == app.info.uid) {
// Technically this app could have multiple processes with different
// activities and so we should be looking for the actual process that
// is bound to the target proc... but I don't really care, do you?
break;
}
pos--;
}
//找到对应位置插入
mLruProcesses.add(pos, app);
// If this process is part of a group, need to pull up any other processes
// in that group to be with it.
int endIndex = pos - 1;
if (endIndex < mLruProcessActivityStart) {
endIndex = mLruProcessActivityStart;
}
nextActivityIndex = endIndex;
updateClientActivitiesOrdering(app, pos, mLruProcessActivityStart, endIndex);
} else {
// Process has activities, put it at the very tipsy-top.
//当前进程有activity直接放到队尾
mLruProcesses.add(app);
nextActivityIndex = mLruProcesses.size() - 1;
}
} else if (hasService) {
// Process has services, put it at the top of the service list.
//有service,把进程放到service的末端,也即是hasActivity段的开头
mLruProcesses.add(mLruProcessActivityStart, app);
nextIndex = mLruProcessServiceStart;
//将mLruProcessActivityStart hasActivity的起始索引+1
mLruProcessActivityStart++;
} else {
// Process not otherwise of interest, it goes to the top of the non-service area.
//即没有activity也没有service的进程
int index = mLruProcessServiceStart;
if (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 (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 (index > 1) {
updateClientActivitiesOrdering(app, mLruProcessServiceStart - 1, 0, index - 1);
}
}
//保存给app自增后的唯一id
app.lruSeq = mLruSeq;
// If the app is currently using a content provider or service,
// bump those processes as well.
//这里是对进程中有service和contentProvider的情况下,需要将其包含的进程也加入到队列中
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.flags & Context.BIND_REDUCTION_FLAGS) == 0
&& !cr.binding.service.app.isPersistent()) {
if (cr.binding.service.app.hasClientActivities()) {
if (nextActivityIndex >= 0) {
nextActivityIndex = updateLruProcessInternalLocked(cr.binding.service.app,
now,
nextActivityIndex, mLruSeq,
"service connection", cr, app);
}
} else {
nextIndex = updateLruProcessInternalLocked(cr.binding.service.app,
now,
nextIndex, mLruSeq,
"service connection", cr, app);
}
}
}
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.isPersistent()) {
nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, mLruSeq,
"provider reference", cpr, app);
}
}
}
总结
核心在于根据进程状态(是否存在activity和service)去调整mLruProcessServiceStart和mLruProcessActivityStart两个指针的位置,维护活动的列表中3个区域里各自进程优先级。
当内存不足时,Android系统会在根据进程所在区域的优先级去回收进程,当然这里不是简单粗暴的从头还是回收,它会结合进程的重要性做调整,这就是下一篇会讲到的Adj算法。