Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31e9a622 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi Committed by Android (Google) Code Review
Browse files

Merge "[res] Correct, optimize adding shared lib assets" into main

parents 6df7a386 9ab48e85
Loading
Loading
Loading
Loading
+89 −24
Original line number Diff line number Diff line
@@ -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(List<String> paths, boolean overlay, boolean appAsLib,
            boolean presetAssets) {
        Objects.requireNonNull(paths, "paths");
        if (paths.isEmpty()) {
            return 0;
        }

    private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
        Objects.requireNonNull(path, "path");
        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 */
+13 −3
Original line number Diff line number Diff line
@@ -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;