diff options
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(), |