1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 22 import android.app.ActivityManager.RunningTaskInfo; 23 import android.os.UserHandle; 24 import android.util.ArraySet; 25 26 import com.android.internal.util.function.pooled.PooledConsumer; 27 import com.android.internal.util.function.pooled.PooledLambda; 28 29 import java.util.Comparator; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.TreeSet; 33 34 /** 35 * Class for resolving the set of running tasks in the system. 36 */ 37 class RunningTasks { 38 39 static final int FLAG_FILTER_ONLY_VISIBLE_RECENTS = 1; 40 static final int FLAG_ALLOWED = 1 << 1; 41 static final int FLAG_CROSS_USERS = 1 << 2; 42 static final int FLAG_KEEP_INTENT_EXTRA = 1 << 3; 43 44 // Comparator to sort by last active time (descending) 45 private static final Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR = 46 (o1, o2) -> { 47 return o1.lastActiveTime == o2.lastActiveTime 48 ? Integer.signum(o2.mTaskId - o1.mTaskId) : 49 Long.signum(o2.lastActiveTime - o1.lastActiveTime); 50 }; 51 52 private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR); 53 54 private int mCallingUid; 55 private int mUserId; 56 private boolean mCrossUser; 57 private ArraySet<Integer> mProfileIds; 58 private boolean mAllowed; 59 private boolean mFilterOnlyVisibleRecents; 60 private RecentTasks mRecentTasks; 61 private boolean mKeepIntentExtra; 62 getTasks(int maxNum, List<RunningTaskInfo> list, int flags, RecentTasks recentTasks, WindowContainer root, int callingUid, ArraySet<Integer> profileIds)63 void getTasks(int maxNum, List<RunningTaskInfo> list, int flags, RecentTasks recentTasks, 64 WindowContainer root, int callingUid, ArraySet<Integer> profileIds) { 65 // Return early if there are no tasks to fetch 66 if (maxNum <= 0) { 67 return; 68 } 69 70 // Gather all of the tasks across all of the tasks, and add them to the sorted set 71 mTmpSortedSet.clear(); 72 mCallingUid = callingUid; 73 mUserId = UserHandle.getUserId(callingUid); 74 mCrossUser = (flags & FLAG_CROSS_USERS) == FLAG_CROSS_USERS; 75 mProfileIds = profileIds; 76 mAllowed = (flags & FLAG_ALLOWED) == FLAG_ALLOWED; 77 mFilterOnlyVisibleRecents = 78 (flags & FLAG_FILTER_ONLY_VISIBLE_RECENTS) == FLAG_FILTER_ONLY_VISIBLE_RECENTS; 79 mRecentTasks = recentTasks; 80 mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA; 81 82 final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this, 83 PooledLambda.__(Task.class)); 84 root.forAllLeafTasks(c, false); 85 c.recycle(); 86 87 // Take the first {@param maxNum} tasks and create running task infos for them 88 final Iterator<Task> iter = mTmpSortedSet.iterator(); 89 while (iter.hasNext()) { 90 if (maxNum == 0) { 91 break; 92 } 93 94 final Task task = iter.next(); 95 list.add(createRunningTaskInfo(task)); 96 maxNum--; 97 } 98 } 99 processTask(Task task)100 private void processTask(Task task) { 101 if (task.getTopNonFinishingActivity() == null) { 102 // Skip if there are no activities in the task 103 return; 104 } 105 if (task.effectiveUid != mCallingUid) { 106 if (task.mUserId != mUserId && !mCrossUser && !mProfileIds.contains(task.mUserId)) { 107 // Skip if the caller does not have cross user permission or cannot access 108 // the task's profile 109 return; 110 } 111 if (!mAllowed) { 112 // Skip if the caller isn't allowed to fetch this task 113 return; 114 } 115 } 116 if (mFilterOnlyVisibleRecents 117 && task.getActivityType() != ACTIVITY_TYPE_HOME 118 && task.getActivityType() != ACTIVITY_TYPE_RECENTS 119 && !mRecentTasks.isVisibleRecentTask(task)) { 120 // Skip if this task wouldn't be visibile (ever) from recents, with an exception for the 121 // home & recent tasks 122 return; 123 } 124 125 if (task.isVisible()) { 126 // For the visible task, update the last active time so that it can be used to determine 127 // the order of the tasks (it may not be set for newly created tasks) 128 task.touchActiveTime(); 129 if (!task.isFocused()) { 130 // TreeSet doesn't allow the same value and make sure this task is lower than the 131 // focused one. 132 task.lastActiveTime -= mTmpSortedSet.size(); 133 } 134 } 135 136 mTmpSortedSet.add(task); 137 } 138 139 /** Constructs a {@link RunningTaskInfo} from a given {@param task}. */ createRunningTaskInfo(Task task)140 private RunningTaskInfo createRunningTaskInfo(Task task) { 141 final RunningTaskInfo rti = new RunningTaskInfo(); 142 task.fillTaskInfo(rti, !mKeepIntentExtra); 143 // Fill in some deprecated values 144 rti.id = rti.taskId; 145 146 if (!mAllowed) { 147 Task.trimIneffectiveInfo(task, rti); 148 } 149 return rti; 150 } 151 } 152