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

Commit ab438ccc authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Do not hold wm lock when loading recent task files" into main

parents fd3284b3 17e2a6b1
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -2505,6 +2505,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
        final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                callingUid);
        if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
            Slog.i(TAG, "User " + userId + " is locked. Cannot load recents");
            return ParceledListSlice.emptyList();
        }
        mRecentTasks.loadRecentTasksIfNeeded(userId);
        synchronized (mGlobalLock) {
            return mRecentTasks.getRecentTasks(maxNum, flags, allowed, userId, callingUid);
        }
@@ -7056,12 +7061,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

        @Override
        public void loadRecentTasksForUser(int userId) {
            synchronized (mGlobalLock) {
                mRecentTasks.loadUserRecentsLocked(userId);
                // TODO renaming the methods(?)
            // This runs on android.fg thread when the user is unlocking.
            mRecentTasks.loadRecentTasksIfNeeded(userId);
            mPackageConfigPersister.loadUserPackages(userId);
        }
        }

        @Override
        public void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
+58 −52
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.wm;

import static android.app.ActivityManager.FLAG_AND_UNLOCKED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
@@ -69,6 +68,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -89,9 +89,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
@@ -167,8 +167,9 @@ class RecentTasks {

    /**
     * Mapping of user id -> whether recent tasks have been loaded for that user.
     * The AtomicBoolean per user will be locked when reading persisted task from storage.
     */
    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
    private final SparseArray<AtomicBoolean> mUsersWithRecentsLoaded = new SparseArray<>(
            DEFAULT_INITIAL_CAPACITY);

    /**
@@ -481,29 +482,49 @@ class RecentTasks {

    /**
     * Loads the persistent recentTasks for {@code userId} into this list from persistent storage.
     * Does nothing if they are already loaded.
     *
     * @param userId the user Id
     * Does nothing if they are already loaded. This may perform IO operation, so the caller should
     * not hold a lock.
     */
    void loadUserRecentsLocked(int userId) {
        if (mUsersWithRecentsLoaded.get(userId)) {
            // User already loaded, return early
    void loadRecentTasksIfNeeded(int userId) {
        AtomicBoolean userLoaded;
        synchronized (mService.mGlobalLock) {
            userLoaded = mUsersWithRecentsLoaded.get(userId);
            if (userLoaded == null) {
                mUsersWithRecentsLoaded.append(userId, userLoaded = new AtomicBoolean());
            }
        }
        synchronized (userLoaded) {
            if (userLoaded.get()) {
                // The recent tasks of the user are already loaded.
                return;
            }
            // Read task files from storage.
            final SparseBooleanArray persistedTaskIds =
                    mTaskPersister.readPersistedTaskIdsFromFileForUser(userId);
            final TaskPersister.RecentTaskFiles taskFiles = TaskPersister.loadTasksForUser(userId);
            synchronized (mService.mGlobalLock) {
                restoreRecentTasksLocked(userId, persistedTaskIds, taskFiles);
            }
            userLoaded.set(true);
        }
    }

        // Load the task ids if not loaded.
        loadPersistedTaskIdsForUserLocked(userId);

        // Check if any tasks are added before recents is loaded
        final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
        for (final Task task : mTasks) {
    /** Restores recent tasks from raw data (the files are already read into memory). */
    private void restoreRecentTasksLocked(int userId, SparseBooleanArray persistedTaskIds,
            TaskPersister.RecentTaskFiles taskFiles) {
        mTaskPersister.setPersistedTaskIds(userId, persistedTaskIds);
        mPersistedTaskIds.put(userId, persistedTaskIds.clone());
        // Check if any tasks are added before recents is loaded.
        final IntArray existedTaskIds = new IntArray();
        for (int i = mTasks.size() - 1; i >= 0; i--) {
            final Task task = mTasks.get(i);
            if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
                preaddedTasks.put(task.mTaskId, true);
                existedTaskIds.add(task.mTaskId);
            }
        }

        Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
        List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
        Slog.i(TAG, "Restoring recents for user " + userId);
        final ArrayList<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, taskFiles,
                existedTaskIds);

        // Tasks are ordered from most recent to least recent. Update the last active time to be
        // in sync with task recency when device reboots, so the most recent task has the
@@ -516,37 +537,34 @@ class RecentTasks {

        mTasks.addAll(tasks);
        cleanupLocked(userId);
        mUsersWithRecentsLoaded.put(userId, true);

        // If we have tasks added before loading recents, we need to update persistent task IDs.
        if (preaddedTasks.size() > 0) {
        if (existedTaskIds.size() > 0) {
            syncPersistentTaskIdsLocked();
        }
    }

    private void loadPersistedTaskIdsForUserLocked(int userId) {
        // An empty instead of a null set here means that no persistent taskIds were present
        // on file when we loaded them.
        if (mPersistedTaskIds.get(userId) == null) {
            mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
            Slog.i(TAG, "Loaded persisted task ids for user " + userId);
        }
    private boolean isRecentTasksLoaded(int userId) {
        final AtomicBoolean userLoaded = mUsersWithRecentsLoaded.get(userId);
        return userLoaded != null && userLoaded.get();
    }

    /**
     * @return whether the {@param taskId} is currently in use for the given user.
     */
    boolean containsTaskId(int taskId, int userId) {
        loadPersistedTaskIdsForUserLocked(userId);
        return mPersistedTaskIds.get(userId).get(taskId);
        final SparseBooleanArray taskIds = mPersistedTaskIds.get(userId);
        return taskIds != null && taskIds.get(taskId);
    }

    /**
     * @return all the task ids for the user with the given {@param userId}.
     */
    SparseBooleanArray getTaskIdsForUser(int userId) {
        loadPersistedTaskIdsForUserLocked(userId);
        return mPersistedTaskIds.get(userId);
    /** Returns all the task ids for the user from {@link #usersWithRecentsLoadedLocked}. */
    SparseBooleanArray getTaskIdsForLoadedUser(int loadedUserId) {
        final SparseBooleanArray taskIds = mPersistedTaskIds.get(loadedUserId);
        if (taskIds == null) {
            Slog.wtf(TAG, "Loaded user without loaded tasks, userId=" + loadedUserId);
            return new SparseBooleanArray();
        }
        return taskIds;
    }

    /**
@@ -565,7 +583,7 @@ class RecentTasks {
    private void syncPersistentTaskIdsLocked() {
        for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
            int userId = mPersistedTaskIds.keyAt(i);
            if (mUsersWithRecentsLoaded.get(userId)) {
            if (isRecentTasksLoaded(userId)) {
                // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
                // referenced here should not be null.
                mPersistedTaskIds.valueAt(i).clear();
@@ -621,7 +639,7 @@ class RecentTasks {
        int len = 0;
        for (int i = 0; i < usersWithRecentsLoaded.length; i++) {
            int userId = mUsersWithRecentsLoaded.keyAt(i);
            if (mUsersWithRecentsLoaded.valueAt(i)) {
            if (mUsersWithRecentsLoaded.valueAt(i).get()) {
                usersWithRecentsLoaded[len++] = userId;
            }
        }
@@ -639,7 +657,7 @@ class RecentTasks {
     * @param userId the id of the user
     */
    void unloadUserDataFromMemoryLocked(int userId) {
        if (mUsersWithRecentsLoaded.get(userId)) {
        if (isRecentTasksLoaded(userId)) {
            Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
            mUsersWithRecentsLoaded.delete(userId);
            removeTasksForUserLocked(userId);
@@ -922,11 +940,6 @@ class RecentTasks {
        return mService.mAmInternal.getCurrentProfileIds();
    }

    @VisibleForTesting
    boolean isUserRunning(int userId, int flags) {
        return mService.mAmInternal.isUserRunning(userId, flags);
    }

    /**
     * @return the list of recent tasks for presentation.
     */
@@ -942,13 +955,6 @@ class RecentTasks {
    private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
            boolean getTasksAllowed, int userId, int callingUid) {
        final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;

        if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
            Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
            return new ArrayList<>();
        }
        loadUserRecentsLocked(userId);

        final Set<Integer> includedUsers = getProfileIds(userId);
        includedUsers.add(Integer.valueOf(userId));

+83 −37
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.os.FileUtils;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -43,20 +44,20 @@ import org.xmlpull.v1.XmlPullParser;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Persister that saves recent tasks into disk.
@@ -129,11 +130,9 @@ public class TaskPersister implements PersisterQueue.Listener {
                ImageWriteQueueItem.class);
    }

    /** Reads task ids from file. This should not be called in lock. */
    @NonNull
    SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
        if (mTaskIdsInFile.get(userId) != null) {
            return mTaskIdsInFile.get(userId).clone();
        }
    SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
        final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
        synchronized (mIoLock) {
            BufferedReader reader = null;
@@ -154,11 +153,10 @@ public class TaskPersister implements PersisterQueue.Listener {
                IoUtils.closeQuietly(reader);
            }
        }
        mTaskIdsInFile.put(userId, persistedTaskIds);
        return persistedTaskIds.clone();
        Slog.i(TAG, "Loaded persisted task ids for user " + userId);
        return persistedTaskIds;
    }


    @VisibleForTesting
    void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
        if (userId < 0) {
@@ -183,6 +181,10 @@ public class TaskPersister implements PersisterQueue.Listener {
        }
    }

    void setPersistedTaskIds(int userId, @NonNull SparseBooleanArray taskIds) {
        mTaskIdsInFile.put(userId, taskIds);
    }

    void unloadUserDataFromMemory(int userId) {
        mTaskIdsInFile.delete(userId);
    }
@@ -241,7 +243,7 @@ public class TaskPersister implements PersisterQueue.Listener {
        return item != null ? item.mImage : null;
    }

    private String fileToString(File file) {
    private static String fileToString(File file) {
        final String newline = System.lineSeparator();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file));
@@ -272,44 +274,64 @@ public class TaskPersister implements PersisterQueue.Listener {
        return null;
    }

    List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
        final ArrayList<Task> tasks = new ArrayList<Task>();
        ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();

        File userTasksDir = getUserTasksDir(userId);

        File[] recentFiles = userTasksDir.listFiles();
    /** Loads task files from disk. This should not be called in lock. */
    static RecentTaskFiles loadTasksForUser(int userId) {
        final ArrayList<RecentTaskFile> taskFiles = new ArrayList<>();
        final File userTasksDir = getUserTasksDir(userId);
        final File[] recentFiles = userTasksDir.listFiles();
        if (recentFiles == null) {
            Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
            return tasks;
        }

        for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
            File taskFile = recentFiles[taskNdx];
            if (DEBUG) {
                Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                        + ", taskFile=" + taskFile.getName());
            Slog.i(TAG, "loadTasksForUser: Unable to list files from " + userTasksDir
                    + " exists=" + userTasksDir.exists());
            return new RecentTaskFiles(new File[0], taskFiles);
        }

        for (File taskFile : recentFiles) {
            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
                continue;
            }
            final int taskId;
            try {
                final int taskId = Integer.parseInt(taskFile.getName().substring(
                taskId = Integer.parseInt(taskFile.getName().substring(
                        0 /* beginIndex */,
                        taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
                if (preaddedTasks.get(taskId, false)) {
                    Slog.w(TAG, "Task #" + taskId +
                            " has already been created so we don't restore again");
                    continue;
                }
            } catch (NumberFormatException e) {
                Slog.w(TAG, "Unexpected task file name", e);
                continue;
            }
            try {
                taskFiles.add(new RecentTaskFile(taskId, taskFile));
            } catch (IOException e) {
                Slog.w(TAG, "Failed to read file: " + fileToString(taskFile), e);
                taskFile.delete();
            }
        }
        return new RecentTaskFiles(recentFiles, taskFiles);
    }

    /** Restores tasks from raw bytes (no read storage operation). */
    ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
            IntArray existedTaskIds) {
        final ArrayList<Task> tasks = new ArrayList<>();
        final ArrayList<RecentTaskFile> taskFiles = recentTaskFiles.mLoadedFiles;
        if (taskFiles.isEmpty()) {
            return tasks;
        }

        final ArraySet<Integer> recoveredTaskIds = new ArraySet<>();
        for (int taskNdx = 0; taskNdx < taskFiles.size(); ++taskNdx) {
            final RecentTaskFile recentTask = taskFiles.get(taskNdx);
            if (existedTaskIds.contains(recentTask.mTaskId)) {
                Slog.w(TAG, "Task #" + recentTask.mTaskId
                        + " has already been created, so skip restoring");
                continue;
            }
            final File taskFile = recentTask.mFile;
            if (DEBUG) {
                Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                        + ", taskFile=" + taskFile.getName());
            }

            boolean deleteFile = false;
            try (InputStream is = new FileInputStream(taskFile)) {
            try (InputStream is = recentTask.mXmlContent) {
                final TypedXmlPullParser in = Xml.resolvePullParser(is);

                int event;
@@ -345,7 +367,7 @@ public class TaskPersister implements PersisterQueue.Listener {
                                } else if (userId != task.mUserId) {
                                    // Should not happen.
                                    Slog.wtf(TAG, "Task with userId " + task.mUserId + " found in "
                                            + userTasksDir.getAbsolutePath());
                                            + taskFile.getAbsolutePath());
                                } else {
                                    // Looks fine.
                                    mTaskSupervisor.setNextTaskIdForUser(taskId, userId);
@@ -377,7 +399,7 @@ public class TaskPersister implements PersisterQueue.Listener {
        }

        if (!DEBUG) {
            removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles());
            removeObsoleteFiles(recoveredTaskIds, recentTaskFiles.mUserTaskFiles);
        }

        // Fix up task affiliation from taskIds
@@ -456,7 +478,7 @@ public class TaskPersister implements PersisterQueue.Listener {
        SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
        synchronized (mService.mGlobalLock) {
            for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId);
                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForLoadedUser(userId);
                SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
                if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
                    continue;
@@ -512,6 +534,30 @@ public class TaskPersister implements PersisterQueue.Listener {
        return parentDir.isDirectory() || parentDir.mkdir();
    }

    private static class RecentTaskFile {
        final int mTaskId;
        final File mFile;
        final ByteArrayInputStream mXmlContent;

        RecentTaskFile(int taskId, File file) throws IOException {
            mTaskId = taskId;
            mFile = file;
            mXmlContent = new ByteArrayInputStream(Files.readAllBytes(file.toPath()));
        }
    }

    static class RecentTaskFiles {
        /** All files under the user task directory. */
        final File[] mUserTaskFiles;
        /** The successfully loaded files. */
        final ArrayList<RecentTaskFile> mLoadedFiles;

        RecentTaskFiles(File[] userFiles, ArrayList<RecentTaskFile> loadedFiles) {
            mUserTaskFiles = userFiles;
            mLoadedFiles = loadedFiles;
        }
    }

    private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
        private final ActivityTaskManagerService mService;
        private final Task mTask;
+14 −15
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -73,6 +72,7 @@ import android.os.SystemClock;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.SparseBooleanArray;
import android.view.Surface;
import android.window.TaskSnapshot;
@@ -527,20 +527,20 @@ public class RecentTasksTest extends WindowTestsBase {
        mTaskPersister.mUserTaskIdsOverride.put(1, true);
        mTaskPersister.mUserTaskIdsOverride.put(2, true);
        mTaskPersister.mUserTasksOverride = new ArrayList<>();
        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));

        // Assert no user tasks are initially loaded
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);

        // Load user 0 tasks
        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
        assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));

        // Load user 1 tasks
        mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_1_ID);
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID);
        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
@@ -575,15 +575,15 @@ public class RecentTasksTest extends WindowTestsBase {
        mTaskPersister.mUserTaskIdsOverride.put(2, true);
        mTaskPersister.mUserTaskIdsOverride.put(3, true);
        mTaskPersister.mUserTasksOverride = new ArrayList<>();
        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build());
        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));
        mTaskPersister.mUserTasksOverride.add(mTasks.get(2));

        // Assert no user tasks are initially loaded
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);

        // Load tasks
        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);

        // Sort the time descendingly so the order should be in-sync with task recency (most
@@ -1419,8 +1419,6 @@ public class RecentTasksTest extends WindowTestsBase {
    }

    private List<RecentTaskInfo> getRecentTasks(int flags) {
        doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
        doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
        return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */,
                TEST_USER_0_ID, 0 /* callingUid */).getList();
    }
@@ -1590,19 +1588,20 @@ public class RecentTasksTest extends WindowTestsBase {
        }

        @Override
        SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
        SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
            if (mUserTaskIdsOverride != null) {
                return mUserTaskIdsOverride;
            }
            return super.loadPersistedTaskIdsForUser(userId);
            return super.readPersistedTaskIdsFromFileForUser(userId);
        }

        @Override
        List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
        ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
                IntArray existedTaskIds) {
            if (mUserTasksOverride != null) {
                return mUserTasksOverride;
            }
            return super.restoreTasksForUserLocked(userId, preaddedTasks);
            return super.restoreTasksForUserLocked(userId, recentTaskFiles, existedTaskIds);
        }
    }

+1 −3
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@ import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;

import androidx.test.filters.FlakyTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -81,7 +79,7 @@ public class TaskPersisterTest {
        }
        mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, mTestUserId);
        SparseBooleanArray newTaskIdsOnFile = mTaskPersister
                .loadPersistedTaskIdsForUser(mTestUserId);
                .readPersistedTaskIdsFromFileForUser(mTestUserId);
        assertEquals("TaskIds written differ from TaskIds read back from file",
                taskIdsOnFile, newTaskIdsOnFile);
    }