Loading AconfigFlags.bp +7 −0 Original line number Diff line number Diff line Loading @@ -492,6 +492,13 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } java_aconfig_library { name: "android.content.res.flags-aconfig-java-host", aconfig_declarations: "android.content.res.flags-aconfig", host_supported: true, defaults: ["framework-minus-apex-aconfig-java-defaults"], } // Media BetterTogether aconfig_declarations { name: "com.android.media.flags.bettertogether-aconfig", Loading core/java/android/app/ResourcesManager.java +137 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,32 @@ public class ResourcesManager { */ private LocaleConfig mLocaleConfig = new LocaleConfig(LocaleList.getEmptyLocaleList()); private final ArrayMap<String, SharedLibraryAssets> mSharedLibAssetsMap = new ArrayMap<>(); /** * The internal function to register the resources paths of a package (e.g. a shared library). * This will collect the package resources' paths from its ApplicationInfo and add them to all * existing and future contexts while the application is running. */ public void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { SharedLibraryAssets sharedLibAssets = new SharedLibraryAssets(appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.sharedLibraryFiles, appInfo.resourceDirs, appInfo.overlayPaths); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId + " has already been registered, this is a no-op."); return; } mSharedLibAssetsMap.put(uniqueId, sharedLibAssets); appendLibAssetsLocked(sharedLibAssets.getAllAssetPaths()); Slog.v(TAG, "The following resources' paths have been added: " + Arrays.toString(sharedLibAssets.getAllAssetPaths())); } } private static class ApkKey { public final String path; public final boolean sharedLib; Loading Loading @@ -278,6 +304,21 @@ public class ResourcesManager { public ResourcesManager() { } /** * Inject a customized ResourcesManager instance for testing, return the old ResourcesManager * instance. */ @UnsupportedAppUsage @VisibleForTesting public static ResourcesManager setInstance(ResourcesManager resourcesManager) { synchronized (ResourcesManager.class) { ResourcesManager oldResourceManager = sResourcesManager; sResourcesManager = resourcesManager; return oldResourceManager; } } @UnsupportedAppUsage public static ResourcesManager getInstance() { synchronized (ResourcesManager.class) { Loading Loading @@ -1480,6 +1521,56 @@ public class ResourcesManager { } } private void appendLibAssetsLocked(String[] libAssets) { synchronized (mLock) { // Record which ResourcesImpl need updating // (and what ResourcesKey they should update to). final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl == null) { Slog.w(TAG, "Found a ResourcesImpl which is null, skip it and continue to " + "append shared library assets for next ResourcesImpl."); continue; } var newDirs = new ArrayList<String>(); var dirsSet = new ArraySet<String>(); if (key.mLibDirs != null) { final int dirsLength = key.mLibDirs.length; for (int k = 0; k < dirsLength; k++) { newDirs.add(key.mLibDirs[k]); dirsSet.add(key.mLibDirs[k]); } } final int assetsLength = libAssets.length; for (int j = 0; j < assetsLength; j++) { if (dirsSet.add(libAssets[j])) { newDirs.add(libAssets[j]); } } String[] newLibAssets = newDirs.toArray(new String[0]); if (!Arrays.equals(newLibAssets, key.mLibDirs)) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, key.mOverlayPaths, newLibAssets, key.mDisplayId, key.mOverrideConfiguration, key.mCompatInfo, key.mLoaders)); } } redirectResourcesToNewImplLocked(updatedResourceKeys); } } private void applyNewResourceDirsLocked(@Nullable final String[] oldSourceDirs, @NonNull final ApplicationInfo appInfo) { try { Loading Loading @@ -1689,4 +1780,50 @@ public class ResourcesManager { } } } public static class SharedLibraryAssets{ private final String[] mAssetPaths; SharedLibraryAssets(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { mAssetPaths = collectAssetPaths(sourceDir, splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths); } private @NonNull String[] collectAssetPaths(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { final String[][] inputLists = { splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths }; final ArraySet<String> assetPathSet = new ArraySet<>(); final List<String> assetPathList = new ArrayList<>(); if (sourceDir != null) { assetPathSet.add(sourceDir); assetPathList.add(sourceDir); } for (int i = 0; i < inputLists.length; i++) { if (inputLists[i] != null) { for (int j = 0; j < inputLists[i].length; j++) { if (assetPathSet.add(inputLists[i][j])) { assetPathList.add(inputLists[i][j]); } } } } return assetPathList.toArray(new String[0]); } /** * @return all the asset paths of this collected in this class. */ public @NonNull String[] getAllAssetPaths() { return mAssetPaths; } } public @NonNull ArrayMap<String, SharedLibraryAssets> getSharedLibAssetsMap() { return new ArrayMap<>(mSharedLibAssetsMap); } } core/java/android/content/res/AssetManager.java +10 −0 Original line number Diff line number Diff line Loading @@ -471,6 +471,16 @@ public final class AssetManager implements AutoCloseable { return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/); } /** * @hide */ public void addSharedLibraryPaths(@NonNull String[] paths) { final int length = paths.length; for (int i = 0; i < length; i++) { addAssetPathInternal(paths[i], false, true); } } private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) { Objects.requireNonNull(path, "path"); synchronized (this) { Loading core/java/android/content/res/Resources.java +7 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.annotation.XmlRes; import android.app.Application; import android.app.ResourcesManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; Loading Loading @@ -2854,6 +2855,11 @@ public class Resources { @FlaggedApi(android.content.res.Flags.FLAG_REGISTER_RESOURCE_PATHS) public static void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { throw new UnsupportedOperationException("The implementation has not been done yet."); if (Flags.registerResourcePaths()) { ResourcesManager.getInstance().registerResourcePaths(uniqueId, appInfo); } else { throw new UnsupportedOperationException("Flag " + Flags.FLAG_REGISTER_RESOURCE_PATHS + " is disabled."); } } } core/java/android/content/res/ResourcesImpl.java +10 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.app.LocaleConfig; import android.app.ResourcesManager; import android.app.ResourcesManager.SharedLibraryAssets; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; Loading @@ -47,6 +48,7 @@ import android.os.Build; import android.os.LocaleList; import android.os.ParcelFileDescriptor; import android.os.Trace; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; Loading Loading @@ -197,6 +199,14 @@ public class ResourcesImpl { public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) { mAssets = assets; if (Flags.registerResourcePaths()) { ArrayMap<String, SharedLibraryAssets> sharedLibMap = ResourcesManager.getInstance().getSharedLibAssetsMap(); final int size = sharedLibMap.size(); for (int i = 0; i < size; i++) { assets.addSharedLibraryPaths(sharedLibMap.valueAt(i).getAllAssetPaths()); } } mMetrics.setToDefaults(); mDisplayAdjustments = displayAdjustments; mConfiguration.setToDefaults(); Loading Loading
AconfigFlags.bp +7 −0 Original line number Diff line number Diff line Loading @@ -492,6 +492,13 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } java_aconfig_library { name: "android.content.res.flags-aconfig-java-host", aconfig_declarations: "android.content.res.flags-aconfig", host_supported: true, defaults: ["framework-minus-apex-aconfig-java-defaults"], } // Media BetterTogether aconfig_declarations { name: "com.android.media.flags.bettertogether-aconfig", Loading
core/java/android/app/ResourcesManager.java +137 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,32 @@ public class ResourcesManager { */ private LocaleConfig mLocaleConfig = new LocaleConfig(LocaleList.getEmptyLocaleList()); private final ArrayMap<String, SharedLibraryAssets> mSharedLibAssetsMap = new ArrayMap<>(); /** * The internal function to register the resources paths of a package (e.g. a shared library). * This will collect the package resources' paths from its ApplicationInfo and add them to all * existing and future contexts while the application is running. */ public void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { SharedLibraryAssets sharedLibAssets = new SharedLibraryAssets(appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.sharedLibraryFiles, appInfo.resourceDirs, appInfo.overlayPaths); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId + " has already been registered, this is a no-op."); return; } mSharedLibAssetsMap.put(uniqueId, sharedLibAssets); appendLibAssetsLocked(sharedLibAssets.getAllAssetPaths()); Slog.v(TAG, "The following resources' paths have been added: " + Arrays.toString(sharedLibAssets.getAllAssetPaths())); } } private static class ApkKey { public final String path; public final boolean sharedLib; Loading Loading @@ -278,6 +304,21 @@ public class ResourcesManager { public ResourcesManager() { } /** * Inject a customized ResourcesManager instance for testing, return the old ResourcesManager * instance. */ @UnsupportedAppUsage @VisibleForTesting public static ResourcesManager setInstance(ResourcesManager resourcesManager) { synchronized (ResourcesManager.class) { ResourcesManager oldResourceManager = sResourcesManager; sResourcesManager = resourcesManager; return oldResourceManager; } } @UnsupportedAppUsage public static ResourcesManager getInstance() { synchronized (ResourcesManager.class) { Loading Loading @@ -1480,6 +1521,56 @@ public class ResourcesManager { } } private void appendLibAssetsLocked(String[] libAssets) { synchronized (mLock) { // Record which ResourcesImpl need updating // (and what ResourcesKey they should update to). final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl == null) { Slog.w(TAG, "Found a ResourcesImpl which is null, skip it and continue to " + "append shared library assets for next ResourcesImpl."); continue; } var newDirs = new ArrayList<String>(); var dirsSet = new ArraySet<String>(); if (key.mLibDirs != null) { final int dirsLength = key.mLibDirs.length; for (int k = 0; k < dirsLength; k++) { newDirs.add(key.mLibDirs[k]); dirsSet.add(key.mLibDirs[k]); } } final int assetsLength = libAssets.length; for (int j = 0; j < assetsLength; j++) { if (dirsSet.add(libAssets[j])) { newDirs.add(libAssets[j]); } } String[] newLibAssets = newDirs.toArray(new String[0]); if (!Arrays.equals(newLibAssets, key.mLibDirs)) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, key.mOverlayPaths, newLibAssets, key.mDisplayId, key.mOverrideConfiguration, key.mCompatInfo, key.mLoaders)); } } redirectResourcesToNewImplLocked(updatedResourceKeys); } } private void applyNewResourceDirsLocked(@Nullable final String[] oldSourceDirs, @NonNull final ApplicationInfo appInfo) { try { Loading Loading @@ -1689,4 +1780,50 @@ public class ResourcesManager { } } } public static class SharedLibraryAssets{ private final String[] mAssetPaths; SharedLibraryAssets(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { mAssetPaths = collectAssetPaths(sourceDir, splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths); } private @NonNull String[] collectAssetPaths(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { final String[][] inputLists = { splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths }; final ArraySet<String> assetPathSet = new ArraySet<>(); final List<String> assetPathList = new ArrayList<>(); if (sourceDir != null) { assetPathSet.add(sourceDir); assetPathList.add(sourceDir); } for (int i = 0; i < inputLists.length; i++) { if (inputLists[i] != null) { for (int j = 0; j < inputLists[i].length; j++) { if (assetPathSet.add(inputLists[i][j])) { assetPathList.add(inputLists[i][j]); } } } } return assetPathList.toArray(new String[0]); } /** * @return all the asset paths of this collected in this class. */ public @NonNull String[] getAllAssetPaths() { return mAssetPaths; } } public @NonNull ArrayMap<String, SharedLibraryAssets> getSharedLibAssetsMap() { return new ArrayMap<>(mSharedLibAssetsMap); } }
core/java/android/content/res/AssetManager.java +10 −0 Original line number Diff line number Diff line Loading @@ -471,6 +471,16 @@ public final class AssetManager implements AutoCloseable { return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/); } /** * @hide */ public void addSharedLibraryPaths(@NonNull String[] paths) { final int length = paths.length; for (int i = 0; i < length; i++) { addAssetPathInternal(paths[i], false, true); } } private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) { Objects.requireNonNull(path, "path"); synchronized (this) { Loading
core/java/android/content/res/Resources.java +7 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.annotation.XmlRes; import android.app.Application; import android.app.ResourcesManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; Loading Loading @@ -2854,6 +2855,11 @@ public class Resources { @FlaggedApi(android.content.res.Flags.FLAG_REGISTER_RESOURCE_PATHS) public static void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { throw new UnsupportedOperationException("The implementation has not been done yet."); if (Flags.registerResourcePaths()) { ResourcesManager.getInstance().registerResourcePaths(uniqueId, appInfo); } else { throw new UnsupportedOperationException("Flag " + Flags.FLAG_REGISTER_RESOURCE_PATHS + " is disabled."); } } }
core/java/android/content/res/ResourcesImpl.java +10 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.app.LocaleConfig; import android.app.ResourcesManager; import android.app.ResourcesManager.SharedLibraryAssets; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; Loading @@ -47,6 +48,7 @@ import android.os.Build; import android.os.LocaleList; import android.os.ParcelFileDescriptor; import android.os.Trace; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; Loading Loading @@ -197,6 +199,14 @@ public class ResourcesImpl { public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) { mAssets = assets; if (Flags.registerResourcePaths()) { ArrayMap<String, SharedLibraryAssets> sharedLibMap = ResourcesManager.getInstance().getSharedLibAssetsMap(); final int size = sharedLibMap.size(); for (int i = 0; i < size; i++) { assets.addSharedLibraryPaths(sharedLibMap.valueAt(i).getAllAssetPaths()); } } mMetrics.setToDefaults(); mDisplayAdjustments = displayAdjustments; mConfiguration.setToDefaults(); Loading