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) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime); 47 48 private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR); 49 50 private int mCallingUid; 51 private int mUserId; 52 private boolean mCrossUser; 53 private ArraySet<Integer> mProfileIds; 54 private boolean mAllowed; 55 private boolean mFilterOnlyVisibleRecents; 56 private Task mTopDisplayFocusRootTask; 57 private Task mTopDisplayAdjacentTask; 58 private RecentTasks mRecentTasks; 59 private boolean mKeepIntentExtra; 60 getTasks(int maxNum, List<RunningTaskInfo> list, int flags, RootWindowContainer root, int callingUid, ArraySet<Integer> profileIds)61 void getTasks(int maxNum, List<RunningTaskInfo> list, int flags, 62 RootWindowContainer root, int callingUid, ArraySet<Integer> profileIds) { 63 // Return early if there are no tasks to fetch 64 if (maxNum <= 0) { 65 return; 66 } 67 68 // Gather all of the tasks across all of the tasks, and add them to the sorted set 69 mTmpSortedSet.clear(); 70 mCallingUid = callingUid; 71 mUserId = UserHandle.getUserId(callingUid); 72 mCrossUser = (flags & FLAG_CROSS_USERS) == FLAG_CROSS_USERS; 73 mProfileIds = profileIds; 74 mAllowed = (flags & FLAG_ALLOWED) == FLAG_ALLOWED; 75 mFilterOnlyVisibleRecents = 76 (flags & FLAG_FILTER_ONLY_VISIBLE_RECENTS) == FLAG_FILTER_ONLY_VISIBLE_RECENTS; 77 mTopDisplayFocusRootTask = root.getTopDisplayFocusedRootTask(); 78 mRecentTasks = root.mService.getRecentTasks(); 79 mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA; 80 81 if (mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) { 82 mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask(); 83 } else { 84 mTopDisplayAdjacentTask = null; 85 } 86 87 final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this, 88 PooledLambda.__(Task.class)); 89 root.forAllLeafTasks(c, false); 90 c.recycle(); 91 92 // Take the first {@param maxNum} tasks and create running task infos for them 93 final Iterator<Task> iter = mTmpSortedSet.iterator(); 94 while (iter.hasNext()) { 95 if (maxNum == 0) { 96 break; 97 } 98 99 final Task task = iter.next(); 100 list.add(createRunningTaskInfo(task)); 101 maxNum--; 102 } 103 } 104 processTask(Task task)105 private void processTask(Task task) { 106 if (task.getTopNonFinishingActivity() == null) { 107 // Skip if there are no activities in the task 108 return; 109 } 110 if (task.effectiveUid != mCallingUid) { 111 if (task.mUserId != mUserId && !mCrossUser && !mProfileIds.contains(task.mUserId)) { 112 // Skip if the caller does not have cross user permission or cannot access 113 // the task's profile 114 return; 115 } 116 if (!mAllowed) { 117 // Skip if the caller isn't allowed to fetch this task 118 return; 119 } 120 } 121 if (mFilterOnlyVisibleRecents 122 && task.getActivityType() != ACTIVITY_TYPE_HOME 123 && task.getActivityType() != ACTIVITY_TYPE_RECENTS 124 && !mRecentTasks.isVisibleRecentTask(task)) { 125 // Skip if this task wouldn't be visibile (ever) from recents, with an exception for the 126 // home & recent tasks 127 return; 128 } 129 130 final Task rootTask = task.getRootTask(); 131 if (rootTask == mTopDisplayFocusRootTask && rootTask.getTopMostTask() == task) { 132 // For the focused top root task, update the last root task active time so that it 133 // can be used to determine the order of the tasks (it may not be set for newly 134 // created tasks) 135 task.touchActiveTime(); 136 } else if (rootTask == mTopDisplayAdjacentTask && rootTask.getTopMostTask() == task) { 137 // The short-term workaround for launcher could get suitable running task info in 138 // split screen. 139 task.touchActiveTime(); 140 // TreeSet doesn't allow same value and make sure this task is lower than focus one. 141 task.lastActiveTime--; 142 } 143 144 mTmpSortedSet.add(task); 145 } 146 147 /** Constructs a {@link RunningTaskInfo} from a given {@param task}. */ createRunningTaskInfo(Task task)148 private RunningTaskInfo createRunningTaskInfo(Task task) { 149 final RunningTaskInfo rti = new RunningTaskInfo(); 150 task.fillTaskInfo(rti, !mKeepIntentExtra); 151 // Fill in some deprecated values 152 rti.id = rti.taskId; 153 return rti; 154 } 155 } 156