diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index c65c55024baba..eea7efc449b9a 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -18,19 +18,19 @@ #include #include +#include #include -#include "android-base/logging.h" -#include "android-base/macros.h" -#include "android-base/stringprintf.h" -#include "androidfw/ResourceTypes.h" -#include "androidfw/TypeWrappers.h" - #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "Source.h" #include "ValueVisitor.h" +#include "android-base/logging.h" +#include "android-base/macros.h" +#include "android-base/stringprintf.h" +#include "androidfw/ResourceTypes.h" +#include "androidfw/TypeWrappers.h" #include "format/binary/ResChunkPullParser.h" #include "util/Util.h" @@ -364,7 +364,7 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, config.copyFromDtoH(type->config); const std::string type_str = util::GetString(type_pool_, type->id - 1); - const ResourceType* parsed_type = ParseResourceType(type_str); + std::optional parsed_type = ParseResourceNamedType(type_str); if (!parsed_type) { diag_->Warn(DiagMessage(source_) << "invalid type name '" << type_str << "' for type with ID " << type->id); diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index b97f1c5de5452..b42e7d0c34cd5 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -607,7 +607,7 @@ class PackageFlattener { expected_type_id++; } expected_type_id++; - type_pool_.MakeRef(to_string(type.named_type.type)); + type_pool_.MakeRef(type.named_type.to_string()); if (!FlattenTypeSpec(type, type.entries, buffer)) { return false; diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index cd1c0af702cfb..c73bbb51f6395 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -837,4 +837,45 @@ TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table)); } +TEST_F(TableFlattenerTest, FlattenCustomResourceTypes) { + std::unique_ptr table = + test::ResourceTableBuilder() + .AddSimple("com.app.test:id/one", ResourceId(0x7f010000)) + .AddSimple("com.app.test:id.2/two", ResourceId(0x7f020000)) + .AddValue("com.app.test:integer/one", ResourceId(0x7f030000), + util::make_unique(uint8_t(Res_value::TYPE_INT_DEC), 10u)) + .AddValue("com.app.test:integer.1/one", ResourceId(0x7f040000), + util::make_unique(uint8_t(Res_value::TYPE_INT_DEC), 1u)) + .AddValue("com.app.test:integer.1/one", test::ParseConfigOrDie("v1"), + ResourceId(0x7f040000), + util::make_unique(uint8_t(Res_value::TYPE_INT_DEC), 2u)) + .AddString("com.app.test:layout.custom/bar", ResourceId(0x7f050000), "res/layout/bar.xml") + .Build(); + + ResTable res_table; + ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table)); + + EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f010000), {}, + Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); + + EXPECT_TRUE(Exists(&res_table, "com.app.test:id.2/two", ResourceId(0x7f020000), {}, + Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); + + EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one", ResourceId(0x7f030000), {}, + Res_value::TYPE_INT_DEC, 10u, 0u)); + + EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000), {}, + Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION)); + + EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000), + test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u, + ResTable_config::CONFIG_VERSION)); + + std::u16string bar_path = u"res/layout/bar.xml"; + auto idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); + ASSERT_TRUE(idx.has_value()); + EXPECT_TRUE(Exists(&res_table, "com.app.test:layout.custom/bar", ResourceId(0x7f050000), {}, + Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); +} + } // namespace aapt diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 475f393ea7596..82c7248f4b88d 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -429,16 +429,15 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr ResourceTablePackage* pkg = out_table->FindOrCreatePackage(pb_package.package_name()); for (const pb::Type& pb_type : pb_package.type()) { - const ResourceType* res_type = ParseResourceType(pb_type.name()); - if (res_type == nullptr) { + auto res_type = ParseResourceNamedType(pb_type.name()); + if (!res_type) { std::ostringstream error; error << "unknown type '" << pb_type.name() << "'"; *out_error = error.str(); return false; } - auto named_type = ResourceNamedTypeWithDefaultName(*res_type); - ResourceTableType* type = pkg->FindOrCreateType(named_type); + ResourceTableType* type = pkg->FindOrCreateType(*res_type); for (const pb::Entry& pb_entry : pb_type.entry()) { ResourceEntry* entry = type->CreateEntry(pb_entry.name()); diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 2481478c93ad3..bb8ea0ce4f296 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -358,7 +358,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table if (type.id) { pb_type->mutable_type_id()->set_id(type.id.value()); } - pb_type->set_name(to_string(type.named_type.type).to_string()); + pb_type->set_name(type.named_type.to_string()); // hardcoded string uses characters which make it an invalid resource name static const char* obfuscated_resource_name = "0_resource_name_obfuscated"; diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index d1d72e012b31a..0247021f1f8aa 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -951,4 +951,76 @@ TEST(ProtoSerializeTest, StagedId) { EXPECT_THAT(result.value().entry->staged_id.value().id, Eq(ResourceId(0x01ff0001))); } +TEST(ProtoSerializeTest, CustomResourceTypes) { + const uint32_t id_one_id = 0x7f020000; + const uint32_t id_2_two_id = 0x7f030000; + const uint32_t integer_three_id = 0x7f030000; + const uint32_t integer_1_four_id = 0x7f030000; + const uint32_t layout_bar_id = 0x7f050000; + std::unique_ptr context = test::ContextBuilder().Build(); + std::unique_ptr table = + test::ResourceTableBuilder() + .AddSimple("com.app.test:id/one", ResourceId(id_one_id)) + .AddSimple("com.app.test:id.2/two", ResourceId(id_2_two_id)) + .AddValue( + "com.app.test:integer/one", ResourceId(integer_three_id), + util::make_unique(uint8_t(android::Res_value::TYPE_INT_DEC), 10u)) + .AddValue( + "com.app.test:integer.1/one", ResourceId(integer_1_four_id), + util::make_unique(uint8_t(android::Res_value::TYPE_INT_DEC), 1u)) + .AddValue( + "com.app.test:integer.1/one", test::ParseConfigOrDie("v1"), + ResourceId(integer_1_four_id), + util::make_unique(uint8_t(android::Res_value::TYPE_INT_DEC), 2u)) + .AddFileReference("com.app.test:layout.custom/bar", ResourceId(layout_bar_id), + "res/layout/bar.xml") + .Build(); + + 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; + pb::ResourceTable pb_table; + std::string error; + SerializeTableToPb(*table, &pb_table, context->GetDiagnostics()); + DeserializeTableFromPb(pb_table, &files, &new_table, &error); + ASSERT_THAT(error, IsEmpty()); + + auto bp = test::GetValueForConfigAndProduct( + &new_table, "com.app.test:integer.1/one", ConfigDescription::DefaultConfig(), ""); + ASSERT_THAT(bp, NotNull()); + EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC)); + EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("1")->value.data)); + + bp = test::GetValueForConfigAndProduct(&new_table, "com.app.test:integer.1/one", + test::ParseConfigOrDie("v1"), ""); + ASSERT_THAT(bp, NotNull()); + EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC)); + EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("2")->value.data)); + + bp = test::GetValueForConfigAndProduct(&new_table, "com.app.test:integer/one", + ConfigDescription::DefaultConfig(), ""); + ASSERT_THAT(bp, NotNull()); + EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC)); + EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("10")->value.data)); + + bp = test::GetValueForConfigAndProduct(&new_table, "com.app.test:integer/one", + test::ParseConfigOrDie("v1"), ""); + ASSERT_THAT(bp, IsNull()); + + auto id = test::GetValueForConfigAndProduct(&new_table, "com.app.test:id/one", + ConfigDescription::DefaultConfig(), ""); + ASSERT_THAT(id, NotNull()); + + id = test::GetValueForConfigAndProduct(&new_table, "com.app.test:id.2/two", + ConfigDescription::DefaultConfig(), ""); + ASSERT_THAT(id, NotNull()); + + auto custom_layout = test::GetValueForConfigAndProduct( + &new_table, "com.app.test:layout.custom/bar", ConfigDescription::DefaultConfig(), ""); + ASSERT_THAT(custom_layout, NotNull()); + EXPECT_THAT(*(custom_layout->path), Eq("res/layout/bar.xml")); +} + } // namespace aapt