implement drawable frros

Test: unit tests
Bug: 251283316
Change-Id: Iead53711c54596c3787eeba6dcf9ced129f94426
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index e804c87..e13a0eb 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -17,6 +17,7 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 #include <idmap2/FabricatedOverlay.h>
+#include "TestHelpers.h"
 
 #include <fstream>
 #include <utility>
@@ -41,6 +42,10 @@
 }
 
 TEST(FabricatedOverlayTests, SetResourceValue) {
+  auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+  auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+  ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
+
   auto overlay =
       FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
           .SetResourceValue(
@@ -54,6 +59,8 @@
               Res_value::TYPE_STRING,
               "foobar",
               "en-rUS-normal-xxhdpi-v21")
+          .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
+          .setFrroPath("/foo/bar/biz.frro")
           .Build();
   ASSERT_TRUE(overlay);
   auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
@@ -67,19 +74,28 @@
 
   auto pairs = container->GetOverlayData(*info);
   ASSERT_TRUE(pairs);
-  ASSERT_EQ(4U, pairs->pairs.size());
+  ASSERT_EQ(5U, pairs->pairs.size());
   auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
                                         pairs->string_pool_data->data_length, false);
 
   auto& it = pairs->pairs[0];
-  ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+  ASSERT_EQ("com.example.target:drawable/dr1", it.resource_name);
   auto entry = std::get_if<TargetValueWithConfig>(&it.value);
   ASSERT_NE(nullptr, entry);
+  ASSERT_EQ(std::string("frro://foo/bar/biz.frro?offset=16&size=8341"),
+      string_pool.string8At(entry->value.data_value).value_or(""));
+  ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
+  ASSERT_EQ("port-xxhdpi-v7", entry->config);
+
+  it = pairs->pairs[1];
+  ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+  entry = std::get_if<TargetValueWithConfig>(&it.value);
+  ASSERT_NE(nullptr, entry);
   ASSERT_EQ(1U, entry->value.data_value);
   ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
   ASSERT_EQ("port", entry->config);
 
-  it = pairs->pairs[1];
+  it = pairs->pairs[2];
   ASSERT_EQ("com.example.target:string/int3", it.resource_name);
   entry = std::get_if<TargetValueWithConfig>(&it.value);
   ASSERT_NE(nullptr, entry);
@@ -87,7 +103,7 @@
   ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->value.data_type);
   ASSERT_EQ("xxhdpi-v7", entry->config);
 
-  it = pairs->pairs[2];
+  it = pairs->pairs[3];
   ASSERT_EQ("com.example.target:string/string1", it.resource_name);
   entry = std::get_if<TargetValueWithConfig>(&it.value);
   ASSERT_NE(nullptr, entry);
@@ -95,7 +111,7 @@
   ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or(""));
   ASSERT_EQ("en-rUS-normal-xxhdpi-v21", entry->config);
 
-  it = pairs->pairs[3];
+  it = pairs->pairs[4];
   ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
   entry = std::get_if<TargetValueWithConfig>(&it.value);
   ASSERT_NE(nullptr, entry);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 7b7dc17..b473f26 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -260,11 +260,17 @@
   auto target = TargetResourceContainer::FromPath(target_apk_path);
   ASSERT_TRUE(target);
 
+  auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+  auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+  ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
+
   auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
                   .SetOverlayable("TestResources")
                   .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
                   .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
                   .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
+                  .SetResourceValue("drawable/dr1", fd, "port-xxhdpi-v7")
+                  .setFrroPath("/foo/bar/biz.frro")
                   .Build();
 
   ASSERT_TRUE(frro);
@@ -293,14 +299,19 @@
   auto string_pool_data = data->GetStringPoolData();
   auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
 
+  std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341";
+  uint32_t uri_index
+      = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1);
 
   const auto& target_inline_entries = data->GetTargetInlineEntries();
-  ASSERT_EQ(target_inline_entries.size(), 3U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1, "land-xxhdpi-v7",
+  ASSERT_EQ(target_inline_entries.size(), 4U);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::drawable::dr1, "port-xxhdpi-v7",
+                             Res_value::TYPE_STRING, uri_index);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::integer::int1, "land-xxhdpi-v7",
                              Res_value::TYPE_INT_DEC, 2U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1, "land",
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str1, "land",
                              Res_value::TYPE_REFERENCE, 0x7f010000);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str2, "xxhdpi-v7",
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[3], R::target::string::str2, "xxhdpi-v7",
                              Res_value::TYPE_STRING,
                              (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1));
 }
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index ad998b9..80c062d 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -26,24 +26,27 @@
 // clang-format off
 namespace R::target {
   namespace integer {  // NOLINT(runtime/indentation_namespace)
-    constexpr ResourceId int1 = 0x7f010000;
+    constexpr ResourceId int1 = 0x7f020000;
+  }
+  namespace drawable {
+    constexpr ResourceId dr1 = 0x7f010000;
   }
   namespace string {  // NOLINT(runtime/indentation_namespace)
-    constexpr ResourceId not_overlayable = 0x7f020003;
-    constexpr ResourceId other = 0x7f020004;
-    constexpr ResourceId policy_actor = 0x7f020005;
-    constexpr ResourceId policy_config_signature = 0x7f020006;
-    constexpr ResourceId policy_odm = 0x7f020007;
-    constexpr ResourceId policy_oem = 0x7f020008;
-    constexpr ResourceId policy_product = 0x7f020009;
-    constexpr ResourceId policy_public = 0x7f02000a;
-    constexpr ResourceId policy_signature = 0x7f02000b;
-    constexpr ResourceId policy_system = 0x7f02000c;
-    constexpr ResourceId policy_system_vendor = 0x7f02000d;
-    constexpr ResourceId str1 = 0x7f02000e;
-    constexpr ResourceId str2 = 0x7f02000f;
-    constexpr ResourceId str3 = 0x7f020010;
-    constexpr ResourceId str4 = 0x7f020011;
+    constexpr ResourceId not_overlayable = 0x7f030003;
+    constexpr ResourceId other = 0x7f030004;
+    constexpr ResourceId policy_actor = 0x7f030005;
+    constexpr ResourceId policy_config_signature = 0x7f030006;
+    constexpr ResourceId policy_odm = 0x7f030007;
+    constexpr ResourceId policy_oem = 0x7f030008;
+    constexpr ResourceId policy_product = 0x7f030009;
+    constexpr ResourceId policy_public = 0x7f03000a;
+    constexpr ResourceId policy_signature = 0x7f03000b;
+    constexpr ResourceId policy_system = 0x7f03000c;
+    constexpr ResourceId policy_system_vendor = 0x7f03000d;
+    constexpr ResourceId str1 = 0x7f03000e;
+    constexpr ResourceId str2 = 0x7f03000f;
+    constexpr ResourceId str3 = 0x7f030010;
+    constexpr ResourceId str4 = 0x7f030011;
   }  // namespace string
 }  // namespace R::target
 
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 7112eeb..68164e2 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -79,22 +79,22 @@
   ASSERT_CONTAINS_REGEX(ADDRESS "00000000  config count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  overlay entry count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "0000000a  string pool index offset", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f010000  target id: integer/int1", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  target id: integer/int1", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f010000  overlay id: integer/int1", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e  target id: string/str1", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e  target id: string/str1", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b  overlay id: string/str1", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f020010  target id: string/str3", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030010  target id: string/str3", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c  overlay id: string/str3", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f020011  target id: string/str4", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030011  target id: string/str4", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d  overlay id: string/str4", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f010000  overlay id: integer/int1", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f010000  target id: integer/int1", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  target id: integer/int1", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b  overlay id: string/str1", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e  target id: string/str1", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e  target id: string/str1", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c  overlay id: string/str3", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f020010  target id: string/str3", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030010  target id: string/str3", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d  overlay id: string/str4", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f020011  target id: string/str4", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030011  target id: string/str4", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "000000b4  string pool size", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "........  string pool", stream.str());
 }
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 016d427..380e462 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -23,6 +23,7 @@
 #include <memory>
 #include <string>
 
+#include <fcntl.h>
 #include "R.h"
 #include "TestConstants.h"
 #include "TestHelpers.h"
@@ -76,7 +77,12 @@
   auto target_map = mapping.GetTargetToOverlayMap();
   auto entry_map = target_map.find(target_resource);
   if (entry_map == target_map.end()) {
-    return Error("Failed to find mapping for target resource");
+    std::string keys;
+    for (const auto &pair : target_map) {
+      keys.append(fmt::format("0x{:x}", pair.first)).append(" ");
+    }
+    return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")",
+        target_resource, keys.c_str());
   }
 
   auto actual_overlay_resource = std::get_if<ResourceId>(&entry_map->second);
@@ -108,7 +114,12 @@
   auto target_map = mapping.GetTargetToOverlayMap();
   auto entry_map = target_map.find(target_resource);
   if (entry_map == target_map.end()) {
-    return Error("Failed to find mapping for target resource");
+    std::string keys;
+    for (const auto &pair : target_map) {
+      keys.append(fmt::format("{:x}", pair.first)).append(" ");
+    }
+    return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")",
+        target_resource, keys.c_str());
   }
 
   auto config_map = std::get_if<ConfigMap>(&entry_map->second);
@@ -193,11 +204,16 @@
 }
 
 TEST(ResourceMappingTests, FabricatedOverlay) {
+  auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+  auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+  ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
   auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
                   .SetOverlayable("TestResources")
                   .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
                   .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
                   .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
+                  .SetResourceValue("drawable/dr1", fd, "")
+                  .setFrroPath("/foo/bar/biz.frro")
                   .Build();
 
   ASSERT_TRUE(frro);
@@ -214,11 +230,16 @@
   auto string_pool_data = res.GetStringPoolData();
   auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
 
-  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
+  std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341";
+  uint32_t uri_index
+      = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1);
+
+  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
   ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
   ASSERT_RESULT(MappingExists(res, R::target::string::str2, Res_value::TYPE_STRING,
                               (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1)));
+  ASSERT_RESULT(MappingExists(res, R::target::drawable::dr1, Res_value::TYPE_STRING, uri_index));
   ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
 }
 
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
index d5799ad..794d622 100644
--- a/cmds/idmap2/tests/TestConstants.h
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -19,8 +19,8 @@
 
 namespace android::idmap2::TestConstants {
 
-constexpr const auto TARGET_CRC = 0x7c2d4719;
-constexpr const auto TARGET_CRC_STRING = "7c2d4719";
+constexpr const auto TARGET_CRC = 0xa960a69;
+constexpr const auto TARGET_CRC_STRING = "0a960a69";
 
 constexpr const auto OVERLAY_CRC = 0xb71095cf;
 constexpr const auto OVERLAY_CRC_STRING = "b71095cf";
diff --git a/cmds/idmap2/tests/data/overlay/res/drawable/android.png b/cmds/idmap2/tests/data/overlay/res/drawable/android.png
new file mode 100644
index 0000000..b7317b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/drawable/android.png
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/build b/cmds/idmap2/tests/data/target/build
index e6df742..cd13a7e 100755
--- a/cmds/idmap2/tests/data/target/build
+++ b/cmds/idmap2/tests/data/target/build
@@ -17,5 +17,7 @@
 rm compiled.flata
 
 aapt2 compile res/values/values.xml -o .
-aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat
-rm values_values.arsc.flat
\ No newline at end of file
+aapt2 compile res/drawable/dr1.png -o .
+aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat drawable_dr1.png.flat
+rm values_values.arsc.flat
+rm drawable_dr1.png.flat
diff --git a/cmds/idmap2/tests/data/target/res/drawable/dr1.png b/cmds/idmap2/tests/data/target/res/drawable/dr1.png
new file mode 100644
index 0000000..1a56e68
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/drawable/dr1.png
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index 57e6c43..aac9081 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -63,6 +63,7 @@
         <item type="string" name="y" />
         <item type="string" name="z" />
         <item type="integer" name="int1" />
+        <item type="drawable" name="dr1" />
     </policy>
 </overlayable>
 
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index cc3491d..680eeb6 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 4a58c5e..145e737 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ