美文网首页SystemUI
SystemUI问题分析之Recents不显示TaskView

SystemUI问题分析之Recents不显示TaskView

作者: Monster_de47 | 来源:发表于2018-12-18 17:13 被阅读189次

    问题

    操作描述:任意打开多个应用后切换到后台,点击最近任务图标显示后台应用为空。
    出现机型:Android 8.1 Go版本
    问题截图:


    问题界面

    分析过程

    拿到这个问题,首先考虑的是有哪些情况会导致这个问题:
    case A:没有获取到activity stack中的数据;
    case B:数据获取到了,没有获取到各个task的快照;
    case C:其他未知原因;
    解决这个问题我们要了解recents获取最近任务数据的基本流程:


    Recents数据获取

    从时序上看,在RecentsTaskLoadPlan中获取stack中的app数据,preloadPlan的代码如下:

    /**
      * Preloads the list of recent tasks from the system. After this call, the TaskStack will
      * have a list of all the recent tasks with their metadata, not including icons or
      * thumbnails which were not cached and have to be loaded.
      *
      * The tasks will be ordered by:
      * - least-recent to most-recent stack tasks
      * - least-recent to most-recent freeform tasks
      *
      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
      * this call (callers should synchronize on the loader before making this call).
      */
    void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
                boolean includeFrontMostExcludedTask) {
            Resources res = mContext.getResources();
            ArrayList<Task> allTasks = new ArrayList<>();
            if (mRawTasks == null) {
                preloadRawTasks(includeFrontMostExcludedTask);
            }
    
            SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
            SparseIntArray affiliatedTaskCounts = new SparseIntArray();
            SparseBooleanArray lockedUsers = new SparseBooleanArray();
            String dismissDescFormat = mContext.getString(
                    R.string.accessibility_recents_item_will_be_dismissed);
            String appInfoDescFormat = mContext.getString(
                    R.string.accessibility_recents_item_open_app_info);
            int currentUserId = mPreloadedUserId;
            long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId);
            long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(),
                    Settings.Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId);
            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, ActivityManager.RecentTaskInfo.getStackId(t), t.baseIntent,
                ActivityManager.RecentTaskInfo.getUserId(t), ActivityManager.RecentTaskInfo.getFirstActiveTime(t),
                        ActivityManager.RecentTaskInfo.getLastActiveTime(t));
    
                // This task is only shown in the stack if it satisfies the historical time or min
                // number of tasks constraints. Freeform tasks are also always shown.
                boolean isFreeformTask = SystemServicesProxy.isFreeformStack(ActivityManagerDelegator.RecentTaskInfoDelegator.getStackId(t));
                boolean isStackTask;
                if (Recents.getConfiguration().isGridEnabled) {
                    // When grid layout is enabled, we only show the first
                    // TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT} tasks.
                    isStackTask = ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime &&
                        i >= taskCount - TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
                } else if (Recents.getConfiguration().isLowRamDevice) {
                    // Show a max of 3 items
                    isStackTask = ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime &&
                            i >= taskCount - TaskStackLowRamLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
                } else {
                    isStackTask = isFreeformTask || !isHistoricalTask(t) ||
                        (ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= 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 = ActivityManager.RecentTaskInfo.getLastActiveTime(t);
                }
    
                // Load the title, icon, and color
                ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
                String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
                String titleDescription = loader.getAndUpdateContentDescription(taskKey,
                        t.taskDescription, res);
                String dismissDescription = String.format(dismissDescFormat, titleDescription);
                String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
                Drawable icon = isStackTask
                        ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                        : null;
                ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
                        false /* loadIfNotCached */, false /* storeInCache */);
                int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
                int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
                boolean isSystemApp = (info != null) &&
                        ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
                if (lockedUsers.indexOfKey(ActivityManager.RecentTaskInfo.getUserId(t)) < 0) {
                    lockedUsers.put(ActivityManager.RecentTaskInfo.getUserId(t), Recents.getSystemServices().isDeviceLocked(ActivityManager.RecentTaskInfo.getUserId(t)));
                }
                boolean isLocked = lockedUsers.get(ActivityManager.RecentTaskInfo.getUserId(t));
    
                // Add the task to the stack
                Task task = new Task(taskKey, t.affiliatedTaskId, ActivityManager.RecentTaskInfo.getAffiliatedTaskColor(t), icon,
                        thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
                        activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
                ActivityManagerRecentTaskInfo.supportsSplitScreenMultiWindow(t), ActivityManager.RecentTaskInfo.bounds(t),
                        t.taskDescription, ActivityManager.RecentTaskInfo.resizeMode(t), t.topActivity, isLocked);
    
                allTasks.add(task);
                affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
                affiliatedTasks.put(taskKey.id, taskKey);
            }
            if (newLastStackActiveTime != -1) {
                Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
                        newLastStackActiveTime, currentUserId);
            }
    
            // Initialize the stacks
            mStack = new TaskStack();
            mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
    }
    

    可以看出mRawTask就是获取到的最近任务的list,我们在遍历该list之前,将list的size打印出来。打印出Log如下:

    06-13 08:59:17.156 1011-2095/com.android.systemui V/monster: taskCount: 2
    

    在此之前打开了settings 和 phone 应用,如上述log,recents已经获取到最近任务数据。接下来,需要查一下是否是没有获取到对应的task的快照呢?
    其获取的地方在此处:

    ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
                        false /* loadIfNotCached */, false /* storeInCache */);
    

    /frameworks/base/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java

    /**
         * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
         */
        synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
                boolean storeInCache) {
            SystemServicesProxy ssp = Recents.getSystemServices();
    
            ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey);
            if (cached != null) {
                return cached;
            }
    
            cached = mTempCache.getAndInvalidateIfModified(taskKey);
            if (cached != null) {
                mThumbnailCache.put(taskKey, cached);
                return cached;
            }
    
            if (loadIfNotCached) {
                RecentsConfiguration config = Recents.getConfiguration();
                if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
                    // Load the thumbnail from the system
                    ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id,
                            true /* reducedResolution */);
                    if (thumbnailData.thumbnail != null) {
                        if (storeInCache) {
                            mThumbnailCache.put(taskKey, thumbnailData);
                        }
                        return thumbnailData;
                    }
                }
            }
    
            // We couldn't load any thumbnail
            return null;
        }
    

    所以需要在获取的地方判断获取的thumbnail是否为空?获取log如下:

    06-13 09:30:33.900 1003-1251/com.android.systemui V/monster: thumbnail: true
    06-13 09:30:36.669 1003-1003/com.android.systemui V/monster: thumbnail: true
    

    可以看出,也获取到了对应的快照了。那么需要再去寻找其他可疑的地方。
    从preload()函数中可以看到这么一段逻辑:

    if (Recents.getConfiguration().isGridEnabled) {
                    // When grid layout is enabled, we only show the first
                    // TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT} tasks.
                    isStackTask = ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime &&
                        i >= taskCount - TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
                } else if (Recents.getConfiguration().isLowRamDevice) {
                    // Show a max of 3 items
                    isStackTask = ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime &&
                            i >= taskCount - TaskStackLowRamLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
                } else {
                    isStackTask = isFreeformTask || !isHistoricalTask(t) ||
                        (ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
                }
    

    从上面可以看出在LowRam的机器上(Android Go)版本,google设计了这么一个逻辑,获取task的lastActiveTime,与一个阈值进行比较,如果小于这个阈值,则获取不到app的相关信息,并不让显示taskView。所以将这些时间打印出来,观察是否有无异常,log如下:

    12-16 12:05:11.241 942-4048/com.android.systemui V/monster: legacyLastStackActiveTime: 0
        lastStackActiveTime: 1505966512318
    12-16 12:05:11.246 942-4048/com.android.systemui V/monster: getLastActiveTime: 1450238711095
    

    异常log中获取到了一些时间戳,转化成正常时间:

    1505966512318 > 2017-09-21 12:01:52
    1450238711095 > 2015-12-16 12:05:11
    

    这里的阈值是1505966512318,而最近任务的lastActiveTime是1450238711095,前面有介绍到此逻辑:

    else if (Recents.getConfiguration().isLowRamDevice) {
                    // Show a max of 3 items
                    isStackTask = ActivityManager.RecentTaskInfo.getLastActiveTime(t) >= lastStackActiveTime &&
                            i >= taskCount - TaskStackLowRamLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
                } 
    

    由于设备是Android Go,这里的isStackTask flag当前就是false了,而正是因为这个flag导致recents在处理的时候,认为当前获取的的recents task是非法的,故没有显示taskView。
    之后经确认,当时问题发现者存在手动调动时间,导致获取的stack active time在阈值时间之前,联网校准时间后,该问题解决。

    相关文章

      网友评论

        本文标题:SystemUI问题分析之Recents不显示TaskView

        本文链接:https://www.haomeiwen.com/subject/fvulkqtx.html