Loading tools/aapt2/LoadedApk.cpp +7 −1 Original line number Diff line number Diff line Loading @@ -267,8 +267,14 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return false; } } else if (format_ == ApkFormat::kProto && path == kProtoResourceTablePath) { SerializeTableOptions proto_serialize_options; proto_serialize_options.collapse_key_stringpool = options.collapse_key_stringpool; proto_serialize_options.name_collapse_exemptions = options.name_collapse_exemptions; pb::ResourceTable pb_table; SerializeTableToPb(*split_table, &pb_table, context->GetDiagnostics()); SerializeTableToPb(*split_table, &pb_table, context->GetDiagnostics(), proto_serialize_options); if (!io::CopyProtoToArchive(context, &pb_table, path, Loading tools/aapt2/format/proto/ProtoDeserialize.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -446,9 +446,12 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr } for (const pb::Entry& pb_entry : pb_type.entry()) { ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name()); ResourceEntry* entry; if (pb_entry.has_entry_id()) { entry->id = static_cast<uint16_t>(pb_entry.entry_id().id()); auto entry_id = static_cast<uint16_t>(pb_entry.entry_id().id()); entry = type->FindOrCreateEntry(pb_entry.name(), entry_id); } else { entry = type->FindOrCreateEntry(pb_entry.name()); } // Deserialize the symbol status (public/private with source and comments). Loading tools/aapt2/format/proto/ProtoSerialize.cpp +10 −1 Original line number Diff line number Diff line Loading @@ -356,12 +356,21 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table } pb_type->set_name(to_string(type->type).to_string()); // hardcoded string uses characters which make it an invalid resource name static const char* obfuscated_resource_name = "0_resource_name_obfuscated"; for (const std::unique_ptr<ResourceEntry>& entry : type->entries) { pb::Entry* pb_entry = pb_type->add_entry(); if (entry->id) { pb_entry->mutable_entry_id()->set_id(entry->id.value()); } ResourceName resource_name({}, type->type, entry->name); if (options.collapse_key_stringpool && options.name_collapse_exemptions.find(resource_name) == options.name_collapse_exemptions.end()) { pb_entry->set_name(obfuscated_resource_name); } else { pb_entry->set_name(entry->name); } // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); Loading tools/aapt2/format/proto/ProtoSerialize.h +9 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,15 @@ struct SerializeXmlOptions { struct SerializeTableOptions { /** Prevent serializing the source pool and source protos. */ bool exclude_sources = false; // When true, all the entry names in pb:ResourceTable are collapsed to a // single entry name. When the proto table is converted to binary // resources.arsc, the key string pool is collapsed to a single entry. All // resource entries have name indices that point to this single value. bool collapse_key_stringpool = false; // Set of resources to avoid collapsing to a single entry in key stringpool. std::set<ResourceName> name_collapse_exemptions; }; // Serializes a Value to its protobuf representation. An optional StringPool will hold the Loading tools/aapt2/format/proto/ProtoSerialize_test.cpp +171 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ using ::android::ConfigDescription; using ::android::StringPiece; using ::testing::Eq; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::NotNull; using ::testing::SizeIs; using ::testing::StrEq; Loading @@ -39,6 +40,13 @@ class MockFileCollection : public io::IFileCollection { MOCK_METHOD0(GetDirSeparator, char()); }; ResourceEntry* GetEntry(ResourceTable* table, const ResourceNameRef& res_name, uint32_t id) { ResourceTablePackage* package = table->FindPackage(res_name.package); ResourceTableType* type = package->FindType(res_name.type); return type->FindEntry(res_name.entry, id); } TEST(ProtoSerializeTest, SerializeSinglePackage) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = Loading Loading @@ -662,4 +670,167 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) { EXPECT_FALSE(actual_ref->is_dynamic); } TEST(ProtoSerializeTest, CollapsingResourceNamesNoNameCollapseExemptionsSucceeds) { const uint32_t id_one_id = 0x7f020000; const uint32_t id_two_id = 0x7f020001; const uint32_t id_three_id = 0x7f020002; const uint32_t integer_three_id = 0x7f030000; const uint32_t string_test_id = 0x7f040000; const uint32_t layout_bar_id = 0x7f050000; std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(id_one_id)) .AddSimple("com.app.test:id/two", ResourceId(id_two_id)) .AddValue("com.app.test:id/three", ResourceId(id_three_id), test::BuildReference("com.app.test:id/one", ResourceId(id_one_id))) .AddValue("com.app.test:integer/one", ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo") .AddFileReference("com.app.test:layout/bar", ResourceId(layout_bar_id), "res/layout/bar.xml") .Build(); SerializeTableOptions options; options.collapse_key_stringpool = true; pb::ResourceTable pb_table; SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options); test::TestFile file_a("res/layout/bar.xml"); MockFileCollection files; EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml"))) .WillRepeatedly(::testing::Return(&file_a)); ResourceTable new_table; std::string error; ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error; EXPECT_THAT(error, IsEmpty()); ResourceName real_id_resource( "com.app.test", ResourceType::kId, "one"); EXPECT_THAT(GetEntry(&new_table, real_id_resource, id_one_id), IsNull()); ResourceName obfuscated_id_resource( "com.app.test", ResourceType::kId, "0_resource_name_obfuscated"); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_one_id), NotNull()); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_two_id), NotNull()); ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id); EXPECT_THAT(entry, NotNull()); ResourceConfigValue* config_value = entry->FindValue({}); Reference* ref = ValueCast<Reference>(config_value->value.get()); EXPECT_THAT(ref->id.value(), Eq(id_one_id)); ResourceName obfuscated_integer_resource( "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(1u)); config_value = entry->FindValue(test::ParseConfigOrDie("v1")); bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(2u)); ResourceName obfuscated_string_resource( "com.app.test", ResourceType::kString, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_string_resource, string_test_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); String* s = ValueCast<String>(config_value->value.get()); EXPECT_THAT(*(s->value), Eq("foo")); ResourceName obfuscated_layout_resource( "com.app.test", ResourceType::kLayout, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_layout_resource, layout_bar_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); FileReference* f = ValueCast<FileReference>(config_value->value.get()); EXPECT_THAT(*(f->path), Eq("res/layout/bar.xml")); } TEST(ProtoSerializeTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) { const uint32_t id_one_id = 0x7f020000; const uint32_t id_two_id = 0x7f020001; const uint32_t id_three_id = 0x7f020002; const uint32_t integer_three_id = 0x7f030000; const uint32_t string_test_id = 0x7f040000; std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(id_one_id)) .AddSimple("com.app.test:id/two", ResourceId(id_two_id)) .AddValue("com.app.test:id/three", ResourceId(id_three_id), test::BuildReference("com.app.test:id/one", ResourceId(id_one_id))) .AddValue("com.app.test:integer/one", ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo") .Build(); SerializeTableOptions options; options.collapse_key_stringpool = true; options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one")); options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test")); pb::ResourceTable pb_table; SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options); MockFileCollection files; ResourceTable new_table; std::string error; ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error; EXPECT_THAT(error, IsEmpty()); EXPECT_THAT(GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kId, "one"), id_one_id), NotNull()); ResourceName obfuscated_id_resource( "com.app.test", ResourceType::kId, "0_resource_name_obfuscated"); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_one_id), IsNull()); ResourceName real_id_resource( "com.app.test", ResourceType::kId, "two"); EXPECT_THAT(GetEntry(&new_table, real_id_resource, id_two_id), IsNull()); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_two_id), NotNull()); ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id); EXPECT_THAT(entry, NotNull()); ResourceConfigValue* config_value = entry->FindValue({}); Reference* ref = ValueCast<Reference>(config_value->value.get()); EXPECT_THAT(ref->id.value(), Eq(id_one_id)); // Note that this resource is also named "one", but it's a different type, so gets obfuscated. ResourceName obfuscated_integer_resource( "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(1u)); config_value = entry->FindValue(test::ParseConfigOrDie("v1")); bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(2u)); entry = GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kString, "test"), string_test_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); String* s = ValueCast<String>(config_value->value.get()); EXPECT_THAT(*(s->value), Eq("foo")); } } // namespace aapt Loading
tools/aapt2/LoadedApk.cpp +7 −1 Original line number Diff line number Diff line Loading @@ -267,8 +267,14 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return false; } } else if (format_ == ApkFormat::kProto && path == kProtoResourceTablePath) { SerializeTableOptions proto_serialize_options; proto_serialize_options.collapse_key_stringpool = options.collapse_key_stringpool; proto_serialize_options.name_collapse_exemptions = options.name_collapse_exemptions; pb::ResourceTable pb_table; SerializeTableToPb(*split_table, &pb_table, context->GetDiagnostics()); SerializeTableToPb(*split_table, &pb_table, context->GetDiagnostics(), proto_serialize_options); if (!io::CopyProtoToArchive(context, &pb_table, path, Loading
tools/aapt2/format/proto/ProtoDeserialize.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -446,9 +446,12 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr } for (const pb::Entry& pb_entry : pb_type.entry()) { ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name()); ResourceEntry* entry; if (pb_entry.has_entry_id()) { entry->id = static_cast<uint16_t>(pb_entry.entry_id().id()); auto entry_id = static_cast<uint16_t>(pb_entry.entry_id().id()); entry = type->FindOrCreateEntry(pb_entry.name(), entry_id); } else { entry = type->FindOrCreateEntry(pb_entry.name()); } // Deserialize the symbol status (public/private with source and comments). Loading
tools/aapt2/format/proto/ProtoSerialize.cpp +10 −1 Original line number Diff line number Diff line Loading @@ -356,12 +356,21 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table } pb_type->set_name(to_string(type->type).to_string()); // hardcoded string uses characters which make it an invalid resource name static const char* obfuscated_resource_name = "0_resource_name_obfuscated"; for (const std::unique_ptr<ResourceEntry>& entry : type->entries) { pb::Entry* pb_entry = pb_type->add_entry(); if (entry->id) { pb_entry->mutable_entry_id()->set_id(entry->id.value()); } ResourceName resource_name({}, type->type, entry->name); if (options.collapse_key_stringpool && options.name_collapse_exemptions.find(resource_name) == options.name_collapse_exemptions.end()) { pb_entry->set_name(obfuscated_resource_name); } else { pb_entry->set_name(entry->name); } // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); Loading
tools/aapt2/format/proto/ProtoSerialize.h +9 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,15 @@ struct SerializeXmlOptions { struct SerializeTableOptions { /** Prevent serializing the source pool and source protos. */ bool exclude_sources = false; // When true, all the entry names in pb:ResourceTable are collapsed to a // single entry name. When the proto table is converted to binary // resources.arsc, the key string pool is collapsed to a single entry. All // resource entries have name indices that point to this single value. bool collapse_key_stringpool = false; // Set of resources to avoid collapsing to a single entry in key stringpool. std::set<ResourceName> name_collapse_exemptions; }; // Serializes a Value to its protobuf representation. An optional StringPool will hold the Loading
tools/aapt2/format/proto/ProtoSerialize_test.cpp +171 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ using ::android::ConfigDescription; using ::android::StringPiece; using ::testing::Eq; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::NotNull; using ::testing::SizeIs; using ::testing::StrEq; Loading @@ -39,6 +40,13 @@ class MockFileCollection : public io::IFileCollection { MOCK_METHOD0(GetDirSeparator, char()); }; ResourceEntry* GetEntry(ResourceTable* table, const ResourceNameRef& res_name, uint32_t id) { ResourceTablePackage* package = table->FindPackage(res_name.package); ResourceTableType* type = package->FindType(res_name.type); return type->FindEntry(res_name.entry, id); } TEST(ProtoSerializeTest, SerializeSinglePackage) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = Loading Loading @@ -662,4 +670,167 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) { EXPECT_FALSE(actual_ref->is_dynamic); } TEST(ProtoSerializeTest, CollapsingResourceNamesNoNameCollapseExemptionsSucceeds) { const uint32_t id_one_id = 0x7f020000; const uint32_t id_two_id = 0x7f020001; const uint32_t id_three_id = 0x7f020002; const uint32_t integer_three_id = 0x7f030000; const uint32_t string_test_id = 0x7f040000; const uint32_t layout_bar_id = 0x7f050000; std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(id_one_id)) .AddSimple("com.app.test:id/two", ResourceId(id_two_id)) .AddValue("com.app.test:id/three", ResourceId(id_three_id), test::BuildReference("com.app.test:id/one", ResourceId(id_one_id))) .AddValue("com.app.test:integer/one", ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo") .AddFileReference("com.app.test:layout/bar", ResourceId(layout_bar_id), "res/layout/bar.xml") .Build(); SerializeTableOptions options; options.collapse_key_stringpool = true; pb::ResourceTable pb_table; SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options); test::TestFile file_a("res/layout/bar.xml"); MockFileCollection files; EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml"))) .WillRepeatedly(::testing::Return(&file_a)); ResourceTable new_table; std::string error; ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error; EXPECT_THAT(error, IsEmpty()); ResourceName real_id_resource( "com.app.test", ResourceType::kId, "one"); EXPECT_THAT(GetEntry(&new_table, real_id_resource, id_one_id), IsNull()); ResourceName obfuscated_id_resource( "com.app.test", ResourceType::kId, "0_resource_name_obfuscated"); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_one_id), NotNull()); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_two_id), NotNull()); ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id); EXPECT_THAT(entry, NotNull()); ResourceConfigValue* config_value = entry->FindValue({}); Reference* ref = ValueCast<Reference>(config_value->value.get()); EXPECT_THAT(ref->id.value(), Eq(id_one_id)); ResourceName obfuscated_integer_resource( "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(1u)); config_value = entry->FindValue(test::ParseConfigOrDie("v1")); bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(2u)); ResourceName obfuscated_string_resource( "com.app.test", ResourceType::kString, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_string_resource, string_test_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); String* s = ValueCast<String>(config_value->value.get()); EXPECT_THAT(*(s->value), Eq("foo")); ResourceName obfuscated_layout_resource( "com.app.test", ResourceType::kLayout, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_layout_resource, layout_bar_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); FileReference* f = ValueCast<FileReference>(config_value->value.get()); EXPECT_THAT(*(f->path), Eq("res/layout/bar.xml")); } TEST(ProtoSerializeTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) { const uint32_t id_one_id = 0x7f020000; const uint32_t id_two_id = 0x7f020001; const uint32_t id_three_id = 0x7f020002; const uint32_t integer_three_id = 0x7f030000; const uint32_t string_test_id = 0x7f040000; std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(id_one_id)) .AddSimple("com.app.test:id/two", ResourceId(id_two_id)) .AddValue("com.app.test:id/three", ResourceId(id_three_id), test::BuildReference("com.app.test:id/one", ResourceId(id_one_id))) .AddValue("com.app.test:integer/one", ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(integer_three_id), util::make_unique<BinaryPrimitive>( uint8_t(android::Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo") .Build(); SerializeTableOptions options; options.collapse_key_stringpool = true; options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one")); options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test")); pb::ResourceTable pb_table; SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options); MockFileCollection files; ResourceTable new_table; std::string error; ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error; EXPECT_THAT(error, IsEmpty()); EXPECT_THAT(GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kId, "one"), id_one_id), NotNull()); ResourceName obfuscated_id_resource( "com.app.test", ResourceType::kId, "0_resource_name_obfuscated"); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_one_id), IsNull()); ResourceName real_id_resource( "com.app.test", ResourceType::kId, "two"); EXPECT_THAT(GetEntry(&new_table, real_id_resource, id_two_id), IsNull()); EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_two_id), NotNull()); ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id); EXPECT_THAT(entry, NotNull()); ResourceConfigValue* config_value = entry->FindValue({}); Reference* ref = ValueCast<Reference>(config_value->value.get()); EXPECT_THAT(ref->id.value(), Eq(id_one_id)); // Note that this resource is also named "one", but it's a different type, so gets obfuscated. ResourceName obfuscated_integer_resource( "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated"); entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(1u)); config_value = entry->FindValue(test::ParseConfigOrDie("v1")); bp = ValueCast<BinaryPrimitive>(config_value->value.get()); EXPECT_THAT(bp->value.data, Eq(2u)); entry = GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kString, "test"), string_test_id); EXPECT_THAT(entry, NotNull()); config_value = entry->FindValue({}); String* s = ValueCast<String>(config_value->value.get()); EXPECT_THAT(*(s->value), Eq("foo")); } } // namespace aapt