diff options
7 files changed, 153 insertions, 51 deletions
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index f2ba16cf43d6..d478b953c774 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -490,6 +490,17 @@ flag { description: "Sets Launch powermode for activity launches earlier" bug: "399380676" is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "scramble_snapshot_file_name" + namespace: "windowing_frontend" + description: "Scramble the file name of task snapshot." + bug: "293139053" + is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java index 21628341ea62..cb122f2080a2 100644 --- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java +++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java @@ -107,8 +107,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord && !ActivityManager.isLowRamDeviceStatic(); // Don't support Android Go setSnapshotEnabled(snapshotEnabled); mSnapshotPersistQueue = persistQueue; - mPersistInfoProvider = createPersistInfoProvider(service, - Environment::getDataSystemCeDirectory); + mPersistInfoProvider = createPersistInfoProvider(service); mPersister = new TaskSnapshotPersister( persistQueue, mPersistInfoProvider, @@ -117,6 +116,11 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord initialize(new ActivitySnapshotCache()); } + @VisibleForTesting + PersistInfoProvider createPersistInfoProvider(WindowManagerService service) { + return createPersistInfoProvider(service, Environment::getDataSystemCeDirectory); + } + @Override protected float initSnapshotScale() { final float config = mService.mContext.getResources().getFloat( diff --git a/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java b/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java index 5db02dff8351..aaa5a0074506 100644 --- a/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java @@ -16,10 +16,20 @@ package com.android.server.wm; +import static com.android.server.wm.AbsAppSnapshotController.TAG; + import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.window.TaskSnapshot; +import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; + import java.io.File; +import java.util.UUID; class BaseAppSnapshotPersister { static final String LOW_RES_FILE_POSTFIX = "_reduced"; @@ -29,6 +39,7 @@ class BaseAppSnapshotPersister { // Shared with SnapshotPersistQueue protected final Object mLock; protected final SnapshotPersistQueue mSnapshotPersistQueue; + @VisibleForTesting protected final PersistInfoProvider mPersistInfoProvider; BaseAppSnapshotPersister(SnapshotPersistQueue persistQueue, @@ -79,6 +90,8 @@ class BaseAppSnapshotPersister { private final boolean mEnableLowResSnapshots; private final float mLowResScaleFactor; private final boolean mUse16BitFormat; + private final SparseBooleanArray mInitializedUsers = new SparseBooleanArray(); + private final SparseArray<File> mScrambleDirectories = new SparseArray<>(); PersistInfoProvider(DirectoryResolver directoryResolver, String dirName, boolean enableLowResSnapshots, float lowResScaleFactor, boolean use16BitFormat) { @@ -91,9 +104,80 @@ class BaseAppSnapshotPersister { @NonNull File getDirectory(int userId) { + if (Flags.scrambleSnapshotFileName()) { + final File directory = getOrInitScrambleDirectory(userId); + if (directory != null) { + return directory; + } + } + return getBaseDirectory(userId); + } + + @NonNull + private File getBaseDirectory(int userId) { return new File(mDirectoryResolver.getSystemDirectoryForUser(userId), mDirName); } + @Nullable + private File getOrInitScrambleDirectory(int userId) { + synchronized (mScrambleDirectories) { + if (mInitializedUsers.get(userId)) { + return mScrambleDirectories.get(userId); + } + mInitializedUsers.put(userId, true); + final File scrambledDirectory = getScrambleDirectory(userId); + final File baseDir = getBaseDirectory(userId); + String newName = null; + // If directory exists, rename + if (scrambledDirectory.exists()) { + newName = UUID.randomUUID().toString(); + final File scrambleTo = new File(baseDir, newName); + if (!scrambledDirectory.renameTo(scrambleTo)) { + Slog.w(TAG, "SnapshotPersister rename scramble folder fail."); + return null; + } + } else { + // If directory not exists, mkDir. + if (!baseDir.exists() && !baseDir.mkdir()) { + Slog.w(TAG, "SnapshotPersister make base folder fail."); + return null; + } + if (!scrambledDirectory.mkdir()) { + Slog.e(TAG, "SnapshotPersister make scramble folder fail"); + return null; + } + // Move any existing files to this folder. + final String[] files = baseDir.list(); + if (files != null) { + for (String file : files) { + final File original = new File(baseDir, file); + if (original.isDirectory()) { + newName = file; + } else { + File to = new File(scrambledDirectory, file); + original.renameTo(to); + } + } + } + } + final File newFolder = new File(baseDir, newName); + mScrambleDirectories.put(userId, newFolder); + return newFolder; + } + } + + @NonNull + private File getScrambleDirectory(int userId) { + final File dir = getBaseDirectory(userId); + final String[] directories = dir.list( + (current, name) -> new File(current, name).isDirectory()); + if (directories != null && directories.length > 0) { + return new File(dir, directories[0]); + } else { + return new File(dir, UUID.randomUUID().toString()); + } + } + /** * Return if task snapshots are stored in 16 bit pixel format. * diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java index 948371f74a9c..ad706e879b72 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java @@ -63,11 +63,23 @@ public class ActivitySnapshotControllerTests extends TaskSnapshotPersisterTestBa super(0.8f /* highResScale */, 0.5f /* lowResScale */); } + private class TestActivitySnapshotController extends ActivitySnapshotController { + TestActivitySnapshotController(WindowManagerService service, + SnapshotPersistQueue persistQueue) { + super(service, persistQueue); + } + @Override + BaseAppSnapshotPersister.PersistInfoProvider createPersistInfoProvider( + WindowManagerService service) { + return mPersister.mPersistInfoProvider; + } + } @Override @Before public void setUp() { super.setUp(); - mActivitySnapshotController = new ActivitySnapshotController(mWm, mSnapshotPersistQueue); + mActivitySnapshotController = new TestActivitySnapshotController( + mWm, mSnapshotPersistQueue); spyOn(mActivitySnapshotController); doReturn(false).when(mActivitySnapshotController).shouldDisableSnapshots(); mActivitySnapshotController.resetTmpFields(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java index 51ea498811fc..f22ecb5eb3f9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java @@ -68,11 +68,8 @@ public class TaskSnapshotLowResDisabledTest extends TaskSnapshotPersisterTestBas public void testPersistAndLoadSnapshot() { mPersister.persistSnapshot(1, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] files = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg")}; - final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; + final File[] files = convertFilePath("1.proto", "1.jpg"); + final File[] nonExistsFiles = convertFilePath("1_reduced.proto"); assertTrueForFiles(files, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */); @@ -92,14 +89,9 @@ public class TaskSnapshotLowResDisabledTest extends TaskSnapshotPersisterTestBas taskIds.add(1); mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId}); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] existsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg")}; - final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2.proto"), - new File(FILES_DIR.getPath() + "/snapshots/2.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; + final File[] existsFiles = convertFilePath("1.proto", "1.jpg"); + final File[] nonExistsFiles = convertFilePath("1_reduced.proto", "2.proto", "2.jpg", + "2_reduced.jpg"); assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } @@ -112,14 +104,8 @@ public class TaskSnapshotLowResDisabledTest extends TaskSnapshotPersisterTestBas mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId}); mPersister.persistSnapshot(2, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] existsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2.proto"), - new File(FILES_DIR.getPath() + "/snapshots/2.jpg")}; - final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; + final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "2.proto", "2.jpg"); + final File[] nonExistsFiles = convertFilePath("1_reduced.jpg", "2_reduced.jpg"); assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 4b54e4464ca7..af06c14516a1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -75,9 +75,7 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa public void testPersistAndLoadSnapshot() { mPersister.persistSnapshot(1, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; + final File[] files = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg"); assertTrueForFiles(files, File::exists, " must exist"); final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */); assertNotNull(snapshot); @@ -140,13 +138,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa mSnapshotPersistQueue.waitForQueueEmpty(); // Make sure 1,2 were purged but removeObsoleteFiles wasn't. - final File[] existsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/3.proto"), - new File(FILES_DIR.getPath() + "/snapshots/4.proto")}; - final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/100.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.proto")}; + 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"); } @@ -427,14 +420,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa taskIds.add(1); mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId}); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] existsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; - final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/2.proto"), - new File(FILES_DIR.getPath() + "/snapshots/2.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; + final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg"); + final File[] nonExistsFiles = convertFilePath("2.proto", "2.jpg", "2_reduced.jpg"); assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } @@ -447,13 +434,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId}); mPersister.persistSnapshot(2, mTestUserId, createSnapshot()); mSnapshotPersistQueue.waitForQueueEmpty(); - final File[] existsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2.proto"), - new File(FILES_DIR.getPath() + "/snapshots/2.jpg"), - new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; + final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg", "2.proto", + "2.jpg", "2_reduced.jpg"); assertTrueForFiles(existsFiles, File::exists, " must exist"); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index 1e16c97de647..b2c195e8ebaa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.ContextWrapper; import android.content.res.Resources; @@ -46,6 +47,7 @@ import android.window.TaskSnapshot; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.AfterClass; @@ -129,12 +131,33 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { return; } for (File file : files) { - if (!file.isDirectory()) { - file.delete(); + if (file.isDirectory()) { + final File[] subFiles = file.listFiles(); + if (subFiles == null) { + continue; + } + for (File subFile : subFiles) { + subFile.delete(); + } } + file.delete(); } } + File[] convertFilePath(@NonNull String... fileNames) { + final File[] files = new File[fileNames.length]; + final String path; + if (Flags.scrambleSnapshotFileName()) { + path = mPersister.mPersistInfoProvider.getDirectory(mTestUserId).getPath(); + } else { + path = FILES_DIR.getPath() + "/snapshots/"; + } + for (int i = 0; i < fileNames.length; i++) { + files[i] = new File(path + fileNames[i]); + } + return files; + } + TaskSnapshot createSnapshot() { return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build(); } |