Loading core/java/android/app/ResourcesManager.java +29 −3 Original line number Diff line number Diff line Loading @@ -160,7 +160,9 @@ public class ResourcesManager { return; } final var sharedLibAssets = new SharedLibraryAssets(appInfo); final var application = ActivityThread.currentActivityThread().getApplication(); final var currentAppInfo = application != null ? application.getApplicationInfo() : null; final var sharedLibAssets = new SharedLibraryAssets(appInfo, currentAppInfo); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId Loading Loading @@ -191,7 +193,7 @@ public class ResourcesManager { synchronized (mLock) { size = mSharedLibAssetsMap.size(); if (assets == AssetManager.getSystem()) { if (size == 0 || assets == AssetManager.getSystem()) { return new Pair<>(assets, size); } collector = new PathCollector(resourcesKeyFromAssets(assets)); Loading Loading @@ -1998,10 +2000,30 @@ public class ResourcesManager { public static class SharedLibraryAssets { private final ResourcesKey mResourcesKey; private SharedLibraryAssets(ApplicationInfo appInfo) { private SharedLibraryAssets(@NonNull ApplicationInfo appInfo, @Nullable ApplicationInfo baseAppInfo) { // We're loading all library's files as shared libs, regardless where they are in // its own ApplicationInfo. final var collector = new PathCollector(null); // Pre-populate the collector's sets with the base app paths so they all get filtered // out if they exist in the info that's being registered as well. // Note: if someone is registering their own appInfo, we can't filter out anything // here and this means any asset path changes are going to be ignored. if (baseAppInfo != null && !baseAppInfo.sourceDir.equals(appInfo.sourceDir)) { collector.libsSet.add(baseAppInfo.sourceDir); if (baseAppInfo.splitSourceDirs != null) { collector.libsSet.addAll(Arrays.asList(baseAppInfo.splitSourceDirs)); } if (baseAppInfo.sharedLibraryFiles != null) { collector.libsSet.addAll(Arrays.asList(baseAppInfo.sharedLibraryFiles)); } if (baseAppInfo.resourceDirs != null) { collector.overlaysSet.addAll(Arrays.asList(baseAppInfo.resourceDirs)); } if (baseAppInfo.overlayPaths != null) { collector.overlaysSet.addAll(Arrays.asList(baseAppInfo.overlayPaths)); } } PathCollector.appendNewPath(appInfo.sourceDir, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.splitSourceDirs, collector.libsSet, Loading @@ -2013,6 +2035,10 @@ public class ResourcesManager { PathCollector.appendAllNewPaths(appInfo.overlayPaths, collector.overlaysSet, collector.orderedOverlays); mResourcesKey = collector.collectedKey(); if (DEBUG) { Log.i(TAG, "Created shared library assets: " + mResourcesKey); } } /** Loading core/tests/coretests/src/android/content/res/ResourcesManagerTest.java +44 −65 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.platform.test.annotations.Postsubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Display; Loading @@ -43,12 +42,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; Loading @@ -66,6 +65,7 @@ public class ResourcesManagerTest { public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private ResourcesManager mResourcesManager; private ResourcesManager mOldResourcesManager; private Map<Integer, DisplayMetrics> mDisplayMetricsMap; @Before Loading Loading @@ -115,6 +115,12 @@ public class ResourcesManagerTest { return mDisplayMetricsMap.get(displayId); } }; mOldResourcesManager = ResourcesManager.setInstance(mResourcesManager); } @After public void tearDown() { ResourcesManager.setInstance(mOldResourcesManager); } private PackageManager getPackageManager() { Loading Loading @@ -363,11 +369,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); // Create a Resources before register resources' paths for a package. Resources resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, Loading @@ -380,16 +381,11 @@ public class ResourcesManagerTest { assertNotSame(oriResImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading @@ -398,11 +394,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); Loading @@ -412,15 +403,11 @@ public class ResourcesManagerTest { CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(resources); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading @@ -429,11 +416,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesCreatedByConstructorAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); // Create a Resources through constructor directly before register resources' paths. final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); Loading @@ -449,15 +431,11 @@ public class ResourcesManagerTest { assertNotSame(oriResImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading Loading @@ -509,9 +487,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesWithOutdatedImplAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); Resources old_resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); Loading @@ -532,44 +507,48 @@ public class ResourcesManagerTest { // which has proper asset paths appended. assertNotSame(oldImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } private static boolean allResourcePathsLoaded(String[] resourcePaths, ApkAssets[] loadedAsset) { for (int i = 0; i < resourcePaths.length; i++) { if (!resourcePaths[i].endsWith(".apk")) { continue; } boolean found = false; for (int j = 0; j < loadedAsset.length; j++) { if (loadedAsset[j].getAssetPath().equals(resourcePaths[i])) { found = true; } } if (!found) { return false; } } return true; @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testRegisteringOwnApplicationInfo() { Resources old_resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(old_resources); ResourcesImpl oldImpl = old_resources.getImpl(); ApplicationInfo appInfo = InstrumentationRegistry.getInstrumentation().getContext().getApplicationInfo(); Resources.registerResourcePaths(TEST_LIB, appInfo); // Create another resources with identical parameters. Resources resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(resources); assertNotSame(oldImpl, resources.getImpl()); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(containsPath(appInfo.sourceDir, loadedAssets)); assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); } private static String[] removeDuplicates(String[] paths) { var pathList = new ArrayList<String>(); var pathSet = new ArraySet<String>(); final int pathsLen = paths.length; for (int i = 0; i < pathsLen; i++) { if (pathSet.add(paths[i])) { pathList.add(paths[i]); private static boolean containsPath(String substring, ApkAssets[] assets) { for (final var asset : assets) { if (asset.getAssetPath().contains(substring)) { return true; } } return pathList.toArray(new String[0]); return false; } } Loading
core/java/android/app/ResourcesManager.java +29 −3 Original line number Diff line number Diff line Loading @@ -160,7 +160,9 @@ public class ResourcesManager { return; } final var sharedLibAssets = new SharedLibraryAssets(appInfo); final var application = ActivityThread.currentActivityThread().getApplication(); final var currentAppInfo = application != null ? application.getApplicationInfo() : null; final var sharedLibAssets = new SharedLibraryAssets(appInfo, currentAppInfo); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId Loading Loading @@ -191,7 +193,7 @@ public class ResourcesManager { synchronized (mLock) { size = mSharedLibAssetsMap.size(); if (assets == AssetManager.getSystem()) { if (size == 0 || assets == AssetManager.getSystem()) { return new Pair<>(assets, size); } collector = new PathCollector(resourcesKeyFromAssets(assets)); Loading Loading @@ -1998,10 +2000,30 @@ public class ResourcesManager { public static class SharedLibraryAssets { private final ResourcesKey mResourcesKey; private SharedLibraryAssets(ApplicationInfo appInfo) { private SharedLibraryAssets(@NonNull ApplicationInfo appInfo, @Nullable ApplicationInfo baseAppInfo) { // We're loading all library's files as shared libs, regardless where they are in // its own ApplicationInfo. final var collector = new PathCollector(null); // Pre-populate the collector's sets with the base app paths so they all get filtered // out if they exist in the info that's being registered as well. // Note: if someone is registering their own appInfo, we can't filter out anything // here and this means any asset path changes are going to be ignored. if (baseAppInfo != null && !baseAppInfo.sourceDir.equals(appInfo.sourceDir)) { collector.libsSet.add(baseAppInfo.sourceDir); if (baseAppInfo.splitSourceDirs != null) { collector.libsSet.addAll(Arrays.asList(baseAppInfo.splitSourceDirs)); } if (baseAppInfo.sharedLibraryFiles != null) { collector.libsSet.addAll(Arrays.asList(baseAppInfo.sharedLibraryFiles)); } if (baseAppInfo.resourceDirs != null) { collector.overlaysSet.addAll(Arrays.asList(baseAppInfo.resourceDirs)); } if (baseAppInfo.overlayPaths != null) { collector.overlaysSet.addAll(Arrays.asList(baseAppInfo.overlayPaths)); } } PathCollector.appendNewPath(appInfo.sourceDir, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.splitSourceDirs, collector.libsSet, Loading @@ -2013,6 +2035,10 @@ public class ResourcesManager { PathCollector.appendAllNewPaths(appInfo.overlayPaths, collector.overlaysSet, collector.orderedOverlays); mResourcesKey = collector.collectedKey(); if (DEBUG) { Log.i(TAG, "Created shared library assets: " + mResourcesKey); } } /** Loading
core/tests/coretests/src/android/content/res/ResourcesManagerTest.java +44 −65 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.platform.test.annotations.Postsubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Display; Loading @@ -43,12 +42,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; Loading @@ -66,6 +65,7 @@ public class ResourcesManagerTest { public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private ResourcesManager mResourcesManager; private ResourcesManager mOldResourcesManager; private Map<Integer, DisplayMetrics> mDisplayMetricsMap; @Before Loading Loading @@ -115,6 +115,12 @@ public class ResourcesManagerTest { return mDisplayMetricsMap.get(displayId); } }; mOldResourcesManager = ResourcesManager.setInstance(mResourcesManager); } @After public void tearDown() { ResourcesManager.setInstance(mOldResourcesManager); } private PackageManager getPackageManager() { Loading Loading @@ -363,11 +369,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); // Create a Resources before register resources' paths for a package. Resources resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, Loading @@ -380,16 +381,11 @@ public class ResourcesManagerTest { assertNotSame(oriResImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading @@ -398,11 +394,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); Loading @@ -412,15 +403,11 @@ public class ResourcesManagerTest { CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(resources); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading @@ -429,11 +416,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesCreatedByConstructorAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all // the static method can interact with this test smoothly. ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); // Create a Resources through constructor directly before register resources' paths. final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); Loading @@ -449,15 +431,11 @@ public class ResourcesManagerTest { assertNotSame(oriResImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } @Test Loading Loading @@ -509,9 +487,6 @@ public class ResourcesManagerTest { @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesWithOutdatedImplAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); Resources old_resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); Loading @@ -532,44 +507,48 @@ public class ResourcesManagerTest { // which has proper asset paths appended. assertNotSame(oldImpl, resources.getImpl()); String[] resourcePaths = appInfo.getAllApkPaths(); resourcePaths = removeDuplicates(resourcePaths); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(allResourcePathsLoaded(resourcePaths, loadedAssets)); assertTrue(containsPath(TEST_LIB, loadedAssets)); // Package resources' paths should be cached in ResourcesManager. assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); // Revert the ResourcesManager instance back. ResourcesManager.setInstance(oriResourcesManager); } private static boolean allResourcePathsLoaded(String[] resourcePaths, ApkAssets[] loadedAsset) { for (int i = 0; i < resourcePaths.length; i++) { if (!resourcePaths[i].endsWith(".apk")) { continue; } boolean found = false; for (int j = 0; j < loadedAsset.length; j++) { if (loadedAsset[j].getAssetPath().equals(resourcePaths[i])) { found = true; } } if (!found) { return false; } } return true; @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testRegisteringOwnApplicationInfo() { Resources old_resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(old_resources); ResourcesImpl oldImpl = old_resources.getImpl(); ApplicationInfo appInfo = InstrumentationRegistry.getInstrumentation().getContext().getApplicationInfo(); Resources.registerResourcePaths(TEST_LIB, appInfo); // Create another resources with identical parameters. Resources resources = mResourcesManager.getResources( null, APP_ONE_RES_DIR, null, null, null, null, null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null); assertNotNull(resources); assertNotSame(oldImpl, resources.getImpl()); ApkAssets[] loadedAssets = resources.getAssets().getApkAssets(); assertTrue(containsPath(appInfo.sourceDir, loadedAssets)); assertNotNull(ResourcesManager.getInstance().getRegisteredResourcePaths().get(TEST_LIB)); } private static String[] removeDuplicates(String[] paths) { var pathList = new ArrayList<String>(); var pathSet = new ArraySet<String>(); final int pathsLen = paths.length; for (int i = 0; i < pathsLen; i++) { if (pathSet.add(paths[i])) { pathList.add(paths[i]); private static boolean containsPath(String substring, ApkAssets[] assets) { for (final var asset : assets) { if (asset.getAssetPath().contains(substring)) { return true; } } return pathList.toArray(new String[0]); return false; } }