AssetManager2: Add GetResourceId

Add ability to lookup a resource by name.

Test: make libandroidfw_tests
Change-Id: I262ba5ce4c9892458226fbdb44cf21f9877fb92d
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 542a125..ef0c967 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -31,6 +31,8 @@
 #endif
 #endif
 
+#include "androidfw/ResourceUtils.h"
+
 namespace android {
 
 AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
@@ -235,9 +237,9 @@
     desired_config = &density_override_config;
   }
 
-  const uint32_t package_id = util::get_package_id(resid);
-  const uint8_t type_id = util::get_type_id(resid);
-  const uint16_t entry_id = util::get_entry_id(resid);
+  const uint32_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 (type_id == 0) {
     LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
@@ -452,7 +454,7 @@
     ResolvedBag::Entry* new_entry = new_bag->entries;
     for (; map_entry != map_entry_end; ++map_entry) {
       uint32_t new_key = dtohl(map_entry->name.ident);
-      if (!util::is_internal_resid(new_key)) {
+      if (!is_internal_resid(new_key)) {
         // 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) {
@@ -501,7 +503,7 @@
   // The keys are expected to be in sorted order. Merge the two bags.
   while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
     uint32_t child_key = dtohl(map_entry->name.ident);
-    if (!util::is_internal_resid(child_key)) {
+    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);
         return nullptr;
@@ -533,7 +535,7 @@
   // Finish the child entries if they exist.
   while (map_entry != map_entry_end) {
     uint32_t new_key = dtohl(map_entry->name.ident);
-    if (!util::is_internal_resid(new_key)) {
+    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);
         return nullptr;
@@ -571,12 +573,71 @@
   return result;
 }
 
+static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
+  ssize_t len =
+      utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false);
+  if (len < 0) {
+    return false;
+  }
+  out->resize(static_cast<size_t>(len));
+  utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(),
+                static_cast<size_t>(len + 1));
+  return true;
+}
+
 uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
                                       const std::string& fallback_type,
                                       const std::string& fallback_package) {
-  (void)resource_name;
-  (void)fallback_type;
-  (void)fallback_package;
+  StringPiece package_name, type, entry;
+  if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
+    return 0u;
+  }
+
+  if (entry.empty()) {
+    return 0u;
+  }
+
+  if (package_name.empty()) {
+    package_name = fallback_package;
+  }
+
+  if (type.empty()) {
+    type = fallback_type;
+  }
+
+  std::u16string type16;
+  if (!Utf8ToUtf16(type, &type16)) {
+    return 0u;
+  }
+
+  std::u16string entry16;
+  if (!Utf8ToUtf16(entry, &entry16)) {
+    return 0u;
+  }
+
+  const StringPiece16 kAttr16 = u"attr";
+  const static std::u16string kAttrPrivate16 = u"^attr-private";
+
+  for (const PackageGroup& package_group : package_groups_) {
+    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;
+      }
+
+      uint32_t resid = package->FindEntryByName(type16, entry16);
+      if (resid == 0u && kAttr16 == type16) {
+        // Private attributes in libraries (such as the framework) are sometimes encoded
+        // under the type '^attr-private' in order to leave the ID space of public 'attr'
+        // free for future additions. Check '^attr-private' for the same name.
+        resid = package->FindEntryByName(kAttrPrivate16, entry16);
+      }
+
+      if (resid != 0u) {
+        return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId);
+      }
+    }
+  }
   return 0u;
 }
 
@@ -619,15 +680,15 @@
 
     // If the resource ID passed in is not a style, the key can be
     // some other identifier that is not a resource ID.
-    if (!util::is_valid_resid(attr_resid)) {
+    if (!is_valid_resid(attr_resid)) {
       return false;
     }
 
-    const uint32_t package_idx = util::get_package_id(attr_resid);
+    const uint32_t package_idx = get_package_id(attr_resid);
 
     // The type ID is 1-based, so subtract 1 to get an index.
-    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+    const uint32_t type_idx = get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = get_entry_id(attr_resid);
 
     std::unique_ptr<Package>& package = packages_[package_idx];
     if (package == nullptr) {
@@ -656,9 +717,9 @@
   // and populate the structures.
   for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
     const uint32_t attr_resid = bag_iter->key;
-    const uint32_t package_idx = util::get_package_id(attr_resid);
-    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+    const uint32_t package_idx = get_package_id(attr_resid);
+    const uint32_t type_idx = get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = get_entry_id(attr_resid);
     Package* package = packages_[package_idx].get();
     util::unique_cptr<Type>& type = package->types[type_idx];
     if (type->entry_count != type->entry_capacity) {
@@ -691,15 +752,15 @@
   uint32_t type_spec_flags = 0u;
 
   for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
-    if (!util::is_valid_resid(resid)) {
+    if (!is_valid_resid(resid)) {
       return kInvalidCookie;
     }
 
-    const uint32_t package_idx = util::get_package_id(resid);
+    const uint32_t package_idx = get_package_id(resid);
 
     // Type ID is 1-based, subtract 1 to get the index.
-    const uint32_t type_idx = util::get_type_id(resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(resid);
+    const uint32_t type_idx = get_type_id(resid) - 1;
+    const uint32_t entry_idx = get_entry_id(resid);
 
     const Package* package = packages_[package_idx].get();
     if (package == nullptr) {