Idmap format changes for bidirectional lookup
This change modifies the idmap file format to allow for target resources
to map to arbitrary type/value combinations and to allow overlay
resources to be mapped back to target resource ids so references to
overlay resources can appear as references to target resources at
runtime.
The mappings of target resources to overlay resources and vice-versa are
both encoded as sparse arrays. Instead of looking up a resource by
indexing into an array that maps to the overlay resource id, the runtime
will binary search over the sparse array to find the type and value that
overlays the target resource.
Bug: 135943783
Test: idmap2_tests
Change-Id: I5d5344cdb7fe35f4f2e8d6781016299dea5d1e20
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 1ef41de..64304f6 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -27,6 +27,7 @@
#include "gtest/gtest.h"
#include "idmap2/ResourceMapping.h"
+using android::Res_value;
using android::idmap2::utils::ExtractOverlayManifestInfo;
namespace android::idmap2 {
@@ -109,14 +110,14 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
- ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
- true /* rewrite */)); // integer/int1
- ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
- true /* rewrite */)); // string/str1
- ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
- true /* rewrite */)); // string/str3
- ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
- true /* rewrite */)); // string/str4
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000,
+ false /* rewrite */)); // integer/int1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000,
+ false /* rewrite */)); // string/str1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001,
+ false /* rewrite */)); // string/str3
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002,
+ false /* rewrite */)); // string/str4
}
TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
@@ -131,15 +132,15 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
- ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002,
true /* rewrite */)); // string/str1 -> string/str4
- ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000,
true /* rewrite */)); // string/str3 -> string/str1
- ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001,
true /* rewrite */)); // string/str4 -> string/str3
}
-TEST(ResourceMappingTests, DoNotRewriteNonResourceMapping) {
+TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
OverlayManifestInfo info{};
info.target_package = "test.target";
info.target_name = "TestResources";
@@ -152,9 +153,9 @@
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
- ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x0104000a,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x0104000a,
false /* rewrite */)); // string/str1 -> android:string/ok
- ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001,
true /* rewrite */)); // string/str3 -> string/str4
}
@@ -172,10 +173,10 @@
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
- ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x03 /* Res_value::TYPE_STRING */,
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_STRING,
overlay_string_pool_size + 0U,
false /* rewrite */)); // string/str1 -> "Hello World"
- ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x10 /* Res_value::TYPE_INT_DEC */, 73U,
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_INT_DEC, 73U,
false /* rewrite */)); // string/str1 -> "Hello World"
}
@@ -188,12 +189,12 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
- ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
- true /* rewrite */)); // string/policy_public
- ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
- true /* rewrite */)); // string/policy_system
- ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
- true /* rewrite */)); // string/policy_system_vendor
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010000,
+ false /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010001,
+ false /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010002,
+ false /* rewrite */)); // string/policy_system_vendor
}
// Resources that are not declared as overlayable and resources that a protected by policies the
@@ -207,12 +208,12 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
- ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
- true /* rewrite */)); // string/policy_public
- ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
- true /* rewrite */)); // string/policy_system
- ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
- true /* rewrite */)); // string/policy_system_vendor
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
+ false /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
+ false /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
+ false /* rewrite */)); // string/policy_system_vendor
}
// Resources that are not declared as overlayable and resources that a protected by policies the
@@ -227,24 +228,24 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U);
- ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
- true /* rewrite */)); // string/not_overlayable
- ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
- true /* rewrite */)); // string/other
- ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
- true /* rewrite */)); // string/policy_odm
- ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
- true /* rewrite */)); // string/policy_oem
- ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
- true /* rewrite */)); // string/policy_product
- ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
- true /* rewrite */)); // string/policy_public
- ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
- true /* rewrite */)); // string/policy_signature
- ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
- true /* rewrite */)); // string/policy_system
- ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
- true /* rewrite */)); // string/policy_system_vendor
+ ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000,
+ false /* rewrite */)); // string/not_overlayable
+ ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001,
+ false /* rewrite */)); // string/other
+ ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002,
+ false /* rewrite */)); // string/policy_odm
+ ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003,
+ false /* rewrite */)); // string/policy_oem
+ ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004,
+ false /* rewrite */)); // string/policy_product
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
+ false /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006,
+ false /* rewrite */)); // string/policy_signature
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
+ false /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
+ false /* rewrite */)); // string/policy_system_vendor
}
// Overlays that do not target an <overlayable> tag can overlay resources defined within any
@@ -257,14 +258,14 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
- ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
- true /* rewrite */)); // integer/int1
- ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
- true /* rewrite */)); // string/str1
- ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
- true /* rewrite */)); // string/str3
- ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
- true /* rewrite */)); // string/str4
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000,
+ false /* rewrite */)); // integer/int1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000,
+ false /* rewrite */)); // string/str1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001,
+ false /* rewrite */)); // string/str3
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002,
+ false /* rewrite */)); // string/str4
}
// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
@@ -291,24 +292,24 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U);
- ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
- true /* rewrite */)); // string/not_overlayable
- ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
- true /* rewrite */)); // string/other
- ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
- true /* rewrite */)); // string/policy_odm
- ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
- true /* rewrite */)); // string/policy_oem
- ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
- true /* rewrite */)); // string/policy_product
- ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
- true /* rewrite */)); // string/policy_public
- ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
- true /* rewrite */)); // string/policy_signature
- ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
- true /* rewrite */)); // string/policy_system
- ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
- true /* rewrite */)); // string/policy_system_vendor
+ ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000,
+ false /* rewrite */)); // string/not_overlayable
+ ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001,
+ false /* rewrite */)); // string/other
+ ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002,
+ false /* rewrite */)); // string/policy_odm
+ ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003,
+ false /* rewrite */)); // string/policy_oem
+ ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004,
+ false /* rewrite */)); // string/policy_product
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
+ false /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006,
+ false /* rewrite */)); // string/policy_signature
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
+ false /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
+ false /* rewrite */)); // string/policy_system_vendor
};
CheckEntries(PolicyFlags::POLICY_SIGNATURE);