Loading services/core/java/com/android/server/am/ActivityManagerService.java +7 −3 Original line number Diff line number Diff line Loading @@ -1894,7 +1894,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; } Loading Loading @@ -2541,7 +2541,7 @@ public final class ActivityManagerService extends ActivityManagerNative } void onUserStoppedLocked(int userId) { mRecentTasks.unloadUserRecentsLocked(userId); mRecentTasks.unloadUserDataFromMemoryLocked(userId); } public void initPowerManagement() { Loading Loading @@ -8739,6 +8739,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(); Loading Loading @@ -12560,7 +12564,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) { services/core/java/com/android/server/am/ActivityStackSupervisor.java +3 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading services/core/java/com/android/server/am/RecentTasks.java +68 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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>(); Loading @@ -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); } Loading @@ -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); Loading @@ -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(); } Loading @@ -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. */ Loading @@ -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); Loading @@ -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++) { Loading services/core/java/com/android/server/am/TaskPersister.java +109 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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"; Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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 { Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -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()) { Loading @@ -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()) { Loading Loading @@ -535,6 +632,7 @@ public class TaskPersister { } removeObsoleteFiles(persistentTaskIds); } writeTaskIdsFiles(); // If mNextWriteTime, then don't delay between each call to saveToXml(). final WriteQueueItem item; Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +7 −3 Original line number Diff line number Diff line Loading @@ -1894,7 +1894,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; } Loading Loading @@ -2541,7 +2541,7 @@ public final class ActivityManagerService extends ActivityManagerNative } void onUserStoppedLocked(int userId) { mRecentTasks.unloadUserRecentsLocked(userId); mRecentTasks.unloadUserDataFromMemoryLocked(userId); } public void initPowerManagement() { Loading Loading @@ -8739,6 +8739,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(); Loading Loading @@ -12560,7 +12564,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) {
services/core/java/com/android/server/am/ActivityStackSupervisor.java +3 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading
services/core/java/com/android/server/am/RecentTasks.java +68 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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>(); Loading @@ -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); } Loading @@ -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); Loading @@ -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(); } Loading @@ -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. */ Loading @@ -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); Loading @@ -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++) { Loading
services/core/java/com/android/server/am/TaskPersister.java +109 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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"; Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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 { Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -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()) { Loading @@ -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()) { Loading Loading @@ -535,6 +632,7 @@ public class TaskPersister { } removeObsoleteFiles(persistentTaskIds); } writeTaskIdsFiles(); // If mNextWriteTime, then don't delay between each call to saveToXml(). final WriteQueueItem item; Loading