方法作用
在AMS服务中对于进程管理有一系列保存进程信息ProcessRecord的容器,其中mLruProcesses列表用于按照进程的最近的使用情况,对进程进行排序保存.
/**
* List of running applications, sorted by recent usage.
* The first entry in the list is the least recently used.
*/
final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
mLruProcesses是一个ArrayList,按照最近使用情况进行排序,最近使用频率高的进程排在列表的末尾,使用频率低的进程在列表头部。当内存空间不足的时候,排在列表头部的进程容易被杀掉来释放内存资源。
AMS将mLruProcesses列表分成了三个区域,使用两个变量来记录三个区域的分割点
- mLruProcessServiceStart 表示从这个位置之后存放包含Service相关组件的进程信息
- mLruProcessActivityStart 表示从这个位置之后存放包含Activity相关组件的进程信息
方法逻辑分析
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
//hasActivity来决定当前的进程中是否包含Activity相关的组件信息
//1: app.activities.size() > 0 进程中包含activity组件
//2: app.hasClientActivities 进程中包含service,并且绑定当前进程service的客户端进程包含activity组件
//3: app.treatLikeActivity 当前进程bindeService使用BIND_TREAT_LIKE_ACTIVITY标志,将service优先级当成activity看待
//4: app.recentTasks.size() > 0 当前进程recentTasks >0
final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
|| app.treatLikeActivity || app.recentTasks.size() > 0;
final boolean hasService = false; // hasSerivce相关的逻辑尚未实现 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.
return;
}
mLruSeq++; //Lru更新序号+1
final long now = SystemClock.uptimeMillis();
app.lastActivityTime = now;
// 如果我们要更新的进程已经处于对应列表位置,则直接返回,无需处理
if (hasActivity) {
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 {
if (mLruProcessServiceStart > 0
&& mLruProcesses.get(mLruProcessServiceStart-1) == app) {
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
return;
}
}
//当前进程在mLruProcesses列表中的位置
int lrui = mLruProcesses.lastIndexOf(app);
//如果是persistent进程,我们不关心它在列表中的位置,因为他是常驻内存,不会被杀死
if (app.persistent && lrui >= 0) {
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
return;
}
第一部分:
- 判断当前进程是否有Activity相关的组件
- 判断当前进程是否有Service相关的组件
- 判断位置,如果位置已经处于对应位置,则无需处理
- 判断进程类型,如果是persistent类型的进程,不关心其位置,无需处理
//更新当前进程processRecord的位置之前,先将其从列中移除
if (lrui >= 0) {
if (lrui < mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
if (lrui < mLruProcessServiceStart) {
mLruProcessServiceStart--;
}
mLruProcesses.remove(lrui);
}
int nextIndex;
if (hasActivity) {
//如果当前进程含有Activity相关组件信息
final int N = mLruProcesses.size();
if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
&& mLruProcessActivityStart < (N - 1)) {
// 没有Activity组件,但是有recentTask组件信息,则将当前进程位置放在列表倒数第二个位置
// 列表尾部第一个必须是有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;
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 {
// 如果有Activity组件,就直接放在列表尾部
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
mLruProcesses.add(app);
}
nextIndex = mLruProcessServiceStart;
} else if (hasService) {
// 如果进程中有Service, 就把进程放在mLruProcesses列表Service区域的尾部
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
mLruProcesses.add(mLruProcessActivityStart, app);
nextIndex = mLruProcessServiceStart;
mLruProcessActivityStart++;
} else {
// 如果进程中既没有Activity,有没有Service,就把进程放在列表中其他区域中末尾.
int index = mLruProcessServiceStart;
if (client != null) {
// 如果当前进程没有Activity,Serivce这两种组件,但是却有客户端进程依赖当前进程,这时候就要根
// 客户端进程调整当前进程的位置
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++;
}
第二部分:根据进程是否有Activity, Service来决定当前进程在列表中的位置
- 首先将ProcessRecord从旧的位置移除
- 有Activity就添加到队列尾部
- 有Service就添加到Service区域的尾部
- 以上两种组件都没有就添加到其他区域的尾部
// 如果当前进程使用了其他进程的Service组件,则需要同时调整其依赖进程的优先级,防止依赖的进程被kill掉.
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组件,则需要同时调整其依赖进程的优先级,防止依赖的进程被kill掉
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);
}
}
}
第三部分: 调整当前进程依赖的其他进程的位置,防止其他进程优先级过低被杀死
- 如果有bind其他进程的Service, 则调整其他进程的在列表中的位置
- 如果有调用其他进程的ContentProvider,则调整其他进程在列表中的位置
调整其他进程的主要逻辑:
- 如果其他进程的位置被自己进程位置靠后,说明自己依赖进程优先级本身就是比自己进程高的,这时候不需要处理
- 如果依赖进程的是包含有Acitivity组件的,也不需要处理
- 如果依赖进程的位置比自己靠前,优先级被自己低,则要适当的将其位置往后调,使其优先级变高