diff options
author | 2020-03-11 10:26:08 -0700 | |
---|---|---|
committer | 2020-03-19 18:33:55 -0700 | |
commit | ef40d2e832e900aba6dbcf8217903d7dbe689ca0 (patch) | |
tree | 96e56c54d587a36b13889d3eac4d89682000a625 | |
parent | ad2d924b3490c01168ad1dfeb2fa05ebc61b8ef2 (diff) |
Refactor ApkAsset loading APIs
To add the partner requested ResourcesProvider#loadFromDir APIs, this
change adds format type integer that allows us to reduce the number of
ApkAssets loading overrides.
This change also adds hidden offset and length based ResourcesProvider
APIs that could not make R.
Bug: 142716192
Test: atest FrameworksResourceLoaderTests
Change-Id: I926fde257cae701901dcd4ca408024feae8c90a6
Merged-In: I926fde257cae701901dcd4ca408024feae8c90a6
20 files changed, 600 insertions, 350 deletions
diff --git a/api/current.txt b/api/current.txt index d944d24d2993..861d6e8e5958 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12871,11 +12871,8 @@ package android.content.res.loader { method @Nullable public android.content.res.loader.AssetsProvider getAssetsProvider(); method @NonNull public static android.content.res.loader.ResourcesProvider loadFromApk(@NonNull android.os.ParcelFileDescriptor) throws java.io.IOException; method @NonNull public static android.content.res.loader.ResourcesProvider loadFromApk(@NonNull android.os.ParcelFileDescriptor, @Nullable android.content.res.loader.AssetsProvider) throws java.io.IOException; - method @NonNull public static android.content.res.loader.ResourcesProvider loadFromApk(@NonNull android.os.SharedMemory) throws java.io.IOException; - method @NonNull public static android.content.res.loader.ResourcesProvider loadFromApk(@NonNull android.os.SharedMemory, @Nullable android.content.res.loader.AssetsProvider) throws java.io.IOException; method @NonNull public static android.content.res.loader.ResourcesProvider loadFromSplit(@NonNull android.content.Context, @NonNull String) throws java.io.IOException; method @NonNull public static android.content.res.loader.ResourcesProvider loadFromTable(@NonNull android.os.ParcelFileDescriptor, @Nullable android.content.res.loader.AssetsProvider) throws java.io.IOException; - method @NonNull public static android.content.res.loader.ResourcesProvider loadFromTable(@NonNull android.os.SharedMemory, @Nullable android.content.res.loader.AssetsProvider) throws java.io.IOException; } } @@ -82233,3 +82230,4 @@ package org.xmlpull.v1.sax2 { } } + diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 81671c349cbd..60f61cef0b61 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -368,10 +368,9 @@ public class ResourcesManager { // We must load this from disk. if (overlay) { - apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), - false /*system*/); + apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), 0 /*flags*/); } else { - apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib); + apkAssets = ApkAssets.loadFromPath(path, sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); } if (mLoadedApkAssets != null) { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c6875a4b3443..5ade26153296 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -55,7 +55,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; @@ -1442,7 +1441,7 @@ public class PackageParser { try { try { apkAssets = fd != null - ? ApkAssets.loadFromFd(fd, debugPathName, false, false) + ? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */) : ApkAssets.loadFromPath(apkPath); } catch (IOException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 4c6da03b4db3..88b4c290c52a 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -220,7 +220,7 @@ public class ApkLiteParseUtils { try { try { apkAssets = fd != null - ? ApkAssets.loadFromFd(fd, debugPathName, false, false) + ? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */) : ApkAssets.loadFromPath(apkPath); } catch (IOException e) { throw new PackageParser.PackageParserException( diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 8db278579cc1..b9dad85fe84c 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -15,17 +15,19 @@ */ package android.content.res; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.om.OverlayableInfo; import android.content.res.loader.ResourcesProvider; -import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -39,14 +41,72 @@ import java.util.Objects; * @hide */ public final class ApkAssets { - @GuardedBy("this") private final long mNativePtr; + + /** + * The apk assets contains framework resource values specified by the system. + * This allows some functions to filter out this package when computing what + * configurations/resources are available. + */ + public static final int PROPERTY_SYSTEM = 1 << 0; + + /** + * The apk assets is a shared library or was loaded as a shared library by force. + * The package ids of dynamic apk assets are assigned at runtime instead of compile time. + */ + public static final int PROPERTY_DYNAMIC = 1 << 1; + + /** + * The apk assets has been loaded dynamically using a {@link ResourcesProvider}. + * Loader apk assets overlay resources like RROs except they are not backed by an idmap. + */ + public static final int PROPERTY_LOADER = 1 << 2; + + /** + * The apk assets is a RRO. + * An RRO overlays resource values of its target package. + */ + private static final int PROPERTY_OVERLAY = 1 << 3; + + /** Flags that change the behavior of loaded apk assets. */ + @IntDef(prefix = { "PROPERTY_" }, value = { + PROPERTY_SYSTEM, + PROPERTY_DYNAMIC, + PROPERTY_LOADER, + PROPERTY_OVERLAY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PropertyFlags {} + + /** The path used to load the apk assets represents an APK file. */ + private static final int FORMAT_APK = 0; + + /** The path used to load the apk assets represents an idmap file. */ + private static final int FORMAT_IDMAP = 1; + + /** The path used to load the apk assets represents an resources.arsc file. */ + private static final int FORMAT_ARSC = 2; + + // Format types that change how the apk assets are loaded. + @IntDef(prefix = { "FORMAT_" }, value = { + FORMAT_APK, + FORMAT_IDMAP, + FORMAT_ARSC, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FormatType {} + + @GuardedBy("this") + private final long mNativePtr; @Nullable - @GuardedBy("this") private final StringBlock mStringBlock; + @GuardedBy("this") + private final StringBlock mStringBlock; - @GuardedBy("this") private boolean mOpen = true; + @GuardedBy("this") + private boolean mOpen = true; - private final boolean mForLoader; + @PropertyFlags + private final int mFlags; /** * Creates a new ApkAssets instance from the given path on disk. @@ -56,59 +116,59 @@ public final class ApkAssets { * @throws IOException if a disk I/O error or parsing error occurred. */ public static @NonNull ApkAssets loadFromPath(@NonNull String path) throws IOException { - return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/, - false /*arscOnly*/, false /*forLoader*/); + return loadFromPath(path, 0 /* flags */); } /** * Creates a new ApkAssets instance from the given path on disk. * * @param path The path to an APK on disk. - * @param system When true, the APK is loaded as a system APK (framework). + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ - public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system) + public static @NonNull ApkAssets loadFromPath(@NonNull String path, @PropertyFlags int flags) throws IOException { - return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/, - false /*arscOnly*/, false /*forLoader*/); + return new ApkAssets(FORMAT_APK, path, flags); } /** - * Creates a new ApkAssets instance from the given path on disk. + * Creates a new ApkAssets instance from the given file descriptor. * - * @param path The path to an APK on disk. - * @param system When true, the APK is loaded as a system APK (framework). - * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are - * loaded as a shared library. + * Performs a dup of the underlying fd, so you must take care of still closing + * the FileDescriptor yourself (and can do that whenever you want). + * + * @param fd The FileDescriptor of an open, readable APK. + * @param friendlyName The friendly name used to identify this ApkAssets when logging. + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ - public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system, - boolean forceSharedLibrary) throws IOException { - return new ApkAssets(path, system, forceSharedLibrary, false /*overlay*/, - false /*arscOnly*/, false /*forLoader*/); + public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd, + @NonNull String friendlyName, @PropertyFlags int flags) throws IOException { + return new ApkAssets(FORMAT_APK, fd, friendlyName, flags); } /** - * Creates a new ApkAssets instance from the given file descriptor. Not for use by applications. + * Creates a new ApkAssets instance from the given file descriptor. * * Performs a dup of the underlying fd, so you must take care of still closing * the FileDescriptor yourself (and can do that whenever you want). * * @param fd The FileDescriptor of an open, readable APK. * @param friendlyName The friendly name used to identify this ApkAssets when logging. - * @param system When true, the APK is loaded as a system APK (framework). - * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are - * loaded as a shared library. + * @param offset The location within the file that the apk starts. This must be 0 if length is + * {@link AssetFileDescriptor#UNKNOWN_LENGTH}. + * @param length The number of bytes of the apk, or {@link AssetFileDescriptor#UNKNOWN_LENGTH} + * if it extends to the end of the file. + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd, - @NonNull String friendlyName, boolean system, boolean forceSharedLibrary) + @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags) throws IOException { - return new ApkAssets(fd, friendlyName, system, forceSharedLibrary, false /*arscOnly*/, - false /*forLoader*/); + return new ApkAssets(FORMAT_APK, fd, friendlyName, offset, length, flags); } /** @@ -116,99 +176,101 @@ public final class ApkAssets { * is encoded within the IDMAP. * * @param idmapPath Path to the IDMAP of an overlay APK. - * @param system When true, the APK is loaded as a system APK (framework). + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ - public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, boolean system) - throws IOException { - return new ApkAssets(idmapPath, system, false /*forceSharedLibrary*/, true /*overlay*/, - false /*arscOnly*/, false /*forLoader*/); + public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, + @PropertyFlags int flags) throws IOException { + return new ApkAssets(FORMAT_IDMAP, idmapPath, flags); } /** - * Creates a new ApkAssets instance from the given path on disk for use with a - * {@link ResourcesProvider}. - * - * @param path The path to an APK on disk. - * @return a new instance of ApkAssets. - * @throws IOException if a disk I/O error or parsing error occurred. - */ - public static @NonNull ApkAssets loadApkForLoader(@NonNull String path) - throws IOException { - return new ApkAssets(path, false /*system*/, false /*forceSharedLibrary*/, - false /*overlay*/, false /*arscOnly*/, true /*forLoader*/); - } - - /** - * Creates a new ApkAssets instance from the given file descriptor for use with a - * {@link ResourcesProvider}. + * Creates a new ApkAssets instance from the given file descriptor representing a resources.arsc + * for use with a {@link ResourcesProvider}. * * Performs a dup of the underlying fd, so you must take care of still closing * the FileDescriptor yourself (and can do that whenever you want). * - * @param fd The FileDescriptor of an open, readable APK. + * @param fd The FileDescriptor of an open, readable resources.arsc. + * @param friendlyName The friendly name used to identify this ApkAssets when logging. + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ - @NonNull - public static ApkAssets loadApkForLoader(@NonNull FileDescriptor fd) throws IOException { - return new ApkAssets(fd, TextUtils.emptyIfNull(fd.toString()), - false /*system*/, false /*forceSharedLib*/, false /*arscOnly*/, true /*forLoader*/); + public static @NonNull ApkAssets loadTableFromFd(@NonNull FileDescriptor fd, + @NonNull String friendlyName, @PropertyFlags int flags) throws IOException { + return new ApkAssets(FORMAT_ARSC, fd, friendlyName, flags); } /** - * Creates a new ApkAssets instance from the given file descriptor representing an ARSC + * Creates a new ApkAssets instance from the given file descriptor representing a resources.arsc * for use with a {@link ResourcesProvider}. * * Performs a dup of the underlying fd, so you must take care of still closing * the FileDescriptor yourself (and can do that whenever you want). * - * @param fd The FileDescriptor of an open, readable .arsc. + * @param fd The FileDescriptor of an open, readable resources.arsc. + * @param friendlyName The friendly name used to identify this ApkAssets when logging. + * @param offset The location within the file that the table starts. This must be 0 if length is + * {@link AssetFileDescriptor#UNKNOWN_LENGTH}. + * @param length The number of bytes of the table, or {@link AssetFileDescriptor#UNKNOWN_LENGTH} + * if it extends to the end of the file. + * @param flags flags that change the behavior of loaded apk assets * @return a new instance of ApkAssets. * @throws IOException if a disk I/O error or parsing error occurred. */ - public static @NonNull ApkAssets loadArscForLoader(@NonNull FileDescriptor fd) + public static @NonNull ApkAssets loadTableFromFd(@NonNull FileDescriptor fd, + @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags) throws IOException { - return new ApkAssets(fd, TextUtils.emptyIfNull(fd.toString()), - false /*system*/, false /*forceSharedLib*/, true /*arscOnly*/, true /*forLoader*/); + return new ApkAssets(FORMAT_ARSC, fd, friendlyName, offset, length, flags); } /** * Generates an entirely empty ApkAssets. Needed because the ApkAssets instance and presence * is required for a lot of APIs, and it's easier to have a non-null reference rather than * tracking a separate identifier. + * + * @param flags flags that change the behavior of loaded apk assets */ @NonNull - public static ApkAssets loadEmptyForLoader() { - return new ApkAssets(true); + public static ApkAssets loadEmptyForLoader(@PropertyFlags int flags) { + return new ApkAssets(flags); } - private ApkAssets(boolean forLoader) { - mForLoader = forLoader; - mNativePtr = nativeLoadEmpty(forLoader); - mStringBlock = null; + private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags) + throws IOException { + Objects.requireNonNull(path, "path"); + mFlags = flags; + mNativePtr = nativeLoad(format, path, flags); + mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); } - private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay, - boolean arscOnly, boolean forLoader) throws IOException { - mForLoader = forLoader; - Objects.requireNonNull(path, "path"); - mNativePtr = arscOnly ? nativeLoadArsc(path, forLoader) - : nativeLoad(path, system, forceSharedLib, overlay, forLoader); + private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, + @NonNull String friendlyName, @PropertyFlags int flags) throws IOException { + Objects.requireNonNull(fd, "fd"); + Objects.requireNonNull(friendlyName, "friendlyName"); + mFlags = flags; + mNativePtr = nativeLoadFd(format, fd, friendlyName, flags); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); } - private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system, - boolean forceSharedLib, boolean arscOnly, boolean forLoader) throws IOException { - mForLoader = forLoader; + private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, + @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags) + throws IOException { Objects.requireNonNull(fd, "fd"); Objects.requireNonNull(friendlyName, "friendlyName"); - mNativePtr = arscOnly ? nativeLoadArscFromFd(fd, friendlyName, forLoader) - : nativeLoadFromFd(fd, friendlyName, system, forceSharedLib, forLoader); + mFlags = flags; + mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); } + private ApkAssets(@PropertyFlags int flags) { + mFlags = flags; + mNativePtr = nativeLoadEmpty(flags); + mStringBlock = null; + } + @UnsupportedAppUsage public @NonNull String getAssetPath() { synchronized (this) { @@ -226,8 +288,9 @@ public final class ApkAssets { } } + /** Returns whether this apk assets was loaded using a {@link ResourcesProvider}. */ public boolean isForLoader() { - return mForLoader; + return (mFlags & PROPERTY_LOADER) != 0; } /** @@ -300,18 +363,14 @@ public final class ApkAssets { } } - private static native long nativeLoad(@NonNull String path, boolean system, - boolean forceSharedLib, boolean overlay, boolean forLoader) - throws IOException; - private static native long nativeLoadFromFd(@NonNull FileDescriptor fd, - @NonNull String friendlyName, boolean system, boolean forceSharedLib, - boolean forLoader) - throws IOException; - private static native long nativeLoadArsc(@NonNull String path, boolean forLoader) - throws IOException; - private static native long nativeLoadArscFromFd(@NonNull FileDescriptor fd, - @NonNull String friendlyName, boolean forLoader) throws IOException; - private static native long nativeLoadEmpty(boolean forLoader); + private static native long nativeLoad(@FormatType int format, @NonNull String path, + @PropertyFlags int flags) throws IOException; + private static native long nativeLoadEmpty(@PropertyFlags int flags); + private static native long nativeLoadFd(@FormatType int format, @NonNull FileDescriptor fd, + @NonNull String friendlyName, @PropertyFlags int flags) throws IOException; + private static native long nativeLoadFdOffsets(@FormatType int format, + @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length, + @PropertyFlags int flags) throws IOException; private static native void nativeDestroy(long ptr); private static native @NonNull String nativeGetAssetPath(long ptr); private static native long nativeGetStringBlock(long ptr); diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index f295f8c531e9..6b9613d6e3be 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -242,12 +242,12 @@ public final class AssetManager implements AutoCloseable { try { final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); - apkAssets.add(ApkAssets.loadFromPath(frameworkPath, true /*system*/)); + apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM)); final String[] systemIdmapPaths = OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); for (String idmapPath : systemIdmapPaths) { - apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); + apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); } sSystemApkAssetsSet = new ArraySet<>(apkAssets); @@ -443,9 +443,10 @@ public final class AssetManager implements AutoCloseable { final String idmapPath = "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; - assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/); + assets = ApkAssets.loadOverlayFromPath(idmapPath, 0 /* flags */); } else { - assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib); + assets = ApkAssets.loadFromPath(path, + appAsLib ? ApkAssets.PROPERTY_DYNAMIC : 0); } } catch (IOException e) { return 0; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index cb809da3b867..e77d8af49873 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2388,6 +2388,9 @@ public class Resources { * Adds a loader to the list of loaders. If the loader is already present in the list, the list * will not be modified. * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * loader changes. + * * @param loaders the loaders to add */ public void addLoaders(@NonNull ResourcesLoader... loaders) { @@ -2419,6 +2422,9 @@ public class Resources { * Removes loaders from the list of loaders. If the loader is not present in the list, the list * will not be modified. * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * loader changes. + * * @param loaders the loaders to remove */ public void removeLoaders(@NonNull ResourcesLoader... loaders) { @@ -2448,6 +2454,9 @@ public class Resources { /** * Removes all {@link ResourcesLoader ResourcesLoader(s)}. + * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * loader changes. * @hide */ @VisibleForTesting diff --git a/core/java/android/content/res/loader/ResourcesLoader.java b/core/java/android/content/res/loader/ResourcesLoader.java index 58fec603a2d5..c3084003c304 100644 --- a/core/java/android/content/res/loader/ResourcesLoader.java +++ b/core/java/android/content/res/loader/ResourcesLoader.java @@ -45,6 +45,11 @@ import java.util.List; * * <p>Providers retrieved with {@link #getProviders()} are listed in increasing precedence order. A * provider will override the resources and assets of providers listed before itself. + * + * <p>Modifying the list of providers a loader contains or the list of loaders a Resources object + * contains can cause lock contention with the UI thread. APIs that modify the lists of loaders or + * providers should only be used on the UI thread. Providers can be instantiated on any thread + * without causing lock contention. */ public class ResourcesLoader { private final Object mLock = new Object(); @@ -88,6 +93,9 @@ public class ResourcesLoader { * Appends a provider to the end of the provider list. If the provider is already present in the * loader list, the list will not be modified. * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * provider changes. + * * @param resourcesProvider the provider to add */ public void addProvider(@NonNull ResourcesProvider resourcesProvider) { @@ -102,6 +110,9 @@ public class ResourcesLoader { * Removes a provider from the provider list. If the provider is not present in the provider * list, the list will not be modified. * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * provider changes. + * * @param resourcesProvider the provider to remove */ public void removeProvider(@NonNull ResourcesProvider resourcesProvider) { @@ -115,6 +126,9 @@ public class ResourcesLoader { /** * Sets the list of providers. * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * provider changes. + * * @param resourcesProviders the new providers */ public void setProviders(@NonNull List<ResourcesProvider> resourcesProviders) { @@ -124,7 +138,12 @@ public class ResourcesLoader { } } - /** Removes all {@link ResourcesProvider ResourcesProvider(s)}. */ + /** + * Removes all {@link ResourcesProvider ResourcesProvider(s)}. + * + * <p>This should only be called from the UI thread to avoid lock contention when propagating + * provider changes. + */ public void clearProviders() { synchronized (mLock) { mProviders = null; @@ -206,7 +225,6 @@ public class ResourcesLoader { return true; } - /** * Invokes registered callbacks when the list of {@link ResourcesProvider} instances this loader * uses changes. diff --git a/core/java/android/content/res/loader/ResourcesProvider.java b/core/java/android/content/res/loader/ResourcesProvider.java index 419ec7882f3d..1d24dda8a4bf 100644 --- a/core/java/android/content/res/loader/ResourcesProvider.java +++ b/core/java/android/content/res/loader/ResourcesProvider.java @@ -21,19 +21,21 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.ApkAssets; +import android.content.res.AssetFileDescriptor; import android.os.ParcelFileDescriptor; -import android.os.SharedMemory; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.Closeable; +import java.io.File; import java.io.IOException; /** * Provides methods to load resources data from APKs ({@code .apk}) and resources tables - * {@code .arsc} for use with {@link ResourcesLoader ResourcesLoader(s)}. + * (eg. {@code resources.arsc}) for use with {@link ResourcesLoader ResourcesLoader(s)}. */ public class ResourcesProvider implements AutoCloseable, Closeable { private static final String TAG = "ResourcesProvider"; @@ -51,102 +53,142 @@ public class ResourcesProvider implements AutoCloseable, Closeable { private final AssetsProvider mAssetsProvider; /** - * Creates an empty ResourcesProvider with no resource data. This is useful for loading assets - * that are not associated with resource identifiers. + * Creates an empty ResourcesProvider with no resource data. This is useful for loading + * file-based assets not associated with resource identifiers. * - * @param assetsProvider the assets provider that overrides the loading of file-based resources + * @param assetsProvider the assets provider that implements the loading of file-based resources */ @NonNull public static ResourcesProvider empty(@NonNull AssetsProvider assetsProvider) { - return new ResourcesProvider(ApkAssets.loadEmptyForLoader(), assetsProvider); + return new ResourcesProvider(ApkAssets.loadEmptyForLoader(ApkAssets.PROPERTY_LOADER), + assetsProvider); } /** * Creates a ResourcesProvider from an APK ({@code .apk}) file descriptor. * - * The file descriptor is duplicated and the original may be closed by the application at any + * <p>The file descriptor is duplicated and the original may be closed by the application at any * time without affecting the ResourcesProvider. * * @param fileDescriptor the file descriptor of the APK to load + * + * @see ParcelFileDescriptor#open(File, int) + * @see android.system.Os#memfd_create(String, int) */ @NonNull public static ResourcesProvider loadFromApk(@NonNull ParcelFileDescriptor fileDescriptor) throws IOException { - return loadFromApk(fileDescriptor, null); + return loadFromApk(fileDescriptor, null /* assetsProvider */); } /** * Creates a ResourcesProvider from an APK ({@code .apk}) file descriptor. * - * The file descriptor is duplicated and the original may be closed by the application at any + * <p>The file descriptor is duplicated and the original may be closed by the application at any * time without affecting the ResourcesProvider. * + * <p>The assets provider can override the loading of files within the APK and can provide + * entirely new files that do not exist in the APK. + * * @param fileDescriptor the file descriptor of the APK to load * @param assetsProvider the assets provider that overrides the loading of file-based resources + * + * @see ParcelFileDescriptor#open(File, int) + * @see android.system.Os#memfd_create(String, int) */ @NonNull public static ResourcesProvider loadFromApk(@NonNull ParcelFileDescriptor fileDescriptor, @Nullable AssetsProvider assetsProvider) throws IOException { - return new ResourcesProvider( - ApkAssets.loadApkForLoader(fileDescriptor.getFileDescriptor()), assetsProvider); + return new ResourcesProvider(ApkAssets.loadFromFd(fileDescriptor.getFileDescriptor(), + fileDescriptor.toString(), ApkAssets.PROPERTY_LOADER), assetsProvider); } /** - * Creates a ResourcesProvider from an {@code .apk} file representation in memory. + * Creates a ResourcesProvider from an APK ({@code .apk}) file descriptor. * - * @param sharedMemory the shared memory containing the data of the APK to load - */ - @NonNull - public static ResourcesProvider loadFromApk(@NonNull SharedMemory sharedMemory) - throws IOException { - return loadFromApk(sharedMemory, null); - } - - /** - * Creates a ResourcesProvider from an {@code .apk} file representation in memory. + * <p>The file descriptor is duplicated and the original may be closed by the application at any + * time without affecting the ResourcesProvider. * - * @param sharedMemory the shared memory containing the data of the APK to load - * @param assetsProvider the assets provider that implements the loading of file-based resources + * <p>The assets provider can override the loading of files within the APK and can provide + * entirely new files that do not exist in the APK. + * + * @param fileDescriptor the file descriptor of the APK to load + * @param offset The location within the file that the apk starts. This must be 0 if length is + * {@link AssetFileDescriptor#UNKNOWN_LENGTH}. + * @param length The number of bytes of the apk, or {@link AssetFileDescriptor#UNKNOWN_LENGTH} + * if it extends to the end of the file. + * @param assetsProvider the assets provider that overrides the loading of file-based resources + * + * @see ParcelFileDescriptor#open(File, int) + * @see android.system.Os#memfd_create(String, int) + * @hide */ + @VisibleForTesting @NonNull - public static ResourcesProvider loadFromApk(@NonNull SharedMemory sharedMemory, - @Nullable AssetsProvider assetsProvider) + public static ResourcesProvider loadFromApk(@NonNull ParcelFileDescriptor fileDescriptor, + long offset, long length, @Nullable AssetsProvider assetsProvider) throws IOException { - return new ResourcesProvider( - ApkAssets.loadApkForLoader(sharedMemory.getFileDescriptor()), assetsProvider); + return new ResourcesProvider(ApkAssets.loadFromFd(fileDescriptor.getFileDescriptor(), + fileDescriptor.toString(), offset, length, ApkAssets.PROPERTY_LOADER), + assetsProvider); } /** * Creates a ResourcesProvider from a resources table ({@code .arsc}) file descriptor. * - * The file descriptor is duplicated and the original may be closed by the application at any + * <p>The file descriptor is duplicated and the original may be closed by the application at any * time without affecting the ResourcesProvider. * + * <p>The resources table format is not an archive format and therefore cannot asset files + * within itself. The assets provider can instead provide files that are potentially referenced + * by path in the resources table. + * * @param fileDescriptor the file descriptor of the resources table to load * @param assetsProvider the assets provider that implements the loading of file-based resources + * + * @see ParcelFileDescriptor#open(File, int) + * @see android.system.Os#memfd_create(String, int) */ @NonNull public static ResourcesProvider loadFromTable(@NonNull ParcelFileDescriptor fileDescriptor, @Nullable AssetsProvider assetsProvider) throws IOException { return new ResourcesProvider( - ApkAssets.loadArscForLoader(fileDescriptor.getFileDescriptor()), assetsProvider); + ApkAssets.loadTableFromFd(fileDescriptor.getFileDescriptor(), + fileDescriptor.toString(), ApkAssets.PROPERTY_LOADER), assetsProvider); } /** - * Creates a ResourcesProvider from a resources table ({@code .arsc}) file representation in - * memory. + * Creates a ResourcesProvider from a resources table ({@code .arsc}) file descriptor. + * + * The file descriptor is duplicated and the original may be closed by the application at any + * time without affecting the ResourcesProvider. + * + * <p>The resources table format is not an archive format and therefore cannot asset files + * within itself. The assets provider can instead provide files that are potentially referenced + * by path in the resources table. * - * @param sharedMemory the shared memory containing the data of the resources table to load + * @param fileDescriptor the file descriptor of the resources table to load + * @param offset The location within the file that the table starts. This must be 0 if length is + * {@link AssetFileDescriptor#UNKNOWN_LENGTH}. + * @param length The number of bytes of the table, or {@link AssetFileDescriptor#UNKNOWN_LENGTH} + * if it extends to the end of the file. * @param assetsProvider the assets provider that overrides the loading of file-based resources + * + * @see ParcelFileDescriptor#open(File, int) + * @see android.system.Os#memfd_create(String, int) + * @hide */ + @VisibleForTesting @NonNull - public static ResourcesProvider loadFromTable(@NonNull SharedMemory sharedMemory, - @Nullable AssetsProvider assetsProvider) + public static ResourcesProvider loadFromTable(@NonNull ParcelFileDescriptor fileDescriptor, + long offset, long length, @Nullable AssetsProvider assetsProvider) throws IOException { return new ResourcesProvider( - ApkAssets.loadArscForLoader(sharedMemory.getFileDescriptor()), assetsProvider); + ApkAssets.loadTableFromFd(fileDescriptor.getFileDescriptor(), + fileDescriptor.toString(), offset, length, ApkAssets.PROPERTY_LOADER), + assetsProvider); } /** @@ -166,7 +208,8 @@ public class ResourcesProvider implements AutoCloseable, Closeable { } String splitPath = appInfo.getSplitCodePaths()[splitIndex]; - return new ResourcesProvider(ApkAssets.loadApkForLoader(splitPath), null); + return new ResourcesProvider(ApkAssets.loadFromPath(splitPath, ApkAssets.PROPERTY_LOADER), + null); } private ResourcesProvider(@NonNull ApkAssets apkAssets, diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index 491d4a61cee4..44f8a31a4e22 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -37,8 +37,21 @@ static struct overlayableinfo_offsets_t { jmethodID constructor; } gOverlayableInfoOffsets; -static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system, - jboolean force_shared_lib, jboolean overlay, jboolean for_loader) { +// Keep in sync with f/b/android/content/res/ApkAssets.java +using format_type_t = jint; +enum : format_type_t { + // The path used to load the apk assets represents an APK file. + FORMAT_APK = 0, + + // The path used to load the apk assets represents an idmap file. + FORMAT_IDMAP = 1, + + // The path used to load the apk assets represents an resources.arsc file. + FORMAT_ARSC = 2, +}; + +static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t format, + jstring java_path, const jint property_flags) { ScopedUtfChars path(env, java_path); if (path.c_str() == nullptr) { return 0; @@ -47,25 +60,33 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboole ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str()); std::unique_ptr<const ApkAssets> apk_assets; - if (overlay) { - apk_assets = ApkAssets::LoadOverlay(path.c_str(), system); - } else if (force_shared_lib) { - apk_assets = ApkAssets::LoadAsSharedLibrary(path.c_str(), system); - } else { - apk_assets = ApkAssets::Load(path.c_str(), system, for_loader); + switch (format) { + case FORMAT_APK: + apk_assets = ApkAssets::Load(path.c_str(), property_flags); + break; + case FORMAT_IDMAP: + apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags); + break; + case FORMAT_ARSC: + apk_assets = ApkAssets::LoadTable(path.c_str(), property_flags); + break; + default: + const std::string error_msg = base::StringPrintf("Unsupported format type %d", format); + jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str()); + return 0; } if (apk_assets == nullptr) { - std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str()); + const std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str()); jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } return reinterpret_cast<jlong>(apk_assets.release()); } -static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor, - jstring friendly_name, jboolean system, jboolean force_shared_lib, - jboolean for_loader) { +static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t format, + jobject file_descriptor, jstring friendly_name, + const jint property_flags) { ScopedUtfChars friendly_name_utf8(env, friendly_name); if (friendly_name_utf8.c_str() == nullptr) { return 0; @@ -85,49 +106,53 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descri return 0; } - auto dup_fd_id = dup_fd.get(); - std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd), - friendly_name_utf8.c_str(), - system, force_shared_lib, - for_loader); + std::unique_ptr<const ApkAssets> apk_assets; + switch (format) { + case FORMAT_APK: + apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd), friendly_name_utf8.c_str(), + property_flags); + break; + case FORMAT_ARSC: + apk_assets = ApkAssets::LoadTableFromFd(std::move(dup_fd), friendly_name_utf8.c_str(), + property_flags); + break; + default: + const std::string error_msg = base::StringPrintf("Unsupported format type %d", format); + jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str()); + return 0; + } if (apk_assets == nullptr) { std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d", - friendly_name_utf8.c_str(), dup_fd_id); + friendly_name_utf8.c_str(), fd); jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } return reinterpret_cast<jlong>(apk_assets.release()); } -static jlong NativeLoadArsc(JNIEnv* env, jclass /*clazz*/, jstring java_path, - jboolean for_loader) { - ScopedUtfChars path(env, java_path); - if (path.c_str() == nullptr) { +static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_type_t format, + jobject file_descriptor, jstring friendly_name, + const jlong offset, const jlong length, + const jint property_flags) { + ScopedUtfChars friendly_name_utf8(env, friendly_name); + if (friendly_name_utf8.c_str() == nullptr) { return 0; } - ATRACE_NAME(base::StringPrintf("LoadApkAssetsArsc(%s)", path.c_str()).c_str()); - - std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadArsc(path.c_str(), for_loader); - - if (apk_assets == nullptr) { - std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str()); - jniThrowException(env, "java/io/IOException", error_msg.c_str()); + if (offset < 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "offset cannot be negative"); return 0; } - return reinterpret_cast<jlong>(apk_assets.release()); -} -static jlong NativeLoadArscFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor, - jstring friendly_name, jboolean for_loader) { - ScopedUtfChars friendly_name_utf8(env, friendly_name); - if (friendly_name_utf8.c_str() == nullptr) { + if (length < 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "length cannot be negative"); return 0; } int fd = jniGetFDFromFileDescriptor(env, file_descriptor); - ATRACE_NAME(base::StringPrintf("LoadApkAssetsArscFd(%d)", fd).c_str()); if (fd < 0) { jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor"); return 0; @@ -139,18 +164,37 @@ static jlong NativeLoadArscFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_de return 0; } - std::unique_ptr<const ApkAssets> apk_assets = - ApkAssets::LoadArsc(std::move(dup_fd), friendly_name_utf8.c_str(), for_loader); + ATRACE_NAME(base::StringPrintf("LoadApkAssetsFd(%s)", friendly_name_utf8.c_str()).c_str()); + + std::unique_ptr<const ApkAssets> apk_assets; + switch (format) { + case FORMAT_APK: + apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd), friendly_name_utf8.c_str(), + property_flags, static_cast<off64_t>(offset), + static_cast<off64_t>(length)); + break; + case FORMAT_ARSC: + apk_assets = ApkAssets::LoadTableFromFd(std::move(dup_fd), friendly_name_utf8.c_str(), + property_flags, static_cast<off64_t>(offset), + static_cast<off64_t>(length)); + break; + default: + const std::string error_msg = base::StringPrintf("Unsupported format type %d", format); + jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str()); + return 0; + } + if (apk_assets == nullptr) { - std::string error_msg = base::StringPrintf("Failed to load asset path from fd %d", fd); + std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d", + friendly_name_utf8.c_str(), fd); jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } return reinterpret_cast<jlong>(apk_assets.release()); } -static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jboolean for_loader) { - std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadEmpty(for_loader); +static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags) { + std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadEmpty(flags); return reinterpret_cast<jlong>(apk_assets.release()); } @@ -252,13 +296,11 @@ static jboolean NativeDefinesOverlayable(JNIEnv* env, jclass /*clazz*/, jlong pt // JNI registration. static const JNINativeMethod gApkAssetsMethods[] = { - {"nativeLoad", "(Ljava/lang/String;ZZZZ)J", (void*)NativeLoad}, - {"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZZ)J", - (void*)NativeLoadFromFd}, - {"nativeLoadArsc", "(Ljava/lang/String;Z)J", (void*)NativeLoadArsc}, - {"nativeLoadArscFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)J", - (void*)NativeLoadArscFromFd}, - {"nativeLoadEmpty", "(Z)J", (void*)NativeLoadEmpty}, + {"nativeLoad", "(ILjava/lang/String;I)J", (void*)NativeLoad}, + {"nativeLoadEmpty", "(I)J", (void*)NativeLoadEmpty}, + {"nativeLoadFd", "(ILjava/io/FileDescriptor;Ljava/lang/String;I)J", (void*)NativeLoadFromFd}, + {"nativeLoadFdOffsets", "(ILjava/io/FileDescriptor;Ljava/lang/String;JJI)J", + (void*)NativeLoadFromFdOffset}, {"nativeDestroy", "(J)V", (void*)NativeDestroy}, {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath}, {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock}, diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index b2b0ec2a54f8..946fcc03f57e 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -41,28 +41,85 @@ using base::unique_fd; static const std::string kResourcesArsc("resources.arsc"); ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, - const std::string& path, + std::string path, time_t last_mod_time, package_property_t property_flags) - : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time), + : zip_handle_(unmanaged_handle, ::CloseArchive), + path_(std::move(path)), + last_mod_time_(last_mod_time), property_flags_(property_flags) { } -std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system, - bool for_loader) { - package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) | - (for_loader ? PROPERTY_LOADER : 0U); - return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags); +std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, + const package_property_t flags) { + ::ZipArchiveHandle unmanaged_handle; + const int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle); + if (result != 0) { + LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result); + ::CloseArchive(unmanaged_handle); + return {}; + } + + return LoadImpl(unmanaged_handle, path, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/, + flags); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path, - bool system) { - package_property_t flags = PROPERTY_DYNAMIC | (system ? PROPERTY_SYSTEM : 0U); - return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags); +std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd, + const std::string& friendly_name, + const package_property_t flags, + const off64_t offset, + const off64_t length) { + CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength; + CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is " + << kUnknownLength; + + ::ZipArchiveHandle unmanaged_handle; + const int32_t result = (length == kUnknownLength) + ? ::OpenArchiveFd(fd.release(), friendly_name.c_str(), &unmanaged_handle) + : ::OpenArchiveFdRange(fd.release(), friendly_name.c_str(), &unmanaged_handle, length, + offset); + + if (result != 0) { + LOG(ERROR) << "Failed to open APK '" << friendly_name << "' through FD with offset " << offset + << " and length " << length << ": " << ::ErrorCodeString(result); + ::CloseArchive(unmanaged_handle); + return {}; + } + + return LoadImpl(unmanaged_handle, friendly_name, nullptr /*idmap_asset*/, + nullptr /*loaded_idmap*/, flags); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(const std::string& path, + const package_property_t flags) { + auto resources_asset = CreateAssetFromFile(path); + if (!resources_asset) { + LOG(ERROR) << "Failed to open ARSC '" << path; + return {}; + } + + return LoadTableImpl(std::move(resources_asset), path, flags); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadTableFromFd(unique_fd fd, + const std::string& friendly_name, + const package_property_t flags, + const off64_t offset, + const off64_t length) { + auto resources_asset = CreateAssetFromFd(std::move(fd), nullptr /* path */, offset, length); + if (!resources_asset) { + LOG(ERROR) << "Failed to open ARSC '" << friendly_name << "' through FD with offset " << offset + << " and length " << length; + return {}; + } + + return LoadTableImpl(std::move(resources_asset), friendly_name, flags); } std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path, - bool system) { + const package_property_t flags) { + CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders"; + std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path); if (idmap_asset == nullptr) { return {}; @@ -77,75 +134,74 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap return {}; } - auto apkPath = loaded_idmap->OverlayApkPath(); - return LoadImpl({} /*fd*/, apkPath, - std::move(idmap_asset), - std::move(loaded_idmap), - PROPERTY_OVERLAY | (system ? PROPERTY_SYSTEM : 0U)); -} -std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd, - const std::string& friendly_name, - bool system, bool force_shared_lib, - bool for_loader) { - package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) | - (force_shared_lib ? PROPERTY_DYNAMIC : 0U) | - (for_loader ? PROPERTY_LOADER : 0U); - return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/, - flags); -} + ::ZipArchiveHandle unmanaged_handle; + auto overlay_path = loaded_idmap->OverlayApkPath(); + const int32_t result = ::OpenArchive(overlay_path.c_str(), &unmanaged_handle); + if (result != 0) { + LOG(ERROR) << "Failed to open overlay APK '" << overlay_path << "' " + << ::ErrorCodeString(result); + ::CloseArchive(unmanaged_handle); + return {}; + } -std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(const std::string& path, - bool for_loader) { - return LoadArscImpl({} /*fd*/, path, for_loader ? PROPERTY_LOADER : 0U); + return LoadImpl(unmanaged_handle, overlay_path, std::move(idmap_asset), std::move(loaded_idmap), + flags | PROPERTY_OVERLAY); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(unique_fd fd, - const std::string& friendly_name, - bool for_loader) { - return LoadArscImpl(std::move(fd), friendly_name, for_loader ? PROPERTY_LOADER : 0U); +std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(const package_property_t flags) { + std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "empty", -1, flags)); + loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty(); + // Need to force a move for mingw32. + return std::move(loaded_apk); } std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) { unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC)); - if (fd == -1) { + if (!fd.ok()) { LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno); return {}; } - const off64_t file_len = lseek64(fd, 0, SEEK_END); - if (file_len < 0) { - LOG(ERROR) << "Failed to get size of file '" << path << "': " << SystemErrorCodeToString(errno); - return {}; - } - - std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>(); - if (!file_map->create(path.c_str(), fd, 0, static_cast<size_t>(file_len), true /*readOnly*/)) { - LOG(ERROR) << "Failed to mmap file '" << path << "': " << SystemErrorCodeToString(errno); - return {}; - } - return Asset::createFromUncompressedMap(std::move(file_map), Asset::AccessMode::ACCESS_RANDOM); + return CreateAssetFromFd(std::move(fd), path.c_str()); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( - unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset, - std::unique_ptr<const LoadedIdmap> loaded_idmap, package_property_t property_flags) { - ::ZipArchiveHandle unmanaged_handle; - int32_t result; - if (fd >= 0) { - result = - ::OpenArchiveFd(fd.release(), path.c_str(), &unmanaged_handle, true /*assume_ownership*/); - } else { - result = ::OpenArchive(path.c_str(), &unmanaged_handle); +std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd, + const char* path, + off64_t offset, + off64_t length) { + CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength; + CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is " + << kUnknownLength; + if (length == kUnknownLength) { + length = lseek64(fd, 0, SEEK_END); + if (length < 0) { + LOG(ERROR) << "Failed to get size of file '" << ((path) ? path : "anon") << "': " + << SystemErrorCodeToString(errno); + return {}; + } } - if (result != 0) { - LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result); - ::CloseArchive(unmanaged_handle); + std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>(); + if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) { + LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': " + << SystemErrorCodeToString(errno); return {}; } - time_t last_mod_time = getFileModDate(path.c_str()); + // If `path` is set, do not pass ownership of the `fd` to the new Asset since + // Asset::openFileDescriptor can use `path` to create new file descriptors. + return Asset::createFromUncompressedMap(std::move(file_map), + (path) ? base::unique_fd(-1) : std::move(fd), + Asset::AccessMode::ACCESS_RANDOM); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(ZipArchiveHandle unmanaged_handle, + const std::string& path, + std::unique_ptr<Asset> idmap_asset, + std::unique_ptr<const LoadedIdmap> idmap, + package_property_t property_flags) { + const time_t last_mod_time = getFileModDate(path.c_str()); // Wrap the handle in a unique_ptr so it gets automatically closed. std::unique_ptr<ApkAssets> @@ -153,7 +209,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( // Find the resource table. ::ZipEntry entry; - result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry); + int32_t result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry); if (result != 0) { // There is no resources.arsc, so create an empty LoadedArsc and return. loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty(); @@ -173,7 +229,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid. loaded_apk->idmap_asset_ = std::move(idmap_asset); - loaded_apk->loaded_idmap_ = std::move(loaded_idmap); + loaded_apk->loaded_idmap_ = std::move(idmap); const StringPiece data( reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)), @@ -189,24 +245,10 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( return std::move(loaded_apk); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd, - const std::string& path, - package_property_t property_flags) { - std::unique_ptr<Asset> resources_asset; - - if (fd >= 0) { - resources_asset = std::unique_ptr<Asset>(Asset::createFromFd(fd.release(), nullptr, - Asset::AccessMode::ACCESS_BUFFER)); - } else { - resources_asset = CreateAssetFromFile(path); - } - - if (resources_asset == nullptr) { - LOG(ERROR) << "Failed to open ARSC '" << path; - return {}; - } - - time_t last_mod_time = getFileModDate(path.c_str()); +std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(std::unique_ptr<Asset> resources_asset, + const std::string& path, + package_property_t property_flags) { + const time_t last_mod_time = getFileModDate(path.c_str()); std::unique_ptr<ApkAssets> loaded_apk( new ApkAssets(nullptr, path, last_mod_time, property_flags)); @@ -225,13 +267,6 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd, return std::move(loaded_apk); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(bool for_loader) { - std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "", -1, for_loader)); - loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty(); - // Need to force a move for mingw32. - return std::move(loaded_apk); -} - std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const { // If this is a resource loader from an .arsc, there will be no zip handle if (zip_handle_ == nullptr) { @@ -244,10 +279,12 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod return {}; } + const int fd = ::GetFileDescriptor(zip_handle_.get()); + const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get()); if (entry.method == kCompressDeflated) { std::unique_ptr<FileMap> map = util::make_unique<FileMap>(); - if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset, - entry.compressed_length, true /*readOnly*/)) { + if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.compressed_length, + true /*readOnly*/)) { LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; return {}; } @@ -261,13 +298,18 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod return asset; } else { std::unique_ptr<FileMap> map = util::make_unique<FileMap>(); - if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset, - entry.uncompressed_length, true /*readOnly*/)) { + if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.uncompressed_length, + true /*readOnly*/)) { LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; return {}; } - std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), mode); + // TODO: apks created from file descriptors residing in RAM currently cannot open file + // descriptors to the assets they contain. This is because the Asset::openFileDeescriptor uses + // the zip path on disk to create a new file descriptor. This is fixed in a future change + // in the change topic. + std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), + unique_fd(-1) /* fd*/, mode); if (asset == nullptr) { LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; return {}; diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index c132f343713f..cd30c184d5a4 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -298,14 +298,13 @@ Asset::Asset(void) /* * Create a new Asset from a memory mapping. */ -/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, - AccessMode mode) +/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, AccessMode mode) { _FileAsset* pAsset; status_t result; pAsset = new _FileAsset; - result = pAsset->openChunk(dataMap); + result = pAsset->openChunk(dataMap, base::unique_fd(-1)); if (result != NO_ERROR) { delete pAsset; return NULL; @@ -316,11 +315,11 @@ Asset::Asset(void) } /*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(std::unique_ptr<FileMap> dataMap, - AccessMode mode) + base::unique_fd fd, AccessMode mode) { std::unique_ptr<_FileAsset> pAsset = util::make_unique<_FileAsset>(); - status_t result = pAsset->openChunk(dataMap.get()); + status_t result = pAsset->openChunk(dataMap.get(), std::move(fd)); if (result != NO_ERROR) { return NULL; } @@ -415,7 +414,7 @@ off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t m * Constructor. */ _FileAsset::_FileAsset(void) - : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL) + : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mMap(NULL), mBuf(NULL) { // Register the Asset with the global list here after it is fully constructed and its // vtable pointer points to this concrete type. b/31113965 @@ -485,7 +484,7 @@ status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, siz /* * Create the chunk from the map. */ -status_t _FileAsset::openChunk(FileMap* dataMap) +status_t _FileAsset::openChunk(FileMap* dataMap, base::unique_fd fd) { assert(mFp == NULL); // no reopen assert(mMap == NULL); @@ -494,6 +493,7 @@ status_t _FileAsset::openChunk(FileMap* dataMap) mMap = dataMap; mStart = -1; // not used mLength = dataMap->getDataLength(); + mFd = std::move(fd); assert(mOffset == 0); return NO_ERROR; @@ -692,6 +692,17 @@ const void* _FileAsset::getBuffer(bool wordAligned) int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const { if (mMap != NULL) { + if (mFd.ok()) { + *outStart = mMap->getDataOffset(); + *outLength = mMap->getDataLength(); + const int fd = dup(mFd); + if (fd < 0) { + ALOGE("Unable to dup fd (%d).", mFd.get()); + return -1; + } + lseek64(fd, 0, SEEK_SET); + return fd; + } const char* fname = mMap->getFileName(); if (fname == NULL) { fname = mFileName; diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index e35c0249fbdf..70bb441f94cb 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -749,7 +749,7 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data, const LoadedIdmap* loaded_idmap, - package_property_t property_flags) { + const package_property_t property_flags) { ATRACE_NAME("LoadedArsc::Load"); // Not using make_unique because the constructor is private. diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index af802b0e50b9..643dc5c861f7 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -37,49 +37,46 @@ class LoadedIdmap; // Holds an APK. class ApkAssets { - public: - // Creates an ApkAssets. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false, - bool for_loader = false); - - // Creates an ApkAssets, but forces any package with ID 0x7f to be loaded as a shared library. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path, - bool system = false); + // This means the data extends to the end of the file. + static constexpr off64_t kUnknownLength = -1; - // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay - // data. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path, - bool system = false); + public: + // Creates an ApkAssets from the zip path. + static std::unique_ptr<const ApkAssets> Load(const std::string& path, + package_property_t flags = 0U); // Creates an ApkAssets from the given file descriptor, and takes ownership of the file // descriptor. The `friendly_name` is some name that will be used to identify the source of // this ApkAssets in log messages and other debug scenarios. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library. + // If `length` equals kUnknownLength, offset must equal 0; otherwise, the apk data will be read + // using the `offset` into the file descriptor and will be `length` bytes long. static std::unique_ptr<const ApkAssets> LoadFromFd(base::unique_fd fd, - const std::string& friendly_name, bool system, - bool force_shared_lib, - bool for_loader = false); + const std::string& friendly_name, + package_property_t flags = 0U, + off64_t offset = 0, + off64_t length = kUnknownLength); + + // Creates an ApkAssets from the given path which points to a resources.arsc. + static std::unique_ptr<const ApkAssets> LoadTable(const std::string& path, + package_property_t flags = 0U); + + // Creates an ApkAssets from the given file descriptor which points to an resources.arsc, and + // takes ownership of the file descriptor. + // If `length` equals kUnknownLength, offset must equal 0; otherwise, the .arsc data will be read + // using the `offset` into the file descriptor and will be `length` bytes long. + static std::unique_ptr<const ApkAssets> LoadTableFromFd(base::unique_fd fd, + const std::string& friendly_name, + package_property_t flags = 0U, + off64_t offset = 0, + off64_t length = kUnknownLength); - // Creates an empty wrapper ApkAssets from the given path which points to an .arsc. - static std::unique_ptr<const ApkAssets> LoadArsc(const std::string& path, - bool for_loader = false); - - // Creates an empty wrapper ApkAssets from the given file descriptor which points to an .arsc, - // Takes ownership of the file descriptor. - static std::unique_ptr<const ApkAssets> LoadArsc(base::unique_fd fd, - const std::string& friendly_name, - bool for_loader = false); + // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay + // data. + static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path, + package_property_t flags = 0U); // Creates a totally empty ApkAssets with no resources table and no file entries. - static std::unique_ptr<const ApkAssets> LoadEmpty(bool for_loader = false); + static std::unique_ptr<const ApkAssets> LoadEmpty(package_property_t flags = 0U); std::unique_ptr<Asset> Open(const std::string& path, Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const; @@ -105,28 +102,38 @@ class ApkAssets { } inline bool IsOverlay() const { - return (property_flags_ & PROPERTY_OVERLAY) != 0; + return loaded_idmap_ != nullptr; } bool IsUpToDate() const; - // Creates an Asset from any file on the file system. + // Creates an Asset from a file on disk. static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path); + // Creates an Asset from a file descriptor. + // + // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset + // must equal 0; otherwise, the asset data will be read using the `offset` into the file + // descriptor and will be `length` bytes long. + static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd, + const char* path, + off64_t offset = 0, + off64_t length = kUnknownLength); private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); - static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path, + static std::unique_ptr<const ApkAssets> LoadImpl(ZipArchiveHandle unmanaged_handle, + const std::string& path, std::unique_ptr<Asset> idmap_asset, - std::unique_ptr<const LoadedIdmap> loaded_idmap, + std::unique_ptr<const LoadedIdmap> idmap, package_property_t property_flags); - static std::unique_ptr<const ApkAssets> LoadArscImpl(base::unique_fd fd, - const std::string& path, - package_property_t property_flags); + static std::unique_ptr<const ApkAssets> LoadTableImpl(std::unique_ptr<Asset> resources_asset, + const std::string& path, + package_property_t property_flags); ApkAssets(ZipArchiveHandle unmanaged_handle, - const std::string& path, + std::string path, time_t last_mod_time, package_property_t property_flags); diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h index 053dbb7864c6..75761747a5b4 100644 --- a/libs/androidfw/include/androidfw/Asset.h +++ b/libs/androidfw/include/androidfw/Asset.h @@ -26,6 +26,7 @@ #include <memory> +#include <android-base/unique_fd.h> #include <utils/Compat.h> #include <utils/Errors.h> #include <utils/String8.h> @@ -202,8 +203,14 @@ private: */ static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode); + /* + * Create the asset from a memory-mapped file segment. + * + * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is + * used to request new file descriptors using "openFileDescriptor". + */ static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap, - AccessMode mode); + base::unique_fd fd, AccessMode mode); /* * Create the asset from a memory-mapped file segment with compressed @@ -256,9 +263,9 @@ public: /* * Use a memory-mapped region. * - * On success, the object takes ownership of "dataMap". + * On success, the object takes ownership of "dataMap" and "fd". */ - status_t openChunk(FileMap* dataMap); + status_t openChunk(FileMap* dataMap, base::unique_fd fd); /* * Standard Asset interfaces. @@ -273,11 +280,12 @@ public: virtual bool isAllocated(void) const { return mBuf != NULL; } private: - off64_t mStart; // absolute file offset of start of chunk - off64_t mLength; // length of the chunk - off64_t mOffset; // current local offset, 0 == mStart - FILE* mFp; // for read/seek - char* mFileName; // for opening + off64_t mStart; // absolute file offset of start of chunk + off64_t mLength; // length of the chunk + off64_t mOffset; // current local offset, 0 == mStart + FILE* mFp; // for read/seek + char* mFileName; // for opening + base::unique_fd mFd; // for opening file descriptors /* * To support getBuffer() we either need to read the entire thing into diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index b5d3a1fc6c1f..89ff9f52125d 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -69,12 +69,24 @@ struct TypeSpec { } }; +// Flags that change the behavior of loaded packages. +// Keep in sync with f/b/android/content/res/ApkAssets.java using package_property_t = uint32_t; enum : package_property_t { - PROPERTY_DYNAMIC = 1, - PROPERTY_LOADER = 2, - PROPERTY_OVERLAY = 4, - PROPERTY_SYSTEM = 8, + // The package contains framework resource values specified by the system. + // This allows some functions to filter out this package when computing + // what configurations/resources are available. + PROPERTY_SYSTEM = 1U << 0U, + + // The package is a shared library or has a package id of 7f and is loaded as a shared library by + // force. + PROPERTY_DYNAMIC = 1U << 1U, + + // The package has been loaded dynamically using a ResourcesProvider. + PROPERTY_LOADER = 1U << 2U, + + // The package is a RRO. + PROPERTY_OVERLAY = 1U << 3U, }; // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp index 0f2ee6fb968e..26bf5ffe5e91 100644 --- a/libs/androidfw/tests/ApkAssets_test.cpp +++ b/libs/androidfw/tests/ApkAssets_test.cpp @@ -70,7 +70,7 @@ TEST(ApkAssetsTest, LoadApkAsSharedLibrary) { ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u)); EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic()); - loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk"); + loaded_apk = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk", PROPERTY_DYNAMIC); ASSERT_THAT(loaded_apk, NotNull()); loaded_arsc = loaded_apk->GetLoadedArsc(); diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 35fea7ab86cb..ac32699c6dfd 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -63,10 +63,12 @@ class AssetManager2Test : public ::testing::Test { libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk"); ASSERT_NE(nullptr, libclient_assets_); - appaslib_assets_ = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk"); + appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk", + PROPERTY_DYNAMIC); ASSERT_NE(nullptr, appaslib_assets_); - system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/); + system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", + PROPERTY_SYSTEM); ASSERT_NE(nullptr, system_assets_); app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk"); diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp index c8dbe205fee2..24361b5817f4 100644 --- a/libs/androidfw/tests/AttributeResolution_test.cpp +++ b/libs/androidfw/tests/AttributeResolution_test.cpp @@ -67,7 +67,7 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest { TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) { AssetManager2 assetmanager; - auto apk_assets = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/styles/styles.apk"); + auto apk_assets = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk", PROPERTY_DYNAMIC); ASSERT_NE(nullptr, apk_assets); assetmanager.SetApkAssets({apk_assets.get()}); diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index b679672ab34e..41ba637da5d7 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -221,8 +221,8 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) { TEST_F(IdmapTest, OverlayLoaderInterop) { std::string contents; - auto loader_assets = ApkAssets::LoadArsc(GetTestDataPath() + "/loader/resources.arsc", - /* for_loader */ true); + auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc", + PROPERTY_LOADER); AssetManager2 asset_manager; asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(), |