Loading core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,17 @@ flag { } } flag { name: "extending_persistence_snapshot_queue_depth" namespace: "windowing_frontend" description: "Use ImageReader to persist snapshot into disk, and extending the persistence snapshot queue depth." bug: "416144425" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "intercept_motion_from_move_to_cancel" namespace: "windowing_frontend" Loading services/core/java/com/android/server/wm/ActivitySnapshotController.java +8 −4 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; import static com.android.server.wm.SnapshotPersistQueue.MAX_HW_STORE_QUEUE_DEPTH; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -34,6 +34,7 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.window.flags.Flags; import java.io.File; import java.io.PrintWriter; Loading @@ -57,7 +58,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord private static final boolean DEBUG = false; private static final String TAG = AbsAppSnapshotController.TAG; // Maximum persisted snapshot count on disk. private static final int MAX_PERSIST_SNAPSHOT_COUNT = 20; static final int MAX_PERSIST_SNAPSHOT_COUNT = 20; static final String SNAPSHOTS_DIRNAME = "activity_snapshots"; Loading Loading @@ -353,8 +354,11 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } if (mPersister.mSnapshotPersistQueue.peekWriteQueueSize() >= MAX_STORE_QUEUE_DEPTH || mPersister.mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { final int maxStoreQueue = Flags.extendingPersistenceSnapshotQueueDepth() ? mSnapshotPersistQueue.mMaxTotalStoreQueue : MAX_HW_STORE_QUEUE_DEPTH; if (mSnapshotPersistQueue.peekWriteQueueSize() >= maxStoreQueue || mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { Slog.w(TAG, "Skipping recording activity snapshot, too many requests!"); return; } Loading services/core/java/com/android/server/wm/SnapshotPersistQueue.java +109 −10 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.hardware.HardwareBuffer; Loading @@ -49,6 +50,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.Iterator; /** * Singleton worker thread to queue up persist or delete tasks of {@link TaskSnapshot}s to disk. Loading @@ -56,7 +58,7 @@ import java.util.ArrayDeque; class SnapshotPersistQueue { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM; private static final long DELAY_MS = 100; static final int MAX_STORE_QUEUE_DEPTH = 2; static final int MAX_HW_STORE_QUEUE_DEPTH = 2; private static final int COMPRESS_QUALITY = 95; @GuardedBy("mLock") Loading @@ -71,9 +73,11 @@ class SnapshotPersistQueue { private final Object mLock = new Object(); private final UserManagerInternal mUserManagerInternal; private boolean mShutdown; final int mMaxTotalStoreQueue; SnapshotPersistQueue() { mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mMaxTotalStoreQueue = ActivityTaskManager.getMaxRecentTasksStatic(); } Object getLock() { Loading Loading @@ -173,7 +177,18 @@ class SnapshotPersistQueue { } private void addToQueueInternal(WriteQueueItem item, boolean insertToFront) { if (Flags.extendingPersistenceSnapshotQueueDepth()) { final Iterator<WriteQueueItem> iterator = mWriteQueue.iterator(); while (iterator.hasNext()) { final WriteQueueItem next = iterator.next(); if (item.isDuplicateOrExclusiveItem(next)) { iterator.remove(); break; } } } else { mWriteQueue.removeFirstOccurrence(item); } if (insertToFront) { mWriteQueue.addFirst(item); } else { Loading @@ -200,11 +215,41 @@ class SnapshotPersistQueue { @GuardedBy("mLock") private void ensureStoreQueueDepthLocked() { while (mStoreQueueItems.size() > MAX_STORE_QUEUE_DEPTH) { if (!Flags.extendingPersistenceSnapshotQueueDepth()) { while (mStoreQueueItems.size() > MAX_HW_STORE_QUEUE_DEPTH) { final StoreWriteQueueItem item = mStoreQueueItems.poll(); mWriteQueue.remove(item); Slog.i(TAG, "Queue is too deep! Purged item with index=" + item.mId); } return; } // Rules for store queue depth: // - Hardware render involved items < MAX_HW_STORE_QUEUE_DEPTH // - Total (SW + HW) items < mMaxTotalStoreQueue int hwStoreCount = 0; int totalStoreCount = 0; // Use descending iterator to keep the latest items. final Iterator<StoreWriteQueueItem> iterator = mStoreQueueItems.descendingIterator(); while (iterator.hasNext() && mStoreQueueItems.size() > MAX_HW_STORE_QUEUE_DEPTH) { final StoreWriteQueueItem item = iterator.next(); totalStoreCount++; boolean removeItem = false; if (mustPersistByHardwareRender(item.mSnapshot)) { hwStoreCount++; if (hwStoreCount > MAX_HW_STORE_QUEUE_DEPTH) { removeItem = true; } } if (!removeItem && totalStoreCount > mMaxTotalStoreQueue) { removeItem = true; } if (removeItem) { iterator.remove(); mWriteQueue.remove(item); Slog.i(TAG, "Queue is too deep! Purged item with index=" + item.mId); } } } void deleteSnapshot(int index, int userId, PersistInfoProvider provider) { Loading Loading @@ -302,6 +347,19 @@ class SnapshotPersistQueue { */ void onDequeuedLocked() { } boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { return false; } } static boolean mustPersistByHardwareRender(@NonNull TaskSnapshot snapshot) { final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); final int pixelFormat = hwBuffer.getFormat(); return !Flags.extendingPersistenceSnapshotQueueDepth() || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888) || !snapshot.isRealSnapshot() || TransitionAnimation.hasProtectedContent(hwBuffer); } StoreWriteQueueItem createStoreWriteQueueItem(int id, int userId, TaskSnapshot snapshot, Loading Loading @@ -411,10 +469,7 @@ class SnapshotPersistQueue { final int width = hwBuffer.getWidth(); final int height = hwBuffer.getHeight(); final int pixelFormat = hwBuffer.getFormat(); final Bitmap swBitmap = !Flags.reduceTaskSnapshotMemoryUsage() || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888) || !mSnapshot.isRealSnapshot() || TransitionAnimation.hasProtectedContent(hwBuffer) final Bitmap swBitmap = mustPersistByHardwareRender(mSnapshot) ? copyToSwBitmapReadBack() : copyToSwBitmapDirect(width, height, pixelFormat); if (swBitmap == null) { Loading Loading @@ -511,6 +566,28 @@ class SnapshotPersistQueue { && mPersistInfoProvider == other.mPersistInfoProvider; } /** Called when the item is going to be removed from write queue. */ void onRemovedFromWriteQueue() { mStoreQueueItems.remove(this); mSnapshot.removeReference(TaskSnapshot.REFERENCE_PERSIST); } @Override boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { if (equals(testItem)) { final StoreWriteQueueItem swqi = (StoreWriteQueueItem) testItem; if (swqi.mSnapshot != mSnapshot) { swqi.onRemovedFromWriteQueue(); return true; } } else if (testItem instanceof DeleteWriteQueueItem) { final DeleteWriteQueueItem dwqi = (DeleteWriteQueueItem) testItem; return dwqi.mId == mId && dwqi.mUserId == mUserId && dwqi.mPersistInfoProvider == mPersistInfoProvider; } return false; } @Override public String toString() { return "StoreWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}"; Loading Loading @@ -541,6 +618,28 @@ class SnapshotPersistQueue { public String toString() { return "DeleteWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}"; } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; final DeleteWriteQueueItem other = (DeleteWriteQueueItem) o; return mId == other.mId && mUserId == other.mUserId && mPersistInfoProvider == other.mPersistInfoProvider; } @Override boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { if (testItem instanceof StoreWriteQueueItem) { final StoreWriteQueueItem swqi = (StoreWriteQueueItem) testItem; if (swqi.mId == mId && swqi.mUserId == mUserId && swqi.mPersistInfoProvider == mPersistInfoProvider) { swqi.onRemovedFromWriteQueue(); return true; } return false; } return equals(testItem); } } void dump(PrintWriter pw, String prefix) { Loading services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +8 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; import static com.android.server.wm.ActivitySnapshotController.MAX_PERSIST_SNAPSHOT_COUNT; import static com.android.server.wm.SnapshotPersistQueue.MAX_HW_STORE_QUEUE_DEPTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; Loading @@ -39,6 +40,8 @@ import android.window.TaskSnapshot; import androidx.test.filters.SmallTest; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -275,7 +278,10 @@ public class ActivitySnapshotControllerTests extends TaskSnapshotPersisterTestBa mSnapshotPersistQueue.setPaused(true); final ArrayList<ActivityRecord> tmpList = new ArrayList<>(); for (int i = 0; i < MAX_STORE_QUEUE_DEPTH; ++i) { final int maxStoreQueue = Flags.extendingPersistenceSnapshotQueueDepth() ? MAX_PERSIST_SNAPSHOT_COUNT : MAX_HW_STORE_QUEUE_DEPTH; for (int i = 0; i < maxStoreQueue; ++i) { tmpList.clear(); final ActivityRecord activity = createActivityRecord(task); tmpList.add(activity); Loading services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; import android.view.Surface; import android.window.TaskSnapshot; Loading @@ -45,6 +47,7 @@ import androidx.test.filters.MediumTest; import com.android.server.wm.AppSnapshotLoader.PreRLegacySnapshotConfig; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -121,6 +124,7 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa * Tests that too many store write queue items are being purged. */ @Test @RequiresFlagsDisabled(Flags.FLAG_EXTENDING_PERSISTENCE_SNAPSHOT_QUEUE_DEPTH) public void testPurging() { mPersister.persistSnapshot(100, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); Loading @@ -143,6 +147,39 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } /** * Tests that too many store write queue items are being purged. */ @Test @RequiresFlagsEnabled(Flags.FLAG_EXTENDING_PERSISTENCE_SNAPSHOT_QUEUE_DEPTH) public void testPurging_HW() { mPersister.persistSnapshot(100, mTestUserId, createFakeSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); mSnapshotPersistQueue.setPaused(true); mPersister.persistSnapshot(1, mTestUserId, createFakeSnapshot()); mPersister.removeObsoleteFiles(new ArraySet<>(), new int[]{mTestUserId}); mPersister.persistSnapshot(2, mTestUserId, createFakeSnapshot()); mPersister.persistSnapshot(3, mTestUserId, createFakeSnapshot()); mPersister.persistSnapshot(4, mTestUserId, createFakeSnapshot()); // Verify there should only keep the latest request when received a duplicated id. mPersister.persistSnapshot(4, mTestUserId, createFakeSnapshot()); // Expected 3: One remove obsolete request, two persist request. assertEquals(3, mSnapshotPersistQueue.peekQueueSize()); mSnapshotPersistQueue.setPaused(false); mSnapshotPersistQueue.waitForQueueEmpty(); // Make sure 1,2 were purged but removeObsoleteFiles wasn't. final File[] existsFiles = convertFilePath("3.proto", "4.proto"); final File[] nonExistsFiles = convertFilePath("100.proto", "1.proto", "2.proto"); assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } TaskSnapshot createFakeSnapshot() { return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()) .setIsRealSnapshot(false).build(); } @Test public void testGetTaskId() { Loading Loading
core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,17 @@ flag { } } flag { name: "extending_persistence_snapshot_queue_depth" namespace: "windowing_frontend" description: "Use ImageReader to persist snapshot into disk, and extending the persistence snapshot queue depth." bug: "416144425" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { name: "intercept_motion_from_move_to_cancel" namespace: "windowing_frontend" Loading
services/core/java/com/android/server/wm/ActivitySnapshotController.java +8 −4 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; import static com.android.server.wm.SnapshotPersistQueue.MAX_HW_STORE_QUEUE_DEPTH; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -34,6 +34,7 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.window.flags.Flags; import java.io.File; import java.io.PrintWriter; Loading @@ -57,7 +58,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord private static final boolean DEBUG = false; private static final String TAG = AbsAppSnapshotController.TAG; // Maximum persisted snapshot count on disk. private static final int MAX_PERSIST_SNAPSHOT_COUNT = 20; static final int MAX_PERSIST_SNAPSHOT_COUNT = 20; static final String SNAPSHOTS_DIRNAME = "activity_snapshots"; Loading Loading @@ -353,8 +354,11 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } if (mPersister.mSnapshotPersistQueue.peekWriteQueueSize() >= MAX_STORE_QUEUE_DEPTH || mPersister.mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { final int maxStoreQueue = Flags.extendingPersistenceSnapshotQueueDepth() ? mSnapshotPersistQueue.mMaxTotalStoreQueue : MAX_HW_STORE_QUEUE_DEPTH; if (mSnapshotPersistQueue.peekWriteQueueSize() >= maxStoreQueue || mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { Slog.w(TAG, "Skipping recording activity snapshot, too many requests!"); return; } Loading
services/core/java/com/android/server/wm/SnapshotPersistQueue.java +109 −10 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.hardware.HardwareBuffer; Loading @@ -49,6 +50,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.Iterator; /** * Singleton worker thread to queue up persist or delete tasks of {@link TaskSnapshot}s to disk. Loading @@ -56,7 +58,7 @@ import java.util.ArrayDeque; class SnapshotPersistQueue { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM; private static final long DELAY_MS = 100; static final int MAX_STORE_QUEUE_DEPTH = 2; static final int MAX_HW_STORE_QUEUE_DEPTH = 2; private static final int COMPRESS_QUALITY = 95; @GuardedBy("mLock") Loading @@ -71,9 +73,11 @@ class SnapshotPersistQueue { private final Object mLock = new Object(); private final UserManagerInternal mUserManagerInternal; private boolean mShutdown; final int mMaxTotalStoreQueue; SnapshotPersistQueue() { mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mMaxTotalStoreQueue = ActivityTaskManager.getMaxRecentTasksStatic(); } Object getLock() { Loading Loading @@ -173,7 +177,18 @@ class SnapshotPersistQueue { } private void addToQueueInternal(WriteQueueItem item, boolean insertToFront) { if (Flags.extendingPersistenceSnapshotQueueDepth()) { final Iterator<WriteQueueItem> iterator = mWriteQueue.iterator(); while (iterator.hasNext()) { final WriteQueueItem next = iterator.next(); if (item.isDuplicateOrExclusiveItem(next)) { iterator.remove(); break; } } } else { mWriteQueue.removeFirstOccurrence(item); } if (insertToFront) { mWriteQueue.addFirst(item); } else { Loading @@ -200,11 +215,41 @@ class SnapshotPersistQueue { @GuardedBy("mLock") private void ensureStoreQueueDepthLocked() { while (mStoreQueueItems.size() > MAX_STORE_QUEUE_DEPTH) { if (!Flags.extendingPersistenceSnapshotQueueDepth()) { while (mStoreQueueItems.size() > MAX_HW_STORE_QUEUE_DEPTH) { final StoreWriteQueueItem item = mStoreQueueItems.poll(); mWriteQueue.remove(item); Slog.i(TAG, "Queue is too deep! Purged item with index=" + item.mId); } return; } // Rules for store queue depth: // - Hardware render involved items < MAX_HW_STORE_QUEUE_DEPTH // - Total (SW + HW) items < mMaxTotalStoreQueue int hwStoreCount = 0; int totalStoreCount = 0; // Use descending iterator to keep the latest items. final Iterator<StoreWriteQueueItem> iterator = mStoreQueueItems.descendingIterator(); while (iterator.hasNext() && mStoreQueueItems.size() > MAX_HW_STORE_QUEUE_DEPTH) { final StoreWriteQueueItem item = iterator.next(); totalStoreCount++; boolean removeItem = false; if (mustPersistByHardwareRender(item.mSnapshot)) { hwStoreCount++; if (hwStoreCount > MAX_HW_STORE_QUEUE_DEPTH) { removeItem = true; } } if (!removeItem && totalStoreCount > mMaxTotalStoreQueue) { removeItem = true; } if (removeItem) { iterator.remove(); mWriteQueue.remove(item); Slog.i(TAG, "Queue is too deep! Purged item with index=" + item.mId); } } } void deleteSnapshot(int index, int userId, PersistInfoProvider provider) { Loading Loading @@ -302,6 +347,19 @@ class SnapshotPersistQueue { */ void onDequeuedLocked() { } boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { return false; } } static boolean mustPersistByHardwareRender(@NonNull TaskSnapshot snapshot) { final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); final int pixelFormat = hwBuffer.getFormat(); return !Flags.extendingPersistenceSnapshotQueueDepth() || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888) || !snapshot.isRealSnapshot() || TransitionAnimation.hasProtectedContent(hwBuffer); } StoreWriteQueueItem createStoreWriteQueueItem(int id, int userId, TaskSnapshot snapshot, Loading Loading @@ -411,10 +469,7 @@ class SnapshotPersistQueue { final int width = hwBuffer.getWidth(); final int height = hwBuffer.getHeight(); final int pixelFormat = hwBuffer.getFormat(); final Bitmap swBitmap = !Flags.reduceTaskSnapshotMemoryUsage() || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888) || !mSnapshot.isRealSnapshot() || TransitionAnimation.hasProtectedContent(hwBuffer) final Bitmap swBitmap = mustPersistByHardwareRender(mSnapshot) ? copyToSwBitmapReadBack() : copyToSwBitmapDirect(width, height, pixelFormat); if (swBitmap == null) { Loading Loading @@ -511,6 +566,28 @@ class SnapshotPersistQueue { && mPersistInfoProvider == other.mPersistInfoProvider; } /** Called when the item is going to be removed from write queue. */ void onRemovedFromWriteQueue() { mStoreQueueItems.remove(this); mSnapshot.removeReference(TaskSnapshot.REFERENCE_PERSIST); } @Override boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { if (equals(testItem)) { final StoreWriteQueueItem swqi = (StoreWriteQueueItem) testItem; if (swqi.mSnapshot != mSnapshot) { swqi.onRemovedFromWriteQueue(); return true; } } else if (testItem instanceof DeleteWriteQueueItem) { final DeleteWriteQueueItem dwqi = (DeleteWriteQueueItem) testItem; return dwqi.mId == mId && dwqi.mUserId == mUserId && dwqi.mPersistInfoProvider == mPersistInfoProvider; } return false; } @Override public String toString() { return "StoreWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}"; Loading Loading @@ -541,6 +618,28 @@ class SnapshotPersistQueue { public String toString() { return "DeleteWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}"; } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; final DeleteWriteQueueItem other = (DeleteWriteQueueItem) o; return mId == other.mId && mUserId == other.mUserId && mPersistInfoProvider == other.mPersistInfoProvider; } @Override boolean isDuplicateOrExclusiveItem(WriteQueueItem testItem) { if (testItem instanceof StoreWriteQueueItem) { final StoreWriteQueueItem swqi = (StoreWriteQueueItem) testItem; if (swqi.mId == mId && swqi.mUserId == mUserId && swqi.mPersistInfoProvider == mPersistInfoProvider) { swqi.onRemovedFromWriteQueue(); return true; } return false; } return equals(testItem); } } void dump(PrintWriter pw, String prefix) { Loading
services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +8 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; import static com.android.server.wm.ActivitySnapshotController.MAX_PERSIST_SNAPSHOT_COUNT; import static com.android.server.wm.SnapshotPersistQueue.MAX_HW_STORE_QUEUE_DEPTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; Loading @@ -39,6 +40,8 @@ import android.window.TaskSnapshot; import androidx.test.filters.SmallTest; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -275,7 +278,10 @@ public class ActivitySnapshotControllerTests extends TaskSnapshotPersisterTestBa mSnapshotPersistQueue.setPaused(true); final ArrayList<ActivityRecord> tmpList = new ArrayList<>(); for (int i = 0; i < MAX_STORE_QUEUE_DEPTH; ++i) { final int maxStoreQueue = Flags.extendingPersistenceSnapshotQueueDepth() ? MAX_PERSIST_SNAPSHOT_COUNT : MAX_HW_STORE_QUEUE_DEPTH; for (int i = 0; i < maxStoreQueue; ++i) { tmpList.clear(); final ActivityRecord activity = createActivityRecord(task); tmpList.add(activity); Loading
services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; import android.view.Surface; import android.window.TaskSnapshot; Loading @@ -45,6 +47,7 @@ import androidx.test.filters.MediumTest; import com.android.server.wm.AppSnapshotLoader.PreRLegacySnapshotConfig; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -121,6 +124,7 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa * Tests that too many store write queue items are being purged. */ @Test @RequiresFlagsDisabled(Flags.FLAG_EXTENDING_PERSISTENCE_SNAPSHOT_QUEUE_DEPTH) public void testPurging() { mPersister.persistSnapshot(100, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); Loading @@ -143,6 +147,39 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } /** * Tests that too many store write queue items are being purged. */ @Test @RequiresFlagsEnabled(Flags.FLAG_EXTENDING_PERSISTENCE_SNAPSHOT_QUEUE_DEPTH) public void testPurging_HW() { mPersister.persistSnapshot(100, mTestUserId, createFakeSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); mSnapshotPersistQueue.setPaused(true); mPersister.persistSnapshot(1, mTestUserId, createFakeSnapshot()); mPersister.removeObsoleteFiles(new ArraySet<>(), new int[]{mTestUserId}); mPersister.persistSnapshot(2, mTestUserId, createFakeSnapshot()); mPersister.persistSnapshot(3, mTestUserId, createFakeSnapshot()); mPersister.persistSnapshot(4, mTestUserId, createFakeSnapshot()); // Verify there should only keep the latest request when received a duplicated id. mPersister.persistSnapshot(4, mTestUserId, createFakeSnapshot()); // Expected 3: One remove obsolete request, two persist request. assertEquals(3, mSnapshotPersistQueue.peekQueueSize()); mSnapshotPersistQueue.setPaused(false); mSnapshotPersistQueue.waitForQueueEmpty(); // Make sure 1,2 were purged but removeObsoleteFiles wasn't. final File[] existsFiles = convertFilePath("3.proto", "4.proto"); final File[] nonExistsFiles = convertFilePath("100.proto", "1.proto", "2.proto"); assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } TaskSnapshot createFakeSnapshot() { return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()) .setIsRealSnapshot(false).build(); } @Test public void testGetTaskId() { Loading