summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Lesinski <adamlesinski@google.com> 2018-01-23 11:41:15 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-01-23 11:41:15 +0000
commita8c7794856c5794fa5b31cf5398b8f773650d6c7 (patch)
tree0752b58dcfe9460eb885d540c8b9cdcf73c700a5
parent9e500594c02689c84184fa15df331d878515ebad (diff)
parent7fb38311361390e24d7e43ce1eb220faccd251ff (diff)
Merge changes Ib67ad0da,Ie532f29a,Ieabc1777,Ied210b3e
* changes: Revert "Replace AssetManager with AssetManager2 implementation" Revert "Make idiomatic use of ApkAssets and AssetManager" Revert "libandroidfw: Add ApplyStyle and SetConfiguration benchmark" Revert "libandroidfw: Improve performance of AssetManager2"
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ResourcesManager.java198
-rw-r--r--core/java/android/content/pm/PackageParser.java60
-rw-r--r--core/java/android/content/pm/split/DefaultSplitAssetLoader.java75
-rw-r--r--core/java/android/content/pm/split/SplitAssetDependencyLoader.java88
-rw-r--r--core/java/android/content/res/ApkAssets.java190
-rw-r--r--core/java/android/content/res/AssetManager.java1334
-rw-r--r--core/java/android/content/res/Resources.java9
-rw-r--r--core/java/android/content/res/ResourcesImpl.java22
-rw-r--r--core/java/android/content/res/TypedArray.java185
-rw-r--r--core/java/android/content/res/XmlBlock.java8
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/FontFamily.cpp29
-rw-r--r--core/jni/android_app_NativeActivity.cpp2
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp150
-rw-r--r--core/jni/android_util_AssetManager.cpp2884
-rw-r--r--core/jni/include/android_runtime/android_util_AssetManager.h15
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/androidfw/AssetManager2.cpp279
-rw-r--r--libs/androidfw/AttributeResolution.cpp263
-rw-r--r--libs/androidfw/LoadedArsc.cpp263
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h66
-rw-r--r--libs/androidfw/include/androidfw/AttributeFinder.h6
-rw-r--r--libs/androidfw/include/androidfw/AttributeResolution.h11
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h110
-rw-r--r--libs/androidfw/include/androidfw/MutexGuard.h101
-rw-r--r--libs/androidfw/tests/ApkAssets_test.cpp78
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp59
-rw-r--r--libs/androidfw/tests/AttributeResolution_bench.cpp175
-rw-r--r--libs/androidfw/tests/AttributeResolution_test.cpp39
-rw-r--r--libs/androidfw/tests/BenchmarkHelpers.cpp16
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp169
-rw-r--r--libs/androidfw/tests/TestHelpers.h1
-rw-r--r--libs/androidfw/tests/data/basic/R.h2
-rw-r--r--libs/androidfw/tests/data/basic/basic.apkbin5260 -> 3124 bytes
-rw-r--r--libs/androidfw/tests/data/basic/res/layout/layout.xml25
-rw-r--r--libs/androidfw/tests/data/basic/res/values/values.xml13
-rw-r--r--native/android/asset_manager.cpp28
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp30
40 files changed, 3055 insertions, 3937 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a6a1f434c411..0a5b848e6220 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6303,8 +6303,6 @@ public class Activity extends ContextThemeWrapper
} else {
writer.print(prefix); writer.println("No AutofillManager");
}
-
- ResourcesManager.getInstance().dump(prefix, writer);
}
/**
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b96e028076e5..fb11272d7e62 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,7 +21,6 @@ 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;
@@ -35,7 +34,6 @@ 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;
@@ -43,13 +41,9 @@ 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;
@@ -65,7 +59,12 @@ public class ResourcesManager {
* Predicate that returns true if a WeakReference is gc'ed.
*/
private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
- weakRef -> weakRef == null || weakRef.get() == null;
+ new Predicate<WeakReference<Resources>>() {
+ @Override
+ public boolean test(WeakReference<Resources> weakRef) {
+ return weakRef == null || weakRef.get() == null;
+ }
+ };
/**
* The global compatibility settings.
@@ -90,48 +89,6 @@ 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.
*/
@@ -303,41 +260,6 @@ public class ResourcesManager {
}
}
- 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) {
- final String idmapPath = "/data/resource-cache/"
- + path.substring(1).replace('/', '@')
- + "@idmap";
- apkAssets = ApkAssets.loadOverlayFromPath(idmapPath, 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.
*
@@ -348,15 +270,13 @@ public class ResourcesManager {
*/
@VisibleForTesting
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
- final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
+ AssetManager assets = new AssetManager();
// 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) {
- try {
- apkAssets.add(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPath(key.mResDir) == 0) {
Log.e(TAG, "failed to add asset path " + key.mResDir);
return null;
}
@@ -364,10 +284,7 @@ public class ResourcesManager {
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
- try {
- apkAssets.add(loadApkAssets(splitResDir, false /*sharedLib*/,
- false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPath(splitResDir) == 0) {
Log.e(TAG, "failed to add split asset path " + splitResDir);
return null;
}
@@ -376,13 +293,7 @@ public class ResourcesManager {
if (key.mOverlayDirs != null) {
for (final String idmapPath : key.mOverlayDirs) {
- try {
- apkAssets.add(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/));
- } catch (IOException e) {
- Log.w(TAG, "failed to add overlay path " + idmapPath);
-
- // continue.
- }
+ assets.addOverlayPath(idmapPath);
}
}
@@ -391,77 +302,16 @@ public class ResourcesManager {
if (libDir.endsWith(".apk")) {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
- try {
- apkAssets.add(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
Log.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
-
- // continue.
}
}
}
}
-
- AssetManager assets = new AssetManager();
- assets.setApkAssets(apkAssets.toArray(new ApkAssets[apkAssets.size()]),
- false /*invalidateCaches*/);
return assets;
}
- 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()));
- }
- }
-
private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
Configuration config;
final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
@@ -780,15 +630,27 @@ 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);
- if (resourcesImpl == null) {
- return null;
- }
+ // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+ ResourcesImpl resourcesImpl = createResourcesImpl(key);
+ if (resourcesImpl == null) {
+ return null;
+ }
- // Add this ResourcesImpl to the cache.
- mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+ 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) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 68aaaa339b0d..4a71467f4b36 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -54,7 +54,6 @@ 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;
@@ -1292,6 +1291,24 @@ public class PackageParser {
}
}
+ 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);
+ }
+ return cookie;
+ }
+
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
@@ -1307,15 +1324,13 @@ 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 {
- final int cookie = assets.findCookieForPath(apkPath);
- if (cookie == 0) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + apkPath);
- }
+ res = new Resources(assets, mMetrics, null);
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);
@@ -1350,18 +1365,15 @@ 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 {
- // 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);
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
@@ -1563,19 +1575,21 @@ public class PackageParser {
int flags) throws PackageParserException {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
+ AssetManager assets = null;
XmlResourceParser parser = null;
try {
- final ApkAssets apkAssets;
- try {
- apkAssets = fd != null
- ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
- : ApkAssets.loadFromPath(apkPath);
- } catch (IOException e) {
+ assets = newConfiguredAssetManager();
+ int cookie = fd != null
+ ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
+ if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath);
}
- parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
+ final DisplayMetrics metrics = new DisplayMetrics();
+ metrics.setToDefaults();
+
+ parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final SigningDetails signingDetails;
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
@@ -1601,7 +1615,7 @@ public class PackageParser {
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
- // TODO(b/72056911): Implement and call close() on ApkAssets.
+ IoUtils.closeQuietly(assets);
}
}
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index 9e3a8f48996c..99eb4702d32e 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,13 +15,10 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
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;
@@ -29,8 +26,6 @@ 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
@@ -38,66 +33,68 @@ import java.io.IOException;
public class DefaultSplitAssetLoader implements SplitAssetLoader {
private final String mBaseCodePath;
private final String[] mSplitCodePaths;
- private final @ParseFlags int mFlags;
+ private final int mFlags;
+
private AssetManager mCachedAssetManager;
- public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
+ public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
mBaseCodePath = pkg.baseCodePath;
mSplitCodePaths = pkg.splitCodePaths;
mFlags = flags;
}
- 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);
+ 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);
}
- try {
- return ApkAssets.loadFromPath(path);
- } catch (IOException e) {
- throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
+ if (assets.addAssetPath(apkPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
}
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
if (mCachedAssetManager != null) {
return mCachedAssetManager;
}
- ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
- ? mSplitCodePaths.length : 0) + 1];
-
- // Load the base.
- int splitIdx = 0;
- apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
+ 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);
+
+ if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+ for (String apkPath : mSplitCodePaths) {
+ loadApkIntoAssetManager(assets, apkPath, mFlags);
+ }
+ }
- // Load any splits.
- if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
- for (String apkPath : mSplitCodePaths) {
- apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags);
+ mCachedAssetManager = assets;
+ assets = null;
+ return mCachedAssetManager;
+ } finally {
+ if (assets != null) {
+ IoUtils.closeQuietly(assets);
}
}
-
- 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;
- return mCachedAssetManager;
}
@Override
- public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int splitIdx)
+ throws PackageParser.PackageParserException {
return getBaseAssetManager();
}
@Override
public void close() throws Exception {
- IoUtils.closeQuietly(mCachedAssetManager);
+ if (mCachedAssetManager != null) {
+ IoUtils.closeQuietly(mCachedAssetManager);
+ }
}
}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 58eaabfa62f2..16023f0d9d97 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,21 +15,17 @@
*/
package android.content.pm.split;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.annotation.NonNull;
-import android.content.pm.PackageManager;
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;
import android.util.SparseArray;
import libcore.io.IoUtils;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,15 +34,17 @@ import java.util.Collections;
* is to be used when an application opts-in to isolated split loading.
* @hide
*/
-public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
+public class SplitAssetDependencyLoader
+ extends SplitDependencyLoader<PackageParser.PackageParserException>
implements SplitAssetLoader {
private final String[] mSplitPaths;
- private final @ParseFlags int mFlags;
- private final ApkAssets[][] mCachedSplitApks;
- private final AssetManager[] mCachedAssetManagers;
+ private final int mFlags;
+
+ private String[][] mCachedPaths;
+ private AssetManager[] mCachedAssetManagers;
public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
- SparseArray<int[]> dependencies, @ParseFlags int flags) {
+ SparseArray<int[]> dependencies, int flags) {
super(dependencies);
// The base is inserted into index 0, so we need to shift all the splits by 1.
@@ -55,7 +53,7 @@ public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackagePar
System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
mFlags = flags;
- mCachedSplitApks = new ApkAssets[mSplitPaths.length][];
+ mCachedPaths = new String[mSplitPaths.length][];
mCachedAssetManagers = new AssetManager[mSplitPaths.length];
}
@@ -64,60 +62,58 @@ public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackagePar
return mCachedAssetManagers[splitIdx] != null;
}
- 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);
- }
-
+ private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
+ throws PackageParser.PackageParserException {
+ final AssetManager assets = new AssetManager();
try {
- return ApkAssets.loadFromPath(path);
- } catch (IOException e) {
- throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+
+ for (String assetPath : assetPaths) {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
+ !PackageParser.isApkPath(assetPath)) {
+ throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + assetPath);
+ }
+
+ if (assets.addAssetPath(assetPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + assetPath);
+ }
+ }
+ return assets;
+ } catch (Throwable e) {
+ IoUtils.closeQuietly(assets);
+ throw e;
}
}
- private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
- final 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*/);
- return assets;
- }
-
@Override
protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
- int parentSplitIdx) throws PackageParserException {
- final ArrayList<ApkAssets> assets = new ArrayList<>();
-
- // Include parent ApkAssets.
+ int parentSplitIdx) throws PackageParser.PackageParserException {
+ final ArrayList<String> assetPaths = new ArrayList<>();
if (parentSplitIdx >= 0) {
- Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]);
+ Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
}
- // Include this ApkAssets.
- assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags));
-
- // Load and include all config splits for this feature.
+ assetPaths.add(mSplitPaths[splitIdx]);
for (int configSplitIdx : configSplitIndices) {
- assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags));
+ assetPaths.add(mSplitPaths[configSplitIdx]);
}
-
- // Cache the results.
- mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]);
- mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]);
+ mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+ mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
+ mFlags);
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
loadDependenciesForSplit(0);
return mCachedAssetManagers[0];
}
@Override
- public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
// Since we insert the base at position 0, and PackageParser keeps splits separate from
// the base, we need to adjust the index.
loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
deleted file mode 100644
index fd664bc731d0..000000000000
--- a/core/java/android/content/res/ApkAssets.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.content.res;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * The loaded, immutable, in-memory representation of an APK.
- *
- * The main implementation is native C++ and there is very little API surface exposed here. The APK
- * is mainly accessed via {@link AssetManager}.
- *
- * Since the ApkAssets instance is immutable, it can be reused and shared across AssetManagers,
- * making the creation of AssetManagers very cheap.
- * @hide
- */
-public final class ApkAssets {
- @GuardedBy("this") private final long mNativePtr;
- @GuardedBy("this") private StringBlock mStringBlock;
-
- /**
- * Creates a new ApkAssets instance from the given path on disk.
- *
- * @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 loadFromPath(@NonNull String path) throws IOException {
- return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/);
- }
-
- /**
- * 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).
- * @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)
- throws IOException {
- return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/);
- }
-
- /**
- * 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 forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
- * loaded as a shared library.
- * @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*/);
- }
-
- /**
- * Creates a new ApkAssets instance from the given file descriptor. Not for use by applications.
- *
- * 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.
- * @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)
- throws IOException {
- return new ApkAssets(fd, friendlyName, system, forceSharedLibrary);
- }
-
- /**
- * Creates a new ApkAssets instance from the IDMAP at idmapPath. The overlay APK path
- * 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).
- * @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*/);
- }
-
- private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
- throws IOException {
- Preconditions.checkNotNull(path, "path");
- mNativePtr = nativeLoad(path, system, forceSharedLib, overlay);
- mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
- }
-
- private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system,
- boolean forceSharedLib) throws IOException {
- Preconditions.checkNotNull(fd, "fd");
- Preconditions.checkNotNull(friendlyName, "friendlyName");
- mNativePtr = nativeLoadFromFd(fd, friendlyName, system, forceSharedLib);
- mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
- }
-
- @NonNull String getAssetPath() {
- synchronized (this) {
- return nativeGetAssetPath(mNativePtr);
- }
- }
-
- CharSequence getStringFromPool(int idx) {
- synchronized (this) {
- return mStringBlock.get(idx);
- }
- }
-
- /**
- * Retrieve a parser for a compiled XML file. This is associated with a single APK and
- * <em>NOT</em> a full AssetManager. This means that shared-library references will not be
- * dynamically assigned runtime package IDs.
- *
- * @param fileName The path to the file within the APK.
- * @return An XmlResourceParser.
- * @throws IOException if the file was not found or an error occurred retrieving it.
- */
- public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
- synchronized (this) {
- long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
- try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
- XmlResourceParser parser = block.newParser();
- // If nativeOpenXml doesn't throw, it will always return a valid native pointer,
- // which makes newParser always return non-null. But let's be paranoid.
- if (parser == null) {
- throw new AssertionError("block.newParser() returned a null parser");
- }
- return parser;
- }
- }
- }
-
- /**
- * Returns false if the underlying APK was changed since this ApkAssets was loaded.
- */
- public boolean isUpToDate() {
- synchronized (this) {
- return nativeIsUpToDate(mNativePtr);
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- nativeDestroy(mNativePtr);
- }
-
- private static native long nativeLoad(
- @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
- throws IOException;
- private static native long nativeLoadFromFd(@NonNull FileDescriptor fd,
- @NonNull String friendlyName, boolean system, boolean forceSharedLib)
- throws IOException;
- private static native void nativeDestroy(long ptr);
- private static native @NonNull String nativeGetAssetPath(long ptr);
- private static native long nativeGetStringBlock(long ptr);
- private static native boolean nativeIsUpToDate(long ptr);
- private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
-}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index c59e6d2562b2..78665609bdd4 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -18,11 +18,9 @@ package android.content.res;
import android.annotation.AnyRes;
import android.annotation.ArrayRes;
-import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
-import android.annotation.StyleRes;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration.NativeConfig;
import android.os.ParcelFileDescriptor;
@@ -30,18 +28,10 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.channels.FileLock;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
/**
@@ -52,19 +42,7 @@ import java.util.HashMap;
* bytes.
*/
public final class AssetManager implements AutoCloseable {
- private static final String TAG = "AssetManager";
- private static final boolean DEBUG_REFS = false;
-
- private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk";
-
- private static final Object sSync = new Object();
-
- private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0];
-
- // Not private for LayoutLib's BridgeAssetManager.
- @GuardedBy("sSync") static AssetManager sSystem = null;
-
- @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0];
+ /* modes used when opening an asset */
/**
* Mode for {@link #open(String, int)}: no specific information about how
@@ -87,311 +65,88 @@ public final class AssetManager implements AutoCloseable {
*/
public static final int ACCESS_BUFFER = 3;
- @GuardedBy("this") private final TypedValue mValue = new TypedValue();
- @GuardedBy("this") private final long[] mOffsets = new long[2];
-
- // Pointer to native implementation, stuffed inside a long.
- @GuardedBy("this") private long mObject;
-
- // The loaded asset paths.
- @GuardedBy("this") private ApkAssets[] mApkAssets;
+ private static final String TAG = "AssetManager";
+ private static final boolean localLOGV = false || false;
+
+ private static final boolean DEBUG_REFS = false;
+
+ private static final Object sSync = new Object();
+ /*package*/ static AssetManager sSystem = null;
- // Debug/reference counting implementation.
- @GuardedBy("this") private boolean mOpen = true;
- @GuardedBy("this") private int mNumRefs = 1;
- @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks;
+ private final TypedValue mValue = new TypedValue();
+ private final long[] mOffsets = new long[2];
+
+ // For communication with native code.
+ private long mObject;
+ private StringBlock mStringBlocks[] = null;
+
+ private int mNumRefs = 1;
+ private boolean mOpen = true;
+ private HashMap<Long, RuntimeException> mRefStacks;
+
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
* appropriate asset manager with {@link Resources#getAssets}. Not for
* use by applications.
- * @hide
+ * {@hide}
*/
public AssetManager() {
- final ApkAssets[] assets;
- synchronized (sSync) {
- createSystemAssetsInZygoteLocked();
- assets = sSystemApkAssets;
- }
-
- mObject = nativeCreate();
- if (DEBUG_REFS) {
- mNumRefs = 0;
- incRefsLocked(hashCode());
+ synchronized (this) {
+ if (DEBUG_REFS) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
+ }
+ init(false);
+ if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+ ensureSystemAssets();
}
-
- // Always set the framework resources.
- setApkAssets(assets, false /*invalidateCaches*/);
}
- /**
- * Private constructor that doesn't call ensureSystemAssets.
- * Used for the creation of system assets.
- */
- @SuppressWarnings("unused")
- private AssetManager(boolean sentinel) {
- mObject = nativeCreate();
- if (DEBUG_REFS) {
- mNumRefs = 0;
- incRefsLocked(hashCode());
+ private static void ensureSystemAssets() {
+ synchronized (sSync) {
+ if (sSystem == null) {
+ AssetManager system = new AssetManager(true);
+ system.makeStringBlocks(null);
+ sSystem = system;
+ }
}
}
-
- /**
- * This must be called from Zygote so that system assets are shared by all applications.
- * @hide
- */
- private static void createSystemAssetsInZygoteLocked() {
- if (sSystem != null) {
- return;
- }
-
- // Make sure that all IDMAPs are up to date.
- nativeVerifySystemIdmaps();
-
- try {
- ArrayList<ApkAssets> apkAssets = new ArrayList<>();
- apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/));
-
- // Load all static RROs.
- try (FileInputStream fis = new FileInputStream(
- "/data/resource-cache/overlays.list");
- BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
- // Acquire a lock so that any idmap scanning doesn't impact the current set.
- try (FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE,
- true /*shared*/)) {
- for (String line; (line = br.readLine()) != null; ) {
- String idmapPath = line.split(" ")[1];
- apkAssets.add(
- ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
- }
- }
+
+ private AssetManager(boolean isSystem) {
+ if (DEBUG_REFS) {
+ synchronized (this) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
}
-
- sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]);
- sSystem = new AssetManager(true /*sentinel*/);
- sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to create system AssetManager", e);
}
+ init(true);
+ if (localLOGV) Log.v(TAG, "New asset manager: " + this);
}
/**
* Return a global shared asset manager that provides access to only
* system assets (no application assets).
- * @hide
+ * {@hide}
*/
public static AssetManager getSystem() {
- synchronized (sSync) {
- createSystemAssetsInZygoteLocked();
- return sSystem;
- }
+ ensureSystemAssets();
+ return sSystem;
}
/**
* Close this asset manager.
*/
- @Override
public void close() {
- synchronized (this) {
- if (!mOpen) {
- return;
- }
-
- mOpen = false;
- decRefsLocked(hashCode());
- }
- }
-
- /**
- * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)}
- * family of methods.
- *
- * @param apkAssets The new set of paths.
- * @param invalidateCaches Whether to invalidate any caches. This should almost always be true.
- * Set this to false if you are appending new resources
- * (not new configurations).
- * @hide
- */
- public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
- Preconditions.checkNotNull(apkAssets, "apkAssets");
-
- // Copy the apkAssets, but prepend the system assets (framework + overlays).
- final ApkAssets[] newApkAssets = new ApkAssets[apkAssets.length + sSystemApkAssets.length];
- System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length);
- System.arraycopy(apkAssets, 0, newApkAssets, sSystemApkAssets.length, apkAssets.length);
-
- synchronized (this) {
- ensureOpenLocked();
- mApkAssets = newApkAssets;
- nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
- if (invalidateCaches) {
- // Invalidate all caches.
- invalidateCachesLocked(-1);
- }
- }
- }
-
- /**
- * Invalidates the caches in this AssetManager according to the bitmask `diff`.
- *
- * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}.
- * @see ActivityInfo.Config
- */
- private void invalidateCachesLocked(int diff) {
- // TODO(adamlesinski): Currently there are no caches to invalidate in Java code.
- }
-
- /**
- * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this
- * returns a 0-length array.
- * @hide
- */
- public @NonNull ApkAssets[] getApkAssets() {
- synchronized (this) {
+ synchronized(this) {
+ //System.out.println("Release: num=" + mNumRefs
+ // + ", released=" + mReleased);
if (mOpen) {
- return mApkAssets;
- }
- }
- return sEmptyApkAssets;
- }
-
- /**
- * Returns a cookie for use with the other APIs of AssetManager.
- * @return 0 if the path was not found, otherwise a positive integer cookie representing
- * this path in the AssetManager.
- * @hide
- */
- public int findCookieForPath(@NonNull String path) {
- Preconditions.checkNotNull(path, "path");
- synchronized (this) {
- ensureValidLocked();
- final int count = mApkAssets.length;
- for (int i = 0; i < count; i++) {
- if (path.equals(mApkAssets[i].getAssetPath())) {
- return i + 1;
- }
+ mOpen = false;
+ decRefsLocked(this.hashCode());
}
}
- return 0;
- }
-
- /**
- * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
- * @hide
- */
- @Deprecated
- public int addAssetPath(String path) {
- return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/);
- }
-
- /**
- * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
- * @hide
- */
- @Deprecated
- public int addAssetPathAsSharedLibrary(String path) {
- return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/);
- }
-
- /**
- * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
- * @hide
- */
- @Deprecated
- public int addOverlayPath(String path) {
- return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
- }
-
- private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
- Preconditions.checkNotNull(path, "path");
- synchronized (this) {
- ensureOpenLocked();
- final int count = mApkAssets.length;
- for (int i = 0; i < count; i++) {
- if (mApkAssets[i].getAssetPath().equals(path)) {
- return i + 1;
- }
- }
-
- final ApkAssets assets;
- try {
- if (overlay) {
- // TODO(b/70343104): This hardcoded path will be removed once
- // addAssetPathInternal is deleted.
- final String idmapPath = "/data/resource-cache/"
- + path.substring(1).replace('/', '@')
- + "@idmap";
- assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
- } else {
- assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib);
- }
- } catch (IOException e) {
- return 0;
- }
-
- final ApkAssets[] newApkAssets = Arrays.copyOf(mApkAssets, count + 1);
- newApkAssets[count] = assets;
- setApkAssets(newApkAssets, true);
- return count + 1;
- }
- }
-
- /**
- * Ensures that the native implementation has not been destroyed.
- * The AssetManager may have been closed, but references to it still exist
- * and therefore the native implementation is not destroyed.
- */
- private void ensureValidLocked() {
- if (mObject == 0) {
- throw new RuntimeException("AssetManager has been destroyed");
- }
- }
-
- /**
- * Ensures that the AssetManager has not been explicitly closed. If this method passes,
- * then this implies that ensureValidLocked() also passes.
- */
- private void ensureOpenLocked() {
- // If mOpen is true, this implies that mObject != 0.
- if (!mOpen) {
- throw new RuntimeException("AssetManager has been closed");
- }
- }
-
- /**
- * Populates {@code outValue} with the data associated a particular
- * resource identifier for the current configuration.
- *
- * @param resId the resource identifier to load
- * @param densityDpi the density bucket for which to load the resource
- * @param outValue the typed value in which to put the data
- * @param resolveRefs {@code true} to resolve references, {@code false}
- * to leave them unresolved
- * @return {@code true} if the data was loaded into {@code outValue},
- * {@code false} otherwise
- */
- boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
- boolean resolveRefs) {
- Preconditions.checkNotNull(outValue, "outValue");
- synchronized (this) {
- ensureValidLocked();
- final int cookie = nativeGetResourceValue(
- mObject, resId, (short) densityDpi, outValue, resolveRefs);
- if (cookie <= 0) {
- return false;
- }
-
- // Convert the changing configurations flags populated by native code.
- outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- outValue.changingConfigurations);
-
- if (outValue.type == TypedValue.TYPE_STRING) {
- outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
- }
- return true;
- }
}
/**
@@ -401,7 +156,8 @@ public final class AssetManager implements AutoCloseable {
* @param resId the resource identifier to load
* @return the string value, or {@code null}
*/
- @Nullable CharSequence getResourceText(@StringRes int resId) {
+ @Nullable
+ final CharSequence getResourceText(@StringRes int resId) {
synchronized (this) {
final TypedValue outValue = mValue;
if (getResourceValue(resId, 0, outValue, true)) {
@@ -416,15 +172,15 @@ public final class AssetManager implements AutoCloseable {
* identifier for the current configuration.
*
* @param resId the resource identifier to load
- * @param bagEntryId the index into the bag to load
+ * @param bagEntryId
* @return the string value, or {@code null}
*/
- @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
+ @Nullable
+ final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
synchronized (this) {
- ensureValidLocked();
final TypedValue outValue = mValue;
- final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue);
- if (cookie <= 0) {
+ final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+ if (block < 0) {
return null;
}
@@ -433,60 +189,52 @@ public final class AssetManager implements AutoCloseable {
outValue.changingConfigurations);
if (outValue.type == TypedValue.TYPE_STRING) {
- return mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+ return mStringBlocks[block].get(outValue.data);
}
return outValue.coerceToString();
}
}
- int getResourceArraySize(@ArrayRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceArraySize(mObject, resId);
- }
- }
-
/**
- * Populates `outData` with array elements of `resId`. `outData` is normally
- * used with
- * {@link TypedArray}.
- *
- * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES}
- * long,
- * with the indices of the data representing the type, value, asset cookie,
- * resource ID,
- * configuration change mask, and density of the element.
- *
- * @param resId The resource ID of an array resource.
- * @param outData The array to populate with data.
- * @return The length of the array.
+ * Retrieves the string array associated with a particular resource
+ * identifier for the current configuration.
*
- * @see TypedArray#STYLE_TYPE
- * @see TypedArray#STYLE_DATA
- * @see TypedArray#STYLE_ASSET_COOKIE
- * @see TypedArray#STYLE_RESOURCE_ID
- * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS
- * @see TypedArray#STYLE_DENSITY
+ * @param resId the resource identifier of the string array
+ * @return the string array, or {@code null}
*/
- int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) {
- Preconditions.checkNotNull(outData, "outData");
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceArray(mObject, resId, outData);
- }
+ @Nullable
+ final String[] getResourceStringArray(@ArrayRes int resId) {
+ return getArrayStringResource(resId);
}
/**
- * Retrieves the string array associated with a particular resource
- * identifier for the current configuration.
+ * Populates {@code outValue} with the data associated a particular
+ * resource identifier for the current configuration.
*
- * @param resId the resource identifier of the string array
- * @return the string array, or {@code null}
+ * @param resId the resource identifier to load
+ * @param densityDpi the density bucket for which to load the resource
+ * @param outValue the typed value in which to put the data
+ * @param resolveRefs {@code true} to resolve references, {@code false}
+ * to leave them unresolved
+ * @return {@code true} if the data was loaded into {@code outValue},
+ * {@code false} otherwise
*/
- @Nullable String[] getResourceStringArray(@ArrayRes int resId) {
+ final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+ boolean resolveRefs) {
synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceStringArray(mObject, resId);
+ final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
+ }
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ outValue.string = mStringBlocks[block].get(outValue.data);
+ }
+ return true;
}
}
@@ -496,48 +244,26 @@ public final class AssetManager implements AutoCloseable {
*
* @param resId the resource id of the string array
*/
- @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+ final @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
synchronized (this) {
- ensureValidLocked();
- final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId);
+ final int[] rawInfoArray = getArrayStringInfo(resId);
if (rawInfoArray == null) {
return null;
}
-
final int rawInfoArrayLen = rawInfoArray.length;
final int infoArrayLen = rawInfoArrayLen / 2;
+ int block;
+ int index;
final CharSequence[] retArray = new CharSequence[infoArrayLen];
for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
- int cookie = rawInfoArray[i];
- int index = rawInfoArray[i + 1];
- retArray[j] = (index >= 0 && cookie > 0)
- ? mApkAssets[cookie - 1].getStringFromPool(index) : null;
+ block = rawInfoArray[i];
+ index = rawInfoArray[i + 1];
+ retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
}
return retArray;
}
}
- @Nullable int[] getResourceIntArray(@ArrayRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceIntArray(mObject, resId);
- }
- }
-
- /**
- * Get the attributes for a style resource. These are the &lt;item&gt;
- * elements in
- * a &lt;style&gt; resource.
- * @param resId The resource ID of the style
- * @return An array of attribute IDs.
- */
- @AttrRes int[] getStyleAttributes(@StyleRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetStyleAttributes(mObject, resId);
- }
- }
-
/**
* Populates {@code outValue} with the data associated with a particular
* resource identifier for the current configuration. Resolves theme
@@ -551,88 +277,73 @@ public final class AssetManager implements AutoCloseable {
* @return {@code true} if the data was loaded into {@code outValue},
* {@code false} otherwise
*/
- boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+ final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
boolean resolveRefs) {
- Preconditions.checkNotNull(outValue, "outValue");
- synchronized (this) {
- ensureValidLocked();
- final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue,
- resolveRefs);
- if (cookie <= 0) {
- return false;
- }
-
- // Convert the changing configurations flags populated by native code.
- outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- outValue.changingConfigurations);
-
- if (outValue.type == TypedValue.TYPE_STRING) {
- outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
- }
- return true;
+ final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
}
- }
- void dumpTheme(long theme, int priority, String tag, String prefix) {
- synchronized (this) {
- ensureValidLocked();
- nativeThemeDump(mObject, theme, priority, tag, prefix);
- }
- }
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
- @Nullable String getResourceName(@AnyRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceName(mObject, resId);
- }
- }
-
- @Nullable String getResourcePackageName(@AnyRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourcePackageName(mObject, resId);
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ final StringBlock[] blocks = ensureStringBlocks();
+ outValue.string = blocks[block].get(outValue.data);
}
+ return true;
}
- @Nullable String getResourceTypeName(@AnyRes int resId) {
+ /**
+ * Ensures the string blocks are loaded.
+ *
+ * @return the string blocks
+ */
+ @NonNull
+ final StringBlock[] ensureStringBlocks() {
synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceTypeName(mObject, resId);
+ if (mStringBlocks == null) {
+ makeStringBlocks(sSystem.mStringBlocks);
+ }
+ return mStringBlocks;
}
}
- @Nullable String getResourceEntryName(@AnyRes int resId) {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetResourceEntryName(mObject, resId);
+ /*package*/ final void makeStringBlocks(StringBlock[] seed) {
+ final int seedNum = (seed != null) ? seed.length : 0;
+ final int num = getStringBlockCount();
+ mStringBlocks = new StringBlock[num];
+ if (localLOGV) Log.v(TAG, "Making string blocks for " + this
+ + ": " + num);
+ for (int i=0; i<num; i++) {
+ if (i < seedNum) {
+ mStringBlocks[i] = seed[i];
+ } else {
+ mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
+ }
}
}
- @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType,
- @Nullable String defPackage) {
+ /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
synchronized (this) {
- ensureValidLocked();
- // name is checked in JNI.
- return nativeGetResourceIdentifier(mObject, name, defType, defPackage);
+ // Cookies map to string blocks starting at 1.
+ return mStringBlocks[cookie - 1].get(id);
}
}
- CharSequence getPooledStringForCookie(int cookie, int id) {
- // Cookies map to ApkAssets starting at 1.
- return getApkAssets()[cookie - 1].getStringFromPool(id);
- }
-
/**
* Open an asset using ACCESS_STREAMING mode. This provides access to
* files that have been bundled with an application as assets -- that is,
* files placed in to the "assets" directory.
*
- * @param fileName The name of the asset to open. This name can be hierarchical.
+ * @param fileName The name of the asset to open. This name can be
+ * hierarchical.
*
* @see #open(String, int)
* @see #list
*/
- public @NonNull InputStream open(@NonNull String fileName) throws IOException {
+ public final InputStream open(String fileName) throws IOException {
return open(fileName, ACCESS_STREAMING);
}
@@ -642,7 +353,8 @@ public final class AssetManager implements AutoCloseable {
* with an application as assets -- that is, files placed in to the
* "assets" directory.
*
- * @param fileName The name of the asset to open. This name can be hierarchical.
+ * @param fileName The name of the asset to open. This name can be
+ * hierarchical.
* @param accessMode Desired access mode for retrieving the data.
*
* @see #ACCESS_UNKNOWN
@@ -652,40 +364,34 @@ public final class AssetManager implements AutoCloseable {
* @see #open(String)
* @see #list
*/
- public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
+ public final InputStream open(String fileName, int accessMode)
+ throws IOException {
synchronized (this) {
- ensureOpenLocked();
- final long asset = nativeOpenAsset(mObject, fileName, accessMode);
- if (asset == 0) {
- throw new FileNotFoundException("Asset file: " + fileName);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ long asset = openAsset(fileName, accessMode);
+ if (asset != 0) {
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
- final AssetInputStream assetInputStream = new AssetInputStream(asset);
- incRefsLocked(assetInputStream.hashCode());
- return assetInputStream;
}
+ throw new FileNotFoundException("Asset file: " + fileName);
}
- /**
- * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}.
- * This provides access to files that have been bundled with an application as assets -- that
- * is, files placed in to the "assets" directory.
- *
- * The asset must be uncompressed, or an exception will be thrown.
- *
- * @param fileName The name of the asset to open. This name can be hierarchical.
- * @return An open AssetFileDescriptor.
- */
- public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
+ public final AssetFileDescriptor openFd(String fileName)
+ throws IOException {
synchronized (this) {
- ensureOpenLocked();
- final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets);
- if (pfd == null) {
- throw new FileNotFoundException("Asset file: " + fileName);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
+ if (pfd != null) {
+ return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
- return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
+ throw new FileNotFoundException("Asset file: " + fileName);
}
/**
@@ -700,121 +406,90 @@ public final class AssetManager implements AutoCloseable {
*
* @see #open
*/
- public @Nullable String[] list(@NonNull String path) throws IOException {
- Preconditions.checkNotNull(path, "path");
- synchronized (this) {
- ensureValidLocked();
- return nativeList(mObject, path);
- }
- }
+ public native final String[] list(String path)
+ throws IOException;
/**
+ * {@hide}
* Open a non-asset file as an asset using ACCESS_STREAMING mode. This
* provides direct access to all of the files included in an application
* package (not only its assets). Applications should not normally use
* this.
- *
- * @param fileName Name of the asset to retrieve.
- *
+ *
* @see #open(String)
- * @hide
*/
- public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException {
+ public final InputStream openNonAsset(String fileName) throws IOException {
return openNonAsset(0, fileName, ACCESS_STREAMING);
}
/**
+ * {@hide}
* Open a non-asset file as an asset using a specific access mode. This
* provides direct access to all of the files included in an application
* package (not only its assets). Applications should not normally use
* this.
- *
- * @param fileName Name of the asset to retrieve.
- * @param accessMode Desired access mode for retrieving the data.
- *
- * @see #ACCESS_UNKNOWN
- * @see #ACCESS_STREAMING
- * @see #ACCESS_RANDOM
- * @see #ACCESS_BUFFER
+ *
* @see #open(String, int)
- * @hide
*/
- public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode)
- throws IOException {
+ public final InputStream openNonAsset(String fileName, int accessMode)
+ throws IOException {
return openNonAsset(0, fileName, accessMode);
}
/**
+ * {@hide}
* Open a non-asset in a specified package. Not for use by applications.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
- * @hide
*/
- public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName)
- throws IOException {
+ public final InputStream openNonAsset(int cookie, String fileName)
+ throws IOException {
return openNonAsset(cookie, fileName, ACCESS_STREAMING);
}
/**
+ * {@hide}
* Open a non-asset in a specified package. Not for use by applications.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
* @param accessMode Desired access mode for retrieving the data.
- * @hide
*/
- public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode)
- throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
+ public final InputStream openNonAsset(int cookie, String fileName, int accessMode)
+ throws IOException {
synchronized (this) {
- ensureOpenLocked();
- final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode);
- if (asset == 0) {
- throw new FileNotFoundException("Asset absolute file: " + fileName);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ long asset = openNonAssetNative(cookie, fileName, accessMode);
+ if (asset != 0) {
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
- final AssetInputStream assetInputStream = new AssetInputStream(asset);
- incRefsLocked(assetInputStream.hashCode());
- return assetInputStream;
}
+ throw new FileNotFoundException("Asset absolute file: " + fileName);
}
- /**
- * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
- * This provides direct access to all of the files included in an application
- * package (not only its assets). Applications should not normally use this.
- *
- * The asset must not be compressed, or an exception will be thrown.
- *
- * @param fileName Name of the asset to retrieve.
- */
- public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName)
+ public final AssetFileDescriptor openNonAssetFd(String fileName)
throws IOException {
return openNonAssetFd(0, fileName);
}
-
- /**
- * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
- * This provides direct access to all of the files included in an application
- * package (not only its assets). Applications should not normally use this.
- *
- * The asset must not be compressed, or an exception will be thrown.
- *
- * @param cookie Identifier of the package to be opened.
- * @param fileName Name of the asset to retrieve.
- */
- public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName)
- throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
+
+ public final AssetFileDescriptor openNonAssetFd(int cookie,
+ String fileName) throws IOException {
synchronized (this) {
- ensureOpenLocked();
- final ParcelFileDescriptor pfd =
- nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets);
- if (pfd == null) {
- throw new FileNotFoundException("Asset absolute file: " + fileName);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
+ fileName, mOffsets);
+ if (pfd != null) {
+ return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
- return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
+ throw new FileNotFoundException("Asset absolute file: " + fileName);
}
/**
@@ -822,7 +497,7 @@ public final class AssetManager implements AutoCloseable {
*
* @param fileName The name of the file to retrieve.
*/
- public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
+ public final XmlResourceParser openXmlResourceParser(String fileName)
throws IOException {
return openXmlResourceParser(0, fileName);
}
@@ -833,252 +508,270 @@ public final class AssetManager implements AutoCloseable {
* @param cookie Identifier of the package to be opened.
* @param fileName The name of the file to retrieve.
*/
- public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName)
- throws IOException {
- try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) {
- XmlResourceParser parser = block.newParser();
- // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with
- // a valid native pointer, which makes newParser always return non-null. But let's
- // be paranoid.
- if (parser == null) {
- throw new AssertionError("block.newParser() returned a null parser");
- }
- return parser;
- }
+ public final XmlResourceParser openXmlResourceParser(int cookie,
+ String fileName) throws IOException {
+ XmlBlock block = openXmlBlockAsset(cookie, fileName);
+ XmlResourceParser rp = block.newParser();
+ block.close();
+ return rp;
}
/**
- * Retrieve a non-asset as a compiled XML file. Not for use by applications.
+ * {@hide}
+ * Retrieve a non-asset as a compiled XML file. Not for use by
+ * applications.
*
* @param fileName The name of the file to retrieve.
- * @hide
*/
- @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException {
+ /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
+ throws IOException {
return openXmlBlockAsset(0, fileName);
}
/**
+ * {@hide}
* Retrieve a non-asset as a compiled XML file. Not for use by
* applications.
*
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
- * @hide
*/
- @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException {
- Preconditions.checkNotNull(fileName, "fileName");
+ /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
+ throws IOException {
synchronized (this) {
- ensureOpenLocked();
- final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName);
- if (xmlBlock == 0) {
- throw new FileNotFoundException("Asset XML file: " + fileName);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ long xmlBlock = openXmlAssetNative(cookie, fileName);
+ if (xmlBlock != 0) {
+ XmlBlock res = new XmlBlock(this, xmlBlock);
+ incRefsLocked(res.hashCode());
+ return res;
}
- final XmlBlock block = new XmlBlock(this, xmlBlock);
- incRefsLocked(block.hashCode());
- return block;
}
+ throw new FileNotFoundException("Asset XML file: " + fileName);
}
- void xmlBlockGone(int id) {
+ /*package*/ void xmlBlockGone(int id) {
synchronized (this) {
decRefsLocked(id);
}
}
- void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
- @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress,
- long outIndicesAddress) {
- Preconditions.checkNotNull(inAttrs, "inAttrs");
- synchronized (this) {
- // Need to synchronize on AssetManager because we will be accessing
- // the native implementation of AssetManager.
- ensureValidLocked();
- nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress,
- outIndicesAddress);
- }
- }
-
- boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
- @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues,
- @NonNull int[] outIndices) {
- Preconditions.checkNotNull(inAttrs, "inAttrs");
- Preconditions.checkNotNull(outValues, "outValues");
- Preconditions.checkNotNull(outIndices, "outIndices");
- synchronized (this) {
- // Need to synchronize on AssetManager because we will be accessing
- // the native implementation of AssetManager.
- ensureValidLocked();
- return nativeResolveAttrs(mObject,
- themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices);
- }
- }
-
- boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs,
- @NonNull int[] outValues, @NonNull int[] outIndices) {
- Preconditions.checkNotNull(parser, "parser");
- Preconditions.checkNotNull(inAttrs, "inAttrs");
- Preconditions.checkNotNull(outValues, "outValues");
- Preconditions.checkNotNull(outIndices, "outIndices");
+ /*package*/ final long createTheme() {
synchronized (this) {
- // Need to synchronize on AssetManager because we will be accessing
- // the native implementation of AssetManager.
- ensureValidLocked();
- return nativeRetrieveAttributes(
- mObject, parser.mParseState, inAttrs, outValues, outIndices);
- }
- }
-
- long createTheme() {
- synchronized (this) {
- ensureValidLocked();
- long themePtr = nativeThemeCreate(mObject);
- incRefsLocked(themePtr);
- return themePtr;
- }
- }
-
- void releaseTheme(long themePtr) {
- synchronized (this) {
- nativeThemeDestroy(themePtr);
- decRefsLocked(themePtr);
+ if (!mOpen) {
+ throw new RuntimeException("Assetmanager has been closed");
+ }
+ long res = newTheme();
+ incRefsLocked(res);
+ return res;
}
}
- void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) {
+ /*package*/ final void releaseTheme(long theme) {
synchronized (this) {
- // Need to synchronize on AssetManager because we will be accessing
- // the native implementation of AssetManager.
- ensureValidLocked();
- nativeThemeApplyStyle(mObject, themePtr, resId, force);
+ deleteTheme(theme);
+ decRefsLocked(theme);
}
}
- @Override
protected void finalize() throws Throwable {
- if (DEBUG_REFS && mNumRefs != 0) {
- Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs);
- if (mRefStacks != null) {
- for (RuntimeException e : mRefStacks.values()) {
- Log.w(TAG, "Reference from here", e);
+ try {
+ if (DEBUG_REFS && mNumRefs != 0) {
+ Log.w(TAG, "AssetManager " + this
+ + " finalized with non-zero refs: " + mNumRefs);
+ if (mRefStacks != null) {
+ for (RuntimeException e : mRefStacks.values()) {
+ Log.w(TAG, "Reference from here", e);
+ }
}
}
- }
-
- if (mObject != 0) {
- nativeDestroy(mObject);
+ destroy();
+ } finally {
+ super.finalize();
}
}
-
- /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread
- safe and it does not rely on AssetManager once it has been created. It completely owns the
- underlying Asset. */
+
public final class AssetInputStream extends InputStream {
- private long mAssetNativePtr;
- private long mLength;
- private long mMarkPos;
-
/**
* @hide
*/
public final int getAssetInt() {
throw new UnsupportedOperationException();
}
-
/**
* @hide
*/
public final long getNativeAsset() {
- return mAssetNativePtr;
+ return mAsset;
}
-
- private AssetInputStream(long assetNativePtr) {
- mAssetNativePtr = assetNativePtr;
- mLength = nativeAssetGetLength(assetNativePtr);
+ private AssetInputStream(long asset)
+ {
+ mAsset = asset;
+ mLength = getAssetLength(asset);
}
-
- @Override
public final int read() throws IOException {
- return nativeAssetReadChar(mAssetNativePtr);
+ return readAssetChar(mAsset);
}
-
- @Override
public final boolean markSupported() {
return true;
}
-
- @Override
public final int available() throws IOException {
- final long len = nativeAssetGetRemainingLength(mAssetNativePtr);
- return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len;
+ long len = getAssetRemainingLength(mAsset);
+ return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
}
-
- @Override
public final void close() throws IOException {
- if (mAssetNativePtr != 0) {
- nativeAssetDestroy(mAssetNativePtr);
- mAssetNativePtr = 0;
-
- synchronized (AssetManager.this) {
+ synchronized (AssetManager.this) {
+ if (mAsset != 0) {
+ destroyAsset(mAsset);
+ mAsset = 0;
decRefsLocked(hashCode());
}
}
}
-
- @Override
public final void mark(int readlimit) {
- mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0);
+ mMarkPos = seekAsset(mAsset, 0, 0);
}
-
- @Override
public final void reset() throws IOException {
- nativeAssetSeek(mAssetNativePtr, mMarkPos, -1);
+ seekAsset(mAsset, mMarkPos, -1);
}
-
- @Override
- public final int read(@NonNull byte[] b) throws IOException {
- Preconditions.checkNotNull(b, "b");
- return nativeAssetRead(mAssetNativePtr, b, 0, b.length);
+ public final int read(byte[] b) throws IOException {
+ return readAsset(mAsset, b, 0, b.length);
}
-
- @Override
- public final int read(@NonNull byte[] b, int off, int len) throws IOException {
- Preconditions.checkNotNull(b, "b");
- return nativeAssetRead(mAssetNativePtr, b, off, len);
+ public final int read(byte[] b, int off, int len) throws IOException {
+ return readAsset(mAsset, b, off, len);
}
-
- @Override
public final long skip(long n) throws IOException {
- long pos = nativeAssetSeek(mAssetNativePtr, 0, 0);
- if ((pos + n) > mLength) {
- n = mLength - pos;
+ long pos = seekAsset(mAsset, 0, 0);
+ if ((pos+n) > mLength) {
+ n = mLength-pos;
}
if (n > 0) {
- nativeAssetSeek(mAssetNativePtr, n, 0);
+ seekAsset(mAsset, n, 0);
}
return n;
}
- @Override
- protected void finalize() throws Throwable {
+ protected void finalize() throws Throwable
+ {
close();
}
+
+ private long mAsset;
+ private long mLength;
+ private long mMarkPos;
+ }
+
+ /**
+ * Add an additional set of assets to the asset manager. This can be
+ * either a directory or ZIP file. Not for use by applications. Returns
+ * the cookie of the added asset, or 0 on failure.
+ * {@hide}
+ */
+ public final int addAssetPath(String path) {
+ return addAssetPathInternal(path, false);
+ }
+
+ /**
+ * Add an application assets to the asset manager and loading it as shared library.
+ * This can be either a directory or ZIP file. Not for use by applications. Returns
+ * the cookie of the added asset, or 0 on failure.
+ * {@hide}
+ */
+ public final int addAssetPathAsSharedLibrary(String path) {
+ return addAssetPathInternal(path, true);
+ }
+
+ private final int addAssetPathInternal(String path, boolean appAsLib) {
+ synchronized (this) {
+ int res = addAssetPathNative(path, appAsLib);
+ makeStringBlocks(mStringBlocks);
+ return res;
+ }
+ }
+
+ private native final int addAssetPathNative(String path, boolean appAsLib);
+
+ /**
+ * Add an additional set of assets to the asset manager from an already open
+ * FileDescriptor. Not for use by applications.
+ * This does not give full AssetManager functionality for these assets,
+ * since the origin of the file is not known for purposes of sharing,
+ * overlay resolution, and other features. However it does allow you
+ * to do simple access to the contents of the given fd as an apk file.
+ * 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).
+ * Returns the cookie of the added asset, or 0 on failure.
+ * {@hide}
+ */
+ public int addAssetFd(FileDescriptor fd, String debugPathName) {
+ return addAssetFdInternal(fd, debugPathName, false);
+ }
+
+ private int addAssetFdInternal(FileDescriptor fd, String debugPathName,
+ boolean appAsLib) {
+ synchronized (this) {
+ int res = addAssetFdNative(fd, debugPathName, appAsLib);
+ makeStringBlocks(mStringBlocks);
+ return res;
+ }
+ }
+
+ private native int addAssetFdNative(FileDescriptor fd, String debugPathName,
+ boolean appAsLib);
+
+ /**
+ * Add a set of assets to overlay an already added set of assets.
+ *
+ * This is only intended for application resources. System wide resources
+ * are handled before any Java code is executed.
+ *
+ * {@hide}
+ */
+
+ public final int addOverlayPath(String idmapPath) {
+ synchronized (this) {
+ int res = addOverlayPathNative(idmapPath);
+ makeStringBlocks(mStringBlocks);
+ return res;
+ }
+ }
+
+ /**
+ * See addOverlayPath.
+ *
+ * {@hide}
+ */
+ public native final int addOverlayPathNative(String idmapPath);
+
+ /**
+ * Add multiple sets of assets to the asset manager at once. See
+ * {@link #addAssetPath(String)} for more information. Returns array of
+ * cookies for each added asset with 0 indicating failure, or null if
+ * the input array of paths is null.
+ * {@hide}
+ */
+ public final int[] addAssetPaths(String[] paths) {
+ if (paths == null) {
+ return null;
+ }
+
+ int[] cookies = new int[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ cookies[i] = addAssetPath(paths[i]);
+ }
+
+ return cookies;
}
/**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
- * @hide
+ * {@hide}
*/
- public boolean isUpToDate() {
- for (ApkAssets apkAssets : getApkAssets()) {
- if (!apkAssets.isUpToDate()) {
- return false;
- }
- }
- return true;
- }
+ public native final boolean isUpToDate();
/**
* Get the locales that this asset manager contains data for.
@@ -1091,12 +784,7 @@ public final class AssetManager implements AutoCloseable {
* are of the form {@code ll_CC} where {@code ll} is a two letter language code,
* and {@code CC} is a two letter country code.
*/
- public String[] getLocales() {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetLocales(mObject, false /*excludeSystem*/);
- }
- }
+ public native final String[] getLocales();
/**
* Same as getLocales(), except that locales that are only provided by the system (i.e. those
@@ -1106,57 +794,131 @@ public final class AssetManager implements AutoCloseable {
* assets support Cherokee and French, getLocales() would return
* [Cherokee, English, French, German], while getNonSystemLocales() would return
* [Cherokee, French].
- * @hide
+ * {@hide}
*/
- public String[] getNonSystemLocales() {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetLocales(mObject, true /*excludeSystem*/);
- }
- }
+ public native final String[] getNonSystemLocales();
- /**
- * @hide
- */
- Configuration[] getSizeConfigurations() {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetSizeConfigurations(mObject);
- }
- }
+ /** {@hide} */
+ public native final Configuration[] getSizeConfigurations();
/**
- * Change the configuration used when retrieving resources. Not for use by
+ * Change the configuation used when retrieving resources. Not for use by
* applications.
- * @hide
+ * {@hide}
*/
- public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation,
- int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
- int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
- int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) {
- synchronized (this) {
- ensureValidLocked();
- nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
- keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
- smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
- colorMode, majorVersion);
- }
- }
+ public native final void setConfiguration(int mcc, int mnc, String locale,
+ int orientation, int touchscreen, int density, int keyboard,
+ int keyboardHidden, int navigation, int screenWidth, int screenHeight,
+ int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
+ int screenLayout, int uiMode, int colorMode, int majorVersion);
/**
- * @hide
+ * Retrieve the resource identifier for the given resource name.
*/
- public SparseArray<String> getAssignedPackageIdentifiers() {
- synchronized (this) {
- ensureValidLocked();
- return nativeGetAssignedPackageIdentifiers(mObject);
- }
- }
+ /*package*/ native final int getResourceIdentifier(String name,
+ String defType,
+ String defPackage);
- private void incRefsLocked(long id) {
+ /*package*/ native final String getResourceName(int resid);
+ /*package*/ native final String getResourcePackageName(int resid);
+ /*package*/ native final String getResourceTypeName(int resid);
+ /*package*/ native final String getResourceEntryName(int resid);
+
+ private native final long openAsset(String fileName, int accessMode);
+ private final native ParcelFileDescriptor openAssetFd(String fileName,
+ long[] outOffsets) throws IOException;
+ private native final long openNonAssetNative(int cookie, String fileName,
+ int accessMode);
+ private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
+ String fileName, long[] outOffsets) throws IOException;
+ private native final void destroyAsset(long asset);
+ private native final int readAssetChar(long asset);
+ private native final int readAsset(long asset, byte[] b, int off, int len);
+ private native final long seekAsset(long asset, long offset, int whence);
+ private native final long getAssetLength(long asset);
+ private native final long getAssetRemainingLength(long asset);
+
+ /** Returns true if the resource was found, filling in mRetStringBlock and
+ * mRetData. */
+ private native final int loadResourceValue(int ident, short density, TypedValue outValue,
+ boolean resolve);
+ /** Returns true if the resource was found, filling in mRetStringBlock and
+ * mRetData. */
+ private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
+ boolean resolve);
+ /*package*/ static final int STYLE_NUM_ENTRIES = 6;
+ /*package*/ static final int STYLE_TYPE = 0;
+ /*package*/ static final int STYLE_DATA = 1;
+ /*package*/ static final int STYLE_ASSET_COOKIE = 2;
+ /*package*/ static final int STYLE_RESOURCE_ID = 3;
+
+ /* Offset within typed data array for native changingConfigurations. */
+ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+
+ /*package*/ static final int STYLE_DENSITY = 5;
+ /*package*/ native static final void applyStyle(long theme,
+ int defStyleAttr, int defStyleRes, long xmlParser,
+ int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
+ /*package*/ native static final boolean resolveAttrs(long theme,
+ int defStyleAttr, int defStyleRes, int[] inValues,
+ int[] inAttrs, int[] outValues, int[] outIndices);
+ /*package*/ native final boolean retrieveAttributes(
+ long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
+ /*package*/ native final int getArraySize(int resource);
+ /*package*/ native final int retrieveArray(int resource, int[] outValues);
+ private native final int getStringBlockCount();
+ private native final long getNativeStringBlock(int block);
+
+ /**
+ * {@hide}
+ */
+ public native final String getCookieName(int cookie);
+
+ /**
+ * {@hide}
+ */
+ public native final SparseArray<String> getAssignedPackageIdentifiers();
+
+ /**
+ * {@hide}
+ */
+ public native static final int getGlobalAssetCount();
+
+ /**
+ * {@hide}
+ */
+ public native static final String getAssetAllocations();
+
+ /**
+ * {@hide}
+ */
+ public native static final int getGlobalAssetManagerCount();
+
+ private native final long newTheme();
+ private native final void deleteTheme(long theme);
+ /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
+ /*package*/ native static final void copyTheme(long dest, long source);
+ /*package*/ native static final void clearTheme(long theme);
+ /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
+ TypedValue outValue,
+ boolean resolve);
+ /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
+ /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
+
+ private native final long openXmlAssetNative(int cookie, String fileName);
+
+ private native final String[] getArrayStringResource(int arrayRes);
+ private native final int[] getArrayStringInfo(int arrayRes);
+ /*package*/ native final int[] getArrayIntResource(int arrayRes);
+ /*package*/ native final int[] getStyleAttributes(int themeRes);
+
+ private native final void init(boolean isSystem);
+ private native final void destroy();
+
+ private final void incRefsLocked(long id) {
if (DEBUG_REFS) {
if (mRefStacks == null) {
- mRefStacks = new HashMap<>();
+ mRefStacks = new HashMap<Long, RuntimeException>();
}
RuntimeException ex = new RuntimeException();
ex.fillInStackTrace();
@@ -1164,118 +926,16 @@ public final class AssetManager implements AutoCloseable {
}
mNumRefs++;
}
-
- private void decRefsLocked(long id) {
+
+ private final void decRefsLocked(long id) {
if (DEBUG_REFS && mRefStacks != null) {
mRefStacks.remove(id);
}
mNumRefs--;
- if (mNumRefs == 0 && mObject != 0) {
- nativeDestroy(mObject);
- mObject = 0;
- mApkAssets = sEmptyApkAssets;
+ //System.out.println("Dec streams: mNumRefs=" + mNumRefs
+ // + " mReleased=" + mReleased);
+ if (mNumRefs == 0) {
+ destroy();
}
}
-
- // AssetManager setup native methods.
- private static native long nativeCreate();
- private static native void nativeDestroy(long ptr);
- private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
- boolean invalidateCaches);
- private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
- @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
- int keyboardHidden, int navigation, int screenWidth, int screenHeight,
- int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
- int uiMode, int colorMode, int majorVersion);
- private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
- long ptr);
-
- // File native methods.
- private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
- throws IOException;
- private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);
- private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr,
- @NonNull String fileName, long[] outOffsets) throws IOException;
- private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName,
- int accessMode);
- private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie,
- @NonNull String fileName, @NonNull long[] outOffsets) throws IOException;
- private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName);
-
- // Primitive resource native methods.
- private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density,
- @NonNull TypedValue outValue, boolean resolveReferences);
- private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId,
- @NonNull TypedValue outValue);
-
- private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
- @StyleRes int resId);
- private static native @Nullable String[] nativeGetResourceStringArray(long ptr,
- @ArrayRes int resId);
- private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
- @ArrayRes int resId);
- private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId);
- private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId);
- private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId,
- @NonNull int[] outValues);
-
- // Resource name/ID native methods.
- private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
- @Nullable String defType, @Nullable String defPackage);
- private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid);
- private static native @Nullable String nativeGetResourcePackageName(long ptr,
- @AnyRes int resid);
- private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid);
- private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
- private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
- private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
-
- // Style attribute retrieval native methods.
- private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
- @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs,
- long outValuesAddress, long outIndicesAddress);
- private static native boolean nativeResolveAttrs(long ptr, long themePtr,
- @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues,
- @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
- private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr,
- @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
-
- // Theme related native methods
- private static native long nativeThemeCreate(long ptr);
- private static native void nativeThemeDestroy(long themePtr);
- private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
- boolean force);
- static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
- static native void nativeThemeClear(long themePtr);
- private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
- @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
- private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
- String prefix);
- static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr);
-
- // AssetInputStream related native methods.
- private static native void nativeAssetDestroy(long assetPtr);
- private static native int nativeAssetReadChar(long assetPtr);
- private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len);
- private static native long nativeAssetSeek(long assetPtr, long offset, int whence);
- private static native long nativeAssetGetLength(long assetPtr);
- private static native long nativeAssetGetRemainingLength(long assetPtr);
-
- private static native void nativeVerifySystemIdmaps();
-
- // Global debug native methods.
- /**
- * @hide
- */
- public static native int getGlobalAssetCount();
-
- /**
- * @hide
- */
- public static native String getAssetAllocations();
-
- /**
- * @hide
- */
- public static native int getGlobalAssetManagerCount();
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8f58891ed556..e173653cd961 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -590,7 +590,7 @@ public class Resources {
*/
@NonNull
public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
- int[] res = mResourcesImpl.getAssets().getResourceIntArray(id);
+ int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
if (res != null) {
return res;
}
@@ -613,13 +613,13 @@ public class Resources {
@NonNull
public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
final ResourcesImpl impl = mResourcesImpl;
- int len = impl.getAssets().getResourceArraySize(id);
+ int len = impl.getAssets().getArraySize(id);
if (len < 0) {
throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
}
TypedArray array = TypedArray.obtain(this, len);
- array.mLength = impl.getAssets().getResourceArray(id, array.mData);
+ array.mLength = impl.getAssets().retrieveArray(id, array.mData);
array.mIndices[0] = 0;
return array;
@@ -1789,7 +1789,8 @@ public class Resources {
// out the attributes from the XML file (applying type information
// contained in the resources and such).
XmlBlock.Parser parser = (XmlBlock.Parser)set;
- mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
+ mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
+ array.mData, array.mIndices);
array.mXml = parser;
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2a4b278bdca8..97cb78bc4243 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -168,6 +168,7 @@ public class ResourcesImpl {
mDisplayAdjustments = displayAdjustments;
mConfiguration.setToDefaults();
updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
+ mAssets.ensureStringBlocks();
}
public DisplayAdjustments getDisplayAdjustments() {
@@ -1273,7 +1274,8 @@ public class ResourcesImpl {
void applyStyle(int resId, boolean force) {
synchronized (mKey) {
- mAssets.applyStyleToTheme(mTheme, resId, force);
+ AssetManager.applyThemeStyle(mTheme, resId, force);
+
mThemeResId = resId;
mKey.append(resId, force);
}
@@ -1282,7 +1284,7 @@ public class ResourcesImpl {
void setTo(ThemeImpl other) {
synchronized (mKey) {
synchronized (other.mKey) {
- AssetManager.nativeThemeCopy(mTheme, other.mTheme);
+ AssetManager.copyTheme(mTheme, other.mTheme);
mThemeResId = other.mThemeResId;
mKey.setTo(other.getKey());
@@ -1305,10 +1307,12 @@ public class ResourcesImpl {
// out the attributes from the XML file (applying type information
// contained in the resources and such).
final XmlBlock.Parser parser = (XmlBlock.Parser) set;
- mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs,
- array.mDataAddress, array.mIndicesAddress);
+ AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0,
+ attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
array.mTheme = wrapper;
array.mXml = parser;
+
return array;
}
}
@@ -1325,7 +1329,7 @@ public class ResourcesImpl {
}
final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
- mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+ AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
array.mTheme = wrapper;
array.mXml = null;
return array;
@@ -1345,14 +1349,14 @@ public class ResourcesImpl {
@Config int getChangingConfigurations() {
synchronized (mKey) {
final @NativeConfig int nativeChangingConfig =
- AssetManager.nativeThemeGetChangingConfigurations(mTheme);
+ AssetManager.getThemeChangingConfigurations(mTheme);
return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
}
}
public void dump(int priority, String tag, String prefix) {
synchronized (mKey) {
- mAssets.dumpTheme(mTheme, priority, tag, prefix);
+ AssetManager.dumpTheme(mTheme, priority, tag, prefix);
}
}
@@ -1381,13 +1385,13 @@ public class ResourcesImpl {
*/
void rebase() {
synchronized (mKey) {
- AssetManager.nativeThemeClear(mTheme);
+ AssetManager.clearTheme(mTheme);
// Reapply the same styles in the same order.
for (int i = 0; i < mKey.mCount; i++) {
final int resId = mKey.mResId[i];
final boolean force = mKey.mForce[i];
- mAssets.applyStyleToTheme(mTheme, resId, force);
+ AssetManager.applyThemeStyle(mTheme, resId, force);
}
}
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cbb3c6df0558..f33c75168a5f 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -61,15 +61,6 @@ public class TypedArray {
return attrs;
}
- // STYLE_ prefixed constants are offsets within the typed data array.
- static final int STYLE_NUM_ENTRIES = 6;
- static final int STYLE_TYPE = 0;
- static final int STYLE_DATA = 1;
- static final int STYLE_ASSET_COOKIE = 2;
- static final int STYLE_RESOURCE_ID = 3;
- static final int STYLE_CHANGING_CONFIGURATIONS = 4;
- static final int STYLE_DENSITY = 5;
-
private final Resources mResources;
private DisplayMetrics mMetrics;
private AssetManager mAssets;
@@ -87,7 +78,7 @@ public class TypedArray {
private void resize(int len) {
mLength = len;
- final int dataLen = len * STYLE_NUM_ENTRIES;
+ final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
final int indicesLen = len + 1;
final VMRuntime runtime = VMRuntime.getRuntime();
if (mDataAddress == 0 || mData.length < dataLen) {
@@ -175,9 +166,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -212,9 +203,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -251,13 +242,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_STRING) {
- final int cookie = data[index + STYLE_ASSET_COOKIE];
+ final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
if (cookie < 0) {
- return mXml.getPooledString(data[index + STYLE_DATA]).toString();
+ return mXml.getPooledString(
+ data[index+AssetManager.STYLE_DATA]).toString();
}
}
return null;
@@ -282,11 +274,11 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
- data[index + STYLE_CHANGING_CONFIGURATIONS]);
+ data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
if ((changingConfigs & ~allowedChangingConfigs) != 0) {
return null;
}
@@ -328,14 +320,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA] != 0;
+ return data[index+AssetManager.STYLE_DATA] != 0;
}
final TypedValue v = mValue;
@@ -367,14 +359,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
}
final TypedValue v = mValue;
@@ -404,16 +396,16 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FLOAT) {
- return Float.intBitsToFloat(data[index + STYLE_DATA]);
+ return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
}
final TypedValue v = mValue;
@@ -454,15 +446,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_STRING) {
final TypedValue value = mValue;
if (getValueAt(index, value)) {
@@ -506,7 +498,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -541,7 +533,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -572,15 +564,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -620,14 +612,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimension(
+ data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -668,14 +661,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelOffset(
+ data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -717,14 +711,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(
+ data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -760,15 +755,16 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(
+ data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -799,14 +795,15 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index + STYLE_DATA];
+ return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(
+ data[index + AssetManager.STYLE_DATA], mMetrics);
}
return defValue;
@@ -836,14 +833,15 @@ public class TypedArray {
}
final int attrIndex = index;
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FRACTION) {
- return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
+ return TypedValue.complexToFraction(
+ data[index+AssetManager.STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -876,10 +874,10 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- if (data[index + STYLE_TYPE] != TypedValue.TYPE_NULL) {
- final int resid = data[index + STYLE_RESOURCE_ID];
+ if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
+ final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
if (resid != 0) {
return resid;
}
@@ -904,10 +902,10 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- if (data[index + STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
- return data[index + STYLE_DATA];
+ if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
+ return data[index + AssetManager.STYLE_DATA];
}
return defValue;
}
@@ -941,7 +939,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -977,7 +975,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -1008,7 +1006,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
return mResources.getTextArray(value.resourceId);
}
return null;
@@ -1029,7 +1027,7 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- return getValueAt(index * STYLE_NUM_ENTRIES, outValue);
+ return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
}
/**
@@ -1045,8 +1043,8 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
- return mData[index + STYLE_TYPE];
+ index *= AssetManager.STYLE_NUM_ENTRIES;
+ return mData[index + AssetManager.STYLE_TYPE];
}
/**
@@ -1065,9 +1063,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
return type != TypedValue.TYPE_NULL;
}
@@ -1086,11 +1084,11 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= STYLE_NUM_ENTRIES;
+ index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
return type != TypedValue.TYPE_NULL
- || data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+ || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
}
/**
@@ -1111,7 +1109,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
- if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
return value;
}
return null;
@@ -1183,16 +1181,16 @@ public class TypedArray {
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
- final int index = i * STYLE_NUM_ENTRIES;
- if (data[index + STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+ final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+ if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
// Not an attribute, ignore.
continue;
}
// Null the entry so that we can safely call getZzz().
- data[index + STYLE_TYPE] = TypedValue.TYPE_NULL;
+ data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
- final int attr = data[index + STYLE_DATA];
+ final int attr = data[index + AssetManager.STYLE_DATA];
if (attr == 0) {
// Useless data, ignore.
continue;
@@ -1233,44 +1231,45 @@ public class TypedArray {
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
- final int index = i * STYLE_NUM_ENTRIES;
- final int type = data[index + STYLE_TYPE];
+ final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+ final int type = data[index + AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
continue;
}
changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
- data[index + STYLE_CHANGING_CONFIGURATIONS]);
+ data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
}
return changingConfig;
}
private boolean getValueAt(int index, TypedValue outValue) {
final int[] data = mData;
- final int type = data[index + STYLE_TYPE];
+ final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return false;
}
outValue.type = type;
- outValue.data = data[index + STYLE_DATA];
- outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
- outValue.resourceId = data[index + STYLE_RESOURCE_ID];
+ outValue.data = data[index+AssetManager.STYLE_DATA];
+ outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
+ outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- data[index + STYLE_CHANGING_CONFIGURATIONS]);
- outValue.density = data[index + STYLE_DENSITY];
+ data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+ outValue.density = data[index+AssetManager.STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
return true;
}
private CharSequence loadStringValueAt(int index) {
final int[] data = mData;
- final int cookie = data[index + STYLE_ASSET_COOKIE];
+ final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
if (cookie < 0) {
if (mXml != null) {
- return mXml.getPooledString(data[index + STYLE_DATA]);
+ return mXml.getPooledString(
+ data[index+AssetManager.STYLE_DATA]);
}
return null;
}
- return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]);
+ return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
}
/** @hide */
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index d4ccffb83ca5..e6b957414ea8 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -16,7 +16,6 @@
package android.content.res;
-import android.annotation.Nullable;
import android.util.TypedValue;
import com.android.internal.util.XmlUtils;
@@ -34,7 +33,7 @@ import java.io.Reader;
*
* {@hide}
*/
-final class XmlBlock implements AutoCloseable {
+final class XmlBlock {
private static final boolean DEBUG=false;
public XmlBlock(byte[] data) {
@@ -49,7 +48,6 @@ final class XmlBlock implements AutoCloseable {
mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
}
- @Override
public void close() {
synchronized (this) {
if (mOpen) {
@@ -480,13 +478,13 @@ final class XmlBlock implements AutoCloseable {
* are doing! The given native object must exist for the entire lifetime
* of this newly creating XmlBlock.
*/
- XmlBlock(@Nullable AssetManager assets, long xmlBlock) {
+ XmlBlock(AssetManager assets, long xmlBlock) {
mAssets = assets;
mNative = xmlBlock;
mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
}
- private @Nullable final AssetManager mAssets;
+ private final AssetManager mAssets;
private final long mNative;
/*package*/ final StringBlock mStrings;
private boolean mOpen = true;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 19cc2d0f5358..543acc7c2158 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,8 +110,8 @@ cc_library_shared {
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_EventLog.cpp",
- "android_util_Log.cpp",
"android_util_MemoryIntArray.cpp",
+ "android_util_Log.cpp",
"android_util_PathParser.cpp",
"android_util_Process.cpp",
"android_util_StringBlock.cpp",
@@ -189,7 +189,6 @@ cc_library_shared {
"android_backup_FileBackupHelperBase.cpp",
"android_backup_BackupHelperDispatcher.cpp",
"android_app_backup_FullBackup.cpp",
- "android_content_res_ApkAssets.cpp",
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_animation_PropertyValuesHolder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e3b5c8f3136a..aa9a82415f97 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -122,7 +122,6 @@ extern int register_android_util_MemoryIntArray(JNIEnv* env);
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
-extern int register_android_content_res_ApkAssets(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
@@ -1341,7 +1340,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
- REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
REG_JNI(register_android_text_MeasuredParagraph),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c50026ea570e..dd3e6f02e9fe 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -28,7 +28,7 @@
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
#include "Utils.h"
#include "FontUtils.h"
@@ -224,8 +224,7 @@ static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong b
NPE_CHECK_RETURN_ZERO(env, jpath);
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-
- Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
+ AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
builder->axes.clear();
return false;
@@ -237,33 +236,27 @@ static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong b
return false;
}
- std::unique_ptr<Asset> asset;
- {
- ScopedLock<AssetManager2> locked_mgr(*mgr);
- if (isAsset) {
- asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
- } else if (cookie > 0) {
- // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
- asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
- Asset::ACCESS_BUFFER);
- } else {
- asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
- }
+ Asset* asset;
+ if (isAsset) {
+ asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+ } else {
+ asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
+ Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
}
- if (nullptr == asset) {
+ if (NULL == asset) {
builder->axes.clear();
return false;
}
const void* buf = asset->getBuffer(false);
if (NULL == buf) {
+ delete asset;
builder->axes.clear();
return false;
}
- sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
- asset.release()));
+ sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a30f77e..09e37e1a3de6 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -361,7 +361,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName
code->sdkVersion = sdkVersion;
code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
- code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
+ code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
if (obbDir != NULL) {
dirStr = env->GetStringUTFChars(obbDir, NULL);
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
deleted file mode 100644
index c0f151b71c93..000000000000
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
-#include "android-base/unique_fd.h"
-#include "androidfw/ApkAssets.h"
-#include "utils/misc.h"
-
-#include "core_jni_helpers.h"
-#include "jni.h"
-#include "nativehelper/ScopedUtfChars.h"
-
-using ::android::base::unique_fd;
-
-namespace android {
-
-static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
- jboolean force_shared_lib, jboolean overlay) {
- ScopedUtfChars path(env, java_path);
- if (path.c_str() == nullptr) {
- return 0;
- }
-
- 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);
- }
-
- 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());
- 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) {
- ScopedUtfChars friendly_name_utf8(env, friendly_name);
- if (friendly_name_utf8.c_str() == nullptr) {
- return 0;
- }
-
- int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
- if (fd < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
- return 0;
- }
-
- unique_fd dup_fd(::dup(fd));
- if (dup_fd < 0) {
- jniThrowIOException(env, errno);
- return 0;
- }
-
- std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd),
- friendly_name_utf8.c_str(),
- system, force_shared_lib);
- 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.get());
- jniThrowException(env, "java/io/IOException", error_msg.c_str());
- return 0;
- }
- return reinterpret_cast<jlong>(apk_assets.release());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- delete reinterpret_cast<ApkAssets*>(ptr);
-}
-
-static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
- const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
- return env->NewStringUTF(apk_assets->GetPath().c_str());
-}
-
-static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
- return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
-}
-
-static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
- (void)apk_assets;
- return JNI_TRUE;
-}
-
-static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
- ScopedUtfChars path_utf8(env, file_name);
- if (path_utf8.c_str() == nullptr) {
- return 0;
- }
-
- const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
- std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
- Asset::AccessMode::ACCESS_RANDOM);
- if (asset == nullptr) {
- jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
- return 0;
- }
-
- // DynamicRefTable is only needed when looking up resource references. Opening an XML file
- // directly from an ApkAssets has no notion of proper resource references.
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
- if (err != NO_ERROR) {
- jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
- return 0;
- }
- return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-// JNI registration.
-static const JNINativeMethod gApkAssetsMethods[] = {
- {"nativeLoad", "(Ljava/lang/String;ZZZ)J", (void*)NativeLoad},
- {"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZ)J",
- (void*)NativeLoadFromFd},
- {"nativeDestroy", "(J)V", (void*)NativeDestroy},
- {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
- {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
- {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
- {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
-};
-
-int register_android_content_res_ApkAssets(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
- arraysize(gApkAssetsMethods));
-}
-
-} // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 557b3ab26e64..c6828c4f60de 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1,1438 +1,1846 @@
-/*
- * Copyright 2006, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/libs/android_runtime/android_util_AssetManager.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
#define LOG_TAG "asset"
+#include <android_runtime/android_util_AssetManager.h>
+
#include <inttypes.h>
#include <linux/capability.h>
#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/system_properties.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/system_properties.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
-#include "android-base/logging.h"
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
-#include "android_runtime/android_util_AssetManager.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_util_Binder.h"
#include "androidfw/Asset.h"
#include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeResolution.h"
-#include "androidfw/MutexGuard.h"
#include "androidfw/ResourceTypes.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
#include "core_jni_helpers.h"
#include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedStringChars.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
#include "utils/Log.h"
-#include "utils/String8.h"
#include "utils/misc.h"
+#include "utils/String8.h"
extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
-using ::android::base::StringPrintf;
namespace android {
+static const bool kThrowOnBadId = false;
+
// ----------------------------------------------------------------------------
-static struct typedvalue_offsets_t {
- jfieldID mType;
- jfieldID mData;
- jfieldID mString;
- jfieldID mAssetCookie;
- jfieldID mResourceId;
- jfieldID mChangingConfigurations;
- jfieldID mDensity;
+static struct typedvalue_offsets_t
+{
+ jfieldID mType;
+ jfieldID mData;
+ jfieldID mString;
+ jfieldID mAssetCookie;
+ jfieldID mResourceId;
+ jfieldID mChangingConfigurations;
+ jfieldID mDensity;
} gTypedValueOffsets;
-static struct assetfiledescriptor_offsets_t {
- jfieldID mFd;
- jfieldID mStartOffset;
- jfieldID mLength;
+static struct assetfiledescriptor_offsets_t
+{
+ jfieldID mFd;
+ jfieldID mStartOffset;
+ jfieldID mLength;
} gAssetFileDescriptorOffsets;
-static struct assetmanager_offsets_t {
- jfieldID mObject;
+static struct assetmanager_offsets_t
+{
+ jfieldID mObject;
} gAssetManagerOffsets;
-static struct {
- jfieldID native_ptr;
-} gApkAssetsFields;
-
-static struct sparsearray_offsets_t {
- jclass classObject;
- jmethodID constructor;
- jmethodID put;
+static struct sparsearray_offsets_t
+{
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
} gSparseArrayOffsets;
-static struct configuration_offsets_t {
- jclass classObject;
- jmethodID constructor;
- jfieldID mSmallestScreenWidthDpOffset;
- jfieldID mScreenWidthDpOffset;
- jfieldID mScreenHeightDpOffset;
+static struct configuration_offsets_t
+{
+ jclass classObject;
+ jmethodID constructor;
+ jfieldID mSmallestScreenWidthDpOffset;
+ jfieldID mScreenWidthDpOffset;
+ jfieldID mScreenHeightDpOffset;
} gConfigurationOffsets;
-jclass g_stringClass = nullptr;
+jclass g_stringClass = NULL;
// ----------------------------------------------------------------------------
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
- return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
+static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+ const Res_value& value, uint32_t ref, ssize_t block,
+ uint32_t typeSpecFlags, ResTable_config* config = NULL);
+
+jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+ const Res_value& value, uint32_t ref, ssize_t block,
+ uint32_t typeSpecFlags, ResTable_config* config)
+{
+ env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
+ env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
+ static_cast<jint>(table->getTableCookie(block)));
+ env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
+ env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
+ env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
+ env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
+ typeSpecFlags);
+ if (config != NULL) {
+ env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
+ }
+ return block;
}
-constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
- return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
+// This is called by zygote (running as user root) as part of preloadResources.
+static void verifySystemIdmaps()
+{
+ pid_t pid;
+ char system_id[10];
+
+ snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
+
+ switch (pid = fork()) {
+ case -1:
+ ALOGE("failed to fork for idmap: %s", strerror(errno));
+ break;
+ case 0: // child
+ {
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata;
+
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = 0;
+
+ if (capget(&capheader, &capdata) != 0) {
+ ALOGE("capget: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ capdata.effective = capdata.permitted;
+ if (capset(&capheader, &capdata) != 0) {
+ ALOGE("capset: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setgid(AID_SYSTEM) != 0) {
+ ALOGE("setgid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setuid(AID_SYSTEM) != 0) {
+ ALOGE("setuid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Generic idmap parameters
+ const char* argv[8];
+ int argc = 0;
+ struct stat st;
+
+ memset(argv, NULL, sizeof(argv));
+ argv[argc++] = AssetManager::IDMAP_BIN;
+ argv[argc++] = "--scan";
+ argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+ argv[argc++] = AssetManager::TARGET_APK_PATH;
+ argv[argc++] = AssetManager::IDMAP_DIR;
+
+ // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
+ // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
+ char subdir[PROP_VALUE_MAX];
+ int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+ if (len > 0) {
+ String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+ if (stat(overlayPath.string(), &st) == 0) {
+ argv[argc++] = overlayPath.string();
+ }
+ }
+ if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+ argv[argc++] = AssetManager::OVERLAY_DIR;
+ }
+
+ // Finally, invoke idmap (if any overlay directory exists)
+ if (argc > 5) {
+ execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+ ALOGE("failed to execv for idmap: %s", strerror(errno));
+ exit(1); // should never get here
+ } else {
+ exit(0);
+ }
+ }
+ break;
+ default: // parent
+ waitpid(pid, NULL, 0);
+ break;
+ }
}
-// This is called by zygote (running as user root) as part of preloadResources.
-static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
- switch (pid_t pid = fork()) {
- case -1:
- PLOG(ERROR) << "failed to fork for idmap";
- break;
-
- // child
- case 0: {
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata;
-
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
-
- capheader.version = _LINUX_CAPABILITY_VERSION;
- capheader.pid = 0;
-
- if (capget(&capheader, &capdata) != 0) {
- PLOG(ERROR) << "capget";
- exit(1);
- }
-
- capdata.effective = capdata.permitted;
- if (capset(&capheader, &capdata) != 0) {
- PLOG(ERROR) << "capset";
- exit(1);
- }
-
- if (setgid(AID_SYSTEM) != 0) {
- PLOG(ERROR) << "setgid";
- exit(1);
- }
-
- if (setuid(AID_SYSTEM) != 0) {
- PLOG(ERROR) << "setuid";
- exit(1);
- }
-
- // Generic idmap parameters
- const char* argv[8];
- int argc = 0;
- struct stat st;
-
- memset(argv, 0, sizeof(argv));
- argv[argc++] = AssetManager::IDMAP_BIN;
- argv[argc++] = "--scan";
- argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
- argv[argc++] = AssetManager::TARGET_APK_PATH;
- argv[argc++] = AssetManager::IDMAP_DIR;
-
- // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
- // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
- std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
- "");
- if (!overlay_theme_path.empty()) {
- overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
- if (stat(overlay_theme_path.c_str(), &st) == 0) {
- argv[argc++] = overlay_theme_path.c_str();
- }
- }
-
- if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
- argv[argc++] = AssetManager::OVERLAY_DIR;
- }
-
- // Finally, invoke idmap (if any overlay directory exists)
- if (argc > 5) {
- execv(AssetManager::IDMAP_BIN, (char* const*)argv);
- PLOG(ERROR) << "failed to execv for idmap";
- exit(1); // should never get here
- } else {
- exit(0);
- }
- } break;
-
- // parent
- default:
- waitpid(pid, nullptr, 0);
- break;
- }
+// ----------------------------------------------------------------------------
+
+// this guy is exported to other jni routines
+AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
+{
+ jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
+ AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
+ if (am != NULL) {
+ return am;
+ }
+ jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
+ return NULL;
}
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
- uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
- ApkAssetsCookieToJavaCookie(cookie));
- env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
- env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
- if (config != nullptr) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
- }
- return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
+static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
+ jstring fileName, jint mode)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
+ return -1;
+ }
+
+ if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+ && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+ return -1;
+ }
+
+ Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
+
+ if (a == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return -1;
+ }
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return reinterpret_cast<jlong>(a);
}
-// ----------------------------------------------------------------------------
+static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
+{
+ off64_t startOffset, length;
+ int fd = a->openFileDescriptor(&startOffset, &length);
+ delete a;
-// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
-struct GuardedAssetManager : public ::AAssetManager {
- Guarded<AssetManager2> guarded_assetmanager;
-};
+ if (fd < 0) {
+ jniThrowException(env, "java/io/FileNotFoundException",
+ "This file can not be opened as a file descriptor; it is probably compressed");
+ return NULL;
+ }
-::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
- jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
- ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
- if (am == nullptr) {
- jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
- return nullptr;
- }
- return am;
+ jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
+ if (offsets == NULL) {
+ close(fd);
+ return NULL;
+ }
+
+ offsets[0] = startOffset;
+ offsets[1] = length;
+
+ env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
+
+ jobject fileDesc = jniCreateFileDescriptor(env, fd);
+ if (fileDesc == NULL) {
+ close(fd);
+ return NULL;
+ }
+
+ return newParcelFileDescriptor(env, fileDesc);
}
-Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
- if (assetmanager == nullptr) {
- return nullptr;
- }
- return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
+static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
+ jstring fileName, jlongArray outOffsets)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ return NULL;
+ }
+
+ Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+ if (a == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return NULL;
+ }
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return returnParcelFileDescriptor(env, a, outOffsets);
}
-Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
- return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
+static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName,
+ jint mode)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ return -1;
+ }
+
+ if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+ && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+ return -1;
+ }
+
+ Asset* a = cookie
+ ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
+ (Asset::AccessMode)mode)
+ : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
+
+ if (a == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return -1;
+ }
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return reinterpret_cast<jlong>(a);
}
-static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
- return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
+static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName,
+ jlongArray outOffsets)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ return NULL;
+ }
+
+ Asset* a = cookie
+ ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
+ : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+ if (a == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return NULL;
+ }
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return returnParcelFileDescriptor(env, a, outOffsets);
}
-static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
- jlongArray out_offsets) {
- off64_t start_offset, length;
- int fd = asset->openFileDescriptor(&start_offset, &length);
- asset.reset();
-
- if (fd < 0) {
- jniThrowException(env, "java/io/FileNotFoundException",
- "This file can not be opened as a file descriptor; it is probably "
- "compressed");
- return nullptr;
- }
-
- jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
- if (offsets == nullptr) {
- close(fd);
- return nullptr;
- }
-
- offsets[0] = start_offset;
- offsets[1] = length;
-
- env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
-
- jobject file_desc = jniCreateFileDescriptor(env, fd);
- if (file_desc == nullptr) {
- close(fd);
- return nullptr;
- }
- return newParcelFileDescriptor(env, file_desc);
+static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
+ jstring fileName)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ return NULL;
+ }
+
+ AssetDir* dir = am->openDir(fileName8.c_str());
+
+ if (dir == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return NULL;
+ }
+
+ size_t N = dir->getFileCount();
+
+ jobjectArray array = env->NewObjectArray(dir->getFileCount(),
+ g_stringClass, NULL);
+ if (array == NULL) {
+ delete dir;
+ return NULL;
+ }
+
+ for (size_t i=0; i<N; i++) {
+ const String8& name = dir->getFileName(i);
+ jstring str = env->NewStringUTF(name.string());
+ if (str == NULL) {
+ delete dir;
+ return NULL;
+ }
+ env->SetObjectArrayElement(array, i, str);
+ env->DeleteLocalRef(str);
+ }
+
+ delete dir;
+
+ return array;
}
-static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
- return Asset::getGlobalCount();
+static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
+ jlong assetHandle)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ //printf("Destroying Asset Stream: %p\n", a);
+
+ if (a == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return;
+ }
+
+ delete a;
}
-static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
- String8 alloc = Asset::getAssetAllocations();
- if (alloc.length() <= 0) {
- return nullptr;
- }
- return env->NewStringUTF(alloc.string());
+static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
+ jlong assetHandle)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ if (a == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return -1;
+ }
+
+ uint8_t b;
+ ssize_t res = a->read(&b, 1);
+ return res == 1 ? b : -1;
}
-static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
- // TODO(adamlesinski): Switch to AssetManager2.
- return AssetManager::getGlobalCount();
+static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
+ jlong assetHandle, jbyteArray bArray,
+ jint off, jint len)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ if (a == NULL || bArray == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return -1;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ jsize bLen = env->GetArrayLength(bArray);
+ if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
+ return -1;
+ }
+
+ jbyte* b = env->GetByteArrayElements(bArray, NULL);
+ ssize_t res = a->read(b+off, len);
+ env->ReleaseByteArrayElements(bArray, b, 0);
+
+ if (res > 0) return static_cast<jint>(res);
+
+ if (res < 0) {
+ jniThrowException(env, "java/io/IOException", "");
+ }
+ return -1;
}
-static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
- // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
- // AssetManager2 in a contiguous block (GuardedAssetManager).
- return reinterpret_cast<jlong>(new GuardedAssetManager());
+static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
+ jlong assetHandle,
+ jlong offset, jint whence)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ if (a == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return -1;
+ }
+
+ return a->seek(
+ offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
}
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- delete reinterpret_cast<GuardedAssetManager*>(ptr);
+static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
+ jlong assetHandle)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ if (a == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return -1;
+ }
+
+ return a->getLength();
}
-static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jobjectArray apk_assets_array, jboolean invalidate_caches) {
- const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
- std::vector<const ApkAssets*> apk_assets;
- apk_assets.reserve(apk_assets_len);
- for (jsize i = 0; i < apk_assets_len; i++) {
- jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
- if (obj == nullptr) {
- std::string msg = StringPrintf("ApkAssets at index %d is null", i);
- jniThrowNullPointerException(env, msg.c_str());
- return;
+static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
+ jlong assetHandle)
+{
+ Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+ if (a == NULL) {
+ jniThrowNullPointerException(env, "asset");
+ return -1;
}
- jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
- if (env->ExceptionCheck()) {
- return;
+ return a->getRemainingLength();
+}
+
+static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
+ jstring path, jboolean appAsLib)
+{
+ ScopedUtfChars path8(env, path);
+ if (path8.c_str() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
}
- apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
- }
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+ int32_t cookie;
+ bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
+
+ return (res) ? static_cast<jint>(cookie) : 0;
}
-static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
- jstring locale, jint orientation, jint touchscreen, jint density,
- jint keyboard, jint keyboard_hidden, jint navigation,
- jint screen_width, jint screen_height,
- jint smallest_screen_width_dp, jint screen_width_dp,
- jint screen_height_dp, jint screen_layout, jint ui_mode,
- jint color_mode, jint major_version) {
- ResTable_config configuration;
- memset(&configuration, 0, sizeof(configuration));
- configuration.mcc = static_cast<uint16_t>(mcc);
- configuration.mnc = static_cast<uint16_t>(mnc);
- configuration.orientation = static_cast<uint8_t>(orientation);
- configuration.touchscreen = static_cast<uint8_t>(touchscreen);
- configuration.density = static_cast<uint16_t>(density);
- configuration.keyboard = static_cast<uint8_t>(keyboard);
- configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
- configuration.navigation = static_cast<uint8_t>(navigation);
- configuration.screenWidth = static_cast<uint16_t>(screen_width);
- configuration.screenHeight = static_cast<uint16_t>(screen_height);
- configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
- configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
- configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
- configuration.screenLayout = static_cast<uint8_t>(screen_layout);
- configuration.uiMode = static_cast<uint8_t>(ui_mode);
- configuration.colorMode = static_cast<uint8_t>(color_mode);
- configuration.sdkVersion = static_cast<uint16_t>(major_version);
-
- if (locale != nullptr) {
- ScopedUtfChars locale_utf8(env, locale);
- CHECK(locale_utf8.c_str() != nullptr);
- configuration.setBcp47Locale(locale_utf8.c_str());
- }
-
- // Constants duplicated from Java class android.content.res.Configuration.
- static const jint kScreenLayoutRoundMask = 0x300;
- static const jint kScreenLayoutRoundShift = 8;
-
- // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
- // in C++. We must extract the round qualifier out of the Java screenLayout and put it
- // into screenLayout2.
- configuration.screenLayout2 =
- static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- assetmanager->SetConfiguration(configuration);
+static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
+ jstring idmapPath)
+{
+ ScopedUtfChars idmapPath8(env, idmapPath);
+ if (idmapPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ int32_t cookie;
+ bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
+
+ return (res) ? (jint)cookie : 0;
}
-static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
+ jobject fileDescriptor, jstring debugPathName,
+ jboolean appAsLib)
+{
+ ScopedUtfChars debugPathName8(env, debugPathName);
- jobject sparse_array =
- env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+ return 0;
+ }
- if (sparse_array == nullptr) {
- // An exception is pending.
- return nullptr;
- }
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
- assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
- jstring jpackage_name = env->NewStringUTF(package_name.c_str());
- if (jpackage_name == nullptr) {
- // An exception is pending.
- return;
+ int dupfd = ::dup(fd);
+ if (dupfd < 0) {
+ jniThrowIOException(env, errno);
+ return 0;
}
- env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
- jpackage_name);
- });
- return sparse_array;
+ int32_t cookie;
+ bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
+
+ return (res) ? static_cast<jint>(cookie) : 0;
}
-static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
- ScopedUtfChars path_utf8(env, path);
- if (path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return nullptr;
- }
-
- std::vector<std::string> all_file_paths;
- {
- StringPiece normalized_path = path_utf8.c_str();
- if (normalized_path.data()[0] == '/') {
- normalized_path = normalized_path.substr(1);
- }
- std::string root_path = StringPrintf("assets/%s", normalized_path.data());
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- for (const ApkAssets* assets : assetmanager->GetApkAssets()) {
- assets->ForEachFile(root_path, [&](const StringPiece& file_path, FileType type) {
- if (type == FileType::kFileTypeRegular) {
- all_file_paths.push_back(file_path.to_string());
- }
- });
+static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_TRUE;
+ }
+ return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
+}
+
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
+{
+ Vector<String8> locales;
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
}
- }
- jobjectArray array = env->NewObjectArray(all_file_paths.size(), g_stringClass, nullptr);
- if (array == nullptr) {
- return nullptr;
- }
+ am->getLocales(&locales, includeSystemLocales);
- jsize index = 0;
- for (const std::string& file_path : all_file_paths) {
- jstring java_string = env->NewStringUTF(file_path.c_str());
+ const int N = locales.size();
- // Check for errors creating the strings (if malformed or no memory).
- if (env->ExceptionCheck()) {
- return nullptr;
+ jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
+ if (result == NULL) {
+ return NULL;
}
- env->SetObjectArrayElement(array, index++, java_string);
+ for (int i=0; i<N; i++) {
+ jstring str = env->NewStringUTF(locales[i].string());
+ if (str == NULL) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(result, i, str);
+ env->DeleteLocalRef(str);
+ }
- // If we have a large amount of string in our array, we might overflow the
- // local reference table of the VM.
- env->DeleteLocalRef(java_string);
- }
- return array;
+ return result;
}
-static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
- jint access_mode) {
- ScopedUtfChars asset_path_utf8(env, asset_path);
- if (asset_path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return 0;
- }
-
- if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
- access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
- return 0;
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::unique_ptr<Asset> asset =
- assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
- if (!asset) {
- jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
- return 0;
- }
- return reinterpret_cast<jlong>(asset.release());
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, true /* include system locales */);
}
-static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
- jlongArray out_offsets) {
- ScopedUtfChars asset_path_utf8(env, asset_path);
- if (asset_path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return nullptr;
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
- if (!asset) {
- jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
- return nullptr;
- }
- return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, false /* don't include system locales */);
}
-static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
- jstring asset_path, jint access_mode) {
- ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- ScopedUtfChars asset_path_utf8(env, asset_path);
- if (asset_path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return 0;
- }
-
- if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
- access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
- return 0;
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::unique_ptr<Asset> asset;
- if (cookie != kInvalidCookie) {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
- static_cast<Asset::AccessMode>(access_mode));
- } else {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
- static_cast<Asset::AccessMode>(access_mode));
- }
-
- if (!asset) {
- jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
- return 0;
- }
- return reinterpret_cast<jlong>(asset.release());
-}
+static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
+ jobject result = env->NewObject(gConfigurationOffsets.classObject,
+ gConfigurationOffsets.constructor);
+ if (result == NULL) {
+ return NULL;
+ }
-static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
- jstring asset_path, jlongArray out_offsets) {
- ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- ScopedUtfChars asset_path_utf8(env, asset_path);
- if (asset_path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return nullptr;
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::unique_ptr<Asset> asset;
- if (cookie != kInvalidCookie) {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
- } else {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
- }
-
- if (!asset) {
- jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
- return nullptr;
- }
- return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
+ env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
+ config.smallestScreenWidthDp);
+ env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
+ env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
-static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
- jstring asset_path) {
- ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- ScopedUtfChars asset_path_utf8(env, asset_path);
- if (asset_path_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return 0;
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::unique_ptr<Asset> asset;
- if (cookie != kInvalidCookie) {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
- } else {
- asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
- }
-
- if (!asset) {
- jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
- return 0;
- }
-
- // May be nullptr.
- const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
-
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
- if (err != NO_ERROR) {
- jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
- return 0;
- }
- return reinterpret_cast<jlong>(xml_tree.release());
+ return result;
}
-static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
- jshort density, jobject typed_value,
- jboolean resolve_references) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
- static_cast<uint16_t>(density), &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
-
- uint32_t ref = static_cast<uint32_t>(resid);
- if (resolve_references) {
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
- }
- return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
+static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
+ const Vector<ResTable_config>& configs) {
+ const int N = configs.size();
+ jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ for (int i=0; i<N; i++) {
+ jobject config = constructConfigurationObject(env, configs[i]);
+ if (config == NULL) {
+ env->DeleteLocalRef(result);
+ return NULL;
+ }
+
+ env->SetObjectArrayElement(result, i, config);
+ env->DeleteLocalRef(config);
+ }
+
+ return result;
}
-static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
- jint bag_entry_id, jobject typed_value) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
-
- uint32_t type_spec_flags = bag->type_spec_flags;
- ApkAssetsCookie cookie = kInvalidCookie;
- const Res_value* bag_value = nullptr;
- for (const ResolvedBag::Entry& entry : bag) {
- if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
- cookie = entry.cookie;
- bag_value = &entry.value;
-
- // Keep searching (the old implementation did that).
- }
- }
-
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
-
- Res_value value = *bag_value;
- uint32_t ref = static_cast<uint32_t>(resid);
- ResTable_config selected_config;
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
- return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
+static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ const ResTable& res(am->getResources());
+ Vector<ResTable_config> configs;
+ res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
+
+ return getSizeConfigurationsInternal(env, configs);
}
-static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return nullptr;
- }
-
- jintArray array = env->NewIntArray(bag->entry_count);
- if (env->ExceptionCheck()) {
- return nullptr;
- }
-
- for (uint32_t i = 0; i < bag->entry_count; i++) {
- jint attr_resid = bag->entries[i].key;
- env->SetIntArrayRegion(array, i, 1, &attr_resid);
- }
- return array;
+static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
+ jint mcc, jint mnc,
+ jstring locale, jint orientation,
+ jint touchscreen, jint density,
+ jint keyboard, jint keyboardHidden,
+ jint navigation,
+ jint screenWidth, jint screenHeight,
+ jint smallestScreenWidthDp,
+ jint screenWidthDp, jint screenHeightDp,
+ jint screenLayout, jint uiMode,
+ jint colorMode, jint sdkVersion)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return;
+ }
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+
+ const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
+
+ // Constants duplicated from Java class android.content.res.Configuration.
+ static const jint kScreenLayoutRoundMask = 0x300;
+ static const jint kScreenLayoutRoundShift = 8;
+
+ config.mcc = (uint16_t)mcc;
+ config.mnc = (uint16_t)mnc;
+ config.orientation = (uint8_t)orientation;
+ config.touchscreen = (uint8_t)touchscreen;
+ config.density = (uint16_t)density;
+ config.keyboard = (uint8_t)keyboard;
+ config.inputFlags = (uint8_t)keyboardHidden;
+ config.navigation = (uint8_t)navigation;
+ config.screenWidth = (uint16_t)screenWidth;
+ config.screenHeight = (uint16_t)screenHeight;
+ config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
+ config.screenWidthDp = (uint16_t)screenWidthDp;
+ config.screenHeightDp = (uint16_t)screenHeightDp;
+ config.screenLayout = (uint8_t)screenLayout;
+ config.uiMode = (uint8_t)uiMode;
+ config.colorMode = (uint8_t)colorMode;
+ config.sdkVersion = (uint16_t)sdkVersion;
+ config.minorVersion = 0;
+
+ // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+ // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+ // into screenLayout2.
+ config.screenLayout2 =
+ (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+ am->setConfiguration(config, locale8);
+
+ if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
}
-static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return nullptr;
- }
-
- jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
- if (array == nullptr) {
- return nullptr;
- }
-
- for (uint32_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
-
- // Resolve any references to their final value.
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return nullptr;
- }
-
- if (value.dataType == Res_value::TYPE_STRING) {
- const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
- const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
-
- jstring java_string = nullptr;
- size_t str_len;
- const char* str_utf8 = pool->string8At(value.data, &str_len);
- if (str_utf8 != nullptr) {
- java_string = env->NewStringUTF(str_utf8);
- } else {
- const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
- java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
- }
-
- // Check for errors creating the strings (if malformed or no memory).
- if (env->ExceptionCheck()) {
- return nullptr;
- }
-
- env->SetObjectArrayElement(array, i, java_string);
-
- // If we have a large amount of string in our array, we might overflow the
- // local reference table of the VM.
- env->DeleteLocalRef(java_string);
- }
- }
- return array;
+static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
+ jstring name,
+ jstring defType,
+ jstring defPackage)
+{
+ ScopedStringChars name16(env, name);
+ if (name16.get() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
+ ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
+ : NULL;
+ jsize defTypeLen = defType
+ ? env->GetStringLength(defType) : 0;
+ const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
+ ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
+ NULL))
+ : NULL;
+ jsize defPackageLen = defPackage
+ ? env->GetStringLength(defPackage) : 0;
+
+ jint ident = am->getResources().identifierForName(
+ reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
+ defType16, defTypeLen, defPackage16, defPackageLen);
+
+ if (defPackage16) {
+ env->ReleaseStringChars(defPackage,
+ reinterpret_cast<const jchar*>(defPackage16));
+ }
+ if (defType16) {
+ env->ReleaseStringChars(defType,
+ reinterpret_cast<const jchar*>(defType16));
+ }
+
+ return ident;
}
-static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return nullptr;
- }
-
- jintArray array = env->NewIntArray(bag->entry_count * 2);
- if (array == nullptr) {
- return nullptr;
- }
-
- jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
- if (buffer == nullptr) {
- return nullptr;
- }
-
- for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
- return nullptr;
- }
-
- jint string_index = -1;
- if (value.dataType == Res_value::TYPE_STRING) {
- string_index = static_cast<jint>(value.data);
- }
-
- buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
- buffer[(i * 2) + 1] = string_index;
- }
- env->ReleasePrimitiveArrayCritical(array, buffer, 0);
- return array;
+static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, true, &name)) {
+ return NULL;
+ }
+
+ String16 str;
+ if (name.package != NULL) {
+ str.setTo(name.package, name.packageLen);
+ }
+ if (name.type8 != NULL || name.type != NULL) {
+ if (str.size() > 0) {
+ char16_t div = ':';
+ str.append(&div, 1);
+ }
+ if (name.type8 != NULL) {
+ str.append(String16(name.type8, name.typeLen));
+ } else {
+ str.append(name.type, name.typeLen);
+ }
+ }
+ if (name.name8 != NULL || name.name != NULL) {
+ if (str.size() > 0) {
+ char16_t div = '/';
+ str.append(&div, 1);
+ }
+ if (name.name8 != NULL) {
+ str.append(String16(name.name8, name.nameLen));
+ } else {
+ str.append(name.name, name.nameLen);
+ }
+ }
+
+ return env->NewString((const jchar*)str.string(), str.size());
}
-static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return nullptr;
- }
-
- jintArray array = env->NewIntArray(bag->entry_count);
- if (array == nullptr) {
- return nullptr;
- }
-
- jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
- if (buffer == nullptr) {
- return nullptr;
- }
-
- for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
- return nullptr;
- }
-
- if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
- buffer[i] = static_cast<jint>(value.data);
- }
- }
- env->ReleasePrimitiveArrayCritical(array, buffer, 0);
- return array;
+static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, true, &name)) {
+ return NULL;
+ }
+
+ if (name.package != NULL) {
+ return env->NewString((const jchar*)name.package, name.packageLen);
+ }
+
+ return NULL;
}
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return -1;
- }
- return static_cast<jint>(bag->entry_count);
+static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, true, &name)) {
+ return NULL;
+ }
+
+ if (name.type8 != NULL) {
+ return env->NewStringUTF(name.type8);
+ }
+
+ if (name.type != NULL) {
+ return env->NewString((const jchar*)name.type, name.typeLen);
+ }
+
+ return NULL;
}
-static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
- jintArray out_data) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return -1;
- }
+static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
- const jsize out_data_length = env->GetArrayLength(out_data);
- if (env->ExceptionCheck()) {
- return -1;
- }
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, true, &name)) {
+ return NULL;
+ }
- if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
- return -1;
- }
+ if (name.name8 != NULL) {
+ return env->NewStringUTF(name.name8);
+ }
- jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
- if (buffer == nullptr) {
- return -1;
- }
-
- jint* cursor = buffer;
- for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- selected_config.density = 0;
- uint32_t flags = bag->type_spec_flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
- return -1;
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- }
-
- cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
- cursor[STYLE_DATA] = static_cast<jint>(value.data);
- cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
- cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
- cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
- cursor += STYLE_NUM_ENTRIES;
- }
- env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
- return static_cast<jint>(bag->entry_count);
+ if (name.name != NULL) {
+ return env->NewString((const jchar*)name.name, name.nameLen);
+ }
+
+ return NULL;
}
-static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
- jstring def_type, jstring def_package) {
- ScopedUtfChars name_utf8(env, name);
- if (name_utf8.c_str() == nullptr) {
- // This will throw NPE.
- return 0;
- }
-
- std::string type;
- if (def_type != nullptr) {
- ScopedUtfChars type_utf8(env, def_type);
- CHECK(type_utf8.c_str() != nullptr);
- type = type_utf8.c_str();
- }
-
- std::string package;
- if (def_package != nullptr) {
- ScopedUtfChars package_utf8(env, def_package);
- CHECK(package_utf8.c_str() != nullptr);
- package = package_utf8.c_str();
- }
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
+static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
+ jint ident,
+ jshort density,
+ jobject outValue,
+ jboolean resolve)
+{
+ if (outValue == NULL) {
+ jniThrowNullPointerException(env, "outValue");
+ return 0;
+ }
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ const ResTable& res(am->getResources());
+
+ Res_value value;
+ ResTable_config config;
+ uint32_t typeSpecFlags;
+ ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return 0;
+ }
+ }
+ uint32_t ref = ident;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return 0;
+ }
+ }
+ }
+ if (block >= 0) {
+ return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+ }
+
+ return static_cast<jint>(block);
}
-static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
- return nullptr;
- }
+static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
+ jint ident, jint bagEntryId,
+ jobject outValue, jboolean resolve)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ const ResTable& res(am->getResources());
- std::string result;
- if (name.package != nullptr) {
- result.append(name.package, name.package_len);
- }
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
- if (name.type != nullptr || name.type16 != nullptr) {
- if (!result.empty()) {
- result += ":";
+ ssize_t block = -1;
+ Res_value value;
+
+ const ResTable::bag_entry* entry = NULL;
+ uint32_t typeSpecFlags;
+ ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
+
+ for (ssize_t i=0; i<entryCount; i++) {
+ if (((uint32_t)bagEntryId) == entry->map.name.ident) {
+ block = entry->stringBlock;
+ value = entry->map.value;
+ }
+ entry++;
}
- if (name.type != nullptr) {
- result.append(name.type, name.type_len);
- } else {
- result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
+ res.unlock();
+
+ if (block < 0) {
+ return static_cast<jint>(block);
}
- }
- if (name.entry != nullptr || name.entry16 != nullptr) {
- if (!result.empty()) {
- result += "/";
+ uint32_t ref = ident;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return 0;
+ }
+ }
}
+ if (block >= 0) {
+ return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
+ }
+
+ return static_cast<jint>(block);
+}
- if (name.entry != nullptr) {
- result.append(name.entry, name.entry_len);
- } else {
- result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
+static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
}
- }
- return env->NewStringUTF(result.c_str());
+ return am->getResources().getTableCount();
}
-static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
- return nullptr;
- }
-
- if (name.package != nullptr) {
- return env->NewStringUTF(name.package);
- }
- return nullptr;
+static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
+ jint block)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
}
-static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
- return nullptr;
- }
-
- if (name.type != nullptr) {
- return env->NewStringUTF(name.type);
- } else if (name.type16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
- }
- return nullptr;
+static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
+ jint cookie)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
+ if (name.length() == 0) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
+ return NULL;
+ }
+ jstring str = env->NewStringUTF(name.string());
+ return str;
}
-static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
- return nullptr;
- }
-
- if (name.entry != nullptr) {
- return env->NewStringUTF(name.entry);
- } else if (name.entry16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
- }
- return nullptr;
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ const ResTable& res = am->getResources();
+
+ jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+ gSparseArrayOffsets.constructor);
+ const size_t N = res.getBasePackageCount();
+ for (size_t i = 0; i < N; i++) {
+ const String16 name = res.getBasePackageName(i);
+ env->CallVoidMethod(
+ sparseArray, gSparseArrayOffsets.put,
+ static_cast<jint>(res.getBasePackageId(i)),
+ env->NewString(reinterpret_cast<const jchar*>(name.string()),
+ name.size()));
+ }
+ return sparseArray;
}
-static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
- jboolean exclude_system) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::set<std::string> locales =
- assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
-
- jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
- if (array == nullptr) {
- return nullptr;
- }
-
- size_t idx = 0;
- for (const std::string& locale : locales) {
- jstring java_string = env->NewStringUTF(locale.c_str());
- if (java_string == nullptr) {
- return nullptr;
- }
- env->SetObjectArrayElement(array, idx++, java_string);
- env->DeleteLocalRef(java_string);
- }
- return array;
+static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
}
-static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
- jobject result =
- env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
- if (result == nullptr) {
- return nullptr;
- }
-
- env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
- config.smallestScreenWidthDp);
- env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
- env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
- return result;
+static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
+ jlong themeHandle)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ delete theme;
}
-static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::set<ResTable_config> configurations =
- assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
+static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
+ jlong themeHandle,
+ jint styleRes,
+ jboolean force)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ theme->applyStyle(styleRes, force ? true : false);
+}
- jobjectArray array =
- env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
- if (array == nullptr) {
- return nullptr;
- }
+static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
+ jlong destHandle, jlong srcHandle)
+{
+ ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
+ ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
+ dest->setTo(*src);
+}
+
+static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ theme->clear();
+}
- size_t idx = 0;
- for (const ResTable_config& configuration : configurations) {
- jobject java_configuration = ConstructConfigurationObject(env, configuration);
- if (java_configuration == nullptr) {
- return nullptr;
+static jint android_content_AssetManager_loadThemeAttributeValue(
+ JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ const ResTable& res(theme->getResTable());
+
+ Res_value value;
+ // XXX value could be different in different configs!
+ uint32_t typeSpecFlags = 0;
+ ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
+ uint32_t ref = 0;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return 0;
+ }
+ }
}
+ return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
- env->SetObjectArrayElement(array, idx++, java_configuration);
- env->DeleteLocalRef(java_configuration);
- }
- return array;
+static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
+ jlong themeHandle)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ return theme->getChangingConfigurations();
}
-static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
- jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
- jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- CHECK(theme->GetAssetManager() == &(*assetmanager));
- (void) assetmanager;
-
- ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
- uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
- uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
-
- jsize attrs_len = env->GetArrayLength(java_attrs);
- jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
- if (attrs == nullptr) {
- return;
- }
-
- ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
- static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
- out_values, out_indices);
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
+ jlong themeHandle, jint pri,
+ jstring tag, jstring prefix)
+{
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+ const ResTable& res(theme->getResTable());
+ (void)res;
+
+ // XXX Need to use params.
+ theme->dumpToLog();
}
-static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
- jint def_style_attr, jint def_style_resid, jintArray java_values,
- jintArray java_attrs, jintArray out_java_values,
- jintArray out_java_indices) {
- const jsize attrs_len = env->GetArrayLength(java_attrs);
- const jsize out_values_len = env->GetArrayLength(out_java_values);
- if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
- return JNI_FALSE;
- }
-
- jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
- if (attrs == nullptr) {
- return JNI_FALSE;
- }
-
- jint* values = nullptr;
- jsize values_len = 0;
- if (java_values != nullptr) {
- values_len = env->GetArrayLength(java_values);
- values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
- if (values == nullptr) {
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return JNI_FALSE;
- }
- }
-
- jint* out_values =
- reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
- if (out_values == nullptr) {
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- if (values != nullptr) {
- env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
- }
- return JNI_FALSE;
- }
-
- jint* out_indices = nullptr;
- if (out_java_indices != nullptr) {
- jsize out_indices_len = env->GetArrayLength(out_java_indices);
- if (out_indices_len > attrs_len) {
- out_indices =
- reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
- if (out_indices == nullptr) {
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- if (values != nullptr) {
- env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
- }
- env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
+ jlong themeToken,
+ jint defStyleAttr,
+ jint defStyleRes,
+ jintArray inValues,
+ jintArray attrs,
+ jintArray outValues,
+ jintArray outIndices)
+{
+ if (themeToken == 0) {
+ jniThrowNullPointerException(env, "theme token");
return JNI_FALSE;
- }
- }
- }
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- CHECK(theme->GetAssetManager() == &(*assetmanager));
- (void) assetmanager;
-
- bool result = ResolveAttrs(
- theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
- reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
- attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
- if (out_indices != nullptr) {
- env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
- }
-
- env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
- if (values != nullptr) {
- env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
- }
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
-}
+ }
+ if (attrs == NULL) {
+ jniThrowNullPointerException(env, "attrs");
+ return JNI_FALSE;
+ }
+ if (outValues == NULL) {
+ jniThrowNullPointerException(env, "out values");
+ return JNI_FALSE;
+ }
-static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jlong xml_parser_ptr, jintArray java_attrs,
- jintArray out_java_values, jintArray out_java_indices) {
- const jsize attrs_len = env->GetArrayLength(java_attrs);
- const jsize out_values_len = env->GetArrayLength(out_java_values);
- if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
- return JNI_FALSE;
- }
-
- jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
- if (attrs == nullptr) {
- return JNI_FALSE;
- }
-
- jint* out_values =
- reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
- if (out_values == nullptr) {
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return JNI_FALSE;
- }
-
- jint* out_indices = nullptr;
- if (out_java_indices != nullptr) {
- jsize out_indices_len = env->GetArrayLength(out_java_indices);
- if (out_indices_len > attrs_len) {
- out_indices =
- reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
- if (out_indices == nullptr) {
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+ const jsize NI = env->GetArrayLength(attrs);
+ const jsize NV = env->GetArrayLength(outValues);
+ if (NV < (NI*STYLE_NUM_ENTRIES)) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
return JNI_FALSE;
- }
}
- }
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
+ jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+ if (src == NULL) {
+ return JNI_FALSE;
+ }
- bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
- reinterpret_cast<uint32_t*>(attrs), attrs_len,
- reinterpret_cast<uint32_t*>(out_values),
- reinterpret_cast<uint32_t*>(out_indices));
+ jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
+ const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
- if (out_indices != nullptr) {
- env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
- }
- env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
- env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
-}
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ if (baseDest == NULL) {
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ return JNI_FALSE;
+ }
-static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
-}
+ jint* indices = NULL;
+ if (outIndices != NULL) {
+ if (env->GetArrayLength(outIndices) > NI) {
+ indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+ }
+ }
+
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
+ (uint32_t*) srcValues, NSV,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
-static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
- delete reinterpret_cast<Theme*>(theme_ptr);
+ if (indices != NULL) {
+ env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+ }
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+ env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ return result ? JNI_TRUE : JNI_FALSE;
}
-static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
- jint resid, jboolean force) {
- // AssetManager is accessed via the theme, so grab an explicit lock here.
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- CHECK(theme->GetAssetManager() == &(*assetmanager));
- (void) assetmanager;
- theme->ApplyStyle(static_cast<uint32_t>(resid), force);
-
- // TODO(adamlesinski): Consider surfacing exception when result is failure.
- // CTS currently expects no exceptions from this method.
- // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
- // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
+static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
+ jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
+ jlong outValuesAddress, jlong outIndicesAddress) {
+ jint* attrs = env->GetIntArrayElements(attrsObj, 0);
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+ uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
+ uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
+ ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
+ reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
+ env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
}
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
- jlong src_theme_ptr) {
- Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
- Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
- if (!dst_theme->SetTo(*src_theme)) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Themes are from different AssetManagers");
- }
+static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
+ jlong xmlParserToken,
+ jintArray attrs,
+ jintArray outValues,
+ jintArray outIndices)
+{
+ if (xmlParserToken == 0) {
+ jniThrowNullPointerException(env, "xmlParserToken");
+ return JNI_FALSE;
+ }
+ if (attrs == NULL) {
+ jniThrowNullPointerException(env, "attrs");
+ return JNI_FALSE;
+ }
+ if (outValues == NULL) {
+ jniThrowNullPointerException(env, "out values");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+ const ResTable& res(am->getResources());
+ ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+
+ const jsize NI = env->GetArrayLength(attrs);
+ const jsize NV = env->GetArrayLength(outValues);
+ if (NV < (NI*STYLE_NUM_ENTRIES)) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+ return JNI_FALSE;
+ }
+
+ jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+ if (src == NULL) {
+ return JNI_FALSE;
+ }
+
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ if (baseDest == NULL) {
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ return JNI_FALSE;
+ }
+
+ jint* indices = NULL;
+ if (outIndices != NULL) {
+ if (env->GetArrayLength(outIndices) > NI) {
+ indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+ }
+ }
+
+ bool result = RetrieveAttributes(&res, xmlParser,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
+
+ if (indices != NULL) {
+ env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+ }
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ return result ? JNI_TRUE : JNI_FALSE;
}
-static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
- reinterpret_cast<Theme*>(theme_ptr)->Clear();
+static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
+ jint id)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ const ResTable& res(am->getResources());
+
+ res.lock();
+ const ResTable::bag_entry* defStyleEnt = NULL;
+ ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
+ res.unlock();
+
+ return static_cast<jint>(bagOff);
}
-static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
- jint resid, jobject typed_value,
- jboolean resolve_references) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- CHECK(theme->GetAssetManager() == &(*assetmanager));
- (void) assetmanager;
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
-
- uint32_t ref = 0u;
- if (resolve_references) {
- ResTable_config selected_config;
- cookie =
- theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
- }
- return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
+ jint id,
+ jintArray outValues)
+{
+ if (outValues == NULL) {
+ jniThrowNullPointerException(env, "out values");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+ const ResTable& res(am->getResources());
+ ResTable_config config;
+ Res_value value;
+ ssize_t block;
+
+ const jsize NV = env->GetArrayLength(outValues);
+
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* dest = baseDest;
+ if (dest == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
+ return JNI_FALSE;
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ const ResTable::bag_entry* arrayEnt = NULL;
+ uint32_t arrayTypeSetFlags = 0;
+ ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+ const ResTable::bag_entry* endArrayEnt = arrayEnt +
+ (bagOff >= 0 ? bagOff : 0);
+
+ int i = 0;
+ uint32_t typeSetFlags;
+ while (i < NV && arrayEnt < endArrayEnt) {
+ block = arrayEnt->stringBlock;
+ typeSetFlags = arrayTypeSetFlags;
+ config.density = 0;
+ value = arrayEnt->map.value;
+
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ //printf("Resolving attribute reference\n");
+ ssize_t newBlock = res.resolveReference(&value, block, &resid,
+ &typeSetFlags, &config);
+ if (kThrowOnBadId) {
+ if (newBlock == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return JNI_FALSE;
+ }
+ }
+ if (newBlock >= 0) block = newBlock;
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ }
+
+ //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+ // Write the final value back to Java.
+ dest[STYLE_TYPE] = value.dataType;
+ dest[STYLE_DATA] = value.data;
+ dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
+ dest[STYLE_RESOURCE_ID] = resid;
+ dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+ dest[STYLE_DENSITY] = config.density;
+ dest += STYLE_NUM_ENTRIES;
+ i+= STYLE_NUM_ENTRIES;
+ arrayEnt++;
+ }
+
+ i /= STYLE_NUM_ENTRIES;
+
+ res.unlock();
+
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+
+ return i;
}
-static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
- jint priority, jstring tag, jstring prefix) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- CHECK(theme->GetAssetManager() == &(*assetmanager));
- (void) assetmanager;
- (void) theme;
- (void) priority;
- (void) tag;
- (void) prefix;
+static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
+
+ ScopedUtfChars fileName8(env, fileName);
+ if (fileName8.c_str() == NULL) {
+ return 0;
+ }
+
+ int32_t assetCookie = static_cast<int32_t>(cookie);
+ Asset* a = assetCookie
+ ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+ : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
+
+ if (a == NULL) {
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+ return 0;
+ }
+
+ const DynamicRefTable* dynamicRefTable =
+ am->getResources().getDynamicRefTableForCookie(assetCookie);
+ ResXMLTree* block = new ResXMLTree(dynamicRefTable);
+ status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
+ a->close();
+ delete a;
+
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+ return 0;
+ }
+
+ return reinterpret_cast<jlong>(block);
}
-static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
- jlong theme_ptr) {
- Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
- return static_cast<jint>(theme->GetChangingConfigurations());
+static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jintArray array = env->NewIntArray(N * 2);
+ if (array == NULL) {
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
+ jint stringIndex = -1;
+ jint stringBlock = 0;
+ value = bag->map.value;
+
+ // Take care of resolving the found resource to its final value.
+ stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (value.dataType == Res_value::TYPE_STRING) {
+ stringIndex = value.data;
+ }
+
+ if (kThrowOnBadId) {
+ if (stringBlock == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return array;
+ }
+ }
+
+ //todo: It might be faster to allocate a C array to contain
+ // the blocknums and indices, put them in there and then
+ // do just one SetIntArrayRegion()
+ env->SetIntArrayRegion(array, j, 1, &stringBlock);
+ env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
+ j = j + 2;
+ }
+ res.unlockBag(startOfBag);
+ return array;
}
-static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- delete reinterpret_cast<Asset*>(asset_ptr);
+static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
+ if (env->ExceptionCheck()) {
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ size_t strLen = 0;
+ for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+ value = bag->map.value;
+ jstring str = NULL;
+
+ // Take care of resolving the found resource to its final value.
+ ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return array;
+ }
+ }
+ if (value.dataType == Res_value::TYPE_STRING) {
+ const ResStringPool* pool = res.getTableStringBlock(block);
+ const char* str8 = pool->string8At(value.data, &strLen);
+ if (str8 != NULL) {
+ str = env->NewStringUTF(str8);
+ } else {
+ const char16_t* str16 = pool->stringAt(value.data, &strLen);
+ str = env->NewString(reinterpret_cast<const jchar*>(str16),
+ strLen);
+ }
+
+ // If one of our NewString{UTF} calls failed due to memory, an
+ // exception will be pending.
+ if (env->ExceptionCheck()) {
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ env->SetObjectArrayElement(array, i, str);
+
+ // str is not NULL at that point, otherwise ExceptionCheck would have been true.
+ // If we have a large amount of strings in our array, we might
+ // overflow the local reference table of the VM.
+ env->DeleteLocalRef(str);
+ }
+ }
+ res.unlockBag(startOfBag);
+ return array;
}
-static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
- uint8_t b;
- ssize_t res = asset->read(&b, sizeof(b));
- return res == sizeof(b) ? static_cast<jint>(b) : -1;
+static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jintArray array = env->NewIntArray(N);
+ if (array == NULL) {
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+ value = bag->map.value;
+
+ // Take care of resolving the found resource to its final value.
+ ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (kThrowOnBadId) {
+ if (block == BAD_INDEX) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+ return array;
+ }
+ }
+ if (value.dataType >= Res_value::TYPE_FIRST_INT
+ && value.dataType <= Res_value::TYPE_LAST_INT) {
+ int intVal = value.data;
+ env->SetIntArrayRegion(array, i, 1, &intVal);
+ }
+ }
+ res.unlockBag(startOfBag);
+ return array;
}
-static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
- jint offset, jint len) {
- if (len == 0) {
- return 0;
- }
+static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
+ jint styleId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
- jsize buffer_len = env->GetArrayLength(java_buffer);
- if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
- (offset + len) > buffer_len) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
- return -1;
- }
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(styleId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
- Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ jintArray array = env->NewIntArray(N);
+ if (array == NULL) {
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
- ScopedByteArrayRW byte_array(env, java_buffer);
- if (byte_array.get() == nullptr) {
- return -1;
- }
+ const ResTable::bag_entry* bag = startOfBag;
+ for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+ int resourceId = bag->map.name.ident;
+ env->SetIntArrayRegion(array, i, 1, &resourceId);
+ }
+ res.unlockBag(startOfBag);
+ return array;
+}
- ssize_t res = asset->read(byte_array.get(), buffer_len);
- if (res < 0) {
- jniThrowException(env, "java/io/IOException", "");
- return -1;
- }
- return res > 0 ? static_cast<jint>(res) : -1;
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
+{
+ if (isSystem) {
+ verifySystemIdmaps();
+ }
+ AssetManager* am = new AssetManager();
+ if (am == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
+ return;
+ }
+
+ am->addDefaultAssets();
+
+ ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
+ env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
+}
+
+static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = (AssetManager*)
+ (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
+ ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
+ if (am != NULL) {
+ delete am;
+ env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
+ }
}
-static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
- jint whence) {
- Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
- return static_cast<jlong>(asset->seek(
- static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
+static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
+{
+ return Asset::getGlobalCount();
}
-static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
- return static_cast<jlong>(asset->getLength());
+static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
+{
+ String8 alloc = Asset::getAssetAllocations();
+ if (alloc.length() <= 0) {
+ return NULL;
+ }
+
+ jstring str = env->NewStringUTF(alloc.string());
+ return str;
}
-static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
- return static_cast<jlong>(asset->getRemainingLength());
+static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
+{
+ return AssetManager::getGlobalCount();
}
// ----------------------------------------------------------------------------
-// JNI registration.
+/*
+ * JNI registration.
+ */
static const JNINativeMethod gAssetManagerMethods[] = {
- // AssetManager setup methods.
- {"nativeCreate", "()J", (void*)NativeCreate},
- {"nativeDestroy", "(J)V", (void*)NativeDestroy},
- {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
- {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
- (void*)NativeSetConfiguration},
- {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
- (void*)NativeGetAssignedPackageIdentifiers},
-
- // AssetManager file methods.
- {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
- {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
- {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
- (void*)NativeOpenAssetFd},
- {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
- {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
- (void*)NativeOpenNonAssetFd},
- {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
-
- // AssetManager resource methods.
- {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
- {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
- (void*)NativeGetResourceBagValue},
- {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
- {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
- (void*)NativeGetResourceStringArray},
- {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
- {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
- {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
- {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
-
- // AssetManager resource name/ID methods.
- {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)NativeGetResourceIdentifier},
- {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
- {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
- {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
- {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
- {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
- {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
- (void*)NativeGetSizeConfigurations},
-
- // Style attribute related methods.
- {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
- {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
- {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
-
- // Theme related methods.
- {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
- {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
- {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
- {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
- {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
- {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
- (void*)NativeThemeGetAttributeValue},
- {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
- {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
-
- // AssetInputStream methods.
- {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
- {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
- {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
- {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
- {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
- {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
-
- // System/idmap related methods.
- {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
-
- // Global management/debug methods.
- {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
- {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
- {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+ /* name, signature, funcPtr */
+
+ // Basic asset stuff.
+ { "openAsset", "(Ljava/lang/String;I)J",
+ (void*) android_content_AssetManager_openAsset },
+ { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*) android_content_AssetManager_openAssetFd },
+ { "openNonAssetNative", "(ILjava/lang/String;I)J",
+ (void*) android_content_AssetManager_openNonAssetNative },
+ { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*) android_content_AssetManager_openNonAssetFdNative },
+ { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
+ (void*) android_content_AssetManager_list },
+ { "destroyAsset", "(J)V",
+ (void*) android_content_AssetManager_destroyAsset },
+ { "readAssetChar", "(J)I",
+ (void*) android_content_AssetManager_readAssetChar },
+ { "readAsset", "(J[BII)I",
+ (void*) android_content_AssetManager_readAsset },
+ { "seekAsset", "(JJI)J",
+ (void*) android_content_AssetManager_seekAsset },
+ { "getAssetLength", "(J)J",
+ (void*) android_content_AssetManager_getAssetLength },
+ { "getAssetRemainingLength", "(J)J",
+ (void*) android_content_AssetManager_getAssetRemainingLength },
+ { "addAssetPathNative", "(Ljava/lang/String;Z)I",
+ (void*) android_content_AssetManager_addAssetPath },
+ { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
+ (void*) android_content_AssetManager_addAssetFd },
+ { "addOverlayPathNative", "(Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_addOverlayPath },
+ { "isUpToDate", "()Z",
+ (void*) android_content_AssetManager_isUpToDate },
+
+ // Resources.
+ { "getLocales", "()[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getLocales },
+ { "getNonSystemLocales", "()[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getNonSystemLocales },
+ { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
+ (void*) android_content_AssetManager_getSizeConfigurations },
+ { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
+ (void*) android_content_AssetManager_setConfiguration },
+ { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_getResourceIdentifier },
+ { "getResourceName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceName },
+ { "getResourcePackageName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourcePackageName },
+ { "getResourceTypeName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceTypeName },
+ { "getResourceEntryName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceEntryName },
+ { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadResourceValue },
+ { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadResourceBagValue },
+ { "getStringBlockCount","()I",
+ (void*) android_content_AssetManager_getStringBlockCount },
+ { "getNativeStringBlock","(I)J",
+ (void*) android_content_AssetManager_getNativeStringBlock },
+ { "getCookieName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getCookieName },
+ { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+ (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
+
+ // Themes.
+ { "newTheme", "()J",
+ (void*) android_content_AssetManager_newTheme },
+ { "deleteTheme", "(J)V",
+ (void*) android_content_AssetManager_deleteTheme },
+ { "applyThemeStyle", "(JIZ)V",
+ (void*) android_content_AssetManager_applyThemeStyle },
+ { "copyTheme", "(JJ)V",
+ (void*) android_content_AssetManager_copyTheme },
+ { "clearTheme", "(J)V",
+ (void*) android_content_AssetManager_clearTheme },
+ { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadThemeAttributeValue },
+ { "getThemeChangingConfigurations", "(J)I",
+ (void*) android_content_AssetManager_getThemeChangingConfigurations },
+ { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
+ (void*) android_content_AssetManager_dumpTheme },
+ { "applyStyle","(JIIJ[IIJJ)V",
+ (void*) android_content_AssetManager_applyStyle },
+ { "resolveAttrs","(JII[I[I[I[I)Z",
+ (void*) android_content_AssetManager_resolveAttrs },
+ { "retrieveAttributes","(J[I[I[I)Z",
+ (void*) android_content_AssetManager_retrieveAttributes },
+ { "getArraySize","(I)I",
+ (void*) android_content_AssetManager_getArraySize },
+ { "retrieveArray","(I[I)I",
+ (void*) android_content_AssetManager_retrieveArray },
+
+ // XML files.
+ { "openXmlAssetNative", "(ILjava/lang/String;)J",
+ (void*) android_content_AssetManager_openXmlAssetNative },
+
+ // Arrays.
+ { "getArrayStringResource","(I)[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getArrayStringResource },
+ { "getArrayStringInfo","(I)[I",
+ (void*) android_content_AssetManager_getArrayStringInfo },
+ { "getArrayIntResource","(I)[I",
+ (void*) android_content_AssetManager_getArrayIntResource },
+ { "getStyleAttributes","(I)[I",
+ (void*) android_content_AssetManager_getStyleAttributes },
+
+ // Bookkeeping.
+ { "init", "(Z)V",
+ (void*) android_content_AssetManager_init },
+ { "destroy", "()V",
+ (void*) android_content_AssetManager_destroy },
+ { "getGlobalAssetCount", "()I",
+ (void*) android_content_AssetManager_getGlobalAssetCount },
+ { "getAssetAllocations", "()Ljava/lang/String;",
+ (void*) android_content_AssetManager_getAssetAllocations },
+ { "getGlobalAssetManagerCount", "()I",
+ (void*) android_content_AssetManager_getGlobalAssetManagerCount },
};
-int register_android_content_AssetManager(JNIEnv* env) {
- jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
- gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
-
- jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
- gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
- gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
- gTypedValueOffsets.mString =
- GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
- gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
- gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
- gTypedValueOffsets.mChangingConfigurations =
- GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
- gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
-
- jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
- gAssetFileDescriptorOffsets.mFd =
- GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
- gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
- gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
-
- jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
- gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
-
- jclass stringClass = FindClassOrDie(env, "java/lang/String");
- g_stringClass = MakeGlobalRefOrDie(env, stringClass);
-
- jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
- gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
- gSparseArrayOffsets.constructor =
- GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
- gSparseArrayOffsets.put =
- GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
-
- jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
- gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
- gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
- gConfigurationOffsets.mSmallestScreenWidthDpOffset =
- GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
- gConfigurationOffsets.mScreenWidthDpOffset =
- GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
- gConfigurationOffsets.mScreenHeightDpOffset =
- GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
-
- return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
- NELEM(gAssetManagerMethods));
+int register_android_content_AssetManager(JNIEnv* env)
+{
+ jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+ gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+ gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+ gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
+ "Ljava/lang/CharSequence;");
+ gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+ gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+ gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
+ "changingConfigurations", "I");
+ gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+
+ jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+ gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
+ "Landroid/os/ParcelFileDescriptor;");
+ gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+ gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+
+ jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+ gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+
+ jclass stringClass = FindClassOrDie(env, "java/lang/String");
+ g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+
+ jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+ gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+ gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
+ "<init>", "()V");
+ gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
+ "(ILjava/lang/Object;)V");
+
+ jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
+ gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
+ gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
+ "<init>", "()V");
+ gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+ "smallestScreenWidthDp", "I");
+ gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+ "screenWidthDp", "I");
+ gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
+ "screenHeightDp", "I");
+
+ return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+ NELEM(gAssetManagerMethods));
}
}; // namespace android
diff --git a/core/jni/include/android_runtime/android_util_AssetManager.h b/core/jni/include/android_runtime/android_util_AssetManager.h
index 2c1e3579eb92..8dd933707a6a 100644
--- a/core/jni/include/android_runtime/android_util_AssetManager.h
+++ b/core/jni/include/android_runtime/android_util_AssetManager.h
@@ -14,20 +14,17 @@
* limitations under the License.
*/
-#ifndef ANDROID_RUNTIME_ASSETMANAGER_H
-#define ANDROID_RUNTIME_ASSETMANAGER_H
+#ifndef android_util_AssetManager_H
+#define android_util_AssetManager_H
-#include "androidfw/AssetManager2.h"
-#include "androidfw/MutexGuard.h"
+#include <androidfw/AssetManager.h>
#include "jni.h"
namespace android {
-extern AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForNdkAssetManager(AAssetManager* assetmanager);
+extern AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject assetMgr);
-} // namespace android
+}
-#endif // ANDROID_RUNTIME_ASSETMANAGER_H
+#endif
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 70d52164ff74..251b2e773cfb 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -145,7 +145,6 @@ cc_test {
"tests/TypeWrappers_test.cpp",
"tests/ZipUtils_test.cpp",
],
- static_libs: ["libgmock"],
target: {
android: {
srcs: [
@@ -172,7 +171,6 @@ cc_benchmark {
// Actual benchmarks.
"tests/AssetManager2_bench.cpp",
- "tests/AttributeResolution_bench.cpp",
"tests/SparseEntry_bench.cpp",
"tests/Theme_bench.cpp",
],
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index a558ff7ccfc1..415d3e36adf9 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -36,31 +36,6 @@
namespace android {
-struct FindEntryResult {
- // A pointer to the resource table entry for this resource.
- // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
- // a ResTable_map_entry and processed as a bag/map.
- const ResTable_entry* entry;
-
- // The configuration for which the resulting entry was defined. This is already swapped to host
- // endianness.
- ResTable_config config;
-
- // The bitmask of configuration axis with which the resource value varies.
- uint32_t type_flags;
-
- // The dynamic package ID map for the package from which this resource came from.
- const DynamicRefTable* dynamic_ref_table;
-
- // The string pool reference to the type's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef type_string_ref;
-
- // The string pool reference to the entry's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef entry_string_ref;
-};
-
AssetManager2::AssetManager2() {
memset(&configuration_, 0, sizeof(configuration_));
}
@@ -69,7 +44,6 @@ bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets
bool invalidate_caches) {
apk_assets_ = apk_assets;
BuildDynamicRefTable();
- RebuildFilterList();
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
@@ -105,7 +79,7 @@ void AssetManager2::BuildDynamicRefTable() {
PackageGroup* package_group = &package_groups_[idx];
// Add the package and to the set of packages with the same ID.
- package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
+ package_group->packages_.push_back(package.get());
package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
// Add the package name -> build time ID mappings.
@@ -120,7 +94,7 @@ void AssetManager2::BuildDynamicRefTable() {
// Now assign the runtime IDs so that we have a build-time to runtime ID map.
const auto package_groups_end = package_groups_.end();
for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
- const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
+ const std::string& package_name = iter->packages_[0]->GetPackageName();
for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
iter->dynamic_ref_table.mAssignedPackageId);
@@ -134,20 +108,17 @@ void AssetManager2::DumpToLog() const {
std::string list;
for (size_t i = 0; i < package_ids_.size(); i++) {
if (package_ids_[i] != 0xff) {
- base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]);
+ base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
}
}
LOG(INFO) << "Package ID map: " << list;
- for (const auto& package_group : package_groups_) {
- list = "";
- for (const auto& package : package_group.packages_) {
- base::StringAppendF(&list, "%s(%02x), ", package.loaded_package_->GetPackageName().c_str(),
- package.loaded_package_->GetPackageId());
- }
- LOG(INFO) << base::StringPrintf("PG (%02x): ",
- package_group.dynamic_ref_table.mAssignedPackageId)
- << list;
+ for (const auto& package_group: package_groups_) {
+ list = "";
+ for (const auto& package : package_group.packages_) {
+ base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
+ }
+ LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
}
}
@@ -186,54 +157,52 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
configuration_ = configuration;
if (diff) {
- RebuildFilterList();
InvalidateCaches(static_cast<uint32_t>(diff));
}
}
std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
- bool exclude_mipmap) const {
+ bool exclude_mipmap) {
ATRACE_CALL();
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
- for (const ConfiguredPackage& package : package_group.packages_) {
- if (exclude_system && package.loaded_package_->IsSystem()) {
+ for (const LoadedPackage* package : package_group.packages_) {
+ if (exclude_system && package->IsSystem()) {
continue;
}
- package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+ package->CollectConfigurations(exclude_mipmap, &configurations);
}
}
return configurations;
}
std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
- bool merge_equivalent_languages) const {
+ bool merge_equivalent_languages) {
ATRACE_CALL();
std::set<std::string> locales;
for (const PackageGroup& package_group : package_groups_) {
- for (const ConfiguredPackage& package : package_group.packages_) {
- if (exclude_system && package.loaded_package_->IsSystem()) {
+ for (const LoadedPackage* package : package_group.packages_) {
+ if (exclude_system && package->IsSystem()) {
continue;
}
- package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
+ package->CollectLocales(merge_equivalent_languages, &locales);
}
}
return locales;
}
-std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename,
- Asset::AccessMode mode) const {
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
const std::string new_path = "assets/" + filename;
return OpenNonAsset(new_path, mode);
}
std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode) const {
+ Asset::AccessMode mode) {
const std::string new_path = "assets/" + filename;
return OpenNonAsset(new_path, cookie, mode);
}
-std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
+std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) {
ATRACE_CALL();
std::string full_path = "assets/" + dirname;
@@ -267,7 +236,7 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con
// is inconsistent for split APKs.
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
Asset::AccessMode mode,
- ApkAssetsCookie* out_cookie) const {
+ ApkAssetsCookie* out_cookie) {
ATRACE_CALL();
for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
@@ -286,8 +255,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
}
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
- ApkAssetsCookie cookie,
- Asset::AccessMode mode) const {
+ ApkAssetsCookie cookie, Asset::AccessMode mode) {
ATRACE_CALL();
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return {};
@@ -296,13 +264,14 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
}
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
- bool /*stop_at_first_match*/,
- FindEntryResult* out_entry) const {
+ bool stop_at_first_match, FindEntryResult* out_entry) {
+ ATRACE_CALL();
+
// Might use this if density_override != 0.
ResTable_config density_override_config;
// Select our configuration or generate a density override configuration.
- const ResTable_config* desired_config = &configuration_;
+ ResTable_config* desired_config = &configuration_;
if (density_override != 0 && density_override != configuration_.density) {
density_override_config = configuration_;
density_override_config.density = density_override;
@@ -316,135 +285,53 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
const uint32_t package_id = get_package_id(resid);
const uint8_t type_idx = get_type_id(resid) - 1;
- const uint16_t entry_idx = get_entry_id(resid);
+ const uint16_t entry_id = get_entry_id(resid);
- const uint8_t package_idx = package_ids_[package_id];
- if (package_idx == 0xff) {
+ const uint8_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
return kInvalidCookie;
}
- const PackageGroup& package_group = package_groups_[package_idx];
- const size_t package_count = package_group.packages_.size();
-
+ FindEntryResult best_entry;
ApkAssetsCookie best_cookie = kInvalidCookie;
- const LoadedPackage* best_package = nullptr;
- const ResTable_type* best_type = nullptr;
- const ResTable_config* best_config = nullptr;
- ResTable_config best_config_copy;
- uint32_t best_offset = 0u;
- uint32_t type_flags = 0u;
-
- // If desired_config is the same as the set configuration, then we can use our filtered list
- // and we don't need to match the configurations, since they already matched.
- const bool use_fast_path = desired_config == &configuration_;
-
- for (size_t pi = 0; pi < package_count; pi++) {
- const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
- const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
- ApkAssetsCookie cookie = package_group.cookies_[pi];
-
- // If the type IDs are offset in this package, we need to take that into account when searching
- // for a type.
- const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx);
- if (UNLIKELY(type_spec == nullptr)) {
+ uint32_t cumulated_flags = 0u;
+
+ const PackageGroup& package_group = package_groups_[idx];
+ const size_t package_count = package_group.packages_.size();
+ FindEntryResult current_entry;
+ for (size_t i = 0; i < package_count; i++) {
+ const LoadedPackage* loaded_package = package_group.packages_[i];
+ if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, &current_entry)) {
continue;
}
- uint16_t local_entry_idx = entry_idx;
+ cumulated_flags |= current_entry.type_flags;
- // If there is an IDMAP supplied with this package, translate the entry ID.
- if (type_spec->idmap_entries != nullptr) {
- if (!LoadedIdmap::Lookup(type_spec->idmap_entries, local_entry_idx, &local_entry_idx)) {
- // There is no mapping, so the resource is not meant to be in this overlay package.
- continue;
- }
- }
-
- type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx);
-
- // If the package is an overlay, then even configurations that are the same MUST be chosen.
- const bool package_is_overlay = loaded_package->IsOverlay();
-
- const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
- if (use_fast_path) {
- const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
- const size_t type_count = candidate_configs.size();
- for (uint32_t i = 0; i < type_count; i++) {
- const ResTable_config& this_config = candidate_configs[i];
-
- // We can skip calling ResTable_config::match() because we know that all candidate
- // configurations that do NOT match have been filtered-out.
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const ResTable_type* type_chunk = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
-
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = type_chunk;
- best_config = &this_config;
- best_offset = offset;
- }
- }
- } else {
- // This is the slower path, which doesn't use the filtered list of configurations.
- // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
- // and fill in any new fields that did not exist when the APK was compiled.
- // Furthermore when selecting configurations we can't just record the pointer to the
- // ResTable_config, we must copy it.
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config;
- this_config.copyFromDtoH((*iter)->config);
-
- if (this_config.match(*desired_config)) {
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
-
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = *iter;
- best_config_copy = this_config;
- best_config = &best_config_copy;
- best_offset = offset;
- }
- }
+ const ResTable_config* current_config = current_entry.config;
+ const ResTable_config* best_config = best_entry.config;
+ if (best_cookie == kInvalidCookie ||
+ current_config->isBetterThan(*best_config, desired_config) ||
+ (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) {
+ best_entry = current_entry;
+ best_cookie = package_group.cookies_[i];
+ if (stop_at_first_match) {
+ break;
}
}
}
- if (UNLIKELY(best_cookie == kInvalidCookie)) {
+ if (best_cookie == kInvalidCookie) {
return kInvalidCookie;
}
- const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
- if (UNLIKELY(best_entry == nullptr)) {
- return kInvalidCookie;
- }
-
- out_entry->entry = best_entry;
- out_entry->config = *best_config;
- out_entry->type_flags = type_flags;
- out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
- out_entry->entry_string_ref =
- StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+ *out_entry = best_entry;
out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+ out_entry->type_flags = cumulated_flags;
return best_cookie;
}
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
ATRACE_CALL();
FindEntryResult entry;
@@ -454,8 +341,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons
return false;
}
- const LoadedPackage* package =
- apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+ const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
if (package == nullptr) {
return false;
}
@@ -483,7 +369,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons
return true;
}
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
FindEntryResult entry;
ApkAssetsCookie cookie =
FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
@@ -497,7 +383,7 @@ bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const
ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
uint16_t density_override, Res_value* out_value,
ResTable_config* out_selected_config,
- uint32_t* out_flags) const {
+ uint32_t* out_flags) {
ATRACE_CALL();
FindEntryResult entry;
@@ -516,7 +402,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
// Create a reference since we can't represent this complex type as a Res_value.
out_value->dataType = Res_value::TYPE_REFERENCE;
out_value->data = resid;
- *out_selected_config = entry.config;
+ *out_selected_config = *entry.config;
*out_flags = entry.type_flags;
return cookie;
}
@@ -528,7 +414,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
// Convert the package ID to the runtime assigned package ID.
entry.dynamic_ref_table->lookupResourceValue(out_value);
- *out_selected_config = entry.config;
+ *out_selected_config = *entry.config;
*out_flags = entry.type_flags;
return cookie;
}
@@ -536,14 +422,16 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config,
uint32_t* in_out_flags,
- uint32_t* out_last_reference) const {
+ uint32_t* out_last_reference) {
ATRACE_CALL();
constexpr const int kMaxIterations = 20;
for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
in_out_value->data != 0u && iteration < kMaxIterations;
iteration++) {
- *out_last_reference = in_out_value->data;
+ if (out_last_reference != nullptr) {
+ *out_last_reference = in_out_value->data;
+ }
uint32_t new_flags = 0u;
cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
in_out_value, in_out_selected_config, &new_flags);
@@ -604,8 +492,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
// Attributes, arrays, etc don't have a resource id as the name. They specify
// other data, which would be wrong to change via a lookup.
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
- resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
return nullptr;
}
}
@@ -637,8 +524,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
const ResolvedBag* parent_bag = GetBag(parent_resid);
if (parent_bag == nullptr) {
// Failed to get the parent that should exist.
- LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
- resid);
+ LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid);
return nullptr;
}
@@ -657,8 +543,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
uint32_t child_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(child_key)) {
if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
- resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
return nullptr;
}
}
@@ -697,8 +582,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
- resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
return nullptr;
}
}
@@ -754,7 +638,7 @@ static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
const std::string& fallback_type,
- const std::string& fallback_package) const {
+ const std::string& fallback_package) {
StringPiece package_name, type, entry;
if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
return 0u;
@@ -786,8 +670,7 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
const static std::u16string kAttrPrivate16 = u"^attr-private";
for (const PackageGroup& package_group : package_groups_) {
- for (const ConfiguredPackage& package_impl : package_group.packages_) {
- const LoadedPackage* package = package_impl.loaded_package_;
+ for (const LoadedPackage* package : package_group.packages_) {
if (package_name != package->GetPackageName()) {
// All packages in the same group are expected to have the same package name.
break;
@@ -809,32 +692,6 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
return 0u;
}
-void AssetManager2::RebuildFilterList() {
- for (PackageGroup& group : package_groups_) {
- for (ConfiguredPackage& impl : group.packages_) {
- // Destroy it.
- impl.filtered_configs_.~ByteBucketArray();
-
- // Re-create it.
- new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
-
- // Create the filters here.
- impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) {
- FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index);
- const auto iter_end = spec->types + spec->type_count;
- for (auto iter = spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config;
- this_config.copyFromDtoH((*iter)->config);
- if (this_config.match(configuration_)) {
- group.configurations.push_back(this_config);
- group.types.push_back(*iter);
- }
- }
- });
- }
- }
-}
-
void AssetManager2::InvalidateCaches(uint32_t diff) {
if (diff == 0xffffffffu) {
// Everything must go.
@@ -1015,7 +872,7 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config,
uint32_t* in_out_type_spec_flags,
- uint32_t* out_last_ref) const {
+ uint32_t* out_last_ref) {
if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
uint32_t new_flags;
cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index f912af4f7190..60e3845d98a9 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -20,18 +20,13 @@
#include <log/log.h>
-#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeFinder.h"
+#include "androidfw/ResourceTypes.h"
constexpr bool kDebugStyles = false;
namespace android {
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
- return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
-}
-
class XmlAttributeFinder
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
@@ -49,53 +44,58 @@ class XmlAttributeFinder
};
class BagAttributeFinder
- : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
+ : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
public:
- BagAttributeFinder(const ResolvedBag* bag)
- : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
- bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
- }
+ BagAttributeFinder(const ResTable::bag_entry* start,
+ const ResTable::bag_entry* end)
+ : BackTrackingAttributeFinder(start, end) {}
- inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
- return entry->key;
+ inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
+ return entry->map.name.ident;
}
};
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
- uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
+ uint32_t def_style_res, uint32_t* src_values,
+ size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values,
+ uint32_t* out_indices) {
if (kDebugStyles) {
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
def_style_attr, def_style_res);
}
- AssetManager2* assetmanager = theme->GetAssetManager();
+ const ResTable& res = theme->getResTable();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
+ uint32_t def_style_bag_type_set_flags = 0;
if (def_style_attr != 0) {
Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+ if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
def_style_res = value.data;
}
}
}
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_res != 0) {
- default_style_bag = assetmanager->GetBag(def_style_res);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
- }
- }
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
- BagAttributeFinder def_style_attr_finder(default_style_bag);
+ // Retrieve the default style bag, if requested.
+ const ResTable::bag_entry* def_style_start = nullptr;
+ uint32_t def_style_type_set_flags = 0;
+ ssize_t bag_off = def_style_res != 0
+ ? res.getBagLocked(def_style_res, &def_style_start,
+ &def_style_type_set_flags)
+ : -1;
+ def_style_type_set_flags |= def_style_bag_type_set_flags;
+ const ResTable::bag_entry* const def_style_end =
+ def_style_start + (bag_off >= 0 ? bag_off : 0);
+ BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -106,7 +106,7 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- ApkAssetsCookie cookie = kInvalidCookie;
+ ssize_t block = -1;
uint32_t type_set_flags = 0;
value.dataType = Res_value::TYPE_NULL;
@@ -122,14 +122,15 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
value.dataType = Res_value::TYPE_ATTRIBUTE;
value.data = src_values[ii];
if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+ ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
+ value.data);
}
} else {
- const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
- if (entry != def_style_attr_finder.end()) {
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
+ const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
+ if (def_style_entry != def_style_end) {
+ block = def_style_entry->stringBlock;
+ type_set_flags = def_style_type_set_flags;
+ value = def_style_entry->map.value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -139,26 +140,22 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
+ ssize_t new_block =
+ theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+ if (new_block >= 0) block = new_block;
if (kDebugStyles) {
ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
- // If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- if (new_cookie != kInvalidCookie) {
+ // If we still don't have a value for this attribute, try to find
+ // it in the theme!
+ ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+ if (new_block >= 0) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
+ new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+ if (new_block >= 0) block = new_block;
if (kDebugStyles) {
ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -172,7 +169,7 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ block = -1;
}
if (kDebugStyles) {
@@ -182,7 +179,9 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+ out_values[STYLE_ASSET_COOKIE] =
+ block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
+ : static_cast<uint32_t>(-1);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -196,80 +195,90 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
out_values += STYLE_NUM_ENTRIES;
}
+ res.unlock();
+
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
return true;
}
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+ uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices) {
if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
- def_style_attr, def_style_resid, xml_parser);
+ ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
+ theme, def_style_attr, def_style_res, xml_parser);
}
- AssetManager2* assetmanager = theme->GetAssetManager();
+ const ResTable& res = theme->getResTable();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
+ uint32_t def_style_bag_type_set_flags = 0;
if (def_style_attr != 0) {
Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+ if (theme->getAttribute(def_style_attr, &value,
+ &def_style_bag_type_set_flags) >= 0) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
+ def_style_res = value.data;
}
}
}
- // Retrieve the style resource ID associated with the current XML tag's style attribute.
- uint32_t style_resid = 0u;
- uint32_t style_flags = 0u;
+ // Retrieve the style class associated with the current XML tag.
+ int style = 0;
+ uint32_t style_bag_type_set_flags = 0;
if (xml_parser != nullptr) {
ssize_t idx = xml_parser->indexOfStyle();
if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
if (value.dataType == value.TYPE_ATTRIBUTE) {
- // Resolve the attribute with out theme.
- if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
+ if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
value.dataType = Res_value::TYPE_NULL;
}
}
-
if (value.dataType == value.TYPE_REFERENCE) {
- style_resid = value.data;
+ style = value.data;
}
}
}
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_resid != 0) {
- default_style_bag = assetmanager->GetBag(def_style_resid);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
- }
- }
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
- BagAttributeFinder def_style_attr_finder(default_style_bag);
+ // Retrieve the default style bag, if requested.
+ const ResTable::bag_entry* def_style_attr_start = nullptr;
+ uint32_t def_style_type_set_flags = 0;
+ ssize_t bag_off = def_style_res != 0
+ ? res.getBagLocked(def_style_res, &def_style_attr_start,
+ &def_style_type_set_flags)
+ : -1;
+ def_style_type_set_flags |= def_style_bag_type_set_flags;
+ const ResTable::bag_entry* const def_style_attr_end =
+ def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
+ BagAttributeFinder def_style_attr_finder(def_style_attr_start,
+ def_style_attr_end);
// Retrieve the style class bag, if requested.
- const ResolvedBag* xml_style_bag = nullptr;
- if (style_resid != 0) {
- xml_style_bag = assetmanager->GetBag(style_resid);
- if (xml_style_bag != nullptr) {
- style_flags |= xml_style_bag->type_spec_flags;
- }
- }
-
- BagAttributeFinder xml_style_attr_finder(xml_style_bag);
+ const ResTable::bag_entry* style_attr_start = nullptr;
+ uint32_t style_type_set_flags = 0;
+ bag_off =
+ style != 0
+ ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
+ : -1;
+ style_type_set_flags |= style_bag_type_set_flags;
+ const ResTable::bag_entry* const style_attr_end =
+ style_attr_start + (bag_off >= 0 ? bag_off : 0);
+ BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
// Retrieve the XML attributes, if requested.
+ static const ssize_t kXmlBlock = 0x10000000;
XmlAttributeFinder xml_attr_finder(xml_parser);
+ const size_t xml_attr_end =
+ xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -280,8 +289,8 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
+ ssize_t block = kXmlBlock;
+ uint32_t type_set_flags = 0;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -293,7 +302,7 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
// Walk through the xml attributes looking for the requested attribute.
const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
- if (xml_attr_idx != xml_attr_finder.end()) {
+ if (xml_attr_idx != xml_attr_end) {
// We found the attribute we were looking for.
xml_parser->getAttributeValue(xml_attr_idx, &value);
if (kDebugStyles) {
@@ -303,12 +312,12 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the style class values looking for the requested attribute.
- const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
- if (entry != xml_style_attr_finder.end()) {
+ const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
+ if (style_attr_entry != style_attr_end) {
// We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = style_flags;
- value = entry->value;
+ block = style_attr_entry->stringBlock;
+ type_set_flags = style_type_set_flags;
+ value = style_attr_entry->map.value;
if (kDebugStyles) {
ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -317,25 +326,25 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the default style values looking for the requested attribute.
- const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
- if (entry != def_style_attr_finder.end()) {
+ const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
+ if (def_style_attr_entry != def_style_attr_end) {
// We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
+ block = def_style_attr_entry->stringBlock;
+ type_set_flags = style_type_set_flags;
+ value = def_style_attr_entry->map.value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
- uint32_t resid = 0u;
+ uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ ssize_t new_block =
+ theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+ if (new_block >= 0) {
+ block = new_block;
}
if (kDebugStyles) {
@@ -343,15 +352,14 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- if (new_cookie != kInvalidCookie) {
+ ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+ if (new_block >= 0) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+ if (new_block >= 0) {
+ block = new_block;
}
if (kDebugStyles) {
@@ -367,7 +375,7 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ block = kXmlBlock;
}
if (kDebugStyles) {
@@ -377,7 +385,9 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+ out_values[STYLE_ASSET_COOKIE] =
+ block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
+ : static_cast<uint32_t>(-1);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -392,28 +402,36 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
out_values += STYLE_NUM_ENTRIES;
}
+ res.unlock();
+
// out_indices must NOT be nullptr.
out_indices[0] = indices_idx;
}
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
+ uint32_t* attrs, size_t attrs_length,
+ uint32_t* out_values, uint32_t* out_indices) {
ResTable_config config;
Res_value value;
int indices_idx = 0;
+ // Now lock down the resource object and start pulling stuff from it.
+ res->lock();
+
// Retrieve the XML attributes, if requested.
const size_t xml_attr_count = xml_parser->getAttributeCount();
size_t ix = 0;
uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
+ static const ssize_t kXmlBlock = 0x10000000;
+
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
+ ssize_t block = kXmlBlock;
+ uint32_t type_set_flags = 0;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -432,27 +450,28 @@ bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, u
cur_xml_attr = xml_parser->getAttributeNameResID(ix);
}
- uint32_t resid = 0u;
+ uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
+ // printf("Resolving attribute reference\n");
+ ssize_t new_block = res->resolveReference(&value, block, &resid,
+ &type_set_flags, &config);
+ if (new_block >= 0) block = new_block;
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ block = kXmlBlock;
}
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+ out_values[STYLE_ASSET_COOKIE] =
+ block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
+ : static_cast<uint32_t>(-1);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -466,6 +485,8 @@ bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, u
out_values += STYLE_NUM_ENTRIES;
}
+ res->unlock();
+
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 1d2c597c4c8c..28548e27baf0 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -44,6 +44,44 @@ namespace android {
constexpr const static int kAppPackageId = 0x7f;
+// Element of a TypeSpec array. See TypeSpec.
+struct Type {
+ // The configuration for which this type defines entries.
+ // This is already converted to host endianness.
+ ResTable_config configuration;
+
+ // Pointer to the mmapped data where entry definitions are kept.
+ const ResTable_type* type;
+};
+
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+ // Pointer to the mmapped data where flags are kept.
+ // Flags denote whether the resource entry is public
+ // and under which configurations it varies.
+ const ResTable_typeSpec* type_spec;
+
+ // Pointer to the mmapped data where the IDMAP mappings for this type
+ // exist. May be nullptr if no IDMAP exists.
+ const IdmapEntry_header* idmap_entries;
+
+ // The number of types that follow this struct.
+ // There is a type for each configuration
+ // that entries are defined for.
+ size_t type_count;
+
+ // Trick to easily access a variable number of Type structs
+ // proceeding this struct, and to ensure their alignment.
+ const Type types[0];
+};
+
+// TypeSpecPtr points to the block of memory that holds
+// a TypeSpec struct, followed by an array of Type structs.
+// TypeSpecPtr is a managed pointer that knows how to delete
+// itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+
namespace {
// Builder that helps accumulate Type structs and then create a single
@@ -57,22 +95,21 @@ class TypeSpecPtrBuilder {
}
void AddType(const ResTable_type* type) {
- types_.push_back(type);
+ ResTable_config config;
+ config.copyFromDtoH(type->config);
+ types_.push_back(Type{config, type});
}
TypeSpecPtr Build() {
// Check for overflow.
- using ElementType = const ResTable_type*;
- if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
- types_.size()) {
+ if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
return {};
}
- TypeSpec* type_spec =
- (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType)));
+ TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
type_spec->type_spec = header_;
type_spec->idmap_entries = idmap_header_;
type_spec->type_count = types_.size();
- memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType));
+ memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
return TypeSpecPtr(type_spec);
}
@@ -81,7 +118,7 @@ class TypeSpecPtrBuilder {
const ResTable_typeSpec* header_;
const IdmapEntry_header* idmap_header_;
- std::vector<const ResTable_type*> types_;
+ std::vector<Type> types_;
};
} // namespace
@@ -125,17 +162,18 @@ static bool VerifyResTableType(const ResTable_type* header) {
return true;
}
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
+static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset,
+ size_t entry_idx) {
// Check that the offset is aligned.
if (entry_offset & 0x03) {
- LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
+ LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned.";
return false;
}
// Check that the offset doesn't overflow.
if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
// Overflow in offset.
- LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
+ LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large.";
return false;
}
@@ -143,7 +181,7 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
entry_offset += dtohl(type->entriesStart);
if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
- LOG(ERROR) << "Entry at offset " << entry_offset
+ LOG(ERROR) << "Entry offset at index " << entry_idx
<< " is too large. No room for ResTable_entry.";
return false;
}
@@ -153,13 +191,13 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
const size_t entry_size = dtohs(entry->size);
if (entry_size < sizeof(*entry)) {
- LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+ LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
<< " is too small.";
return false;
}
if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
- LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+ LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
<< " is too large.";
return false;
}
@@ -167,7 +205,7 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
if (entry_size < sizeof(ResTable_map_entry)) {
// There needs to be room for one Res_value struct.
if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
- LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
+ LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx
<< " for type " << (int)type->id << ".";
return false;
}
@@ -176,12 +214,12 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
const size_t value_size = dtohs(value->size);
if (value_size < sizeof(Res_value)) {
- LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
+ LOG(ERROR) << "Res_value at index " << entry_idx << " is too small.";
return false;
}
if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
- LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
+ LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx
<< " is too large.";
return false;
}
@@ -190,76 +228,119 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
const size_t map_entry_count = dtohl(map->count);
size_t map_entries_start = entry_offset + entry_size;
if (map_entries_start & 0x03) {
- LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
+ LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset.";
return false;
}
// Each entry is sizeof(ResTable_map) big.
if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
- LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
+ LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << ".";
return false;
}
}
return true;
}
-const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
- uint16_t entry_index) {
- uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
- if (entry_offset == ResTable_type::NO_ENTRY) {
- return nullptr;
- }
- return GetEntryFromOffset(type_chunk, entry_offset);
-}
-
-uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const size_t entry_count = dtohl(type_chunk->entryCount);
- const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
+ const ResTable_config& config, FindEntryResult* out_entry) const {
+ const ResTable_config* best_config = nullptr;
+ const ResTable_type* best_type = nullptr;
+ uint32_t best_offset = 0;
+
+ for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
+ const Type* type = &type_spec_ptr->types[i];
+ const ResTable_type* type_chunk = type->type;
+
+ if (type->configuration.match(config) &&
+ (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const size_t entry_count = dtohl(type_chunk->entryCount);
+ const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+
+ // Check if there is the desired entry in this type.
+
+ if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
+ // This is encoded as a sparse map, so perform a binary search.
+ const ResTable_sparseTypeEntry* sparse_indices =
+ reinterpret_cast<const ResTable_sparseTypeEntry*>(
+ reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
+ const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
+ const ResTable_sparseTypeEntry* result =
+ std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
+ [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
+ return dtohs(entry.idx) < entry_idx;
+ });
+
+ if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
+ // No entry found.
+ continue;
+ }
- // Check if there is the desired entry in this type.
+ // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
+ // the real offset divided by 4.
+ best_offset = uint32_t{dtohs(result->offset)} * 4u;
+ } else {
+ if (entry_idx >= entry_count) {
+ // This entry cannot be here.
+ continue;
+ }
- if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
- // This is encoded as a sparse map, so perform a binary search.
- const ResTable_sparseTypeEntry* sparse_indices =
- reinterpret_cast<const ResTable_sparseTypeEntry*>(
+ const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
- const ResTable_sparseTypeEntry* result =
- std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
- [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
- return dtohs(entry.idx) < entry_idx;
- });
-
- if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
- // No entry found.
- return ResTable_type::NO_ENTRY;
+ const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ // There is an entry for this resource, record it.
+ best_offset = offset;
+ }
+
+ best_config = &type->configuration;
+ best_type = type_chunk;
}
+ }
- // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
- // the real offset divided by 4.
- return uint32_t{dtohs(result->offset)} * 4u;
+ if (best_type == nullptr) {
+ return false;
}
- // This type is encoded as a dense array.
- if (entry_index >= entry_count) {
- // This entry cannot be here.
- return ResTable_type::NO_ENTRY;
+ if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) {
+ return false;
}
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- return dtohl(entry_offsets[entry_index]);
+ const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
+ reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart));
+
+ const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1);
+ out_entry->type_flags = dtohl(flags[entry_idx]);
+ out_entry->entry = best_entry;
+ out_entry->config = best_config;
+ out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
+ out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
+ return true;
}
-const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
- uint32_t offset) {
- if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
- return nullptr;
+bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+ FindEntryResult* out_entry) const {
+ ATRACE_CALL();
+
+ // If the type IDs are offset in this package, we need to take that into account when searching
+ // for a type.
+ const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
+ if (UNLIKELY(ptr == nullptr)) {
+ return false;
}
- return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
- offset + dtohl(type_chunk->entriesStart));
+
+ // If there is an IDMAP supplied with this package, translate the entry ID.
+ if (ptr->idmap_entries != nullptr) {
+ if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
+ // There is no mapping, so the resource is not meant to be in this overlay package.
+ return false;
+ }
+ }
+ return FindEntry(ptr, entry_idx, config, out_entry);
}
void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
@@ -267,7 +348,7 @@ void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
const static std::u16string kMipMap = u"mipmap";
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
- const TypeSpecPtr& type_spec = type_specs_[i];
+ const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
if (type_spec != nullptr) {
if (exclude_mipmap) {
const int type_idx = type_spec->type_spec->id - 1;
@@ -288,11 +369,8 @@ void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
}
}
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config config;
- config.copyFromDtoH((*iter)->config);
- out_configs->insert(config);
+ for (size_t j = 0; j < type_spec->type_count; j++) {
+ out_configs->insert(type_spec->types[j].configuration);
}
}
}
@@ -302,12 +380,10 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out
char temp_locale[RESTABLE_MAX_LOCALE_LEN];
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
- const TypeSpecPtr& type_spec = type_specs_[i];
+ const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
if (type_spec != nullptr) {
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config configuration;
- configuration.copyFromDtoH((*iter)->config);
+ for (size_t j = 0; j < type_spec->type_count; j++) {
+ const ResTable_config& configuration = type_spec->types[j].configuration;
if (configuration.locale != 0) {
configuration.getBcp47Locale(temp_locale, canonicalize);
std::string locale(temp_locale);
@@ -335,17 +411,17 @@ uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
return 0u;
}
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- const ResTable_type* type = *iter;
- size_t entry_count = dtohl(type->entryCount);
+ for (size_t ti = 0; ti < type_spec->type_count; ti++) {
+ const Type* type = &type_spec->types[ti];
+ size_t entry_count = dtohl(type->type->entryCount);
for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
+ reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
const uint32_t offset = dtohl(entry_offsets[entry_idx]);
if (offset != ResTable_type::NO_ENTRY) {
- const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
+ const ResTable_entry* entry =
+ reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
+ dtohl(type->type->entriesStart) + offset);
if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
// The package ID will be overridden by the caller (due to runtime assignment of package
// IDs for shared libraries).
@@ -357,7 +433,8 @@ uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
return 0u;
}
-const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
+const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
+ const uint8_t package_id = get_package_id(resid);
for (const auto& loaded_package : packages_) {
if (loaded_package->GetPackageId() == package_id) {
return loaded_package.get();
@@ -605,6 +682,26 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
return std::move(loaded_package);
}
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
+ FindEntryResult* out_entry) const {
+ ATRACE_CALL();
+
+ const uint8_t package_id = get_package_id(resid);
+ const uint8_t type_id = get_type_id(resid);
+ const uint16_t entry_id = get_entry_id(resid);
+
+ if (UNLIKELY(type_id == 0)) {
+ LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
+ return false;
+ }
+
+ for (const auto& loaded_package : packages_) {
+ if (loaded_package->GetPackageId() == package_id) {
+ return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry);
+ }
+ }
+ return false;
+}
bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
bool load_as_shared_library) {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ef08897d997a..b033137b4764 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -69,8 +69,6 @@ struct ResolvedBag {
Entry entries[0];
};
-struct FindEntryResult;
-
// AssetManager2 is the main entry point for accessing assets and resources.
// AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
class AssetManager2 {
@@ -129,7 +127,7 @@ class AssetManager2 {
// If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
// will be excluded from the list.
std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
- bool exclude_mipmap = false) const;
+ bool exclude_mipmap = false);
// Returns all the locales for which there are resources defined. This includes resource
// locales in all the ApkAssets set for this AssetManager.
@@ -138,24 +136,24 @@ class AssetManager2 {
// If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
// and de-duped in the resulting list.
std::set<std::string> GetResourceLocales(bool exclude_system = false,
- bool merge_equivalent_languages = false) const;
+ bool merge_equivalent_languages = false);
// Searches the set of APKs loaded by this AssetManager and opens the first one found located
// in the assets/ directory.
// `mode` controls how the file is opened.
//
// NOTE: The loaded APKs are searched in reverse order.
- std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const;
+ std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
// Opens a file within the assets/ directory of the APK specified by `cookie`.
// `mode` controls how the file is opened.
std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode) const;
+ Asset::AccessMode mode);
// Opens the directory specified by `dirname`. The result is an AssetDir that is the combination
// of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded.
// The entries are sorted by their ASCII name.
- std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const;
+ std::unique_ptr<AssetDir> OpenDir(const std::string& dirname);
// Searches the set of APKs loaded by this AssetManager and opens the first one found.
// `mode` controls how the file is opened.
@@ -163,24 +161,24 @@ class AssetManager2 {
//
// NOTE: The loaded APKs are searched in reverse order.
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
- ApkAssetsCookie* out_cookie = nullptr) const;
+ ApkAssetsCookie* out_cookie = nullptr);
// Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
// This is typically used to open a specific AndroidManifest.xml, or a binary XML file
// referenced by a resource lookup with GetResource().
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode) const;
+ Asset::AccessMode mode);
// Populates the `out_name` parameter with resource name information.
// Utf8 strings are preferred, and only if they are unavailable are
// the Utf16 variants populated.
// Returns false if the resource was not found or the name was missing/corrupt.
- bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
+ bool GetResourceName(uint32_t resid, ResourceName* out_name);
// Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
// See ResTable_config for the list of configuration axis.
// Returns false if the resource was not found.
- bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
+ bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
// Finds the resource ID assigned to `resource_name`.
// `resource_name` must be of the form '[package:][type/]entry'.
@@ -188,7 +186,7 @@ class AssetManager2 {
// If no type is specified in `resource_name`, then `fallback_type` is used as the type.
// Returns 0x0 if no resource by that name was found.
uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
- const std::string& fallback_package = {}) const;
+ const std::string& fallback_package = {});
// Retrieves the best matching resource with ID `resid`. The resource value is filled into
// `out_value` and the configuration for the selected value is populated in `out_selected_config`.
@@ -201,7 +199,7 @@ class AssetManager2 {
// this function logs if the resource was a map/bag type before returning kInvalidCookie.
ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
Res_value* out_value, ResTable_config* out_selected_config,
- uint32_t* out_flags) const;
+ uint32_t* out_flags);
// Resolves the resource reference in `in_out_value` if the data type is
// Res_value::TYPE_REFERENCE.
@@ -217,7 +215,7 @@ class AssetManager2 {
// it was not found.
ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
- uint32_t* out_last_reference) const;
+ uint32_t* out_last_reference);
// Retrieves the best matching bag/map resource with ID `resid`.
// This method will resolve all parent references for this bag and merge keys with the child.
@@ -235,9 +233,9 @@ class AssetManager2 {
std::unique_ptr<Theme> NewTheme();
template <typename Func>
- void ForEachPackage(Func func) const {
+ void ForEachPackage(Func func) {
for (const PackageGroup& package_group : package_groups_) {
- func(package_group.packages_.front().loaded_package_->GetPackageName(),
+ func(package_group.packages_.front()->GetPackageName(),
package_group.dynamic_ref_table.mAssignedPackageId);
}
}
@@ -262,7 +260,7 @@ class AssetManager2 {
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- FindEntryResult* out_entry) const;
+ FindEntryResult* out_entry);
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
@@ -272,43 +270,13 @@ class AssetManager2 {
// bitmask `diff`.
void InvalidateCaches(uint32_t diff);
- // Triggers the re-construction of lists of types that match the set configuration.
- // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
- void RebuildFilterList();
-
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
std::vector<const ApkAssets*> apk_assets_;
- // A collection of configurations and their associated ResTable_type that match the current
- // AssetManager configuration.
- struct FilteredConfigGroup {
- std::vector<ResTable_config> configurations;
- std::vector<const ResTable_type*> types;
- };
-
- // Represents an single package.
- struct ConfiguredPackage {
- // A pointer to the immutable, loaded package info.
- const LoadedPackage* loaded_package_;
-
- // A mutable AssetManager-specific list of configurations that match the AssetManager's
- // current configuration. This is used as an optimization to avoid checking every single
- // candidate configuration when looking up resources.
- ByteBucketArray<FilteredConfigGroup> filtered_configs_;
- };
-
- // Represents a logical package, which can be made up of many individual packages. Each package
- // in a PackageGroup shares the same package name and package ID.
struct PackageGroup {
- // The set of packages that make-up this group.
- std::vector<ConfiguredPackage> packages_;
-
- // The cookies associated with each package in the group. They share the same order as
- // packages_.
+ std::vector<const LoadedPackage*> packages_;
std::vector<ApkAssetsCookie> cookies_;
-
- // A library reference table that contains build-package ID to runtime-package ID mappings.
DynamicRefTable dynamic_ref_table;
};
@@ -382,7 +350,7 @@ class Theme {
ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config = nullptr,
uint32_t* in_out_type_spec_flags = nullptr,
- uint32_t* out_last_ref = nullptr) const;
+ uint32_t* out_last_ref = nullptr);
private:
DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
index 03fad4947dfe..f281921824e7 100644
--- a/libs/androidfw/include/androidfw/AttributeFinder.h
+++ b/libs/androidfw/include/androidfw/AttributeFinder.h
@@ -58,7 +58,6 @@ class BackTrackingAttributeFinder {
BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
Iterator Find(uint32_t attr);
- inline Iterator end();
private:
void JumpToClosestAttribute(uint32_t package_id);
@@ -202,11 +201,6 @@ Iterator BackTrackingAttributeFinder<Derived, Iterator>::Find(uint32_t attr) {
return end_;
}
-template <typename Derived, typename Iterator>
-Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() {
- return end_;
-}
-
} // namespace android
#endif // ANDROIDFW_ATTRIBUTE_FINDER_H
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d8c704..69b760414846 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -17,8 +17,7 @@
#ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
#define ANDROIDFW_ATTRIBUTERESOLUTION_H
-#include "androidfw/AssetManager2.h"
-#include "androidfw/ResourceTypes.h"
+#include <androidfw/ResourceTypes.h>
namespace android {
@@ -43,19 +42,19 @@ enum {
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+ uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
} // namespace android
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fcd9e7b..965e2dbd2fb2 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -41,40 +41,32 @@ class DynamicPackageEntry {
int package_id = 0;
};
-// TypeSpec is going to be immediately proceeded by
-// an array of Type structs, all in the same block of memory.
-struct TypeSpec {
- // Pointer to the mmapped data where flags are kept.
- // Flags denote whether the resource entry is public
- // and under which configurations it varies.
- const ResTable_typeSpec* type_spec;
-
- // Pointer to the mmapped data where the IDMAP mappings for this type
- // exist. May be nullptr if no IDMAP exists.
- const IdmapEntry_header* idmap_entries;
-
- // The number of types that follow this struct.
- // There is a type for each configuration that entries are defined for.
- size_t type_count;
-
- // Trick to easily access a variable number of Type structs
- // proceeding this struct, and to ensure their alignment.
- const ResTable_type* types[0];
-
- inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
- if (entry_index >= dtohl(type_spec->entryCount)) {
- return 0u;
- }
-
- const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
- return flags[entry_index];
- }
+struct FindEntryResult {
+ // A pointer to the resource table entry for this resource.
+ // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+ // a ResTable_map_entry and processed as a bag/map.
+ const ResTable_entry* entry = nullptr;
+
+ // The configuration for which the resulting entry was defined.
+ const ResTable_config* config = nullptr;
+
+ // Stores the resulting bitmask of configuration axis with which the resource value varies.
+ uint32_t type_flags = 0u;
+
+ // The dynamic package ID map for the package from which this resource came from.
+ const DynamicRefTable* dynamic_ref_table = nullptr;
+
+ // The string pool reference to the type's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef type_string_ref;
+
+ // The string pool reference to the entry's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef entry_string_ref;
};
-// TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
-// ResTable_type pointers.
-// TypeSpecPtr is a managed pointer that knows how to delete itself.
-using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+struct TypeSpec;
+class LoadedArsc;
class LoadedPackage {
public:
@@ -84,6 +76,9 @@ class LoadedPackage {
~LoadedPackage();
+ bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+ FindEntryResult* out_entry) const;
+
// Finds the entry with the specified type name and entry name. The names are in UTF-16 because
// the underlying ResStringPool API expects this. For now this is acceptable, but since
// the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
@@ -91,12 +86,6 @@ class LoadedPackage {
// for patching the correct package ID to the resource ID.
uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
- static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
-
- static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
-
- static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
-
// Returns the string pool where type names are stored.
inline const ResStringPool* GetTypeStringPool() const {
return &type_string_pool_;
@@ -146,32 +135,14 @@ class LoadedPackage {
// before being inserted into the set. This may cause some equivalent locales to de-dupe.
void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
- // type_idx is TT - 1 from 0xPPTTEEEE.
- inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
- // If the type IDs are offset in this package, we need to take that into account when searching
- // for a type.
- return type_specs_[type_index - type_id_offset_].get();
- }
-
- template <typename Func>
- void ForEachTypeSpec(Func f) const {
- for (size_t i = 0; i < type_specs_.size(); i++) {
- const TypeSpecPtr& ptr = type_specs_[i];
- if (ptr != nullptr) {
- uint8_t type_id = ptr->type_spec->id;
- if (ptr->idmap_entries != nullptr) {
- type_id = ptr->idmap_entries->target_type_id;
- }
- f(ptr.get(), type_id - 1);
- }
- }
- }
-
private:
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
LoadedPackage();
+ bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
+ const ResTable_config& config, FindEntryResult* out_entry) const;
+
ResStringPool type_string_pool_;
ResStringPool key_string_pool_;
std::string package_name_;
@@ -181,7 +152,7 @@ class LoadedPackage {
bool system_ = false;
bool overlay_ = false;
- ByteBucketArray<TypeSpecPtr> type_specs_;
+ ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
};
@@ -209,20 +180,25 @@ class LoadedArsc {
return &global_string_pool_;
}
- // Gets a pointer to the package with the specified package ID, or nullptr if no such package
- // exists.
- const LoadedPackage* GetPackageById(uint8_t package_id) const;
+ // Finds the resource with ID `resid` with the best value for configuration `config`.
+ // The parameter `out_entry` will be filled with the resulting resource entry.
+ // The resource entry can be a simple entry (ResTable_entry) or a complex bag
+ // (ResTable_entry_map).
+ bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const;
- // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
- inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
- return packages_;
- }
+ // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
+ const LoadedPackage* GetPackageForId(uint32_t resid) const;
// Returns true if this is a system provided resource.
inline bool IsSystem() const {
return system_;
}
+ // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
+ inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
+ return packages_;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h
deleted file mode 100644
index 64924f433245..000000000000
--- a/libs/androidfw/include/androidfw/MutexGuard.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROIDFW_MUTEXGUARD_H
-#define ANDROIDFW_MUTEXGUARD_H
-
-#include <mutex>
-#include <type_traits>
-
-#include "android-base/macros.h"
-
-namespace android {
-
-template <typename T>
-class ScopedLock;
-
-// Owns the guarded object and protects access to it via a mutex.
-// The guarded object is inaccessible via this class.
-// The mutex is locked and the object accessed via the ScopedLock<T> class.
-//
-// NOTE: The template parameter T should not be a raw pointer, since ownership
-// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
-//
-// Example use:
-//
-// Guarded<std::string> shared_string("hello");
-// {
-// ScopedLock<std::string> locked_string(shared_string);
-// *locked_string += " world";
-// }
-//
-template <typename T>
-class Guarded {
- static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
-
- public:
- explicit Guarded() : guarded_() {
- }
-
- template <typename U = T>
- explicit Guarded(const T& guarded,
- typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
- : guarded_(guarded) {
- }
-
- template <typename U = T>
- explicit Guarded(T&& guarded,
- typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
- : guarded_(std::move(guarded)) {
- }
-
- private:
- friend class ScopedLock<T>;
-
- DISALLOW_COPY_AND_ASSIGN(Guarded);
-
- std::mutex lock_;
- T guarded_;
-};
-
-template <typename T>
-class ScopedLock {
- public:
- explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
- }
-
- T& operator*() {
- return guarded_;
- }
-
- T* operator->() {
- return &guarded_;
- }
-
- T* get() {
- return &guarded_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ScopedLock);
-
- std::lock_guard<std::mutex> lock_;
- T& guarded_;
-};
-
-} // namespace android
-
-#endif // ANDROIDFW_MUTEXGUARD_H
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index e2b9f0040989..6c43a67e602f 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -26,56 +26,58 @@
using ::android::base::unique_fd;
using ::com::android::basic::R;
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
namespace android {
TEST(ApkAssetsTest, LoadApk) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_THAT(loaded_apk, NotNull());
+ ASSERT_NE(nullptr, loaded_apk);
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_THAT(loaded_arsc, NotNull());
- ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
- ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+ ASSERT_NE(nullptr, loaded_package);
+
+ std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+ ASSERT_NE(nullptr, asset);
}
TEST(ApkAssetsTest, LoadApkFromFd) {
const std::string path = GetTestDataPath() + "/basic/basic.apk";
unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
- ASSERT_THAT(fd.get(), Ge(0));
+ ASSERT_GE(fd.get(), 0);
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
- ASSERT_THAT(loaded_apk, NotNull());
+ ASSERT_NE(nullptr, loaded_apk);
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_THAT(loaded_arsc, NotNull());
- ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
- ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+ ASSERT_NE(nullptr, loaded_package);
+
+ std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+ ASSERT_NE(nullptr, asset);
}
TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
- ASSERT_THAT(loaded_apk, NotNull());
-
+ ASSERT_NE(nullptr, loaded_apk);
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_THAT(loaded_arsc, NotNull());
- ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+ ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
- ASSERT_THAT(loaded_apk, NotNull());
+ ASSERT_NE(nullptr, loaded_apk);
loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_THAT(loaded_arsc, NotNull());
- ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+ ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
}
@@ -84,22 +86,19 @@ TEST(ApkAssetsTest, LoadApkWithIdmap) {
ResTable target_table;
const std::string target_path = GetTestDataPath() + "/basic/basic.apk";
ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents));
- ASSERT_THAT(target_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
- Eq(NO_ERROR));
+ ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
ResTable overlay_table;
const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk";
ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents));
- ASSERT_THAT(overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
- Eq(NO_ERROR));
+ ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
util::unique_cptr<void> idmap_data;
void* temp_data;
size_t idmap_len;
- ASSERT_THAT(target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
- overlay_path.c_str(), &temp_data, &idmap_len),
- Eq(NO_ERROR));
+ ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
+ overlay_path.c_str(), &temp_data, &idmap_len));
idmap_data.reset(temp_data);
TemporaryFile tf;
@@ -109,30 +108,37 @@ TEST(ApkAssetsTest, LoadApkWithIdmap) {
// Open something so that the destructor of TemporaryFile closes a valid fd.
tf.fd = open("/dev/null", O_WRONLY);
- ASSERT_THAT(ApkAssets::LoadOverlay(tf.path), NotNull());
+ std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path);
+ ASSERT_NE(nullptr, loaded_overlay_apk);
}
TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_THAT(loaded_apk, NotNull());
+ ASSERT_NE(nullptr, loaded_apk);
- { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+ {
+ std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+ ASSERT_NE(nullptr, assets);
+ }
- { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+ {
+ std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+ ASSERT_NE(nullptr, assets);
+ }
}
TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_THAT(loaded_apk, NotNull());
+ ASSERT_NE(nullptr, loaded_apk);
auto asset = loaded_apk->Open("assets/uncompressed.txt", Asset::ACCESS_UNKNOWN);
- ASSERT_THAT(asset, NotNull());
+ ASSERT_NE(nullptr, asset);
off64_t start, length;
unique_fd fd(asset->openFileDescriptor(&start, &length));
- ASSERT_THAT(fd.get(), Ge(0));
+ EXPECT_GE(fd.get(), 0);
lseek64(fd.get(), start, SEEK_SET);
@@ -140,7 +146,7 @@ TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
buffer.resize(length);
ASSERT_TRUE(base::ReadFully(fd.get(), &*buffer.begin(), length));
- EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n"));
+ EXPECT_EQ("This should be uncompressed.\n\n", buffer);
}
} // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 437e14772964..85e8f25394e9 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -81,18 +81,17 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) {
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
-static void BM_AssetManagerGetResource(benchmark::State& state, uint32_t resid) {
- GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, state);
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+ GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+ basic::R::integer::number1, state);
}
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResource);
-static void BM_AssetManagerGetResourceOld(benchmark::State& state, uint32_t resid) {
- GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid,
- state);
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+ GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+ basic::R::integer::number1, state);
}
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResourceOld);
static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
GetResourceBenchmark(
@@ -197,7 +196,7 @@ BENCHMARK(BM_AssetManagerGetResourceLocales);
static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
AssetManager assets;
if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
- true /*isSystemAssets*/)) {
+ false /*isSystemAssets*/)) {
state.SkipWithError("Failed to load assets");
return;
}
@@ -212,44 +211,4 @@ static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
}
BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
-static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
- if (apk == nullptr) {
- state.SkipWithError("Failed to load assets");
- return;
- }
-
- AssetManager2 assets;
- assets.SetApkAssets({apk.get()});
-
- ResTable_config config;
- memset(&config, 0, sizeof(config));
-
- while (state.KeepRunning()) {
- config.sdkVersion = ~config.sdkVersion;
- assets.SetConfiguration(config);
- }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFramework);
-
-static void BM_AssetManagerSetConfigurationFrameworkOld(benchmark::State& state) {
- AssetManager assets;
- if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
- true /*isSystemAssets*/)) {
- state.SkipWithError("Failed to load assets");
- return;
- }
-
- const ResTable& table = assets.getResources(true);
-
- ResTable_config config;
- memset(&config, 0, sizeof(config));
-
- while (state.KeepRunning()) {
- config.sdkVersion = ~config.sdkVersion;
- assets.setConfiguration(config);
- }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFrameworkOld);
-
} // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
deleted file mode 100644
index fa300c50218a..000000000000
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "benchmark/benchmark.h"
-
-//#include "android-base/stringprintf.h"
-#include "androidfw/ApkAssets.h"
-#include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
-#include "androidfw/AttributeResolution.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "BenchmarkHelpers.h"
-#include "data/basic/R.h"
-#include "data/styles/R.h"
-
-namespace app = com::android::app;
-namespace basic = com::android::basic;
-
-namespace android {
-
-constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
-constexpr const static uint32_t Theme_Material_Light = 0x01030237u;
-
-static void BM_ApplyStyle(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> styles_apk =
- ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
- if (styles_apk == nullptr) {
- state.SkipWithError("failed to load assets");
- return;
- }
-
- AssetManager2 assetmanager;
- assetmanager.SetApkAssets({styles_apk.get()});
-
- std::unique_ptr<Asset> asset =
- assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- state.SkipWithError("failed to load layout");
- return;
- }
-
- ResXMLTree xml_tree;
- if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
- state.SkipWithError("corrupt xml layout");
- return;
- }
-
- // Skip to the first tag.
- while (xml_tree.next() != ResXMLParser::START_TAG) {
- }
-
- std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- theme->ApplyStyle(app::R::style::StyleTwo);
-
- std::array<uint32_t, 6> attrs{{app::R::attr::attr_one, app::R::attr::attr_two,
- app::R::attr::attr_three, app::R::attr::attr_four,
- app::R::attr::attr_five, app::R::attr::attr_empty}};
- std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- std::array<uint32_t, attrs.size() + 1> indices;
-
- while (state.KeepRunning()) {
- ApplyStyle(theme.get(), &xml_tree, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
- attrs.size(), values.data(), indices.data());
- }
-}
-BENCHMARK(BM_ApplyStyle);
-
-static void BM_ApplyStyleFramework(benchmark::State& state) {
- std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath);
- if (framework_apk == nullptr) {
- state.SkipWithError("failed to load framework assets");
- return;
- }
-
- std::unique_ptr<const ApkAssets> basic_apk =
- ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- if (basic_apk == nullptr) {
- state.SkipWithError("failed to load assets");
- return;
- }
-
- AssetManager2 assetmanager;
- assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()});
-
- ResTable_config device_config;
- memset(&device_config, 0, sizeof(device_config));
- device_config.language[0] = 'e';
- device_config.language[1] = 'n';
- device_config.country[0] = 'U';
- device_config.country[1] = 'S';
- device_config.orientation = ResTable_config::ORIENTATION_PORT;
- device_config.smallestScreenWidthDp = 700;
- device_config.screenWidthDp = 700;
- device_config.screenHeightDp = 1024;
- device_config.sdkVersion = 27;
-
- Res_value value;
- ResTable_config config;
- uint32_t flags = 0u;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
- 0u /*density_override*/, &value, &config, &flags);
- if (cookie == kInvalidCookie) {
- state.SkipWithError("failed to find R.layout.layout");
- return;
- }
-
- size_t len = 0u;
- const char* layout_path =
- assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
- if (layout_path == nullptr || len == 0u) {
- state.SkipWithError("failed to lookup layout path");
- return;
- }
-
- std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
- StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- state.SkipWithError("failed to load layout");
- return;
- }
-
- ResXMLTree xml_tree;
- if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
- state.SkipWithError("corrupt xml layout");
- return;
- }
-
- // Skip to the first tag.
- while (xml_tree.next() != ResXMLParser::START_TAG) {
- }
-
- std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- theme->ApplyStyle(Theme_Material_Light);
-
- std::array<uint32_t, 92> attrs{
- {0x0101000e, 0x01010034, 0x01010095, 0x01010096, 0x01010097, 0x01010098, 0x01010099,
- 0x0101009a, 0x0101009b, 0x010100ab, 0x010100af, 0x010100b0, 0x010100b1, 0x0101011f,
- 0x01010120, 0x0101013f, 0x01010140, 0x0101014e, 0x0101014f, 0x01010150, 0x01010151,
- 0x01010152, 0x01010153, 0x01010154, 0x01010155, 0x01010156, 0x01010157, 0x01010158,
- 0x01010159, 0x0101015a, 0x0101015b, 0x0101015c, 0x0101015d, 0x0101015e, 0x0101015f,
- 0x01010160, 0x01010161, 0x01010162, 0x01010163, 0x01010164, 0x01010165, 0x01010166,
- 0x01010167, 0x01010168, 0x01010169, 0x0101016a, 0x0101016b, 0x0101016c, 0x0101016d,
- 0x0101016e, 0x0101016f, 0x01010170, 0x01010171, 0x01010217, 0x01010218, 0x0101021d,
- 0x01010220, 0x01010223, 0x01010224, 0x01010264, 0x01010265, 0x01010266, 0x010102c5,
- 0x010102c6, 0x010102c7, 0x01010314, 0x01010315, 0x01010316, 0x0101035e, 0x0101035f,
- 0x01010362, 0x01010374, 0x0101038c, 0x01010392, 0x01010393, 0x010103ac, 0x0101045d,
- 0x010104b6, 0x010104b7, 0x010104d6, 0x010104d7, 0x010104dd, 0x010104de, 0x010104df,
- 0x01010535, 0x01010536, 0x01010537, 0x01010538, 0x01010546, 0x01010567, 0x011100c9,
- 0x011100ca}};
-
- std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- std::array<uint32_t, attrs.size() + 1> indices;
- while (state.KeepRunning()) {
- ApplyStyle(theme.get(), &xml_tree, 0x01010084u /*def_style_attr*/, 0u /*def_style_res*/,
- attrs.data(), attrs.size(), values.data(), indices.data());
- }
-}
-BENCHMARK(BM_ApplyStyleFramework);
-
-} // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index cc3053798e7b..2d73ce8f8ee3 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -21,7 +21,6 @@
#include "android-base/file.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
-#include "androidfw/AssetManager2.h"
#include "TestHelpers.h"
#include "data/styles/R.h"
@@ -33,14 +32,15 @@ namespace android {
class AttributeResolutionTest : public ::testing::Test {
public:
virtual void SetUp() override {
- styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
- ASSERT_NE(nullptr, styles_assets_);
- assetmanager_.SetApkAssets({styles_assets_.get()});
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(
+ GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
+ ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
+ 1 /*cookie*/, true /*copyData*/));
}
protected:
- std::unique_ptr<const ApkAssets> styles_assets_;
- AssetManager2 assetmanager_;
+ ResTable table_;
};
class AttributeResolutionXmlTest : public AttributeResolutionTest {
@@ -48,12 +48,13 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest {
virtual void SetUp() override {
AttributeResolutionTest::SetUp();
- std::unique_ptr<Asset> asset =
- assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
- ASSERT_NE(nullptr, asset);
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
+ "res/layout/layout.xml", &contents));
- ASSERT_EQ(NO_ERROR,
- xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
+ ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
+ true /*copyData*/));
// Skip to the first tag.
while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -65,14 +66,14 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest {
};
TEST_F(AttributeResolutionTest, Theme) {
- std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ResTable::Theme theme(table_);
+ ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
+ ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
attrs.size(), values.data(), nullptr /*out_indices*/));
@@ -125,8 +126,8 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
- values.data(), nullptr /*out_indices*/));
+ ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
+ nullptr /*out_indices*/));
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -170,15 +171,15 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
}
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
- std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ResTable::Theme theme(table_);
+ ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
+ ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
attrs.size(), values.data(), indices.data());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index faddfe599af4..7149beef797f 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -33,21 +33,19 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab
}
}
- // Make sure to force creation of the ResTable first, or else the configuration doesn't get set.
- const ResTable& table = assetmanager.getResources(true);
if (config != nullptr) {
assetmanager.setConfiguration(*config);
}
+ const ResTable& table = assetmanager.getResources(true);
+
Res_value value;
ResTable_config selected_config;
uint32_t flags;
- uint32_t last_ref = 0u;
while (state.KeepRunning()) {
- ssize_t block = table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
- &selected_config);
- table.resolveReference(&value, block, &last_ref, &flags, &selected_config);
+ table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
+ &selected_config);
}
}
@@ -74,12 +72,10 @@ void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_
Res_value value;
ResTable_config selected_config;
uint32_t flags;
- uint32_t last_id = 0u;
while (state.KeepRunning()) {
- ApkAssetsCookie cookie = assetmanager.GetResource(
- resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
- assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
+ assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
+ &selected_config, &flags);
}
}
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index bedebd66cb2f..37ddafb14fd3 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,8 +16,6 @@
#include "androidfw/LoadedArsc.h"
-#include "androidfw/ResourceUtils.h"
-
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
@@ -29,13 +27,6 @@ namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
namespace sparse = com::android::sparse;
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
-
namespace android {
TEST(LoadedArscTest, LoadSinglePackageArsc) {
@@ -44,24 +35,39 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName());
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+ config.sdkVersion = 24;
+
+ FindEntryResult entry;
- const LoadedPackage* package =
- loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
- ASSERT_THAT(package, NotNull());
- EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
- EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
+ ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry));
+ ASSERT_NE(nullptr, entry.entry);
+}
- const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
- const uint16_t entry_index = get_entry_id(app::R::string::string_one);
+TEST(LoadedArscTest, FindDefaultEntry) {
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
- const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
- ASSERT_THAT(type_spec, NotNull());
- ASSERT_THAT(type_spec->type_count, Ge(1u));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+ desired_config.language[0] = 'd';
+ desired_config.language[1] = 'e';
+
+ FindEntryResult entry;
+ ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry));
+ ASSERT_NE(nullptr, entry.entry);
}
TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -70,22 +76,15 @@ TEST(LoadedArscTest, LoadSparseEntryApp) {
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_THAT(loaded_arsc, NotNull());
-
- const LoadedPackage* package =
- loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
- ASSERT_THAT(package, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
- const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
- const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+ config.sdkVersion = 26;
- const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
- ASSERT_THAT(type_spec, NotNull());
- ASSERT_THAT(type_spec->type_count, Ge(1u));
-
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ FindEntryResult entry;
+ ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
+ ASSERT_NE(nullptr, entry.entry);
}
TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -94,13 +93,14 @@ TEST(LoadedArscTest, LoadSharedLibrary) {
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_THAT(packages, SizeIs(1u));
+ ASSERT_EQ(1u, packages.size());
+
EXPECT_TRUE(packages[0]->IsDynamic());
- EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
- EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
+ EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName());
+ EXPECT_EQ(0, packages[0]->GetPackageId());
const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
@@ -114,23 +114,25 @@ TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
"resources.arsc", &contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_THAT(packages, SizeIs(1u));
+ ASSERT_EQ(1u, packages.size());
+
EXPECT_FALSE(packages[0]->IsDynamic());
- EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
- EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+ EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName());
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
// The library has two dependencies.
- ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
- EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
- EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
+ ASSERT_EQ(2u, dynamic_pkg_map.size());
- EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
- EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
+ EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name);
+ EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id);
+
+ EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name);
+ EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id);
}
TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
@@ -141,12 +143,13 @@ TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
std::unique_ptr<const LoadedArsc> loaded_arsc =
LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
true /*load_as_shared_library*/);
- ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_THAT(packages, SizeIs(1u));
+ ASSERT_EQ(1u, packages.size());
+
EXPECT_TRUE(packages[0]->IsDynamic());
- EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+ EXPECT_EQ(0x7f, packages[0]->GetPackageId());
}
TEST(LoadedArscTest, LoadFeatureSplit) {
@@ -154,27 +157,21 @@ TEST(LoadedArscTest, LoadFeatureSplit) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_NE(nullptr, loaded_arsc);
- const LoadedPackage* package =
- loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
- ASSERT_THAT(package, NotNull());
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
- uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
- uint8_t entry_index = get_entry_id(basic::R::string::test3);
-
- const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
- ASSERT_THAT(type_spec, NotNull());
- ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
+ FindEntryResult entry;
+ ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry));
size_t len;
- const char16_t* type_name16 =
- package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
- ASSERT_THAT(type_name16, NotNull());
- EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
+ const char16_t* type_name16 = entry.type_string_ref.string16(&len);
+ ASSERT_NE(nullptr, type_name16);
+ ASSERT_NE(0u, len);
- ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
+ std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len));
+ EXPECT_EQ(std::string("string"), type_name);
}
class MockLoadedIdmap : public LoadedIdmap {
@@ -202,33 +199,23 @@ class MockLoadedIdmap : public LoadedIdmap {
};
TEST(LoadedArscTest, LoadOverlay) {
- std::string contents;
+ std::string contents, overlay_contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
- &contents));
+ &overlay_contents));
MockLoadedIdmap loaded_idmap;
std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
- ASSERT_THAT(loaded_arsc, NotNull());
-
- const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
- ASSERT_THAT(package, NotNull());
-
- const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
- ASSERT_THAT(type_spec, NotNull());
- ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
-
- // The entry being overlaid doesn't exist at the original entry index.
- ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
-
- // Since this is an overlay, the actual entry ID must be mapped.
- ASSERT_THAT(type_spec->idmap_entries, NotNull());
- uint16_t target_entry_id = 0u;
- ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
- ASSERT_THAT(target_entry_id, Eq(0x0u));
- ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
+ LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap);
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+
+ FindEntryResult entry;
+ ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry));
}
// structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index df0c642f4565..43a995536d89 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -20,7 +20,6 @@
#include <string>
#include "androidfw/ResourceTypes.h"
-#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "CommonHelpers.h"
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index b7e814fea079..94a2a14ced87 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -34,7 +34,6 @@ struct R {
struct layout {
enum : uint32_t {
main = 0x7f020000,
- layoutt = 0x7f020001,
};
};
@@ -56,7 +55,6 @@ struct R {
number2 = 0x7f040001,
ref1 = 0x7f040002,
ref2 = 0x7f040003,
- deep_ref = 0x7f040004,
// From feature
number3 = 0x80030000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 1733b6a16546..18ef75e91ded 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/layout/layout.xml b/libs/androidfw/tests/data/basic/res/layout/layout.xml
deleted file mode 100644
index 045ede454bca..000000000000
--- a/libs/androidfw/tests/data/basic/res/layout/layout.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ok"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:layout_marginStart="2dip"
- android:layout_marginEnd="2dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold"
- android:text="@android:string/ok" /> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index b3435629265b..6c474596b5cd 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -22,7 +22,6 @@
<attr name="attr2" format="reference|integer" />
<public type="layout" name="main" id="0x7f020000" />
- <public type="layout" name="layout" id="0x7f020001" />
<public type="string" name="test1" id="0x7f030000" />
<string name="test1">test1</string>
@@ -44,18 +43,6 @@
<public type="integer" name="ref2" id="0x7f040003" />
<integer name="ref2">12000</integer>
- <public type="integer" name="deep_ref" id="0x7f040004" />
- <integer name="deep_ref">@integer/deep_ref_1</integer>
- <integer name="deep_ref_1">@integer/deep_ref_2</integer>
- <integer name="deep_ref_2">@integer/deep_ref_3</integer>
- <integer name="deep_ref_3">@integer/deep_ref_4</integer>
- <integer name="deep_ref_4">@integer/deep_ref_5</integer>
- <integer name="deep_ref_5">@integer/deep_ref_6</integer>
- <integer name="deep_ref_6">@integer/deep_ref_7</integer>
- <integer name="deep_ref_7">@integer/deep_ref_8</integer>
- <integer name="deep_ref_8">@integer/deep_ref_9</integer>
- <integer name="deep_ref_9">100</integer>
-
<public type="style" name="Theme1" id="0x7f050000" />
<style name="Theme1">
<item name="com.android.basic:attr1">100</item>
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index e70d5ea0d566..98e9a42d944d 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,11 +18,9 @@
#include <utils/Log.h>
#include <android/asset_manager_jni.h>
-#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/Asset.h>
#include <androidfw/AssetDir.h>
#include <androidfw/AssetManager.h>
-#include <androidfw/AssetManager2.h>
#include <utils/threads.h>
#include "jni.h"
@@ -37,20 +35,21 @@ using namespace android;
// -----
struct AAssetDir {
- std::unique_ptr<AssetDir> mAssetDir;
+ AssetDir* mAssetDir;
size_t mCurFileIndex;
String8 mCachedFileName;
- explicit AAssetDir(std::unique_ptr<AssetDir> dir) :
- mAssetDir(std::move(dir)), mCurFileIndex(0) { }
+ explicit AAssetDir(AssetDir* dir) : mAssetDir(dir), mCurFileIndex(0) { }
+ ~AAssetDir() { delete mAssetDir; }
};
// -----
struct AAsset {
- std::unique_ptr<Asset> mAsset;
+ Asset* mAsset;
- explicit AAsset(std::unique_ptr<Asset> asset) : mAsset(std::move(asset)) { }
+ explicit AAsset(Asset* asset) : mAsset(asset) { }
+ ~AAsset() { delete mAsset; }
};
// -------------------- Public native C API --------------------
@@ -105,18 +104,19 @@ AAsset* AAssetManager_open(AAssetManager* amgr, const char* filename, int mode)
return NULL;
}
- ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
- std::unique_ptr<Asset> asset = locked_mgr->Open(filename, amMode);
- if (asset == nullptr) {
- return nullptr;
+ AssetManager* mgr = static_cast<AssetManager*>(amgr);
+ Asset* asset = mgr->open(filename, amMode);
+ if (asset == NULL) {
+ return NULL;
}
- return new AAsset(std::move(asset));
+
+ return new AAsset(asset);
}
AAssetDir* AAssetManager_openDir(AAssetManager* amgr, const char* dirName)
{
- ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
- return new AAssetDir(locked_mgr->OpenDir(dirName));
+ AssetManager* mgr = static_cast<AssetManager*>(amgr);
+ return new AAssetDir(mgr->openDir(dirName));
}
/**
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 52d0e08e4e7f..b32be736533b 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,9 +24,8 @@
#include <utils/misc.h>
#include <inttypes.h>
-#include <android-base/macros.h>
#include <androidfw/Asset.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
#include <android-base/macros.h>
@@ -1665,22 +1664,18 @@ nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con, jlong nati
static jlong
nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
{
- Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+ AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
- std::unique_ptr<Asset> asset;
- {
- ScopedLock<AssetManager2> locked_mgr(*mgr);
- asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- return 0;
- }
+ Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ return 0;
}
- jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset.release());
+ jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
return id;
}
@@ -1757,25 +1752,22 @@ static jlong
nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
jfloat fontSize, jint dpi)
{
- Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+ AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
- std::unique_ptr<Asset> asset;
- {
- ScopedLock<AssetManager2> locked_mgr(*mgr);
- asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- return 0;
- }
+ Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ return 0;
}
jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
str.c_str(), str.length(),
fontSize, dpi,
asset->getBuffer(false), asset->getLength());
+ delete asset;
return id;
}