Stop restoring tasks added before recent is loaded

Previously we can have duplicated tasks sharing the same taskId in
RecentTasks due to race condition.

1. A task is created before RecentTasks#loadUserRecentsLocked
   (e.g. through adb)
2. RecentTasks#notifyTaskPersisterLocked eventually writes the task file
   to storage (e.g. XX_task.xml)
3. RecentTasks#loadUserRecentsLocked tries to recover XX_task.xml while
   the task has already been added to RecentTasks.

To fix the issue, the CL stops restoring tasks added before recent is
loaded.

Bug: 36796576
Test: Build and boot Android, check the recent is correctly loaded
Change-Id: Ib57977f2a0a63f7bf7db4d3fd70bdcc359e76f7d
(cherry picked from commit b8aeb6f12e51e6d3ecf6a5f40c953dc76ff64884)
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 9deabb3..e56b09d 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -78,9 +78,8 @@
     /** Special value for mWriteTime to mean don't wait, just write */
     private static final long FLUSH_QUEUE = -1;
 
-    private static final String RECENTS_FILENAME = "_task";
     private static final String TASKS_DIRNAME = "recent_tasks";
-    private static final String TASK_EXTENSION = ".xml";
+    private static final String TASK_FILENAME_SUFFIX = "_task.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";
@@ -412,7 +411,7 @@
         return null;
     }
 
-    List<TaskRecord> restoreTasksForUserLocked(final int userId) {
+    List<TaskRecord> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
         final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
@@ -430,6 +429,24 @@
                 Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                         + ", taskFile=" + taskFile.getName());
             }
+
+            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
+                continue;
+            }
+            try {
+                final int 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;
+            }
+
             BufferedReader reader = null;
             boolean deleteFile = false;
             try {
@@ -744,13 +761,11 @@
                         try {
                             atomicFile = new AtomicFile(new File(
                                     getUserTasksDir(task.userId),
-                                    String.valueOf(task.taskId) + RECENTS_FILENAME
-                                    + TASK_EXTENSION));
+                                    String.valueOf(task.taskId) + TASK_FILENAME_SUFFIX));
                             file = atomicFile.startWrite();
                             file.write(stringWriter.toString().getBytes());
                             file.write('\n');
                             atomicFile.finishWrite(file);
-
                         } catch (IOException e) {
                             if (file != null) {
                                 atomicFile.failWrite(file);