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));
 }