diff options
-rw-r--r-- | core/java/android/content/res/AssetManager.java | 113 | ||||
-rw-r--r-- | core/java/android/content/res/ResourcesImpl.java | 16 |
2 files changed, 102 insertions, 27 deletions
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 273e40a21bb2..c0c1c31a832a 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -32,6 +32,7 @@ import android.content.res.Configuration.NativeConfig; import android.content.res.loader.ResourcesLoader; import android.os.Build; import android.os.ParcelFileDescriptor; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -448,7 +449,7 @@ public final class AssetManager implements AutoCloseable { @Deprecated @UnsupportedAppUsage public int addAssetPath(String path) { - return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/); + return addAssetPathInternal(List.of(path), false, false, false); } /** @@ -458,7 +459,7 @@ public final class AssetManager implements AutoCloseable { @Deprecated @UnsupportedAppUsage public int addAssetPathAsSharedLibrary(String path) { - return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/); + return addAssetPathInternal(List.of(path), false, true, false); } /** @@ -468,35 +469,103 @@ public final class AssetManager implements AutoCloseable { @Deprecated @UnsupportedAppUsage public int addOverlayPath(String path) { - return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/); + return addAssetPathInternal(List.of(path), true, false, false); } /** * @hide */ - public void addSharedLibraryPaths(@NonNull String[] paths) { - final int length = paths.length; - for (int i = 0; i < length; i++) { - addAssetPathInternal(paths[i], false, true); - } + public void addSharedLibraryPaths(@NonNull List<String> paths) { + addAssetPathInternal(paths, false, true, true); } - private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) { - Objects.requireNonNull(path, "path"); + private int addAssetPathInternal(List<String> paths, boolean overlay, boolean appAsLib, + boolean presetAssets) { + Objects.requireNonNull(paths, "paths"); + if (paths.isEmpty()) { + return 0; + } + synchronized (this) { ensureOpenLocked(); - final int count = mApkAssets.length; - // See if we already have it loaded. - for (int i = 0; i < count; i++) { - if (mApkAssets[i].getAssetPath().equals(path)) { - return i + 1; + // See if we already have some of the paths loaded. + final int originalAssetsCount = mApkAssets.length; + + // Getting an assets' path is a relatively expensive operation, cache them. + final ArrayMap<String, Integer> assetPaths = new ArrayMap<>(originalAssetsCount); + for (int i = 0; i < originalAssetsCount; i++) { + assetPaths.put(mApkAssets[i].getAssetPath(), i); + } + + final ArrayList<String> newPaths = new ArrayList<>(paths.size()); + int lastFoundIndex = -1; + for (int i = 0, pathsSize = paths.size(); i < pathsSize; i++) { + final var path = paths.get(i); + final int index = assetPaths.getOrDefault(path, -1); + if (index < 0) { + newPaths.add(path); + } else { + lastFoundIndex = index; } } + if (newPaths.isEmpty()) { + return lastFoundIndex + 1; + } - final ApkAssets assets; + final var newAssets = loadAssets(newPaths, overlay, appAsLib); + if (newAssets.isEmpty()) { + return 0; + } + mApkAssets = makeNewAssetsArrayLocked(newAssets); + nativeSetApkAssets(mObject, mApkAssets, true, presetAssets); + invalidateCachesLocked(-1); + return originalAssetsCount + 1; + } + } + + /** + * Insert the new assets preserving the correct order: all non-loader assets go before all + * of the loader assets. + */ + @GuardedBy("this") + private @NonNull ApkAssets[] makeNewAssetsArrayLocked( + @NonNull ArrayList<ApkAssets> newNonLoaderAssets) { + final int originalAssetsCount = mApkAssets.length; + int firstLoaderIndex = originalAssetsCount; + for (int i = 0; i < originalAssetsCount; i++) { + if (mApkAssets[i].isForLoader()) { + firstLoaderIndex = i; + break; + } + } + final int newAssetsSize = newNonLoaderAssets.size(); + final var newAssetsArray = new ApkAssets[originalAssetsCount + newAssetsSize]; + if (firstLoaderIndex > 0) { + // This should always be true, but who knows... + System.arraycopy(mApkAssets, 0, newAssetsArray, 0, firstLoaderIndex); + } + for (int i = 0; i < newAssetsSize; i++) { + newAssetsArray[firstLoaderIndex + i] = newNonLoaderAssets.get(i); + } + if (originalAssetsCount > firstLoaderIndex) { + System.arraycopy( + mApkAssets, firstLoaderIndex, + newAssetsArray, firstLoaderIndex + newAssetsSize, + originalAssetsCount - firstLoaderIndex); + } + return newAssetsArray; + } + + private static @NonNull ArrayList<ApkAssets> loadAssets(@NonNull ArrayList<String> paths, + boolean overlay, boolean appAsLib) { + final int pathsSize = paths.size(); + final var loadedAssets = new ArrayList<ApkAssets>(pathsSize); + for (int i = 0; i < pathsSize; i++) { + final var path = paths.get(i); try { - if (overlay) { + final ApkAssets assets; + if (overlay || path.endsWith(".frro")) { // TODO(b/70343104): This hardcoded path will be removed once // addAssetPathInternal is deleted. final String idmapPath = "/data/resource-cache/" @@ -507,16 +576,12 @@ public final class AssetManager implements AutoCloseable { assets = ApkAssets.loadFromPath(path, appAsLib ? ApkAssets.PROPERTY_DYNAMIC : 0); } + loadedAssets.add(assets); } catch (IOException e) { - return 0; + Log.w(TAG, "Failed to load asset, path = " + path, e); } - - mApkAssets = Arrays.copyOf(mApkAssets, count + 1); - mApkAssets[count] = assets; - nativeSetApkAssets(mObject, mApkAssets, true, false); - invalidateCachesLocked(-1); - return count + 1; } + return loadedAssets; } /** @hide */ diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 31cacb705d0e..9f8b97418cbf 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -49,6 +49,7 @@ import android.os.LocaleList; import android.os.ParcelFileDescriptor; import android.os.Trace; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -71,6 +72,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; @@ -205,13 +207,21 @@ public class ResourcesImpl { @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) { mAssets = assets; if (Flags.registerResourcePaths()) { - ArrayMap<String, SharedLibraryAssets> sharedLibMap = + final ArraySet<String> uniquePaths = new ArraySet<>(); + final ArrayList<String> orderedPaths = new ArrayList<>(); + final 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()); + final var paths = sharedLibMap.valueAt(i).getAllAssetPaths(); + for (int j = 0; j < paths.length; j++) { + if (uniquePaths.add(paths[j])) { + orderedPaths.add(paths[j]); + } + } } - mSharedLibCount = sharedLibMap.size(); + assets.addSharedLibraryPaths(orderedPaths); + mSharedLibCount = size; } mMetrics.setToDefaults(); mDisplayAdjustments = displayAdjustments; |