任务管理器Recent

任务管理器Recent

(基于androidR整理一些任务管理器相关内容)
任务管理器功能主要分为两部分:最近任务列表以及任务快照,在framework中其两部分主要由两个类来管理:RecentTasks.java和TaskSnapshotController.java

最近任务列表

(代码位置:aosp/frameworks/base/services/core/java/com/android/server/am/RecentTasks.java)
RecentTasks其主要负责将最近TaskRecord存入列表以及负责获取最近列表,其在ActivityTaskManagerService中被实例化

获取最近任务列表getRecentTasks()

应用获取AMS,通过AMS.getRecentTasks()获取当前最近任务列表。主要代码在RecentTasks.getRecentTasksImpl()中:
任务管理器Recent_第1张图片

 /**
     * @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。具体流程见下图:
任务管理器Recent_第2张图片
主要代码从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;
        }
    }

任务管理器Recent_第3张图片

//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();
    }

任务Task的存储RecentTasks

当一个Activity的状态为RESUMED后,通过RecentTasks.add()方法存储,最后利用TaskPersister将task存储到内存(/data/system_ce/0/recent_tasks),主要代码见RecentTask.add(Task task):
任务管理器Recent_第4张图片

 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)

Snapshot保存

从源码的注释来看,在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);
                }
            }
        }
    }
}

Snapshot获取

获取的主要流程见下图,应用可以通过AMS.getTaskSnapshot()方法获取TaskSnapshot,同时可以注册监听ITaskStackListener,当缩略图变化时会callback onTaskSnapshotChanged()
任务管理器Recent_第5张图片

你可能感兴趣的:(framework,android)