Andorid N 最近任務管理器流程詳解(二)

2、Task的獲取

本章主要承接上面的來講,解析一下Task的獲取流程

2.1 preloadTasks

文件:RecentsTaskLoader.java

    public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
            boolean includeFrontMostExcludedTask) {
        // 見2.2
        plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
    }

2.2 preloadPlan

文件:RecentsTaskLoadPlan.java

    public synchronized void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
            boolean includeFrontMostExcludedTask) {
        Resources res = mContext.getResources();
        ArrayList<Task> allTasks = new ArrayList<>();
        if (mRawTasks == null) {
            // 見2.2.1 主要是爲了獲取mRecentTasks,並轉換成RecentTaskInfo
            preloadRawTasks(includeFrontMostExcludedTask);
        }

        SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
        SparseIntArray affiliatedTaskCounts = new SparseIntArray();
        String dismissDescFormat = mContext.getString(
                R.string.accessibility_recents_item_will_be_dismissed);
        String appInfoDescFormat = mContext.getString(
                R.string.accessibility_recents_item_open_app_info);
        long lastStackActiveTime = Prefs.getLong(mContext,
                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
        if (RecentsDebugFlags.Static.EnableMockTasks) {
            lastStackActiveTime = 0;
        }
        long newLastStackActiveTime = -1;
        int taskCount = mRawTasks.size();
        for (int i = 0; i < taskCount; i++) {
            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);

            // Compose the task key
            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                    t.userId, t.firstActiveTime, t.lastActiveTime);

            // This task is only shown in the stack if it statisfies the historical time or min
            // number of tasks constraints. Freeform tasks are also always shown.
            boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
            boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
                    (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
            boolean isLaunchTarget = taskKey.id == runningTaskId;

            // The last stack active time is the baseline for which we show visible tasks.  Since
            // the system will store all the tasks, we don't want to show the tasks prior to the
            // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy
            // the other stack-task constraints.
            if (isStackTask && newLastStackActiveTime < 0) {
                newLastStackActiveTime = t.lastActiveTime;
            }

            // 加載標題,圖標和顏色
            ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
            String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
            String titleDescription = loader.getAndUpdateContentDescription(taskKey, res);
            String dismissDescription = String.format(dismissDescFormat, titleDescription);
            String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
            Drawable icon = isStackTask
                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                    : null;

            // 見3 縮略圖的獲取
            Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false /* loadIfNotCached */);
            int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
            int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
            boolean isSystemApp = (info != null) &&
                    ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);

            // 將任務添加到棧
            Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
                    thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
                    activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
                    t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity);

            allTasks.add(task);
            affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
            affiliatedTasks.put(taskKey.id, taskKey);
        }
        if (newLastStackActiveTime != -1) {
            Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
                    newLastStackActiveTime);
        }

        // Initialize the stacks
        mStack = new TaskStack();
        mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
    }

2.2.1 獲取mRecentTasks

文件:RecentsTaskLoadPlan.java

    public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) {
        int currentUserId = UserHandle.USER_CURRENT;
        updateCurrentQuietProfilesCache(currentUserId);
        SystemServicesProxy ssp = Recents.getSystemServices();
        // 見2.3
        mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);

        // 按照most-recent to least-recent的順序進行排序
        Collections.reverse(mRawTasks);
    }

2.3 getRecentTasks

文件:SystemServicesProxy.java

    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
            boolean includeFrontMostExcludedTask, ArraySet<Integer> quietProfileIds) {
        if (mAm == null) return null;

        ......

        // 移除掉 home/recents/excluded 這三種tasks
        int minNumTasksToQuery = 10;
        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
        int flags = ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
                ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
                ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
                ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                ActivityManager.RECENT_INCLUDE_PROFILES;
        if (includeFrontMostExcludedTask) {
            flags |= ActivityManager.RECENT_WITH_EXCLUDED;
        }
        List<ActivityManager.RecentTaskInfo> tasks = null;
        try {
            // 見2.4 得到RecentTaskInfo
            tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to get recent tasks", e);
        }

        // 如果沒有獲得可用的tasks,那就提前退出
        if (tasks == null) {
            return new ArrayList<>();
        }

        boolean isFirstValidTask = true;
        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
        while (iter.hasNext()) {
            ActivityManager.RecentTaskInfo t = iter.next();

            // NOTE: The order of these checks happens in the expected order of the traversal of the
            // tasks

            // Remove the task if it or it's package are blacklsited
            if (sRecentsBlacklist.contains(t.realActivity.getClassName()) ||
                    sRecentsBlacklist.contains(t.realActivity.getPackageName())) {
                iter.remove();
                continue;
            }

            // Remove the task if it is marked as excluded, unless it is the first most task and we
            // are requested to include it
            boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                    == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
            isExcluded |= quietProfileIds.contains(t.userId);
            // 顯示每一個任務信息的LOG***
            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
            t.userId, t.firstActiveTime, t.lastActiveTime);
            Log.d(TAG, "getRecentTasks:TASK = " + taskKey.toString()
                  + "/isExcluded = " + isExcluded
                  + "/includeFrontMostExcludedTask = " + includeFrontMostExcludedTask
                  + "/isFirstValidTask = " + isFirstValidTask
                  + "/t.id = " + t.id);
            if (isExcluded && (!isFirstValidTask || !includeFrontMostExcludedTask)) {
                iter.remove();
            }

            isFirstValidTask = false;
        }

        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
    }

這個方法的作用是返回一個最近任務的list

2.4 得到RecentTaskInfo

通過binder調用,可以得知最後調用的是AMS的getRecentTasks
文件:ActivityManagerService.java

    @Override
    public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
            int userId) {

            ......

            // 見2.4.1 根據userId來獲取mRecentTasks
            mRecentTasks.loadUserRecentsLocked(userId);

            ......

            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Only add calling user or related users recent tasks
                if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
                    continue;
                }

                if (tr.realActivitySuspended) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
                    continue;
                }

                if (i == 0
                        || withExcluded
                        || (tr.intent == null)
                        || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                                == 0)) {

                    ......  // 根據之前設置的flag去排除掉不需要的task                   

                    // 見2.4.2 調用createRecentTaskInfoFromTaskRecord()方法把mRecentTasks裏的TaskRecord轉換成RecentTaskInfo
                    ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
                    if (!detailed) {
                        rti.baseIntent.replaceExtras((Bundle)null);
                    }

                    res.add(rti);
                    maxNum--;
                }
            }
            return new ParceledListSlice<>(res);
        }
    }

2.4.1 根據userId來獲取mRecentTasks

文件:RecentTasks.java

    void loadUserRecentsLocked(int userId) {
        // 如果沒有存儲則進來,如果存儲了就不做任何事情
        if (!mUsersWithRecentsLoaded.get(userId)) {
            // 如果沒有導入則導入
            loadPersistedTaskIdsForUserLocked(userId);
            Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
            // 通過restoreTasksForUserLocked獲取TaskRecord
            addAll(mTaskPersister.restoreTasksForUserLocked(userId)); 
            cleanupLocked(userId);
            mUsersWithRecentsLoaded.put(userId, true);
        }
    }

其中restoreTasksForUserLocked主要是去解析xml文件,位於/data/system_ce/0/recent_tasks目錄下,可以看到這些task信息是以文件形式保存的,這就是重啓後進RecentsActivity看到task還在的原因。解析完這些xml文件就獲取到了初始的task信息。但實際上loadUserRecentsLocked裏面的語句是只會在開機初始化時執行一次

2.4.2 把mRecentTasks裏的TaskRecord轉換成RecentTaskInfo

文件:ActivityManagerService.java

    private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
        // Update the task description to reflect any changes in the task stack
        tr.updateTaskDescription();
        // Compose the recent task info
        ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
        rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
        rti.persistentId = tr.taskId;
        rti.baseIntent = new Intent(tr.getBaseIntent());
        rti.origActivity = tr.origActivity;
        rti.realActivity = tr.realActivity;
        rti.description = tr.lastDescription;
        rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;
        rti.userId = tr.userId;
        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
        rti.firstActiveTime = tr.firstActiveTime;
        rti.lastActiveTime = tr.lastActiveTime;
        rti.affiliatedTaskId = tr.mAffiliatedTaskId;
        rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
        rti.numActivities = 0;
        if (tr.mBounds != null) {
            rti.bounds = new Rect(tr.mBounds);
        }
        rti.isDockable = tr.canGoInDockedStack();
        rti.resizeMode = tr.mResizeMode;

        ActivityRecord base = null;
        ActivityRecord top = null;
        ActivityRecord tmp;

        for (int i = tr.mActivities.size() - 1; i >= 0; --i) {
            tmp = tr.mActivities.get(i);
            if (tmp.finishing) {
                continue;
            }
            base = tmp;
            if (top == null || (top.state == ActivityState.INITIALIZING)) {
                top = base;
            }
            rti.numActivities++;
        }

        rti.baseActivity = (base != null) ? base.intent.getComponent() : null;
        rti.topActivity = (top != null) ? top.intent.getComponent() : null;

        return rti;
    }

Task的獲取就講到這裏,接下來講講縮略圖的獲取

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章