Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2014 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.am;
     18 
     19 import static android.app.ActivityManager.FLAG_AND_UNLOCKED;
     20 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
     21 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
     22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
     23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
     24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
     25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
     26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
     27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     28 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
     29 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
     30 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
     31 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
     32 
     33 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
     34 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
     35 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
     36 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
     37 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
     38 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
     39 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
     40 import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
     41 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
     42 
     43 import android.app.ActivityManager;
     44 import android.app.AppGlobals;
     45 import android.content.ComponentName;
     46 import android.content.Intent;
     47 import android.content.pm.ActivityInfo;
     48 import android.content.pm.ApplicationInfo;
     49 import android.content.pm.IPackageManager;
     50 import android.content.pm.PackageManager;
     51 import android.content.pm.ParceledListSlice;
     52 import android.content.pm.UserInfo;
     53 import android.content.res.Resources;
     54 import android.graphics.Bitmap;
     55 import android.graphics.Rect;
     56 import android.os.Bundle;
     57 import android.os.Environment;
     58 import android.os.IBinder;
     59 import android.os.RemoteException;
     60 import android.os.SystemProperties;
     61 import android.os.UserHandle;
     62 import android.text.TextUtils;
     63 import android.util.ArraySet;
     64 import android.util.Slog;
     65 import android.util.SparseArray;
     66 import android.util.SparseBooleanArray;
     67 
     68 import com.android.internal.annotations.VisibleForTesting;
     69 import com.android.server.am.TaskRecord.TaskActivitiesReport;
     70 
     71 import com.google.android.collect.Sets;
     72 
     73 import java.io.File;
     74 import java.io.PrintWriter;
     75 import java.util.ArrayList;
     76 import java.util.Arrays;
     77 import java.util.Collections;
     78 import java.util.Comparator;
     79 import java.util.HashMap;
     80 import java.util.Set;
     81 import java.util.concurrent.TimeUnit;
     82 
     83 /**
     84  * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
     85  * least recent.
     86  *
     87  * The trimming logic can be boiled down to the following.  For recent task list with a number of
     88  * tasks, the visible tasks are an interleaving subset of tasks that would normally be presented to
     89  * the user. Non-visible tasks are not considered for trimming. Of the visible tasks, only a
     90  * sub-range are presented to the user, based on the device type, last task active time, or other
     91  * task state. Tasks that are not in the visible range and are not returnable from the SystemUI
     92  * (considering the back stack) are considered trimmable. If the device does not support recent
     93  * tasks, then trimming is completely disabled.
     94  *
     95  * eg.
     96  * L = [TTTTTTTTTTTTTTTTTTTTTTTTTT] // list of tasks
     97  *     [VVV  VV   VVVV  V V V     ] // Visible tasks
     98  *     [RRR  RR   XXXX  X X X     ] // Visible range tasks, eg. if the device only shows 5 tasks,
     99  *                                  // 'X' tasks are trimmed.
    100  */
    101 class RecentTasks {
    102     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
    103     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
    104     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
    105     private static final boolean TRIMMED = true;
    106 
    107     private static final int DEFAULT_INITIAL_CAPACITY = 5;
    108 
    109     // Whether or not to move all affiliated tasks to the front when one of the tasks is launched
    110     private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false;
    111 
    112     // Comparator to sort by taskId
    113     private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
    114             (lhs, rhs) -> rhs.taskId - lhs.taskId;
    115 
    116     // Placeholder variables to keep track of activities/apps that are no longer avialble while
    117     // iterating through the recents list
    118     private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo();
    119     private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo();
    120 
    121     /**
    122      * Callbacks made when manipulating the list.
    123      */
    124     interface Callbacks {
    125         /**
    126          * Called when a task is added to the recent tasks list.
    127          */
    128         void onRecentTaskAdded(TaskRecord task);
    129 
    130         /**
    131          * Called when a task is removed from the recent tasks list.
    132          */
    133         void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed);
    134     }
    135 
    136     /**
    137      * Save recent tasks information across reboots.
    138      */
    139     private final TaskPersister mTaskPersister;
    140     private final ActivityManagerService mService;
    141     private final UserController mUserController;
    142 
    143     /**
    144      * Keeps track of the static recents package/component which is granted additional permissions
    145      * to call recents-related APIs.
    146      */
    147     private int mRecentsUid = -1;
    148     private ComponentName mRecentsComponent = null;
    149 
    150     /**
    151      * Mapping of user id -> whether recent tasks have been loaded for that user.
    152      */
    153     private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
    154             DEFAULT_INITIAL_CAPACITY);
    155 
    156     /**
    157      * Stores for each user task ids that are taken by tasks residing in persistent storage. These
    158      * tasks may or may not currently be in memory.
    159      */
    160     private final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
    161             DEFAULT_INITIAL_CAPACITY);
    162 
    163     // List of all active recent tasks
    164     private final ArrayList<TaskRecord> mTasks = new ArrayList<>();
    165     private final ArrayList<Callbacks> mCallbacks = new ArrayList<>();
    166 
    167     // These values are generally loaded from resources, but can be set dynamically in the tests
    168     private boolean mHasVisibleRecentTasks;
    169     private int mGlobalMaxNumTasks;
    170     private int mMinNumVisibleTasks;
    171     private int mMaxNumVisibleTasks;
    172     private long mActiveTasksSessionDurationMs;
    173 
    174     // Mainly to avoid object recreation on multiple calls.
    175     private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
    176     private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
    177     private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
    178     private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
    179     private final TaskActivitiesReport mTmpReport = new TaskActivitiesReport();
    180 
    181     @VisibleForTesting
    182     RecentTasks(ActivityManagerService service, TaskPersister taskPersister,
    183             UserController userController) {
    184         mService = service;
    185         mUserController = userController;
    186         mTaskPersister = taskPersister;
    187         mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic();
    188         mHasVisibleRecentTasks = true;
    189     }
    190 
    191     RecentTasks(ActivityManagerService service, ActivityStackSupervisor stackSupervisor) {
    192         final File systemDir = Environment.getDataSystemDirectory();
    193         final Resources res = service.mContext.getResources();
    194         mService = service;
    195         mUserController = service.mUserController;
    196         mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this);
    197         mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic();
    198         mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
    199         loadParametersFromResources(res);
    200     }
    201 
    202     @VisibleForTesting
    203     void setParameters(int minNumVisibleTasks, int maxNumVisibleTasks,
    204             long activeSessionDurationMs) {
    205         mMinNumVisibleTasks = minNumVisibleTasks;
    206         mMaxNumVisibleTasks = maxNumVisibleTasks;
    207         mActiveTasksSessionDurationMs = activeSessionDurationMs;
    208     }
    209 
    210     @VisibleForTesting
    211     void setGlobalMaxNumTasks(int globalMaxNumTasks) {
    212         mGlobalMaxNumTasks = globalMaxNumTasks;
    213     }
    214 
    215     /**
    216      * Loads the parameters from the system resources.
    217      */
    218     @VisibleForTesting
    219     void loadParametersFromResources(Resources res) {
    220         if (ActivityManager.isLowRamDeviceStatic()) {
    221             mMinNumVisibleTasks = res.getInteger(
    222                     com.android.internal.R.integer.config_minNumVisibleRecentTasks_lowRam);
    223             mMaxNumVisibleTasks = res.getInteger(
    224                     com.android.internal.R.integer.config_maxNumVisibleRecentTasks_lowRam);
    225         } else if (SystemProperties.getBoolean("ro.recents.grid", false)) {
    226             mMinNumVisibleTasks = res.getInteger(
    227                     com.android.internal.R.integer.config_minNumVisibleRecentTasks_grid);
    228             mMaxNumVisibleTasks = res.getInteger(
    229                     com.android.internal.R.integer.config_maxNumVisibleRecentTasks_grid);
    230         } else {
    231             mMinNumVisibleTasks = res.getInteger(
    232                     com.android.internal.R.integer.config_minNumVisibleRecentTasks);
    233             mMaxNumVisibleTasks = res.getInteger(
    234                     com.android.internal.R.integer.config_maxNumVisibleRecentTasks);
    235         }
    236         final int sessionDurationHrs = res.getInteger(
    237                 com.android.internal.R.integer.config_activeTaskDurationHours);
    238         mActiveTasksSessionDurationMs = (sessionDurationHrs > 0)
    239                 ? TimeUnit.HOURS.toMillis(sessionDurationHrs)
    240                 : -1;
    241     }
    242 
    243     /**
    244      * Loads the static recents component.  This is called after the system is ready, but before
    245      * any dependent services (like SystemUI) is started.
    246      */
    247     void loadRecentsComponent(Resources res) {
    248         final String rawRecentsComponent = res.getString(
    249                 com.android.internal.R.string.config_recentsComponentName);
    250         if (TextUtils.isEmpty(rawRecentsComponent)) {
    251             return;
    252         }
    253 
    254         final ComponentName cn = ComponentName.unflattenFromString(rawRecentsComponent);
    255         if (cn != null) {
    256             try {
    257                 final ApplicationInfo appInfo = AppGlobals.getPackageManager()
    258                         .getApplicationInfo(cn.getPackageName(), 0, mService.mContext.getUserId());
    259                 if (appInfo != null) {
    260                     mRecentsUid = appInfo.uid;
    261                     mRecentsComponent = cn;
    262                 }
    263             } catch (RemoteException e) {
    264                 Slog.w(TAG, "Could not load application info for recents component: " + cn);
    265             }
    266         }
    267     }
    268 
    269     /**
    270      * @return whether the current caller has the same uid as the recents component.
    271      */
    272     boolean isCallerRecents(int callingUid) {
    273         return UserHandle.isSameApp(callingUid, mRecentsUid);
    274     }
    275 
    276     /**
    277      * @return whether the given component is the recents component and shares the same uid as the
    278      *         recents component.
    279      */
    280     boolean isRecentsComponent(ComponentName cn, int uid) {
    281         return cn.equals(mRecentsComponent) && UserHandle.isSameApp(uid, mRecentsUid);
    282     }
    283 
    284     /**
    285      * @return whether the home app is also the active handler of recent tasks.
    286      */
    287     boolean isRecentsComponentHomeActivity(int userId) {
    288         final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked()
    289                 .getDefaultHomeActivity(userId);
    290         return defaultHomeActivity != null && mRecentsComponent != null &&
    291                 defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName());
    292     }
    293 
    294     /**
    295      * @return the recents component.
    296      */
    297     ComponentName getRecentsComponent() {
    298         return mRecentsComponent;
    299     }
    300 
    301     /**
    302      * @return the uid for the recents component.
    303      */
    304     int getRecentsComponentUid() {
    305         return mRecentsUid;
    306     }
    307 
    308     void registerCallback(Callbacks callback) {
    309         mCallbacks.add(callback);
    310     }
    311 
    312     void unregisterCallback(Callbacks callback) {
    313         mCallbacks.remove(callback);
    314     }
    315 
    316     private void notifyTaskAdded(TaskRecord task) {
    317         for (int i = 0; i < mCallbacks.size(); i++) {
    318             mCallbacks.get(i).onRecentTaskAdded(task);
    319         }
    320     }
    321 
    322     private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed) {
    323         for (int i = 0; i < mCallbacks.size(); i++) {
    324             mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed);
    325         }
    326     }
    327 
    328     /**
    329      * Loads the persistent recentTasks for {@code userId} into this list from persistent storage.
    330      * Does nothing if they are already loaded.
    331      *
    332      * @param userId the user Id
    333      */
    334     void loadUserRecentsLocked(int userId) {
    335         if (mUsersWithRecentsLoaded.get(userId)) {
    336             // User already loaded, return early
    337             return;
    338         }
    339 
    340         // Load the task ids if not loaded.
    341         loadPersistedTaskIdsForUserLocked(userId);
    342 
    343         // Check if any tasks are added before recents is loaded
    344         final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
    345         for (final TaskRecord task : mTasks) {
    346             if (task.userId == userId && shouldPersistTaskLocked(task)) {
    347                 preaddedTasks.put(task.taskId, true);
    348             }
    349         }
    350 
    351         Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
    352         mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
    353         cleanupLocked(userId);
    354         mUsersWithRecentsLoaded.put(userId, true);
    355 
    356         // If we have tasks added before loading recents, we need to update persistent task IDs.
    357         if (preaddedTasks.size() > 0) {
    358             syncPersistentTaskIdsLocked();
    359         }
    360     }
    361 
    362     private void loadPersistedTaskIdsForUserLocked(int userId) {
    363         // An empty instead of a null set here means that no persistent taskIds were present
    364         // on file when we loaded them.
    365         if (mPersistedTaskIds.get(userId) == null) {
    366             mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
    367             Slog.i(TAG, "Loaded persisted task ids for user " + userId);
    368         }
    369     }
    370 
    371     /**
    372      * @return whether the {@param taskId} is currently in use for the given user.
    373      */
    374     boolean containsTaskId(int taskId, int userId) {
    375         loadPersistedTaskIdsForUserLocked(userId);
    376         return mPersistedTaskIds.get(userId).get(taskId);
    377     }
    378 
    379     /**
    380      * @return all the task ids for the user with the given {@param userId}.
    381      */
    382     SparseBooleanArray getTaskIdsForUser(int userId) {
    383         loadPersistedTaskIdsForUserLocked(userId);
    384         return mPersistedTaskIds.get(userId);
    385     }
    386 
    387     /**
    388      * Kicks off the task persister to write any pending tasks to disk.
    389      */
    390     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
    391         final ActivityStack stack = task != null ? task.getStack() : null;
    392         if (stack != null && stack.isHomeOrRecentsStack()) {
    393             // Never persist the home or recents stack.
    394             return;
    395         }
    396         syncPersistentTaskIdsLocked();
    397         mTaskPersister.wakeup(task, flush);
    398     }
    399 
    400     private void syncPersistentTaskIdsLocked() {
    401         for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
    402             int userId = mPersistedTaskIds.keyAt(i);
    403             if (mUsersWithRecentsLoaded.get(userId)) {
    404                 // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
    405                 // referenced here should not be null.
    406                 mPersistedTaskIds.valueAt(i).clear();
    407             }
    408         }
    409         for (int i = mTasks.size() - 1; i >= 0; i--) {
    410             final TaskRecord task = mTasks.get(i);
    411             if (shouldPersistTaskLocked(task)) {
    412                 // Set of persisted taskIds for task.userId should not be null here
    413                 // TODO Investigate why it can happen. For now initialize with an empty set
    414                 if (mPersistedTaskIds.get(task.userId) == null) {
    415                     Slog.wtf(TAG, "No task ids found for userId " + task.userId + ". task=" + task
    416                             + " mPersistedTaskIds=" + mPersistedTaskIds);
    417                     mPersistedTaskIds.put(task.userId, new SparseBooleanArray());
    418                 }
    419                 mPersistedTaskIds.get(task.userId).put(task.taskId, true);
    420             }
    421         }
    422     }
    423 
    424     private static boolean shouldPersistTaskLocked(TaskRecord task) {
    425         final ActivityStack stack = task.getStack();
    426         return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack());
    427     }
    428 
    429     void onSystemReadyLocked() {
    430         loadRecentsComponent(mService.mContext.getResources());
    431         mTasks.clear();
    432         mTaskPersister.startPersisting();
    433     }
    434 
    435     Bitmap getTaskDescriptionIcon(String path) {
    436         return mTaskPersister.getTaskDescriptionIcon(path);
    437     }
    438 
    439     void saveImage(Bitmap image, String path) {
    440         mTaskPersister.saveImage(image, path);
    441     }
    442 
    443     void flush() {
    444         synchronized (mService) {
    445             syncPersistentTaskIdsLocked();
    446         }
    447         mTaskPersister.flush();
    448     }
    449 
    450     /**
    451      * Returns all userIds for which recents from persistent storage are loaded into this list.
    452      *
    453      * @return an array of userIds.
    454      */
    455     int[] usersWithRecentsLoadedLocked() {
    456         int[] usersWithRecentsLoaded = new int[mUsersWithRecentsLoaded.size()];
    457         int len = 0;
    458         for (int i = 0; i < usersWithRecentsLoaded.length; i++) {
    459             int userId = mUsersWithRecentsLoaded.keyAt(i);
    460             if (mUsersWithRecentsLoaded.valueAt(i)) {
    461                 usersWithRecentsLoaded[len++] = userId;
    462             }
    463         }
    464         if (len < usersWithRecentsLoaded.length) {
    465             // should never happen.
    466             return Arrays.copyOf(usersWithRecentsLoaded, len);
    467         }
    468         return usersWithRecentsLoaded;
    469     }
    470 
    471     /**
    472      * Removes recent tasks and any other state kept in memory for the passed in user. Does not
    473      * touch the information present on persistent storage.
    474      *
    475      * @param userId the id of the user
    476      */
    477     void unloadUserDataFromMemoryLocked(int userId) {
    478         if (mUsersWithRecentsLoaded.get(userId)) {
    479             Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
    480             mUsersWithRecentsLoaded.delete(userId);
    481             removeTasksForUserLocked(userId);
    482         }
    483         mPersistedTaskIds.delete(userId);
    484         mTaskPersister.unloadUserDataFromMemory(userId);
    485     }
    486 
    487     /** Remove recent tasks for a user. */
    488     private void removeTasksForUserLocked(int userId) {
    489         if(userId <= 0) {
    490             Slog.i(TAG, "Can't remove recent task on user " + userId);
    491             return;
    492         }
    493 
    494         for (int i = mTasks.size() - 1; i >= 0; --i) {
    495             TaskRecord tr = mTasks.get(i);
    496             if (tr.userId == userId) {
    497                 if(DEBUG_TASKS) Slog.i(TAG_TASKS,
    498                         "remove RecentTask " + tr + " when finishing user" + userId);
    499                 remove(mTasks.get(i));
    500             }
    501         }
    502     }
    503 
    504     void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
    505         final Set<String> packageNames = Sets.newHashSet(packages);
    506         for (int i = mTasks.size() - 1; i >= 0; --i) {
    507             final TaskRecord tr = mTasks.get(i);
    508             if (tr.realActivity != null
    509                     && packageNames.contains(tr.realActivity.getPackageName())
    510                     && tr.userId == userId
    511                     && tr.realActivitySuspended != suspended) {
    512                tr.realActivitySuspended = suspended;
    513                if (suspended) {
    514                    mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
    515                            REMOVE_FROM_RECENTS, "suspended-package");
    516                }
    517                notifyTaskPersisterLocked(tr, false);
    518             }
    519         }
    520     }
    521 
    522     void onLockTaskModeStateChanged(int lockTaskModeState, int userId) {
    523         if (lockTaskModeState != ActivityManager.LOCK_TASK_MODE_LOCKED) {
    524             return;
    525         }
    526         for (int i = mTasks.size() - 1; i >= 0; --i) {
    527             final TaskRecord tr = mTasks.get(i);
    528             if (tr.userId == userId && !mService.getLockTaskController().isTaskWhitelisted(tr)) {
    529                 remove(tr);
    530             }
    531         }
    532     }
    533 
    534     void removeTasksByPackageName(String packageName, int userId) {
    535         for (int i = mTasks.size() - 1; i >= 0; --i) {
    536             final TaskRecord tr = mTasks.get(i);
    537             final String taskPackageName =
    538                     tr.getBaseIntent().getComponent().getPackageName();
    539             if (tr.userId != userId) continue;
    540             if (!taskPackageName.equals(packageName)) continue;
    541 
    542             mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS,
    543                     "remove-package-task");
    544         }
    545     }
    546 
    547     void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
    548             int userId) {
    549         for (int i = mTasks.size() - 1; i >= 0; --i) {
    550             final TaskRecord tr = mTasks.get(i);
    551             if (userId != UserHandle.USER_ALL && tr.userId != userId) {
    552                 continue;
    553             }
    554 
    555             ComponentName cn = tr.intent != null ? tr.intent.getComponent() : null;
    556             final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
    557                     && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
    558             if (sameComponent) {
    559                 mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
    560                         REMOVE_FROM_RECENTS, "disabled-package");
    561             }
    562         }
    563     }
    564 
    565     /**
    566      * Update the recent tasks lists: make sure tasks should still be here (their
    567      * applications / activities still exist), update their availability, fix-up ordering
    568      * of affiliations.
    569      */
    570     void cleanupLocked(int userId) {
    571         int recentsCount = mTasks.size();
    572         if (recentsCount == 0) {
    573             // Happens when called from the packagemanager broadcast before boot,
    574             // or just any empty list.
    575             return;
    576         }
    577 
    578         // Clear the temp lists
    579         mTmpAvailActCache.clear();
    580         mTmpAvailAppCache.clear();
    581 
    582         final IPackageManager pm = AppGlobals.getPackageManager();
    583         for (int i = recentsCount - 1; i >= 0; i--) {
    584             final TaskRecord task = mTasks.get(i);
    585             if (userId != UserHandle.USER_ALL && task.userId != userId) {
    586                 // Only look at tasks for the user ID of interest.
    587                 continue;
    588             }
    589             if (task.autoRemoveRecents && task.getTopActivity() == null) {
    590                 // This situation is broken, and we should just get rid of it now.
    591                 mTasks.remove(i);
    592                 notifyTaskRemoved(task, !TRIMMED);
    593                 Slog.w(TAG, "Removing auto-remove without activity: " + task);
    594                 continue;
    595             }
    596             // Check whether this activity is currently available.
    597             if (task.realActivity != null) {
    598                 ActivityInfo ai = mTmpAvailActCache.get(task.realActivity);
    599                 if (ai == null) {
    600                     try {
    601                         // At this first cut, we're only interested in
    602                         // activities that are fully runnable based on
    603                         // current system state.
    604                         ai = pm.getActivityInfo(task.realActivity,
    605                                 PackageManager.MATCH_DEBUG_TRIAGED_MISSING
    606                                         | ActivityManagerService.STOCK_PM_FLAGS, userId);
    607                     } catch (RemoteException e) {
    608                         // Will never happen.
    609                         continue;
    610                     }
    611                     if (ai == null) {
    612                         ai = NO_ACTIVITY_INFO_TOKEN;
    613                     }
    614                     mTmpAvailActCache.put(task.realActivity, ai);
    615                 }
    616                 if (ai == NO_ACTIVITY_INFO_TOKEN) {
    617                     // This could be either because the activity no longer exists, or the
    618                     // app is temporarily gone. For the former we want to remove the recents
    619                     // entry; for the latter we want to mark it as unavailable.
    620                     ApplicationInfo app = mTmpAvailAppCache
    621                             .get(task.realActivity.getPackageName());
    622                     if (app == null) {
    623                         try {
    624                             app = pm.getApplicationInfo(task.realActivity.getPackageName(),
    625                                     PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
    626                         } catch (RemoteException e) {
    627                             // Will never happen.
    628                             continue;
    629                         }
    630                         if (app == null) {
    631                             app = NO_APPLICATION_INFO_TOKEN;
    632                         }
    633                         mTmpAvailAppCache.put(task.realActivity.getPackageName(), app);
    634                     }
    635                     if (app == NO_APPLICATION_INFO_TOKEN
    636                             || (app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
    637                         // Doesn't exist any more! Good-bye.
    638                         mTasks.remove(i);
    639                         notifyTaskRemoved(task, !TRIMMED);
    640                         Slog.w(TAG, "Removing no longer valid recent: " + task);
    641                         continue;
    642                     } else {
    643                         // Otherwise just not available for now.
    644                         if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
    645                                 "Making recent unavailable: " + task);
    646                         task.isAvailable = false;
    647                     }
    648                 } else {
    649                     if (!ai.enabled || !ai.applicationInfo.enabled
    650                             || (ai.applicationInfo.flags
    651                                     & ApplicationInfo.FLAG_INSTALLED) == 0) {
    652                         if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
    653                                 "Making recent unavailable: " + task
    654                                         + " (enabled=" + ai.enabled + "/"
    655                                         + ai.applicationInfo.enabled
    656                                         + " flags="
    657                                         + Integer.toHexString(ai.applicationInfo.flags)
    658                                         + ")");
    659                         task.isAvailable = false;
    660                     } else {
    661                         if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
    662                                 "Making recent available: " + task);
    663                         task.isAvailable = true;
    664                     }
    665                 }
    666             }
    667         }
    668 
    669         // Verify the affiliate chain for each task.
    670         int i = 0;
    671         recentsCount = mTasks.size();
    672         while (i < recentsCount) {
    673             i = processNextAffiliateChainLocked(i);
    674         }
    675         // recent tasks are now in sorted, affiliated order.
    676     }
    677 
    678     /**
    679      * @return whether the given {@param task} can be added to the list without causing another
    680      * task to be trimmed as a result of that add.
    681      */
    682     private boolean canAddTaskWithoutTrim(TaskRecord task) {
    683         return findRemoveIndexForAddTask(task) == -1;
    684     }
    685 
    686     /**
    687      * Returns the list of {@link ActivityManager.AppTask}s.
    688      */
    689     ArrayList<IBinder> getAppTasksList(int callingUid, String callingPackage) {
    690         final ArrayList<IBinder> list = new ArrayList<>();
    691         final int size = mTasks.size();
    692         for (int i = 0; i < size; i++) {
    693             final TaskRecord tr = mTasks.get(i);
    694             // Skip tasks that do not match the caller.  We don't need to verify
    695             // callingPackage, because we are also limiting to callingUid and know
    696             // that will limit to the correct security sandbox.
    697             if (tr.effectiveUid != callingUid) {
    698                 continue;
    699             }
    700             Intent intent = tr.getBaseIntent();
    701             if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
    702                 continue;
    703             }
    704             ActivityManager.RecentTaskInfo taskInfo = createRecentTaskInfo(tr);
    705             AppTaskImpl taskImpl = new AppTaskImpl(mService, taskInfo.persistentId, callingUid);
    706             list.add(taskImpl.asBinder());
    707         }
    708         return list;
    709     }
    710 
    711     /**
    712      * @return the list of recent tasks for presentation.
    713      */
    714     ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
    715             boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
    716         final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
    717 
    718         if (!mService.isUserRunning(userId, FLAG_AND_UNLOCKED)) {
    719             Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
    720             return ParceledListSlice.emptyList();
    721         }
    722         loadUserRecentsLocked(userId);
    723 
    724         final Set<Integer> includedUsers = mUserController.getProfileIds(userId);
    725         includedUsers.add(Integer.valueOf(userId));
    726 
    727         final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
    728         final int size = mTasks.size();
    729         int numVisibleTasks = 0;
    730         for (int i = 0; i < size; i++) {
    731             final TaskRecord tr = mTasks.get(i);
    732 
    733             if (isVisibleRecentTask(tr)) {
    734                 numVisibleTasks++;
    735                 if (isInVisibleRange(tr, numVisibleTasks)) {
    736                     // Fall through
    737                 } else {
    738                     // Not in visible range
    739                     continue;
    740                 }
    741             } else {
    742                 // Not visible
    743                 continue;
    744             }
    745 
    746             // Skip remaining tasks once we reach the requested size
    747             if (res.size() >= maxNum) {
    748                 continue;
    749             }
    750 
    751             // Only add calling user or related users recent tasks
    752             if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
    753                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
    754                 continue;
    755             }
    756 
    757             if (tr.realActivitySuspended) {
    758                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
    759                 continue;
    760             }
    761 
    762             // Return the entry if desired by the caller.  We always return
    763             // the first entry, because callers always expect this to be the
    764             // foreground app.  We may filter others if the caller has
    765             // not supplied RECENT_WITH_EXCLUDED and there is some reason
    766             // we should exclude the entry.
    767 
    768             if (i == 0
    769                     || withExcluded
    770                     || (tr.intent == null)
    771                     || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
    772                     == 0)) {
    773                 if (!getTasksAllowed) {
    774                     // If the caller doesn't have the GET_TASKS permission, then only
    775                     // allow them to see a small subset of tasks -- their own and home.
    776                     if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
    777                         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
    778                         continue;
    779                     }
    780                 }
    781                 if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
    782                     // Don't include auto remove tasks that are finished or finishing.
    783                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    784                             "Skipping, auto-remove without activity: " + tr);
    785                     continue;
    786                 }
    787                 if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
    788                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    789                             "Skipping, unavail real act: " + tr);
    790                     continue;
    791                 }
    792 
    793                 if (!tr.mUserSetupComplete) {
    794                     // Don't include task launched while user is not done setting-up.
    795                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    796                             "Skipping, user setup not complete: " + tr);
    797                     continue;
    798                 }
    799 
    800                 final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
    801                 if (!getDetailedTasks) {
    802                     rti.baseIntent.replaceExtras((Bundle)null);
    803                 }
    804 
    805                 res.add(rti);
    806             }
    807         }
    808         return new ParceledListSlice<>(res);
    809     }
    810 
    811     /**
    812      * @return the list of persistable task ids.
    813      */
    814     void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) {
    815         final int size = mTasks.size();
    816         for (int i = 0; i < size; i++) {
    817             final TaskRecord task = mTasks.get(i);
    818             if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
    819                     + " persistable=" + task.isPersistable);
    820             final ActivityStack stack = task.getStack();
    821             if ((task.isPersistable || task.inRecents)
    822                     && (stack == null || !stack.isHomeOrRecentsStack())) {
    823                 if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
    824                 persistentTaskIds.add(task.taskId);
    825             } else {
    826                 if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task="
    827                         + task);
    828             }
    829         }
    830     }
    831 
    832     @VisibleForTesting
    833     ArrayList<TaskRecord> getRawTasks() {
    834         return mTasks;
    835     }
    836 
    837     /**
    838      * @return ids of tasks that are presented in Recents UI.
    839      */
    840     SparseBooleanArray getRecentTaskIds() {
    841         final SparseBooleanArray res = new SparseBooleanArray();
    842         final int size = mTasks.size();
    843         int numVisibleTasks = 0;
    844         for (int i = 0; i < size; i++) {
    845             final TaskRecord tr = mTasks.get(i);
    846             if (isVisibleRecentTask(tr)) {
    847                 numVisibleTasks++;
    848                 if (isInVisibleRange(tr, numVisibleTasks)) {
    849                     res.put(tr.taskId, true);
    850                 }
    851             }
    852         }
    853         return res;
    854     }
    855 
    856     /**
    857      * @return the task in the task list with the given {@param id} if one exists.
    858      */
    859     TaskRecord getTask(int id) {
    860         final int recentsCount = mTasks.size();
    861         for (int i = 0; i < recentsCount; i++) {
    862             TaskRecord tr = mTasks.get(i);
    863             if (tr.taskId == id) {
    864                 return tr;
    865             }
    866         }
    867         return null;
    868     }
    869 
    870     /**
    871      * Add a new task to the recent tasks list.
    872      */
    873     void add(TaskRecord task) {
    874         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
    875 
    876         final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
    877                 || task.mNextAffiliateTaskId != INVALID_TASK_ID
    878                 || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
    879 
    880         int recentsCount = mTasks.size();
    881         // Quick case: never add voice sessions.
    882         // TODO: VI what about if it's just an activity?
    883         // Probably nothing to do here
    884         if (task.voiceSession != null) {
    885             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    886                     "addRecent: not adding voice interaction " + task);
    887             return;
    888         }
    889         // Another quick case: check if the top-most recent task is the same.
    890         if (!isAffiliated && recentsCount > 0 && mTasks.get(0) == task) {
    891             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
    892             return;
    893         }
    894         // Another quick case: check if this is part of a set of affiliated
    895         // tasks that are at the top.
    896         if (isAffiliated && recentsCount > 0 && task.inRecents
    897                 && task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) {
    898             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
    899                     + " at top when adding " + task);
    900             return;
    901         }
    902 
    903         boolean needAffiliationFix = false;
    904 
    905         // Slightly less quick case: the task is already in recents, so all we need
    906         // to do is move it.
    907         if (task.inRecents) {
    908             int taskIndex = mTasks.indexOf(task);
    909             if (taskIndex >= 0) {
    910                 if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) {
    911                     // Simple case: this is not an affiliated task, so we just move it to the front.
    912                     mTasks.remove(taskIndex);
    913                     mTasks.add(0, task);
    914                     notifyTaskPersisterLocked(task, false);
    915                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
    916                             + " from " + taskIndex);
    917                     return;
    918                 } else {
    919                     // More complicated: need to keep all affiliated tasks together.
    920                     if (moveAffiliatedTasksToFront(task, taskIndex)) {
    921                         // All went well.
    922                         return;
    923                     }
    924 
    925                     // Uh oh...  something bad in the affiliation chain, try to rebuild
    926                     // everything and then go through our general path of adding a new task.
    927                     needAffiliationFix = true;
    928                 }
    929             } else {
    930                 Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
    931                 needAffiliationFix = true;
    932             }
    933         }
    934 
    935         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
    936         removeForAddTask(task);
    937 
    938         task.inRecents = true;
    939         if (!isAffiliated || needAffiliationFix) {
    940             // If this is a simple non-affiliated task, or we had some failure trying to
    941             // handle it as part of an affilated task, then just place it at the top.
    942             mTasks.add(0, task);
    943             notifyTaskAdded(task);
    944             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
    945         } else if (isAffiliated) {
    946             // If this is a new affiliated task, then move all of the affiliated tasks
    947             // to the front and insert this new one.
    948             TaskRecord other = task.mNextAffiliate;
    949             if (other == null) {
    950                 other = task.mPrevAffiliate;
    951             }
    952             if (other != null) {
    953                 int otherIndex = mTasks.indexOf(other);
    954                 if (otherIndex >= 0) {
    955                     // Insert new task at appropriate location.
    956                     int taskIndex;
    957                     if (other == task.mNextAffiliate) {
    958                         // We found the index of our next affiliation, which is who is
    959                         // before us in the list, so add after that point.
    960                         taskIndex = otherIndex+1;
    961                     } else {
    962                         // We found the index of our previous affiliation, which is who is
    963                         // after us in the list, so add at their position.
    964                         taskIndex = otherIndex;
    965                     }
    966                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    967                             "addRecent: new affiliated task added at " + taskIndex + ": " + task);
    968                     mTasks.add(taskIndex, task);
    969                     notifyTaskAdded(task);
    970 
    971                     // Now move everything to the front.
    972                     if (moveAffiliatedTasksToFront(task, taskIndex)) {
    973                         // All went well.
    974                         return;
    975                     }
    976 
    977                     // Uh oh...  something bad in the affiliation chain, try to rebuild
    978                     // everything and then go through our general path of adding a new task.
    979                     needAffiliationFix = true;
    980                 } else {
    981                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    982                             "addRecent: couldn't find other affiliation " + other);
    983                     needAffiliationFix = true;
    984                 }
    985             } else {
    986                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
    987                         "addRecent: adding affiliated task without next/prev:" + task);
    988                 needAffiliationFix = true;
    989             }
    990         }
    991 
    992         if (needAffiliationFix) {
    993             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
    994             cleanupLocked(task.userId);
    995         }
    996 
    997         // Trim the set of tasks to the active set
    998         trimInactiveRecentTasks();
    999     }
   1000 
   1001     /**
   1002      * Add the task to the bottom if possible.
   1003      */
   1004     boolean addToBottom(TaskRecord task) {
   1005         if (!canAddTaskWithoutTrim(task)) {
   1006             // Adding this task would cause the task to be removed (since it's appended at
   1007             // the bottom and would be trimmed) so just return now
   1008             return false;
   1009         }
   1010 
   1011         add(task);
   1012         return true;
   1013     }
   1014 
   1015     /**
   1016      * Remove a task from the recent tasks list.
   1017      */
   1018     void remove(TaskRecord task) {
   1019         mTasks.remove(task);
   1020         notifyTaskRemoved(task, !TRIMMED);
   1021     }
   1022 
   1023     /**
   1024      * Trims the recents task list to the global max number of recents.
   1025      */
   1026     private void trimInactiveRecentTasks() {
   1027         int recentsCount = mTasks.size();
   1028 
   1029         // Remove from the end of the list until we reach the max number of recents
   1030         while (recentsCount > mGlobalMaxNumTasks) {
   1031             final TaskRecord tr = mTasks.remove(recentsCount - 1);
   1032             notifyTaskRemoved(tr, TRIMMED);
   1033             recentsCount--;
   1034             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr
   1035                     + " max=" + mGlobalMaxNumTasks);
   1036         }
   1037 
   1038         // Remove any tasks that belong to currently quiet profiles
   1039         final int[] profileUserIds = mUserController.getCurrentProfileIds();
   1040         mTmpQuietProfileUserIds.clear();
   1041         for (int userId : profileUserIds) {
   1042             final UserInfo userInfo = mUserController.getUserInfo(userId);
   1043             if (userInfo != null && userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) {
   1044                 mTmpQuietProfileUserIds.put(userId, true);
   1045             }
   1046             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo
   1047                     + " quiet=" + mTmpQuietProfileUserIds.get(userId));
   1048         }
   1049 
   1050         // Remove any inactive tasks, calculate the latest set of visible tasks
   1051         int numVisibleTasks = 0;
   1052         for (int i = 0; i < mTasks.size();) {
   1053             final TaskRecord task = mTasks.get(i);
   1054 
   1055             if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
   1056                 if (!mHasVisibleRecentTasks) {
   1057                     // Keep all active tasks if visible recent tasks is not supported
   1058                     i++;
   1059                     continue;
   1060                 }
   1061 
   1062                 if (!isVisibleRecentTask(task)) {
   1063                     // Keep all active-but-invisible tasks
   1064                     i++;
   1065                     continue;
   1066                 } else {
   1067                     numVisibleTasks++;
   1068                     if (isInVisibleRange(task, numVisibleTasks) || !isTrimmable(task)) {
   1069                         // Keep visible tasks in range
   1070                         i++;
   1071                         continue;
   1072                     } else {
   1073                         // Fall through to trim visible tasks that are no longer in range and
   1074                         // trimmable
   1075                         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
   1076                                 "Trimming out-of-range visible task=" + task);
   1077                     }
   1078                 }
   1079             } else {
   1080                 // Fall through to trim inactive tasks
   1081                 if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming inactive task=" + task);
   1082             }
   1083 
   1084             // Task is no longer active, trim it from the list
   1085             mTasks.remove(task);
   1086             notifyTaskRemoved(task, TRIMMED);
   1087             notifyTaskPersisterLocked(task, false /* flush */);
   1088         }
   1089     }
   1090 
   1091     /**
   1092      * @return whether the given task should be considered active.
   1093      */
   1094     private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) {
   1095         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
   1096                 + " globalMax=" + mGlobalMaxNumTasks);
   1097 
   1098         if (quietProfileUserIds.get(task.userId)) {
   1099             // Quiet profile user's tasks are never active
   1100             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\tisQuietProfileTask=true");
   1101             return false;
   1102         }
   1103 
   1104         if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.taskId) {
   1105             // Keep the task active if its affiliated task is also active
   1106             final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId);
   1107             if (affiliatedTask != null) {
   1108                 if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
   1109                     if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
   1110                             "\taffiliatedWithTask=" + affiliatedTask + " is not active");
   1111                     return false;
   1112                 }
   1113             }
   1114         }
   1115 
   1116         // All other tasks are considered active
   1117         return true;
   1118     }
   1119 
   1120     /**
   1121      * @return whether the given active task should be presented to the user through SystemUI.
   1122      */
   1123     private boolean isVisibleRecentTask(TaskRecord task) {
   1124         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
   1125                 + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
   1126                 + " sessionDuration=" + mActiveTasksSessionDurationMs
   1127                 + " inactiveDuration=" + task.getInactiveDuration()
   1128                 + " activityType=" + task.getActivityType()
   1129                 + " windowingMode=" + task.getWindowingMode()
   1130                 + " intentFlags=" + task.getBaseIntent().getFlags());
   1131 
   1132         switch (task.getActivityType()) {
   1133             case ACTIVITY_TYPE_HOME:
   1134             case ACTIVITY_TYPE_RECENTS:
   1135                 // Ignore certain activity types completely
   1136                 return false;
   1137             case ACTIVITY_TYPE_ASSISTANT:
   1138                 // Ignore assistant that chose to be excluded from Recents, even if it's a top
   1139                 // task.
   1140                 if ((task.getBaseIntent().getFlags()
   1141                         & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
   1142                         == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) {
   1143                     return false;
   1144                 }
   1145         }
   1146 
   1147         // Ignore certain windowing modes
   1148         switch (task.getWindowingMode()) {
   1149             case WINDOWING_MODE_PINNED:
   1150                 return false;
   1151             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
   1152                 if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().topTask());
   1153                 final ActivityStack stack = task.getStack();
   1154                 if (stack != null && stack.topTask() == task) {
   1155                     // Only the non-top task of the primary split screen mode is visible
   1156                     return false;
   1157                 }
   1158         }
   1159 
   1160         // If we're in lock task mode, ignore the root task
   1161         if (task == mService.getLockTaskController().getRootTask()) {
   1162             return false;
   1163         }
   1164 
   1165         return true;
   1166     }
   1167 
   1168     /**
   1169      * @return whether the given visible task is within the policy range.
   1170      */
   1171     private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks) {
   1172         // Keep the last most task even if it is excluded from recents
   1173         final boolean isExcludeFromRecents =
   1174                 (task.getBaseIntent().getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
   1175                         == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
   1176         if (isExcludeFromRecents) {
   1177             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
   1178             return numVisibleTasks == 1;
   1179         }
   1180 
   1181         if (mMinNumVisibleTasks >= 0 && numVisibleTasks <= mMinNumVisibleTasks) {
   1182             // Always keep up to the min number of recent tasks, after that fall through to the
   1183             // checks below
   1184             return true;
   1185         }
   1186 
   1187         if (mMaxNumVisibleTasks >= 0) {
   1188             // Always keep up to the max number of recent tasks, but return false afterwards
   1189             return numVisibleTasks <= mMaxNumVisibleTasks;
   1190         }
   1191 
   1192         if (mActiveTasksSessionDurationMs > 0) {
   1193             // Keep the task if the inactive time is within the session window, this check must come
   1194             // after the checks for the min/max visible task range
   1195             if (task.getInactiveDuration() <= mActiveTasksSessionDurationMs) {
   1196                 return true;
   1197             }
   1198         }
   1199 
   1200         return false;
   1201     }
   1202 
   1203     /**
   1204      * @return whether the given task can be trimmed even if it is outside the visible range.
   1205      */
   1206     protected boolean isTrimmable(TaskRecord task) {
   1207         final ActivityStack stack = task.getStack();
   1208         final ActivityStack homeStack = mService.mStackSupervisor.mHomeStack;
   1209 
   1210         // No stack for task, just trim it
   1211         if (stack == null) {
   1212             return true;
   1213         }
   1214 
   1215         // Ignore tasks from different displays
   1216         if (stack.getDisplay() != homeStack.getDisplay()) {
   1217             return false;
   1218         }
   1219 
   1220         // Trim tasks that are in stacks that are behind the home stack
   1221         final ActivityDisplay display = stack.getDisplay();
   1222         return display.getIndexOf(stack) < display.getIndexOf(homeStack);
   1223     }
   1224 
   1225     /**
   1226      * If needed, remove oldest existing entries in recents that are for the same kind
   1227      * of task as the given one.
   1228      */
   1229     private void removeForAddTask(TaskRecord task) {
   1230         final int removeIndex = findRemoveIndexForAddTask(task);
   1231         if (removeIndex == -1) {
   1232             // Nothing to trim
   1233             return;
   1234         }
   1235 
   1236         // There is a similar task that will be removed for the addition of {@param task}, but it
   1237         // can be the same task, and if so, the task will be re-added in add(), so skip the
   1238         // callbacks here.
   1239         final TaskRecord removedTask = mTasks.remove(removeIndex);
   1240         if (removedTask != task) {
   1241             notifyTaskRemoved(removedTask, !TRIMMED);
   1242             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
   1243                     + " for addition of task=" + task);
   1244         }
   1245         notifyTaskPersisterLocked(removedTask, false /* flush */);
   1246     }
   1247 
   1248     /**
   1249      * Find the task that would be removed if the given {@param task} is added to the recent tasks
   1250      * list (if any).
   1251      */
   1252     private int findRemoveIndexForAddTask(TaskRecord task) {
   1253         final int recentsCount = mTasks.size();
   1254         final Intent intent = task.intent;
   1255         final boolean document = intent != null && intent.isDocument();
   1256         int maxRecents = task.maxRecents - 1;
   1257         for (int i = 0; i < recentsCount; i++) {
   1258             final TaskRecord tr = mTasks.get(i);
   1259             if (task != tr) {
   1260                 if (!hasCompatibleActivityTypeAndWindowingMode(task, tr)
   1261                         || task.userId != tr.userId) {
   1262                     continue;
   1263                 }
   1264                 final Intent trIntent = tr.intent;
   1265                 final boolean sameAffinity =
   1266                         task.affinity != null && task.affinity.equals(tr.affinity);
   1267                 final boolean sameIntent = intent != null && intent.filterEquals(trIntent);
   1268                 boolean multiTasksAllowed = false;
   1269                 final int flags = intent.getFlags();
   1270                 if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0
   1271                         && (flags & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
   1272                     multiTasksAllowed = true;
   1273                 }
   1274                 final boolean trIsDocument = trIntent != null && trIntent.isDocument();
   1275                 final boolean bothDocuments = document && trIsDocument;
   1276                 if (!sameAffinity && !sameIntent && !bothDocuments) {
   1277                     continue;
   1278                 }
   1279 
   1280                 if (bothDocuments) {
   1281                     // Do these documents belong to the same activity?
   1282                     final boolean sameActivity = task.realActivity != null
   1283                             && tr.realActivity != null
   1284                             && task.realActivity.equals(tr.realActivity);
   1285                     if (!sameActivity) {
   1286                         // If the document is open in another app or is not the same document, we
   1287                         // don't need to trim it.
   1288                         continue;
   1289                     } else if (maxRecents > 0) {
   1290                         --maxRecents;
   1291                         if (!sameIntent || multiTasksAllowed) {
   1292                             // We don't want to trim if we are not over the max allowed entries and
   1293                             // the tasks are not of the same intent filter, or multiple entries for
   1294                             // the task is allowed.
   1295                             continue;
   1296                         }
   1297                     }
   1298                     // Hit the maximum number of documents for this task. Fall through
   1299                     // and remove this document from recents.
   1300                 } else if (document || trIsDocument) {
   1301                     // Only one of these is a document. Not the droid we're looking for.
   1302                     continue;
   1303                 }
   1304             }
   1305             return i;
   1306         }
   1307         return -1;
   1308     }
   1309 
   1310     // Extract the affiliates of the chain containing recent at index start.
   1311     private int processNextAffiliateChainLocked(int start) {
   1312         final TaskRecord startTask = mTasks.get(start);
   1313         final int affiliateId = startTask.mAffiliatedTaskId;
   1314 
   1315         // Quick identification of isolated tasks. I.e. those not launched behind.
   1316         if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
   1317                 startTask.mNextAffiliate == null) {
   1318             // There is still a slim chance that there are other tasks that point to this task
   1319             // and that the chain is so messed up that this task no longer points to them but
   1320             // the gain of this optimization outweighs the risk.
   1321             startTask.inRecents = true;
   1322             return start + 1;
   1323         }
   1324 
   1325         // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
   1326         mTmpRecents.clear();
   1327         for (int i = mTasks.size() - 1; i >= start; --i) {
   1328             final TaskRecord task = mTasks.get(i);
   1329             if (task.mAffiliatedTaskId == affiliateId) {
   1330                 mTasks.remove(i);
   1331                 mTmpRecents.add(task);
   1332             }
   1333         }
   1334 
   1335         // Sort them all by taskId. That is the order they were create in and that order will
   1336         // always be correct.
   1337         Collections.sort(mTmpRecents, TASK_ID_COMPARATOR);
   1338 
   1339         // Go through and fix up the linked list.
   1340         // The first one is the end of the chain and has no next.
   1341         final TaskRecord first = mTmpRecents.get(0);
   1342         first.inRecents = true;
   1343         if (first.mNextAffiliate != null) {
   1344             Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
   1345             first.setNextAffiliate(null);
   1346             notifyTaskPersisterLocked(first, false);
   1347         }
   1348         // Everything in the middle is doubly linked from next to prev.
   1349         final int tmpSize = mTmpRecents.size();
   1350         for (int i = 0; i < tmpSize - 1; ++i) {
   1351             final TaskRecord next = mTmpRecents.get(i);
   1352             final TaskRecord prev = mTmpRecents.get(i + 1);
   1353             if (next.mPrevAffiliate != prev) {
   1354                 Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
   1355                         " setting prev=" + prev);
   1356                 next.setPrevAffiliate(prev);
   1357                 notifyTaskPersisterLocked(next, false);
   1358             }
   1359             if (prev.mNextAffiliate != next) {
   1360                 Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
   1361                         " setting next=" + next);
   1362                 prev.setNextAffiliate(next);
   1363                 notifyTaskPersisterLocked(prev, false);
   1364             }
   1365             prev.inRecents = true;
   1366         }
   1367         // The last one is the beginning of the list and has no prev.
   1368         final TaskRecord last = mTmpRecents.get(tmpSize - 1);
   1369         if (last.mPrevAffiliate != null) {
   1370             Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
   1371             last.setPrevAffiliate(null);
   1372             notifyTaskPersisterLocked(last, false);
   1373         }
   1374 
   1375         // Insert the group back into mTmpTasks at start.
   1376         mTasks.addAll(start, mTmpRecents);
   1377         mTmpRecents.clear();
   1378 
   1379         // Let the caller know where we left off.
   1380         return start + tmpSize;
   1381     }
   1382 
   1383     private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
   1384         int recentsCount = mTasks.size();
   1385         TaskRecord top = task;
   1386         int topIndex = taskIndex;
   1387         while (top.mNextAffiliate != null && topIndex > 0) {
   1388             top = top.mNextAffiliate;
   1389             topIndex--;
   1390         }
   1391         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
   1392                 + topIndex + " from intial " + taskIndex);
   1393         // Find the end of the chain, doing a sanity check along the way.
   1394         boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
   1395         int endIndex = topIndex;
   1396         TaskRecord prev = top;
   1397         while (endIndex < recentsCount) {
   1398             TaskRecord cur = mTasks.get(endIndex);
   1399             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
   1400                     + endIndex + " " + cur);
   1401             if (cur == top) {
   1402                 // Verify start of the chain.
   1403                 if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
   1404                     Slog.wtf(TAG, "Bad chain @" + endIndex
   1405                             + ": first task has next affiliate: " + prev);
   1406                     sane = false;
   1407                     break;
   1408                 }
   1409             } else {
   1410                 // Verify middle of the chain's next points back to the one before.
   1411                 if (cur.mNextAffiliate != prev
   1412                         || cur.mNextAffiliateTaskId != prev.taskId) {
   1413                     Slog.wtf(TAG, "Bad chain @" + endIndex
   1414                             + ": middle task " + cur + " @" + endIndex
   1415                             + " has bad next affiliate "
   1416                             + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId
   1417                             + ", expected " + prev);
   1418                     sane = false;
   1419                     break;
   1420                 }
   1421             }
   1422             if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) {
   1423                 // Chain ends here.
   1424                 if (cur.mPrevAffiliate != null) {
   1425                     Slog.wtf(TAG, "Bad chain @" + endIndex
   1426                             + ": last task " + cur + " has previous affiliate "
   1427                             + cur.mPrevAffiliate);
   1428                     sane = false;
   1429                 }
   1430                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex);
   1431                 break;
   1432             } else {
   1433                 // Verify middle of the chain's prev points to a valid item.
   1434                 if (cur.mPrevAffiliate == null) {
   1435                     Slog.wtf(TAG, "Bad chain @" + endIndex
   1436                             + ": task " + cur + " has previous affiliate "
   1437                             + cur.mPrevAffiliate + " but should be id "
   1438                             + cur.mPrevAffiliate);
   1439                     sane = false;
   1440                     break;
   1441                 }
   1442             }
   1443             if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) {
   1444                 Slog.wtf(TAG, "Bad chain @" + endIndex
   1445                         + ": task " + cur + " has affiliated id "
   1446                         + cur.mAffiliatedTaskId + " but should be "
   1447                         + task.mAffiliatedTaskId);
   1448                 sane = false;
   1449                 break;
   1450             }
   1451             prev = cur;
   1452             endIndex++;
   1453             if (endIndex >= recentsCount) {
   1454                 Slog.wtf(TAG, "Bad chain ran off index " + endIndex
   1455                         + ": last task " + prev);
   1456                 sane = false;
   1457                 break;
   1458             }
   1459         }
   1460         if (sane) {
   1461             if (endIndex < taskIndex) {
   1462                 Slog.wtf(TAG, "Bad chain @" + endIndex
   1463                         + ": did not extend to task " + task + " @" + taskIndex);
   1464                 sane = false;
   1465             }
   1466         }
   1467         if (sane) {
   1468             // All looks good, we can just move all of the affiliated tasks
   1469             // to the top.
   1470             for (int i=topIndex; i<=endIndex; i++) {
   1471                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
   1472                         + " from " + i + " to " + (i-topIndex));
   1473                 TaskRecord cur = mTasks.remove(i);
   1474                 mTasks.add(i - topIndex, cur);
   1475             }
   1476             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
   1477                     + " to " + endIndex);
   1478             return true;
   1479         }
   1480 
   1481         // Whoops, couldn't do it.
   1482         return false;
   1483     }
   1484 
   1485     void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
   1486         pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
   1487         pw.println("mRecentsUid=" + mRecentsUid);
   1488         pw.println("mRecentsComponent=" + mRecentsComponent);
   1489         if (mTasks.isEmpty()) {
   1490             return;
   1491         }
   1492 
   1493         boolean printedAnything = false;
   1494         boolean printedHeader = false;
   1495         final int size = mTasks.size();
   1496         for (int i = 0; i < size; i++) {
   1497             final TaskRecord tr = mTasks.get(i);
   1498             if (dumpPackage != null && (tr.realActivity == null ||
   1499                     !dumpPackage.equals(tr.realActivity.getPackageName()))) {
   1500                 continue;
   1501             }
   1502 
   1503             if (!printedHeader) {
   1504                 pw.println("  Recent tasks:");
   1505                 printedHeader = true;
   1506                 printedAnything = true;
   1507             }
   1508             pw.print("  * Recent #"); pw.print(i); pw.print(": ");
   1509             pw.println(tr);
   1510             if (dumpAll) {
   1511                 tr.dump(pw, "    ");
   1512             }
   1513         }
   1514 
   1515         if (!printedAnything) {
   1516             pw.println("  (nothing)");
   1517         }
   1518     }
   1519 
   1520     /**
   1521      * Creates a new RecentTaskInfo from a TaskRecord.
   1522      */
   1523     ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
   1524         // Compose the recent task info
   1525         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
   1526         rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
   1527         rti.persistentId = tr.taskId;
   1528         rti.baseIntent = new Intent(tr.getBaseIntent());
   1529         rti.origActivity = tr.origActivity;
   1530         rti.realActivity = tr.realActivity;
   1531         rti.description = tr.lastDescription;
   1532         rti.stackId = tr.getStackId();
   1533         rti.userId = tr.userId;
   1534         rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
   1535         rti.lastActiveTime = tr.lastActiveTime;
   1536         rti.affiliatedTaskId = tr.mAffiliatedTaskId;
   1537         rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
   1538         rti.numActivities = 0;
   1539         if (!tr.matchParentBounds()) {
   1540             rti.bounds = new Rect(tr.getOverrideBounds());
   1541         }
   1542         rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
   1543         rti.resizeMode = tr.mResizeMode;
   1544         rti.configuration.setTo(tr.getConfiguration());
   1545 
   1546         tr.getNumRunningActivities(mTmpReport);
   1547         rti.numActivities = mTmpReport.numActivities;
   1548         rti.baseActivity = (mTmpReport.base != null) ? mTmpReport.base.intent.getComponent() : null;
   1549         rti.topActivity = (mTmpReport.top != null) ? mTmpReport.top.intent.getComponent() : null;
   1550 
   1551         return rti;
   1552     }
   1553 
   1554     /**
   1555      * @return Whether the activity types and windowing modes of the two tasks are considered
   1556      *         compatible. This is necessary because we currently don't persist the activity type
   1557      *         or the windowing mode with the task, so they can be undefined when restored.
   1558      */
   1559     private boolean hasCompatibleActivityTypeAndWindowingMode(TaskRecord t1, TaskRecord t2) {
   1560         final int activityType = t1.getActivityType();
   1561         final int windowingMode = t1.getWindowingMode();
   1562         final boolean isUndefinedType = activityType == ACTIVITY_TYPE_UNDEFINED;
   1563         final boolean isUndefinedMode = windowingMode == WINDOWING_MODE_UNDEFINED;
   1564         final int otherActivityType = t2.getActivityType();
   1565         final int otherWindowingMode = t2.getWindowingMode();
   1566         final boolean isOtherUndefinedType = otherActivityType == ACTIVITY_TYPE_UNDEFINED;
   1567         final boolean isOtherUndefinedMode = otherWindowingMode == WINDOWING_MODE_UNDEFINED;
   1568 
   1569         // An activity type and windowing mode is compatible if they are the exact same type/mode,
   1570         // or if one of the type/modes is undefined
   1571         final boolean isCompatibleType = activityType == otherActivityType
   1572                 || isUndefinedType || isOtherUndefinedType;
   1573         final boolean isCompatibleMode = windowingMode == otherWindowingMode
   1574                 || isUndefinedMode || isOtherUndefinedMode;
   1575 
   1576         return isCompatibleType && isCompatibleMode;
   1577     }
   1578 }
   1579