Surface <overlayable> info in Java AssetManager
Add a new, hidden method to AssetManager to extract a mapping
overlayable name -> overlayable actor for all <overlayable> blocks in a
package. [This will eventually be used to check if the caller of the OMS
AIDL API is the registered actor for a given overlay.]
Also, teach AssetManager2 to not accept packages that re-use the same
overlayable name. [Such packages have always been ill-formed.]
Bug: 123894537
Test: make libandroidfw_tests
Change-Id: I1117fd3503f04fe4c73eb7114901e022508f4d9e
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d493ddf..a212f47 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -104,6 +104,12 @@
jfieldID mScreenHeightDpOffset;
} gConfigurationOffsets;
+static struct arraymap_offsets_t {
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
+} gArrayMapOffsets;
+
jclass g_stringClass = nullptr;
// ----------------------------------------------------------------------------
@@ -326,6 +332,50 @@
return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
}
+static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jstring package_name) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ScopedUtfChars package_name_utf8(env, package_name);
+ CHECK(package_name_utf8.c_str() != nullptr);
+ const std::string std_package_name(package_name_utf8.c_str());
+ const std::unordered_map<std::string, std::string>* map = nullptr;
+
+ assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
+ if (this_package_name == std_package_name) {
+ map = assetmanager->GetOverlayableMapForPackage(package_id);
+ }
+ });
+
+ if (map == nullptr) {
+ return nullptr;
+ }
+
+ jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor);
+ if (array_map == nullptr) {
+ return nullptr;
+ }
+
+ for (const auto& iter : *map) {
+ jstring name = env->NewStringUTF(iter.first.c_str());
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+
+ jstring actor = env->NewStringUTF(iter.second.c_str());
+ if (env->ExceptionCheck()) {
+ env->DeleteLocalRef(name);
+ return nullptr;
+ }
+
+ env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor);
+
+ env->DeleteLocalRef(name);
+ env->DeleteLocalRef(actor);
+ }
+
+ return array_map;
+}
+
static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
jlongArray out_offsets) {
off64_t start_offset, length;
@@ -1524,6 +1574,8 @@
{"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
{"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
(void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
+ {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
+ (void*)NativeGetOverlayableMap},
// Global management/debug methods.
{"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
@@ -1575,6 +1627,14 @@
gConfigurationOffsets.mScreenHeightDpOffset =
GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
+ jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
+ gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
+ gArrayMapOffsets.constructor =
+ GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V");
+ gArrayMapOffsets.put =
+ GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
NELEM(gAssetManagerMethods));
}