(基于androidR整理一些任务管理器相关内容)
任务管理器功能主要分为两部分:最近任务列表以及任务快照,在framework中其两部分主要由两个类来管理:RecentTasks.java和TaskSnapshotController.java
(代码位置:aosp/frameworks/base/services/core/java/com/android/server/am/RecentTasks.java)
RecentTasks其主要负责将最近TaskRecord存入列表以及负责获取最近列表,其在ActivityTaskManagerService中被实例化
应用获取AMS,通过AMS.getRecentTasks()获取当前最近任务列表。主要代码在RecentTasks.getRecentTasksImpl()中:
/**
* @return the list of recent tasks for presentation.
*/
/*
*maxNum:最多取几个最近任务;flags:用来判断是否排除设置FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS flag的应用;
*getTasksAllowed:是否允许获取最近任务列表; userId:调用者的用户Id; callingUid:调用者的Uid
*/
private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
boolean getTasksAllowed, int userId, int callingUid) {
//flags的取值有两个:RECENT_WITH_EXCLUDED和RECENT_IGNORE_UNAVAILABLE
//如果flags=RECENT_WITH_EXCLUDED 的话,则withExcluded=true,说明需要返回所有的task,即便设置了 android:excludeFromRecents=“true”
final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
return new ArrayList<>();
}
//从内存(/data/system_ce/0/recent_tasks)中读取持久recentTask,加载到mTasks列表中。如果它们已经加载,则不执行任何操作
loadUserRecentsLocked(userId);
final Set<Integer> includedUsers = getProfileIds(userId);
includedUsers.add(Integer.valueOf(userId));
final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
final int size = mTasks.size();
int numVisibleTasks = 0;
for (int i = 0; i < size; i++) {
final Task task = mTasks.get(i);
//给定的活动任务是否应该通过SystemUI呈现给用户。
if (isVisibleRecentTask(task)) {
numVisibleTasks++;
//isInVisibleRange()在该方法中会判断给定的可见任务是否在策略范围内.
//注意在这里会无条件将task中的第一个返回给最近任务列表,因为系统默认第一个应该是任务管理器应用,但可能会出现的问题是,如果任务管理器应用在还没有add进task时,就获取最近任务列表,就有可能将不应该返回的应用给返回。
if (isInVisibleRange(task, i, numVisibleTasks, withExcluded)) {
// Fall through
} else {
// Not in visible range
continue;
}
} else {
// Not visible
continue;
}
// Skip remaining tasks once we reach the requested size
if (res.size() >= maxNum) {
continue;
}
//只添加调用的用户或相关用户的近期任务
if (!includedUsers.contains(Integer.valueOf(task.mUserId))) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + task);
continue;
}
if (task.realActivitySuspended) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + task);
continue;
}
if (!getTasksAllowed) {
//如果调用者没有GET_TASKS权限,那么只允许他们查看任务的一小部分——他们自己的和家的。
if (!task.isActivityTypeHome() && task.effectiveUid != callingUid) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + task);
continue;
}
}
if (task.autoRemoveRecents && task.getTopNonFinishingActivity() == null) {
//不要包括已完成或正在完成的自动删除任务。.
if (DEBUG_RECENTS) {
Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + task);
}
continue;
}
if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !task.isAvailable) {
if (DEBUG_RECENTS) {
Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + task);
}
continue;
}
if (!task.mUserSetupComplete) {
// 不要包括在用户未完成设置时启动的任务。
if (DEBUG_RECENTS) {
Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + task);
}
continue;
}
res.add(createRecentTaskInfo(task, true /* stripExtras */));
}
return res;
}
应用可以通过AMS.removeTask(int taskId)来指定删除某个task。具体流程见下图:
主要代码从ActivityTaskManagerService.removeTask()开始
//ActivityTaskManagerService
public boolean removeTask(int taskId) {
enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
//REMOVE_FROM_RECENTS=true,代表要从最近任务中删除
return mStackSupervisor.removeTaskById(taskId, true, REMOVE_FROM_RECENTS,
"remove-task");
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
//ActivityStackSupervisor
boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
String reason) {
//killProcess=true:如果可能,终止与任务相关的任何进程。
//anyTaskForId():根据传进来的taskId,找到对应的task
final Task task =
mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task != null) {
removeTask(task, killProcess, removeFromRecents, reason);
return true;
}
Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
return false;
}
//ActivityStackSupervisor
void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
if (task.mInRemoveTask) {
// Prevent recursion.
return;
}
task.mInRemoveTask = true;
try {
//完全删除与现有任务关联的所有活动
task.performClearTask(reason);
//cleanUpRemovedTaskLocked()
cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
mService.getLockTaskController().clearLockedTask(task);
//向上层通知task变化,onTaskStackChanged()
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
if (task.isPersistable) {
//如果task.isPersistable为ture(该信息可以通过adb shell dumpsys activity activities查看),则去更新RecentTasks中的mPersistedTaskIds,并且将其task信息从内存中删除
mService.notifyTaskPersisterLocked(null, true);
}
} finally {
task.mInRemoveTask = false;
}
}
//ActivityStackSupervisor
void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
mRecentTasks.remove(task);
}
........
}
/**
* Remove a task from the recent tasks list.
*/
//RecentTasks
void remove(Task task) {
mTasks.remove(task);
//通知上层onRecentTaskRemoved()
notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
}
//RecentTasks
private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
}
mTaskNotificationController.notifyTaskListUpdated();
}
当一个Activity的状态为RESUMED后,通过RecentTasks.add()方法存储,最后利用TaskPersister将task存储到内存(/data/system_ce/0/recent_tasks),主要代码见RecentTask.add(Task task):
void add(Task task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
// Only allow trimming task if it is not updating visibility for activities, so the caller
// doesn't need to handle unexpected size and index when looping task containers.
final boolean canTrimTask = !mSupervisor.inActivityVisibilityUpdate();
// Clean up the hidden tasks when going to home because the user may not be unable to return
// to the task from recents.
if (canTrimTask && !mHiddenTasks.isEmpty() && task.isActivityTypeHome()) {
removeUnreachableHiddenTasks(task.getWindowingMode());
}
final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
|| task.mNextAffiliateTaskId != INVALID_TASK_ID
|| task.mPrevAffiliateTaskId != INVALID_TASK_ID;
int recentsCount = mTasks.size();
// Quick case: never add voice sessions.
// TODO: VI what about if it's just an activity?
// Probably nothing to do here
if (task.voiceSession != null) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"addRecent: not adding voice interaction " + task);
return;
}
// Another quick case: check if the top-most recent task is the same.
if (!isAffiliated && recentsCount > 0 && mTasks.get(0) == task) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
return;
}
// Another quick case: check if this is part of a set of affiliated
// tasks that are at the top.
if (isAffiliated && recentsCount > 0 && task.inRecents
&& task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
+ " at top when adding " + task);
return;
}
boolean needAffiliationFix = false;
// Slightly less quick case: the task is already in recents, so all we need
// to do is move it.
if (task.inRecents) {
int taskIndex = mTasks.indexOf(task);
if (taskIndex >= 0) {
if (!isAffiliated) {
if (!mFreezeTaskListReordering) {
// Simple case: this is not an affiliated task, so we just move it to the
// front unless overridden by the provided activity options
mTasks.remove(taskIndex);
mTasks.add(0, task);
if (DEBUG_RECENTS) {
Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
+ " from " + taskIndex);
}
}
notifyTaskPersisterLocked(task, false);
return;
}
} else {
Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
needAffiliationFix = true;
}
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
removeForAddTask(task);
task.inRecents = true;
if (!isAffiliated || needAffiliationFix) {
// If this is a simple non-affiliated task, or we had some failure trying to
// handle it as part of an affilated task, then just place it at the top.
mTasks.add(0, task);
notifyTaskAdded(task);
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
} else if (isAffiliated) {
// If this is a new affiliated task, then move all of the affiliated tasks
// to the front and insert this new one.
Task other = task.mNextAffiliate;
if (other == null) {
other = task.mPrevAffiliate;
}
if (other != null) {
int otherIndex = mTasks.indexOf(other);
if (otherIndex >= 0) {
// Insert new task at appropriate location.
int taskIndex;
if (other == task.mNextAffiliate) {
// We found the index of our next affiliation, which is who is
// before us in the list, so add after that point.
taskIndex = otherIndex+1;
} else {
// We found the index of our previous affiliation, which is who is
// after us in the list, so add at their position.
taskIndex = otherIndex;
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"addRecent: new affiliated task added at " + taskIndex + ": " + task);
mTasks.add(taskIndex, task);
notifyTaskAdded(task);
// Now move everything to the front.
if (moveAffiliatedTasksToFront(task, taskIndex)) {
// All went well.
return;
}
// Uh oh... something bad in the affiliation chain, try to rebuild
// everything and then go through our general path of adding a new task.
needAffiliationFix = true;
} else {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"addRecent: couldn't find other affiliation " + other);
needAffiliationFix = true;
}
} else {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"addRecent: adding affiliated task without next/prev:" + task);
needAffiliationFix = true;
}
}
if (needAffiliationFix) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
cleanupLocked(task.mUserId);
}
// Trim the set of tasks to the active set
if (canTrimTask) {
trimInactiveRecentTasks();
}
notifyTaskPersisterLocked(task, false /* flush */);
}
(代码位置:aosp/frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java)
从源码的注释来看,在app token变为不可见时,会触发截取Snapshot,然后通过TaskSnapshotPersister.java被保存到内存中(/data/system_ce/0/snapshots),其在内存中的存储形式有两种:proto和.jpg
/**
* When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
* put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
* like without any copying.
*
* System applications may retrieve a snapshot to represent the current state of a task, and draw
* them in their own process.
*
* When we task becomes visible again, we show a starting window with the snapshot as the content to
* make app transitions more responsive.
*
* To access this class, acquire the global window manager lock.
*/
class TaskSnapshotController {
当app切换时,触发TaskSnapshotController.onTransitionStarting()方法
//TaskSnapshotController
void onTransitionStarting(DisplayContent displayContent) {
handleClosingApps(displayContent.mClosingApps);
}
//TaskSnapshotController
private void handleClosingApps(ArraySet<ActivityRecord> closingApps) {
if (shouldDisableSnapshots()) {
return;
}
//在getClosingTasks()方法中进行判断任务的所有activity是否全都是closing or hidden
getClosingTasks(closingApps, mTmpTasks);
//snapshotTasks()进行截图
snapshotTasks(mTmpTasks);
mSkipClosingAppSnapshotTasks.clear();
}
//TaskSnapshotController
void snapshotTasks(ArraySet<Task> tasks) {
snapshotTasks(tasks, false /* allowSnapshotHome */);
}
//TaskSnapshotController
private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
final TaskSnapshot snapshot;
final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
if (snapshotHome) {
snapshot = snapshotTask(task);
} else {
switch (getSnapshotMode(task)) {
//SNAPSHOT_MODE_NONE:此模式下,将不启用TaskSnapshot功能
case SNAPSHOT_MODE_NONE:
continue;
//SNAPSHOT_MODE_APP_THEME:一般如果应用程序的窗口设置了FLAG_SECURE属性,便会处于该模式,该模式下TaskSnapshot的内容一般只绘制一些ActionBar,应用内容将会被白色替代
case SNAPSHOT_MODE_APP_THEME:
snapshot = drawAppThemeSnapshot(task);
break;
//SNAPSHOT_MODE_REAL:正常显示的模式,一般我们都处于该模式
case SNAPSHOT_MODE_REAL:
snapshot = snapshotTask(task);
break;
default:
snapshot = null;
break;
}
}
if (snapshot != null) {
final GraphicBuffer buffer = snapshot.getSnapshot();
if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
buffer.destroy();
Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+ buffer.getHeight());
} else {
//存储snapshot
mCache.putSnapshot(task, snapshot);
// Don't persist or notify the change for the temporal snapshot.
if (!snapshotHome) {
//将snapshot存储到内存,持久化
mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
//通知应用层snapshot变化了
task.onSnapshotChanged(snapshot);
}
}
}
}
}
获取的主要流程见下图,应用可以通过AMS.getTaskSnapshot()方法获取TaskSnapshot,同时可以注册监听ITaskStackListener,当缩略图变化时会callback onTaskSnapshotChanged()