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

Commit ee2a86f5 authored by Brandon Liu's avatar Brandon Liu Committed by Android (Google) Code Review
Browse files

Merge "Register resources paths for shared library in runtime" into main

parents 0ecb9bf6 209523a5
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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",
+137 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
@@ -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 {
@@ -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);
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -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) {
+7 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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.");
        }
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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