Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1dbc8112 authored by Winson Chung's avatar Winson Chung
Browse files

1/Clean up RecentTasks list

- Move some logic into the RecentTasks list
- Added some callbacks for future handling of trimming recent tasks based
  on additional policy
- Fix issue when cleaning up tasks where the wrong activity/app info can
  be fetched since the tmp caches were not cleared
- Add some initial tests for existing task list behaviour.

Bug: 34270611
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java

Change-Id: I26730461fa5fb3f5afdabe092438c229381f4f2b
parent aaa64d0a
Loading
Loading
Loading
Loading
+24 −407
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
@@ -130,7 +129,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -5960,16 +5958,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (appInfo != null) {
                    forceStopPackageLocked(packageName, appInfo.uid, "clear data");
                    // Remove all tasks match the cleared application package and user
                    for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
                        final TaskRecord tr = mRecentTasks.get(i);
                        final String taskPackageName =
                                tr.getBaseIntent().getComponent().getPackageName();
                        if (tr.userId != resolvedUserId) continue;
                        if (!taskPackageName.equals(packageName)) continue;
                        mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
                                REMOVE_FROM_RECENTS);
                    }
                    mRecentTasks.removeTasksByPackageName(packageName, resolvedUserId);
                }
            }
@@ -6550,7 +6539,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        // Clean-up disabled tasks
        cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
        mRecentTasks.cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
        // Clean-up disabled services.
        mServices.bringDownDisabledPackageServicesLocked(
@@ -9797,36 +9786,13 @@ public class ActivityManagerService extends IActivityManager.Stub
    public List<IBinder> getAppTasks(String callingPackage) {
        int callingUid = Binder.getCallingUid();
        long ident = Binder.clearCallingIdentity();
        synchronized(this) {
            ArrayList<IBinder> list = new ArrayList<IBinder>();
        try {
                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
                final int N = mRecentTasks.size();
                for (int i = 0; i < N; i++) {
                    TaskRecord tr = mRecentTasks.get(i);
                    // Skip tasks that do not match the caller.  We don't need to verify
                    // callingPackage, because we are also limiting to callingUid and know
                    // that will limit to the correct security sandbox.
                    if (tr.effectiveUid != callingUid) {
                        continue;
                    }
                    Intent intent = tr.getBaseIntent();
                    if (intent == null ||
                            !callingPackage.equals(intent.getComponent().getPackageName())) {
                        continue;
                    }
                    ActivityManager.RecentTaskInfo taskInfo =
                            createRecentTaskInfoFromTaskRecord(tr);
                    AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
                    list.add(taskImpl.asBinder());
            synchronized(this) {
                return mRecentTasks.getAppTasksList(callingUid, callingPackage);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
            return list;
        }
    }
    @Override
@@ -9848,58 +9814,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        return list;
    }
    /**
     * Creates a new RecentTaskInfo from a TaskRecord.
     */
    private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
        // Update the task description to reflect any changes in the task stack
        tr.updateTaskDescription();
        // Compose the recent task info
        ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
        rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
        rti.persistentId = tr.taskId;
        rti.baseIntent = new Intent(tr.getBaseIntent());
        rti.origActivity = tr.origActivity;
        rti.realActivity = tr.realActivity;
        rti.description = tr.lastDescription;
        rti.stackId = tr.getStackId();
        rti.userId = tr.userId;
        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
        rti.firstActiveTime = tr.firstActiveTime;
        rti.lastActiveTime = tr.lastActiveTime;
        rti.affiliatedTaskId = tr.mAffiliatedTaskId;
        rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
        rti.numActivities = 0;
        if (tr.mBounds != null) {
            rti.bounds = new Rect(tr.mBounds);
        }
        rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
        rti.resizeMode = tr.mResizeMode;
        rti.configuration.setTo(tr.getConfiguration());
        ActivityRecord base = null;
        ActivityRecord top = null;
        ActivityRecord tmp;
        for (int i = tr.mActivities.size() - 1; i >= 0; --i) {
            tmp = tr.mActivities.get(i);
            if (tmp.finishing) {
                continue;
            }
            base = tmp;
            if (top == null || (top.state == ActivityState.INITIALIZING)) {
                top = base;
            }
            rti.numActivities++;
        }
        rti.baseActivity = (base != null) ? base.intent.getComponent() : null;
        rti.topActivity = (top != null) ? top.intent.getComponent() : null;
        return rti;
    }
    private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
        boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
@@ -9933,119 +9847,15 @@ public class ActivityManagerService extends IActivityManager.Stub
        final int callingUid = Binder.getCallingUid();
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                false, ALLOW_FULL_ONLY, "getRecentTasks", null);
        final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
        final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
        synchronized (this) {
        final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                callingUid);
        final boolean detailed = checkCallingPermission(
                android.Manifest.permission.GET_DETAILED_TASKS)
                        == PackageManager.PERMISSION_GRANTED;
            if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
                Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
                return ParceledListSlice.emptyList();
            }
            mRecentTasks.loadUserRecentsLocked(userId);
            final int recentsCount = mRecentTasks.size();
            ArrayList<ActivityManager.RecentTaskInfo> res =
                    new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
            final Set<Integer> includedUsers;
            if (includeProfiles) {
                includedUsers = mUserController.getProfileIds(userId);
            } else {
                includedUsers = new HashSet<>();
            }
            includedUsers.add(Integer.valueOf(userId));
            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Only add calling user or related users recent tasks
                if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
                    continue;
                }
                if (tr.realActivitySuspended) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
                    continue;
                }
                // Return the entry if desired by the caller.  We always return
                // the first entry, because callers always expect this to be the
                // foreground app.  We may filter others if the caller has
                // not supplied RECENT_WITH_EXCLUDED and there is some reason
                // we should exclude the entry.
                if (i == 0
                        || withExcluded
                        || (tr.intent == null)
                        || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                                == 0)) {
                    if (!allowed) {
                        // If the caller doesn't have the GET_TASKS permission, then only
                        // allow them to see a small subset of tasks -- their own and home.
                        if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
                            continue;
                        }
                    }
                    final ActivityStack stack = tr.getStack();
                    if ((flags & ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS) != 0) {
                        if (stack != null && stack.isHomeOrRecentsStack()) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, home or recents stack task: " + tr);
                            continue;
                        }
                    }
                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
                        if (stack != null && stack.inSplitScreenPrimaryWindowingMode()
                                && stack.topTask() == tr) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, top task in docked stack: " + tr);
                            continue;
                        }
                    }
                    if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
                        if (stack != null && stack.inPinnedWindowingMode()) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, pinned stack task: " + tr);
                            continue;
                        }
                    }
                    if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
                        // Don't include auto remove tasks that are finished or finishing.
                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                "Skipping, auto-remove without activity: " + tr);
                        continue;
                    }
                    if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
                            && !tr.isAvailable) {
                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                "Skipping, unavail real act: " + tr);
                        continue;
                    }
                    if (!tr.mUserSetupComplete) {
                        // Don't include task launched while user is not done setting-up.
                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                "Skipping, user setup not complete: " + tr);
                        continue;
                    }
                    ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
                    if (!detailed) {
                        rti.baseIntent.replaceExtras((Bundle)null);
                    }
                    res.add(rti);
                    maxNum--;
                }
            }
            return new ParceledListSlice<>(res);
        synchronized (this) {
            return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId,
                    callingUid);
        }
    }
@@ -10117,22 +9927,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                TaskRecord task = new TaskRecord(this,
                        mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
                        ainfo, intent, description);
                int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
                if (trimIdx >= 0) {
                    // If this would have caused a trim, then we'll abort because that
                    // means it would be added at the end of the list but then just removed.
                if (!mRecentTasks.addToBottom(task)) {
                    return INVALID_TASK_ID;
                }
                final int N = mRecentTasks.size();
                if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) {
                    final TaskRecord tr = mRecentTasks.remove(N - 1);
                    tr.removedFromRecents();
                }
                task.inRecents = true;
                mRecentTasks.add(task);
                r.getStack().addTask(task, false, "addAppTask");
                // TODO: Send the thumbnail to WM to store it.
@@ -10349,38 +10147,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        mWindowManager.executeAppTransition();
    }
    private void removeTasksByPackageNameLocked(String packageName, int userId) {
        // Remove all tasks with activities in the specified package from the list of recent tasks
        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
            TaskRecord tr = mRecentTasks.get(i);
            if (tr.userId != userId) continue;
            ComponentName cn = tr.intent.getComponent();
            if (cn != null && cn.getPackageName().equals(packageName)) {
                // If the package name matches, remove the task.
                mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
            }
        }
    }
    private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
            int userId) {
        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
            TaskRecord tr = mRecentTasks.get(i);
            if (userId != UserHandle.USER_ALL && tr.userId != userId) {
                continue;
            }
            ComponentName cn = tr.intent.getComponent();
            final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
                    && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
            if (sameComponent) {
                mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
            }
        }
    }
    @Override
    public void removeStack(int stackId) {
        enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
@@ -15133,7 +14899,9 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
            } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                synchronized (this) {
                    dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
                    if (mRecentTasks != null) {
                        mRecentTasks.dump(pw, true /* dumpAll */, dumpPackage);
                    }
                }
            } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
                String[] newArgs;
@@ -15354,7 +15122,9 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
                if (mRecentTasks != null) {
                    mRecentTasks.dump(pw, dumpAll, dumpPackage);
                }
                pw.println();
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
@@ -15424,7 +15194,9 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
                if (mRecentTasks != null) {
                    mRecentTasks.dump(pw, dumpAll, dumpPackage);
                }
                pw.println();
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
@@ -15510,42 +15282,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
            int opti, boolean dumpAll, String dumpPackage) {
        pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
        boolean printedAnything = false;
        if (mRecentTasks != null && mRecentTasks.size() > 0) {
            boolean printedHeader = false;
            final int N = mRecentTasks.size();
            for (int i=0; i<N; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                if (dumpPackage != null) {
                    if (tr.realActivity == null ||
                            !dumpPackage.equals(tr.realActivity.getPackageName())) {
                        continue;
                    }
                }
                if (!printedHeader) {
                    pw.println("  Recent tasks:");
                    printedHeader = true;
                    printedAnything = true;
                }
                pw.print("  * Recent #"); pw.print(i); pw.print(": ");
                        pw.println(tr);
                if (dumpAll) {
                    mRecentTasks.get(i).dump(pw, "    ");
                }
            }
        }
        if (!printedAnything) {
            pw.println("  (nothing)");
        }
    }
    void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
            int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
        pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)");
@@ -19360,7 +19096,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                                        // Remove all permissions granted from/to this package
                                        removeUriPermissionsForPackageLocked(ssp, userId, true);
                                        removeTasksByPackageNameLocked(ssp, userId);
                                        mRecentTasks.removeTasksByPackageName(ssp, userId);
                                        mServices.forceStopPackageLocked(ssp, userId);
@@ -24367,125 +24103,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    /**
     * An implementation of IAppTask, that allows an app to manage its own tasks via
     * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
     * only the process that calls getAppTasks() can call the AppTask methods.
     */
    class AppTaskImpl extends IAppTask.Stub {
        private int mTaskId;
        private int mCallingUid;
        public AppTaskImpl(int taskId, int callingUid) {
            mTaskId = taskId;
            mCallingUid = callingUid;
        }
        private void checkCaller() {
            if (mCallingUid != Binder.getCallingUid()) {
                throw new SecurityException("Caller " + mCallingUid
                        + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
            }
        }
        @Override
        public void finishAndRemoveTask() {
            checkCaller();
            synchronized (ActivityManagerService.this) {
                long origId = Binder.clearCallingIdentity();
                try {
                    // We remove the task from recents to preserve backwards
                    if (!mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
                            REMOVE_FROM_RECENTS)) {
                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                    }
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
        @Override
        public ActivityManager.RecentTaskInfo getTaskInfo() {
            checkCaller();
            synchronized (ActivityManagerService.this) {
                long origId = Binder.clearCallingIdentity();
                try {
                    TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
                    if (tr == null) {
                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                    }
                    return createRecentTaskInfoFromTaskRecord(tr);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
        @Override
        public void moveToFront() {
            checkCaller();
            // Will bring task to front if it already has a root activity.
            final long origId = Binder.clearCallingIdentity();
            try {
                synchronized (this) {
                    mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
        @Override
        public int startActivity(IBinder whoThread, String callingPackage,
                Intent intent, String resolvedType, Bundle bOptions) {
            checkCaller();
            int callingUser = UserHandle.getCallingUserId();
            TaskRecord tr;
            IApplicationThread appThread;
            synchronized (ActivityManagerService.this) {
                tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
                if (tr == null) {
                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                }
                appThread = IApplicationThread.Stub.asInterface(whoThread);
                if (appThread == null) {
                    throw new IllegalArgumentException("Bad app thread " + appThread);
                }
            }
            return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
                    resolvedType, null, null, null, null, 0, 0, null, null,
                    null, bOptions, false, callingUser, tr, "AppTaskImpl");
        }
        @Override
        public void setExcludeFromRecents(boolean exclude) {
            checkCaller();
            synchronized (ActivityManagerService.this) {
                long origId = Binder.clearCallingIdentity();
                try {
                    TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
                    if (tr == null) {
                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                    }
                    Intent intent = tr.getBaseIntent();
                    if (exclude) {
                        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    } else {
                        intent.setFlags(intent.getFlags()
                                & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    }
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    }
    /**
     * Kill processes for the user with id userId and that depend on the package named packageName
     */
+8 −6

File changed.

Preview size limit exceeded, changes collapsed.

+23 −23

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -1239,8 +1239,8 @@ class ActivityStarter {
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mSupervisor.addRecentActivity(mStartActivity);
        } else if (mStartActivity != null) {
            mSupervisor.mRecentTasks.add(mStartActivity.getTask());
        }
        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

+150 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading