Merge "Block the shutdown process until the snapshots are written to disk." into main
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 70a8f56..a077a0b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2054,6 +2054,8 @@
                 break;
             }
         }
+        long timeRemaining = endTime - System.currentTimeMillis();
+        mWindowManager.mSnapshotController.mTaskSnapshotController.waitFlush(timeRemaining);
 
         // Force checkReadyForSleep to complete.
         checkReadyForSleepLocked(false /* allowDelay */);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c89feb4..46312af 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2853,11 +2853,9 @@
     }
 
     void prepareForShutdown() {
+        mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown();
         for (int i = 0; i < getChildCount(); i++) {
-            final int displayId = getChildAt(i).mDisplayId;
-            mWindowManager.mSnapshotController.mTaskSnapshotController
-                    .snapshotForShutdown(displayId);
-            createSleepToken("shutdown", displayId);
+            createSleepToken("shutdown", getChildAt(i).mDisplayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index bd8e8f4..8b63ecf7 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -103,12 +103,42 @@
     }
 
     /**
-     * Write out everything in the queue because of shutdown.
+     * Prepare to enqueue all visible task snapshots because of shutdown.
      */
-    void shutdown() {
+    void prepareShutdown() {
         synchronized (mLock) {
             mShutdown = true;
-            mLock.notifyAll();
+        }
+    }
+
+    private boolean isQueueEmpty() {
+        synchronized (mLock) {
+            return mWriteQueue.isEmpty() || mQueueIdling || mPaused;
+        }
+    }
+
+    void waitFlush(long timeout) {
+        if (timeout <= 0) {
+            return;
+        }
+        final long endTime = System.currentTimeMillis() + timeout;
+        while (true) {
+            if (!isQueueEmpty()) {
+                long timeRemaining = endTime - System.currentTimeMillis();
+                if (timeRemaining > 0) {
+                    synchronized (mLock) {
+                        try {
+                            mLock.wait(timeRemaining);
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Snapshot Persist Queue flush timed out");
+                    break;
+                }
+            } else {
+                break;
+            }
         }
     }
 
@@ -139,7 +169,9 @@
             mWriteQueue.addLast(item);
         }
         item.onQueuedLocked();
-        ensureStoreQueueDepthLocked();
+        if (!mShutdown) {
+            ensureStoreQueueDepthLocked();
+        }
         if (!mPaused) {
             mLock.notifyAll();
         }
@@ -213,6 +245,9 @@
                     if (!writeQueueEmpty && !mPaused) {
                         continue;
                     }
+                    if (mShutdown && writeQueueEmpty) {
+                        mLock.notifyAll();
+                    }
                     try {
                         mQueueIdling = writeQueueEmpty;
                         mLock.wait();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 9fe3f756..c130931 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -309,23 +309,31 @@
     /**
      * Record task snapshots before shutdown.
      */
-    void snapshotForShutdown(int displayId) {
+    void prepareShutdown() {
         if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) {
             return;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
-        if (displayContent == null) {
+        // Make write items run in a batch.
+        mPersister.mSnapshotPersistQueue.setPaused(true);
+        mPersister.mSnapshotPersistQueue.prepareShutdown();
+        for (int i = 0; i < mService.mRoot.getChildCount(); i++) {
+            mService.mRoot.getChildAt(i).forAllLeafTasks(task -> {
+                if (task.isVisible() && !task.isActivityTypeHome()) {
+                    final TaskSnapshot snapshot = captureSnapshot(task);
+                    if (snapshot != null) {
+                        mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                    }
+                }
+            }, true /* traverseTopToBottom */);
+        }
+        mPersister.mSnapshotPersistQueue.setPaused(false);
+    }
+
+    void waitFlush(long timeout) {
+        if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) {
             return;
         }
-        displayContent.forAllLeafTasks(task -> {
-            if (task.isVisible() && !task.isActivityTypeHome()) {
-                final TaskSnapshot snapshot = captureSnapshot(task);
-                if (snapshot != null) {
-                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
-                }
-            }
-        }, true /* traverseTopToBottom */);
-        mPersister.mSnapshotPersistQueue.shutdown();
+        mPersister.mSnapshotPersistQueue.waitFlush(timeout);
     }
 
     /**