Loading config/hiddenapi-light-greylist.txt +0 −20 Original line number Diff line number Diff line Loading @@ -526,41 +526,22 @@ Landroid/content/res/AssetFileDescriptor;->mLength:J Landroid/content/res/AssetFileDescriptor;->mStartOffset:J Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I Landroid/content/res/AssetManager;->addAssetPathNative(Ljava/lang/String;Z)I Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V Landroid/content/res/AssetManager;->ensureStringBlocks()[Landroid/content/res/StringBlock; Landroid/content/res/AssetManager;->getArraySize(I)I Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray; Landroid/content/res/AssetManager;->getCookieName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getNativeStringBlock(I)J Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence; Landroid/content/res/AssetManager;->getResourceEntryName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourceIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I Landroid/content/res/AssetManager;->getResourceName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourcePackageName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourceTypeName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getStringBlockCount()I Landroid/content/res/AssetManager;-><init>()V Landroid/content/res/AssetManager;->isUpToDate()Z Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->mObject:J Landroid/content/res/AssetManager;->mStringBlocks:[Landroid/content/res/StringBlock; Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor; Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;I)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAssetNative(ILjava/lang/String;I)J Landroid/content/res/AssetManager;->openXmlAssetNative(ILjava/lang/String;)J Landroid/content/res/AssetManager;->resolveAttrs(JII[I[I[I[I)Z Landroid/content/res/AssetManager;->retrieveArray(I[I)I Landroid/content/res/AssetManager;->retrieveAttributes(J[I[I[I)Z Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V Landroid/content/res/AssetManager;->STYLE_NUM_ENTRIES:I Landroid/content/res/AssetManager;->STYLE_RESOURCE_ID:I Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V Landroid/content/res/ColorStateList;->mColors:[I Landroid/content/res/ColorStateList;->mDefaultColor:I Loading Loading @@ -602,7 +583,6 @@ Landroid/content/res/TypedArray;->mResources:Landroid/content/res/Resources; Landroid/content/res/TypedArray;->mTheme:Landroid/content/res/Resources$Theme; Landroid/content/res/TypedArray;->mValue:Landroid/util/TypedValue; Landroid/content/res/TypedArray;->mXml:Landroid/content/res/XmlBlock$Parser; Landroid/content/res/XmlBlock;->close()V Landroid/content/res/XmlBlock;-><init>([B)V Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser; Landroid/content/res/XmlBlock$Parser;->mParseState:J Loading core/java/android/app/Activity.java +2 −0 Original line number Diff line number Diff line Loading @@ -6366,6 +6366,8 @@ public class Activity extends ContextThemeWrapper } else { writer.print(prefix); writer.println("No AutofillManager"); } ResourcesManager.getInstance().dump(prefix, writer); } /** Loading core/java/android/app/ResourcesManager.java +171 −31 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.ActivityThread.DEBUG_CONFIGURATION; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ActivityInfo; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.content.res.CompatResources; import android.content.res.CompatibilityInfo; Loading @@ -34,6 +35,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.LruCache; import android.util.Pair; import android.util.Slog; import android.view.Display; Loading @@ -41,9 +43,13 @@ import android.view.DisplayAdjustments; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Predicate; Loading @@ -59,12 +65,7 @@ public class ResourcesManager { * Predicate that returns true if a WeakReference is gc'ed. */ private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate = new Predicate<WeakReference<Resources>>() { @Override public boolean test(WeakReference<Resources> weakRef) { return weakRef == null || weakRef.get() == null; } }; weakRef -> weakRef == null || weakRef.get() == null; /** * The global compatibility settings. Loading @@ -89,6 +90,48 @@ public class ResourcesManager { */ private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>(); private static class ApkKey { public final String path; public final boolean sharedLib; public final boolean overlay; ApkKey(String path, boolean sharedLib, boolean overlay) { this.path = path; this.sharedLib = sharedLib; this.overlay = overlay; } @Override public int hashCode() { int result = 1; result = 31 * result + this.path.hashCode(); result = 31 * result + Boolean.hashCode(this.sharedLib); result = 31 * result + Boolean.hashCode(this.overlay); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof ApkKey)) { return false; } ApkKey other = (ApkKey) obj; return this.path.equals(other.path) && this.sharedLib == other.sharedLib && this.overlay == other.overlay; } } /** * The ApkAssets we are caching and intend to hold strong references to. */ private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15); /** * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't * in our LRU cache. Bonus resources :) */ private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>(); /** * Resources and base configuration override associated with an Activity. */ Loading Loading @@ -260,6 +303,43 @@ public class ResourcesManager { } } private static String overlayPathToIdmapPath(String path) { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay) throws IOException { final ApkKey newKey = new ApkKey(path, sharedLib, overlay); ApkAssets apkAssets = mLoadedApkAssets.get(newKey); if (apkAssets != null) { return apkAssets; } // Optimistically check if this ApkAssets exists somewhere else. final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey); if (apkAssetsRef != null) { apkAssets = apkAssetsRef.get(); if (apkAssets != null) { mLoadedApkAssets.put(newKey, apkAssets); return apkAssets; } else { // Clean up the reference. mCachedApkAssets.remove(newKey); } } // We must load this from disk. if (overlay) { apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), false /*system*/); } else { apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib); } mLoadedApkAssets.put(newKey, apkAssets); mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets)); return apkAssets; } /** * Creates an AssetManager from the paths within the ResourcesKey. * Loading @@ -270,13 +350,16 @@ public class ResourcesManager { */ @VisibleForTesting protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { AssetManager assets = new AssetManager(); final AssetManager.Builder builder = new AssetManager.Builder(); // resDir can be null if the 'android' package is creating a new Resources object. // This is fine, since each AssetManager automatically loads the 'android' package // already. if (key.mResDir != null) { if (assets.addAssetPath(key.mResDir) == 0) { try { builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.e(TAG, "failed to add asset path " + key.mResDir); return null; } Loading @@ -284,7 +367,10 @@ public class ResourcesManager { if (key.mSplitResDirs != null) { for (final String splitResDir : key.mSplitResDirs) { if (assets.addAssetPath(splitResDir) == 0) { try { builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.e(TAG, "failed to add split asset path " + splitResDir); return null; } Loading @@ -293,7 +379,14 @@ public class ResourcesManager { if (key.mOverlayDirs != null) { for (final String idmapPath : key.mOverlayDirs) { assets.addOverlayPath(idmapPath); try { builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/)); } catch (IOException e) { Log.w(TAG, "failed to add overlay path " + idmapPath); // continue. } } } Loading @@ -302,14 +395,73 @@ public class ResourcesManager { if (libDir.endsWith(".apk")) { // Avoid opening files we know do not have resources, // like code-only .jar files. if (assets.addAssetPathAsSharedLibrary(libDir) == 0) { try { builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.w(TAG, "Asset path '" + libDir + "' does not exist or contains no resources."); // continue. } } } } return builder.build(); } private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) { int count = 0; for (WeakReference<T> ref : collection) { final T value = ref != null ? ref.get() : null; if (value != null) { count++; } } return count; } /** * @hide */ public void dump(String prefix, PrintWriter printWriter) { synchronized (this) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); for (int i = 0; i < prefix.length() / 2; i++) { pw.increaseIndent(); } pw.println("ResourcesManager:"); pw.increaseIndent(); pw.print("cached apks: total="); pw.print(mLoadedApkAssets.size()); pw.print(" created="); pw.print(mLoadedApkAssets.createCount()); pw.print(" evicted="); pw.print(mLoadedApkAssets.evictionCount()); pw.print(" hit="); pw.print(mLoadedApkAssets.hitCount()); pw.print(" miss="); pw.print(mLoadedApkAssets.missCount()); pw.print(" max="); pw.print(mLoadedApkAssets.maxSize()); pw.println(); pw.print("total apks: "); pw.println(countLiveReferences(mCachedApkAssets.values())); pw.print("resources: "); int references = countLiveReferences(mResourceReferences); for (ActivityResources activityResources : mActivityResourceReferences.values()) { references += countLiveReferences(activityResources.activityResources); } pw.println(references); pw.print("resource impls: "); pw.println(countLiveReferences(mResourceImpls.values())); } return assets; } private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) { Loading Loading @@ -630,7 +782,6 @@ public class ResourcesManager { // We will create the ResourcesImpl object outside of holding this lock. } } // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now. ResourcesImpl resourcesImpl = createResourcesImpl(key); Loading @@ -638,19 +789,8 @@ public class ResourcesManager { return null; } synchronized (this) { ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key); if (existingResourcesImpl != null) { if (DEBUG) { Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl + " new impl=" + resourcesImpl); } resourcesImpl.getAssets().close(); resourcesImpl = existingResourcesImpl; } else { // Add this ResourcesImpl to the cache. mResourceImpls.put(key, new WeakReference<>(resourcesImpl)); } final Resources resources; if (activityToken != null) { Loading core/java/android/content/pm/PackageParser.java +26 −40 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.content.pm.PackageParserCacheHelper.WriteHelper; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; import android.content.pm.split.SplitAssetLoader; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -1287,7 +1288,6 @@ public class PackageParser { */ @Deprecated public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { final AssetManager assets = newConfiguredAssetManager(); final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps) { if (!lite.coreApp) { Loading @@ -1296,8 +1296,9 @@ public class PackageParser { } } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); try { final Package pkg = parseBaseApk(apkFile, assets, flags); final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags); pkg.setCodePath(apkFile.getCanonicalPath()); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; Loading @@ -1305,26 +1306,8 @@ public class PackageParser { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to get path: " + apkFile, e); } finally { IoUtils.closeQuietly(assets); } } private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) throws PackageParserException { if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + apkPath); } // The AssetManager guarantees uniqueness for asset paths, so if this asset path // already exists in the AssetManager, addAssetPath will only return the cookie // assigned to it. int cookie = assets.addAssetPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); IoUtils.closeQuietly(assetLoader); } return cookie; } private Package parseBaseApk(File apkFile, AssetManager assets, int flags) Loading @@ -1342,13 +1325,15 @@ public class PackageParser { if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); Resources res = null; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); final int cookie = assets.findCookieForPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); } parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final Resources res = new Resources(assets, mMetrics, null); final String[] outError = new String[1]; final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError); Loading Loading @@ -1383,15 +1368,18 @@ public class PackageParser { if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); final Resources res; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); // This must always succeed, as the path has been added to the AssetManager before. final int cookie = assets.findCookieForPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); } parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); res = new Resources(assets, mMetrics, null); final String[] outError = new String[1]; pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError); Loading Loading @@ -1593,21 +1581,19 @@ public class PackageParser { int flags) throws PackageParserException { final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); AssetManager assets = null; XmlResourceParser parser = null; try { assets = newConfiguredAssetManager(); int cookie = fd != null ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath); if (cookie == 0) { final ApkAssets apkAssets; try { apkAssets = fd != null ? ApkAssets.loadFromFd(fd, debugPathName, false, false) : ApkAssets.loadFromPath(apkPath); } catch (IOException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Failed to parse " + apkPath); } final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME); final SigningDetails signingDetails; if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { Loading @@ -1634,7 +1620,7 @@ public class PackageParser { "Failed to parse " + apkPath, e); } finally { IoUtils.closeQuietly(parser); IoUtils.closeQuietly(assets); // TODO(b/72056911): Implement and call close() on ApkAssets. } } Loading core/java/android/content/pm/split/DefaultSplitAssetLoader.java +39 −36 Original line number Diff line number Diff line Loading @@ -15,10 +15,13 @@ */ package android.content.pm.split; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.os.Build; Loading @@ -26,6 +29,8 @@ import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import java.io.IOException; /** * Loads the base and split APKs into a single AssetManager. * @hide Loading @@ -33,68 +38,66 @@ import libcore.io.IoUtils; public class DefaultSplitAssetLoader implements SplitAssetLoader { private final String mBaseCodePath; private final String[] mSplitCodePaths; private final int mFlags; private final @ParseFlags int mFlags; private AssetManager mCachedAssetManager; public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) { public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) { mBaseCodePath = pkg.baseCodePath; mSplitCodePaths = pkg.splitCodePaths; mFlags = flags; } private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) throws PackageParser.PackageParserException { if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) { throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + apkPath); private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) throws PackageParserException { if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + path); } if (assets.addAssetPath(apkPath) == 0) { throw new PackageParser.PackageParserException( INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); try { return ApkAssets.loadFromPath(path); } catch (IOException e) { throw new PackageParserException(INSTALL_FAILED_INVALID_APK, "Failed to load APK at path " + path, e); } } @Override public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException { public AssetManager getBaseAssetManager() throws PackageParserException { if (mCachedAssetManager != null) { return mCachedAssetManager; } AssetManager assets = new AssetManager(); try { assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); loadApkIntoAssetManager(assets, mBaseCodePath, mFlags); ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null ? mSplitCodePaths.length : 0) + 1]; // Load the base. int splitIdx = 0; apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags); // Load any splits. if (!ArrayUtils.isEmpty(mSplitCodePaths)) { for (String apkPath : mSplitCodePaths) { loadApkIntoAssetManager(assets, apkPath, mFlags); apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); } } AssetManager assets = new AssetManager(); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); mCachedAssetManager = assets; assets = null; return mCachedAssetManager; } finally { if (assets != null) { IoUtils.closeQuietly(assets); } } } @Override public AssetManager getSplitAssetManager(int splitIdx) throws PackageParser.PackageParserException { public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException { return getBaseAssetManager(); } @Override public void close() throws Exception { if (mCachedAssetManager != null) { IoUtils.closeQuietly(mCachedAssetManager); } } } Loading
config/hiddenapi-light-greylist.txt +0 −20 Original line number Diff line number Diff line Loading @@ -526,41 +526,22 @@ Landroid/content/res/AssetFileDescriptor;->mLength:J Landroid/content/res/AssetFileDescriptor;->mStartOffset:J Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I Landroid/content/res/AssetManager;->addAssetPathNative(Ljava/lang/String;Z)I Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V Landroid/content/res/AssetManager;->ensureStringBlocks()[Landroid/content/res/StringBlock; Landroid/content/res/AssetManager;->getArraySize(I)I Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray; Landroid/content/res/AssetManager;->getCookieName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getNativeStringBlock(I)J Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence; Landroid/content/res/AssetManager;->getResourceEntryName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourceIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I Landroid/content/res/AssetManager;->getResourceName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourcePackageName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getResourceTypeName(I)Ljava/lang/String; Landroid/content/res/AssetManager;->getStringBlockCount()I Landroid/content/res/AssetManager;-><init>()V Landroid/content/res/AssetManager;->isUpToDate()Z Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I Landroid/content/res/AssetManager;->mObject:J Landroid/content/res/AssetManager;->mStringBlocks:[Landroid/content/res/StringBlock; Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor; Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;I)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;)Ljava/io/InputStream; Landroid/content/res/AssetManager;->openNonAssetNative(ILjava/lang/String;I)J Landroid/content/res/AssetManager;->openXmlAssetNative(ILjava/lang/String;)J Landroid/content/res/AssetManager;->resolveAttrs(JII[I[I[I[I)Z Landroid/content/res/AssetManager;->retrieveArray(I[I)I Landroid/content/res/AssetManager;->retrieveAttributes(J[I[I[I)Z Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V Landroid/content/res/AssetManager;->STYLE_NUM_ENTRIES:I Landroid/content/res/AssetManager;->STYLE_RESOURCE_ID:I Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V Landroid/content/res/ColorStateList;->mColors:[I Landroid/content/res/ColorStateList;->mDefaultColor:I Loading Loading @@ -602,7 +583,6 @@ Landroid/content/res/TypedArray;->mResources:Landroid/content/res/Resources; Landroid/content/res/TypedArray;->mTheme:Landroid/content/res/Resources$Theme; Landroid/content/res/TypedArray;->mValue:Landroid/util/TypedValue; Landroid/content/res/TypedArray;->mXml:Landroid/content/res/XmlBlock$Parser; Landroid/content/res/XmlBlock;->close()V Landroid/content/res/XmlBlock;-><init>([B)V Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser; Landroid/content/res/XmlBlock$Parser;->mParseState:J Loading
core/java/android/app/Activity.java +2 −0 Original line number Diff line number Diff line Loading @@ -6366,6 +6366,8 @@ public class Activity extends ContextThemeWrapper } else { writer.print(prefix); writer.println("No AutofillManager"); } ResourcesManager.getInstance().dump(prefix, writer); } /** Loading
core/java/android/app/ResourcesManager.java +171 −31 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.ActivityThread.DEBUG_CONFIGURATION; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ActivityInfo; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.content.res.CompatResources; import android.content.res.CompatibilityInfo; Loading @@ -34,6 +35,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.LruCache; import android.util.Pair; import android.util.Slog; import android.view.Display; Loading @@ -41,9 +43,13 @@ import android.view.DisplayAdjustments; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Predicate; Loading @@ -59,12 +65,7 @@ public class ResourcesManager { * Predicate that returns true if a WeakReference is gc'ed. */ private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate = new Predicate<WeakReference<Resources>>() { @Override public boolean test(WeakReference<Resources> weakRef) { return weakRef == null || weakRef.get() == null; } }; weakRef -> weakRef == null || weakRef.get() == null; /** * The global compatibility settings. Loading @@ -89,6 +90,48 @@ public class ResourcesManager { */ private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>(); private static class ApkKey { public final String path; public final boolean sharedLib; public final boolean overlay; ApkKey(String path, boolean sharedLib, boolean overlay) { this.path = path; this.sharedLib = sharedLib; this.overlay = overlay; } @Override public int hashCode() { int result = 1; result = 31 * result + this.path.hashCode(); result = 31 * result + Boolean.hashCode(this.sharedLib); result = 31 * result + Boolean.hashCode(this.overlay); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof ApkKey)) { return false; } ApkKey other = (ApkKey) obj; return this.path.equals(other.path) && this.sharedLib == other.sharedLib && this.overlay == other.overlay; } } /** * The ApkAssets we are caching and intend to hold strong references to. */ private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15); /** * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't * in our LRU cache. Bonus resources :) */ private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>(); /** * Resources and base configuration override associated with an Activity. */ Loading Loading @@ -260,6 +303,43 @@ public class ResourcesManager { } } private static String overlayPathToIdmapPath(String path) { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay) throws IOException { final ApkKey newKey = new ApkKey(path, sharedLib, overlay); ApkAssets apkAssets = mLoadedApkAssets.get(newKey); if (apkAssets != null) { return apkAssets; } // Optimistically check if this ApkAssets exists somewhere else. final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey); if (apkAssetsRef != null) { apkAssets = apkAssetsRef.get(); if (apkAssets != null) { mLoadedApkAssets.put(newKey, apkAssets); return apkAssets; } else { // Clean up the reference. mCachedApkAssets.remove(newKey); } } // We must load this from disk. if (overlay) { apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), false /*system*/); } else { apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib); } mLoadedApkAssets.put(newKey, apkAssets); mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets)); return apkAssets; } /** * Creates an AssetManager from the paths within the ResourcesKey. * Loading @@ -270,13 +350,16 @@ public class ResourcesManager { */ @VisibleForTesting protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { AssetManager assets = new AssetManager(); final AssetManager.Builder builder = new AssetManager.Builder(); // resDir can be null if the 'android' package is creating a new Resources object. // This is fine, since each AssetManager automatically loads the 'android' package // already. if (key.mResDir != null) { if (assets.addAssetPath(key.mResDir) == 0) { try { builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.e(TAG, "failed to add asset path " + key.mResDir); return null; } Loading @@ -284,7 +367,10 @@ public class ResourcesManager { if (key.mSplitResDirs != null) { for (final String splitResDir : key.mSplitResDirs) { if (assets.addAssetPath(splitResDir) == 0) { try { builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.e(TAG, "failed to add split asset path " + splitResDir); return null; } Loading @@ -293,7 +379,14 @@ public class ResourcesManager { if (key.mOverlayDirs != null) { for (final String idmapPath : key.mOverlayDirs) { assets.addOverlayPath(idmapPath); try { builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/)); } catch (IOException e) { Log.w(TAG, "failed to add overlay path " + idmapPath); // continue. } } } Loading @@ -302,14 +395,73 @@ public class ResourcesManager { if (libDir.endsWith(".apk")) { // Avoid opening files we know do not have resources, // like code-only .jar files. if (assets.addAssetPathAsSharedLibrary(libDir) == 0) { try { builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/)); } catch (IOException e) { Log.w(TAG, "Asset path '" + libDir + "' does not exist or contains no resources."); // continue. } } } } return builder.build(); } private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) { int count = 0; for (WeakReference<T> ref : collection) { final T value = ref != null ? ref.get() : null; if (value != null) { count++; } } return count; } /** * @hide */ public void dump(String prefix, PrintWriter printWriter) { synchronized (this) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); for (int i = 0; i < prefix.length() / 2; i++) { pw.increaseIndent(); } pw.println("ResourcesManager:"); pw.increaseIndent(); pw.print("cached apks: total="); pw.print(mLoadedApkAssets.size()); pw.print(" created="); pw.print(mLoadedApkAssets.createCount()); pw.print(" evicted="); pw.print(mLoadedApkAssets.evictionCount()); pw.print(" hit="); pw.print(mLoadedApkAssets.hitCount()); pw.print(" miss="); pw.print(mLoadedApkAssets.missCount()); pw.print(" max="); pw.print(mLoadedApkAssets.maxSize()); pw.println(); pw.print("total apks: "); pw.println(countLiveReferences(mCachedApkAssets.values())); pw.print("resources: "); int references = countLiveReferences(mResourceReferences); for (ActivityResources activityResources : mActivityResourceReferences.values()) { references += countLiveReferences(activityResources.activityResources); } pw.println(references); pw.print("resource impls: "); pw.println(countLiveReferences(mResourceImpls.values())); } return assets; } private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) { Loading Loading @@ -630,7 +782,6 @@ public class ResourcesManager { // We will create the ResourcesImpl object outside of holding this lock. } } // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now. ResourcesImpl resourcesImpl = createResourcesImpl(key); Loading @@ -638,19 +789,8 @@ public class ResourcesManager { return null; } synchronized (this) { ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key); if (existingResourcesImpl != null) { if (DEBUG) { Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl + " new impl=" + resourcesImpl); } resourcesImpl.getAssets().close(); resourcesImpl = existingResourcesImpl; } else { // Add this ResourcesImpl to the cache. mResourceImpls.put(key, new WeakReference<>(resourcesImpl)); } final Resources resources; if (activityToken != null) { Loading
core/java/android/content/pm/PackageParser.java +26 −40 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.content.pm.PackageParserCacheHelper.WriteHelper; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; import android.content.pm.split.SplitAssetLoader; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -1287,7 +1288,6 @@ public class PackageParser { */ @Deprecated public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { final AssetManager assets = newConfiguredAssetManager(); final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps) { if (!lite.coreApp) { Loading @@ -1296,8 +1296,9 @@ public class PackageParser { } } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); try { final Package pkg = parseBaseApk(apkFile, assets, flags); final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags); pkg.setCodePath(apkFile.getCanonicalPath()); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; Loading @@ -1305,26 +1306,8 @@ public class PackageParser { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to get path: " + apkFile, e); } finally { IoUtils.closeQuietly(assets); } } private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) throws PackageParserException { if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + apkPath); } // The AssetManager guarantees uniqueness for asset paths, so if this asset path // already exists in the AssetManager, addAssetPath will only return the cookie // assigned to it. int cookie = assets.addAssetPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); IoUtils.closeQuietly(assetLoader); } return cookie; } private Package parseBaseApk(File apkFile, AssetManager assets, int flags) Loading @@ -1342,13 +1325,15 @@ public class PackageParser { if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); Resources res = null; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); final int cookie = assets.findCookieForPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); } parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final Resources res = new Resources(assets, mMetrics, null); final String[] outError = new String[1]; final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError); Loading Loading @@ -1383,15 +1368,18 @@ public class PackageParser { if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); final Resources res; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); // This must always succeed, as the path has been added to the AssetManager before. final int cookie = assets.findCookieForPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); } parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); res = new Resources(assets, mMetrics, null); final String[] outError = new String[1]; pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError); Loading Loading @@ -1593,21 +1581,19 @@ public class PackageParser { int flags) throws PackageParserException { final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); AssetManager assets = null; XmlResourceParser parser = null; try { assets = newConfiguredAssetManager(); int cookie = fd != null ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath); if (cookie == 0) { final ApkAssets apkAssets; try { apkAssets = fd != null ? ApkAssets.loadFromFd(fd, debugPathName, false, false) : ApkAssets.loadFromPath(apkPath); } catch (IOException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Failed to parse " + apkPath); } final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME); final SigningDetails signingDetails; if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { Loading @@ -1634,7 +1620,7 @@ public class PackageParser { "Failed to parse " + apkPath, e); } finally { IoUtils.closeQuietly(parser); IoUtils.closeQuietly(assets); // TODO(b/72056911): Implement and call close() on ApkAssets. } } Loading
core/java/android/content/pm/split/DefaultSplitAssetLoader.java +39 −36 Original line number Diff line number Diff line Loading @@ -15,10 +15,13 @@ */ package android.content.pm.split; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.os.Build; Loading @@ -26,6 +29,8 @@ import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import java.io.IOException; /** * Loads the base and split APKs into a single AssetManager. * @hide Loading @@ -33,68 +38,66 @@ import libcore.io.IoUtils; public class DefaultSplitAssetLoader implements SplitAssetLoader { private final String mBaseCodePath; private final String[] mSplitCodePaths; private final int mFlags; private final @ParseFlags int mFlags; private AssetManager mCachedAssetManager; public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) { public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) { mBaseCodePath = pkg.baseCodePath; mSplitCodePaths = pkg.splitCodePaths; mFlags = flags; } private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) throws PackageParser.PackageParserException { if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) { throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + apkPath); private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) throws PackageParserException { if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + path); } if (assets.addAssetPath(apkPath) == 0) { throw new PackageParser.PackageParserException( INSTALL_PARSE_FAILED_BAD_MANIFEST, "Failed adding asset path: " + apkPath); try { return ApkAssets.loadFromPath(path); } catch (IOException e) { throw new PackageParserException(INSTALL_FAILED_INVALID_APK, "Failed to load APK at path " + path, e); } } @Override public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException { public AssetManager getBaseAssetManager() throws PackageParserException { if (mCachedAssetManager != null) { return mCachedAssetManager; } AssetManager assets = new AssetManager(); try { assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); loadApkIntoAssetManager(assets, mBaseCodePath, mFlags); ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null ? mSplitCodePaths.length : 0) + 1]; // Load the base. int splitIdx = 0; apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags); // Load any splits. if (!ArrayUtils.isEmpty(mSplitCodePaths)) { for (String apkPath : mSplitCodePaths) { loadApkIntoAssetManager(assets, apkPath, mFlags); apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); } } AssetManager assets = new AssetManager(); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); mCachedAssetManager = assets; assets = null; return mCachedAssetManager; } finally { if (assets != null) { IoUtils.closeQuietly(assets); } } } @Override public AssetManager getSplitAssetManager(int splitIdx) throws PackageParser.PackageParserException { public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException { return getBaseAssetManager(); } @Override public void close() throws Exception { if (mCachedAssetManager != null) { IoUtils.closeQuietly(mCachedAssetManager); } } }