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

Commit 4bccb465 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Moving recent tasks and images to /data/system_ce

Moved user sensitive recents data to the credential encrypted directory
/data/system_ce. Since this directory is not available before the user
is unlocked, and unavailable task ids are needed to be known before
assigning an id to a new task, this change adds a file in /data/system_de
for each user, to store the ids of the tasks present in /data/system_ce.

Bug: b/24569398
Change-Id: I340d1abe23e2594e2cee4bff89a697bd8dc61fc7
parent 05bdf88b
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -1892,7 +1892,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            case SYSTEM_USER_UNLOCK_MSG: {
                final int userId = msg.arg1;
                mSystemServiceManager.unlockUser(userId);
                mRecentTasks.cleanupLocked(userId);
                mRecentTasks.loadUserRecentsLocked(userId);
                installEncryptionUnawareProviders(userId);
                break;
            }
@@ -2539,7 +2539,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    }
    void onUserStoppedLocked(int userId) {
        mRecentTasks.unloadUserRecentsLocked(userId);
        mRecentTasks.unloadUserDataFromMemoryLocked(userId);
    }
    public void initPowerManagement() {
@@ -8725,6 +8725,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                    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 Collections.emptyList();
            }
            mRecentTasks.loadUserRecentsLocked(userId);
            final int recentsCount = mRecentTasks.size();
@@ -12519,7 +12523,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            // Make sure we have the current profile info, since it is needed for security checks.
            mUserController.onSystemReady();
            mRecentTasks.onSystemReady();
            mRecentTasks.onSystemReadyLocked();
            // Check to see if there are any update receivers to run.
            if (!mDidUpdate) {
                if (mWaitingUpdate) {
+3 −3
Original line number Diff line number Diff line
@@ -719,13 +719,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
    }

    int getNextTaskIdForUserLocked(int userId) {
        mRecentTasks.loadUserRecentsLocked(userId);
        final int currentTaskId = mCurTaskIdForUser.get(userId, userId * MAX_TASK_IDS_PER_USER);
        // for a userId u, a taskId can only be in the range
        // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
        // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
        int candidateTaskId = currentTaskId;
        while (anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
        while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
                || anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
                        INVALID_STACK_ID) != null) {
            candidateTaskId++;
            if (candidateTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
+68 −13
Original line number Diff line number Diff line
@@ -37,8 +37,12 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Environment;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings.System;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;

import java.io.File;
@@ -59,12 +63,22 @@ class RecentTasks extends ArrayList<TaskRecord> {

    // Maximum number recent bitmaps to keep in memory.
    private static final int MAX_RECENT_BITMAPS = 3;
    private static final int DEFAULT_INITIAL_CAPACITY = 5;

    /**
     * Save recent tasks information across reboots.
     */
    private final TaskPersister mTaskPersister;
    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(5);
    private final ActivityManagerService mService;
    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
            DEFAULT_INITIAL_CAPACITY);

    /**
     * Stores for each user task ids that are taken by tasks residing in persistent storage. These
     * tasks may or may not currently be in memory.
     */
    final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
            DEFAULT_INITIAL_CAPACITY);

    // Mainly to avoid object recreation on multiple calls.
    private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
@@ -75,6 +89,7 @@ class RecentTasks extends ArrayList<TaskRecord> {

    RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {
        File systemDir = Environment.getDataSystemDirectory();
        mService = service;
        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this);
        mStackSupervisor.setRecentTasks(this);
    }
@@ -87,6 +102,8 @@ class RecentTasks extends ArrayList<TaskRecord> {
     */
    void loadUserRecentsLocked(int userId) {
        if (!mUsersWithRecentsLoaded.get(userId)) {
            // Load the task ids if not loaded.
            loadPersistedTaskIdsForUserLocked(userId);
            Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
            addAll(mTaskPersister.restoreTasksForUserLocked(userId));
            cleanupLocked(userId);
@@ -94,21 +111,49 @@ class RecentTasks extends ArrayList<TaskRecord> {
        }
    }

    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));
        }
    }

    boolean taskIdTakenForUserLocked(int taskId, int userId) {
        loadPersistedTaskIdsForUserLocked(userId);
        return mPersistedTaskIds.get(userId).get(taskId);
    }

    void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
        if (task != null && task.stack != null && task.stack.isHomeStack()) {
            // Never persist the home stack.
            return;
        }
        syncPersistentTaskIdsLocked();
        mTaskPersister.wakeup(task, flush);
    }

    void onSystemReady() {
        clear();
        loadUserRecentsLocked(UserHandle.USER_SYSTEM);
        startPersisting();
    private void syncPersistentTaskIdsLocked() {
        for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
            int userId = mPersistedTaskIds.keyAt(i);
            if (mUsersWithRecentsLoaded.get(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();
            }
        }
        for (int i = size() - 1; i >= 0; i--) {
            TaskRecord task = get(i);
            if (task.isPersistable && (task.stack == null || !task.stack.isHomeStack())) {
                // Set of persisted taskIds for task.userId should not be null here
                mPersistedTaskIds.get(task.userId).put(task.taskId, true);
            }
        }
    }


    void startPersisting() {
    void onSystemReadyLocked() {
        clear();
        mTaskPersister.startPersisting();
    }

@@ -125,11 +170,14 @@ class RecentTasks extends ArrayList<TaskRecord> {
    }

    void flush() {
        synchronized (mService) {
            syncPersistentTaskIdsLocked();
        }
        mTaskPersister.flush();
    }

    /**
     * Returns all userIds for which recents from storage are loaded
     * Returns all userIds for which recents from persistent storage are loaded into this list.
     *
     * @return an array of userIds.
     */
@@ -149,12 +197,7 @@ class RecentTasks extends ArrayList<TaskRecord> {
        return usersWithRecentsLoaded;
    }

    /**
     * Removes recent tasks for this user if they are loaded, does not do anything otherwise.
     *
     * @param userId the user id.
     */
    void unloadUserRecentsLocked(int userId) {
    private void unloadUserRecentsLocked(int userId) {
        if (mUsersWithRecentsLoaded.get(userId)) {
            Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
            mUsersWithRecentsLoaded.delete(userId);
@@ -162,6 +205,18 @@ class RecentTasks extends ArrayList<TaskRecord> {
        }
    }

    /**
     * Removes recent tasks and any other state kept in memory for the passed in user. Does not
     * touch the information present on persistent storage.
     *
     * @param userId the id of the user
     */
    void unloadUserDataFromMemoryLocked(int userId) {
        unloadUserRecentsLocked(userId);
        mPersistedTaskIds.delete(userId);
        mTaskPersister.unloadUserDataFromMemory(userId);
    }

    TaskRecord taskForIdLocked(int id) {
        final int recentsCount = size();
        for (int i = 0; i < recentsCount; i++) {
+109 −11
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.am;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Debug;
@@ -26,11 +29,13 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;

import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParser;
@@ -38,9 +43,12 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -71,6 +79,7 @@ public class TaskPersister {
    private static final String TASKS_DIRNAME = "recent_tasks";
    private static final String TASK_EXTENSION = ".xml";
    private static final String IMAGES_DIRNAME = "recent_images";
    private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
    static final String IMAGE_EXTENSION = ".png";

    private static final String TAG_TASK = "task";
@@ -78,6 +87,7 @@ public class TaskPersister {
    private final ActivityManagerService mService;
    private final ActivityStackSupervisor mStackSupervisor;
    private final RecentTasks mRecentTasks;
    private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();

    /**
     * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
@@ -170,6 +180,64 @@ public class TaskPersister {
        }
    }

    @NonNull
    SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
        if (mTaskIdsInFile.get(userId) != null) {
            return mTaskIdsInFile.get(userId).clone();
        }
        final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
        BufferedReader reader = null;
        String line;
        try {
            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
            while ((line = reader.readLine()) != null) {
                for (String taskIdString : line.split("\\s+")) {
                    int id = Integer.parseInt(taskIdString);
                    persistedTaskIds.put(id, true);
                }
            }
        } catch (FileNotFoundException e) {
            // File doesn't exist. Ignore.
        } catch (Exception e) {
            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
        } finally {
            IoUtils.closeQuietly(reader);
        }
        mTaskIdsInFile.put(userId, persistedTaskIds);
        return persistedTaskIds.clone();
    }

    private void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds,
            int userId) {
        if (userId < 0) {
            return;
        }
        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
            return;
        }
        final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
            for (int i = 0; i < taskIds.size(); i++) {
                if (taskIds.valueAt(i)) {
                    writer.write(String.valueOf(taskIds.keyAt(i)));
                    writer.newLine();
                }
            }
        } catch (Exception e) {
            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
        } finally {
            IoUtils.closeQuietly(writer);
        }
        mTaskIdsInFile.put(userId, taskIds.clone());
    }

    void unloadUserDataFromMemory(int userId) {
        mTaskIdsInFile.delete(userId);
    }

    void wakeup(TaskRecord task, boolean flush) {
        synchronized (this) {
            if (task != null) {
@@ -336,14 +404,16 @@ public class TaskPersister {

        File[] recentFiles = userTasksDir.listFiles();
        if (recentFiles == null) {
            Slog.e(TAG, "restoreTasksForUser: Unable to list files from " + userTasksDir);
            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, "restoreTasksForUser: userId=" + userId
            if (DEBUG) {
                Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                        + ", taskFile=" + taskFile.getName());
            }
            BufferedReader reader = null;
            boolean deleteFile = false;
            try {
@@ -366,20 +436,29 @@ public class TaskPersister {
                                // out the stuff we just read, if we don't write it we will
                                // read the same thing again.
                                // mWriteQueue.add(new TaskWriteQueueItem(task));

                                final int taskId = task.taskId;
                                if (mStackSupervisor.anyTaskForIdLocked(taskId,
                                        /* restoreFromRecents= */ false, 0) != null) {
                                    // Should not happen.
                                    Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
                                } else if (userId != task.userId) {
                                    // Should not happen.
                                    Slog.wtf(TAG, "Task with userId " + task.userId + " found in "
                                            + userTasksDir.getAbsolutePath());
                                } else {
                                    // Looks fine.
                                    mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
                                // Check if it's a valid user id. Don't add tasks for removed users.
                                if (userId == task.userId) {
                                    task.isPersistable = true;
                                    tasks.add(task);
                                    recoveredTaskIds.add(taskId);
                                }
                            } else {
                                Slog.e(TAG, "restoreTasksForUser: Unable to restore taskFile="
                                Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="
                                        + taskFile + ": " + fileToString(taskFile));
                            }
                        } else {
                            Slog.wtf(TAG, "restoreTasksForUser: Unknown xml event=" + event
                            Slog.wtf(TAG, "restoreTasksForUserLocked: Unknown xml event=" + event
                                    + " name=" + name);
                        }
                    }
@@ -454,6 +533,20 @@ public class TaskPersister {
        }
    }

    private void writeTaskIdsFiles() {
        int candidateUserIds[];
        synchronized (mService) {
            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
        }
        SparseBooleanArray taskIdsToSave;
        for (int userId : candidateUserIds) {
            synchronized (mService) {
                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
            }
            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
        }
    }

    private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
        int[] candidateUserIds;
        synchronized (mService) {
@@ -472,8 +565,12 @@ public class TaskPersister {
        return BitmapFactory.decodeFile(filename);
    }

    static File getUserPersistedTaskIdsFile(int userId) {
        return new File(Environment.getDataSystemDeDirectory(userId), PERSISTED_TASK_IDS_FILENAME);
    }

    static File getUserTasksDir(int userId) {
        File userTasksDir = new File(Environment.getUserSystemDirectory(userId), TASKS_DIRNAME);
        File userTasksDir = new File(Environment.getDataSystemCeDirectory(userId), TASKS_DIRNAME);

        if (!userTasksDir.exists()) {
            if (!userTasksDir.mkdir()) {
@@ -485,7 +582,7 @@ public class TaskPersister {
    }

    static File getUserImagesDir(int userId) {
        File userImagesDir = new File(Environment.getUserSystemDirectory(userId), IMAGES_DIRNAME);
        File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);

        if (!userImagesDir.exists()) {
            if (!userImagesDir.mkdir()) {
@@ -535,6 +632,7 @@ public class TaskPersister {
                    }
                    removeObsoleteFiles(persistentTaskIds);
                }
                writeTaskIdsFiles();

                // If mNextWriteTime, then don't delay between each call to saveToXml().
                final WriteQueueItem item;