diff options
Diffstat (limited to 'tools/aapt2/format')
-rw-r--r-- | tools/aapt2/format/Archive.cpp | 9 | ||||
-rw-r--r-- | tools/aapt2/format/Archive_test.cpp | 209 | ||||
-rw-r--r-- | tools/aapt2/format/binary/BinaryResourceParser.cpp | 32 | ||||
-rw-r--r-- | tools/aapt2/format/binary/TableFlattener.cpp | 62 | ||||
-rw-r--r-- | tools/aapt2/format/binary/TableFlattener.h | 5 | ||||
-rw-r--r-- | tools/aapt2/format/binary/TableFlattener_test.cpp | 124 | ||||
-rw-r--r-- | tools/aapt2/format/binary/XmlFlattener_test.cpp | 6 | ||||
-rw-r--r-- | tools/aapt2/format/proto/ProtoDeserialize.cpp | 22 | ||||
-rw-r--r-- | tools/aapt2/format/proto/ProtoSerialize.cpp | 64 | ||||
-rw-r--r-- | tools/aapt2/format/proto/ProtoSerialize.h | 8 | ||||
-rw-r--r-- | tools/aapt2/format/proto/ProtoSerialize_test.cpp | 94 |
11 files changed, 477 insertions, 158 deletions
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp index d152a9cc7e62..41f01a01ed7c 100644 --- a/tools/aapt2/format/Archive.cpp +++ b/tools/aapt2/format/Archive.cpp @@ -103,7 +103,13 @@ class DirectoryWriter : public IArchiveWriter { return false; } } - return !in->HadError(); + + if (in->HadError()) { + error_ = in->GetError(); + return false; + } + + return FinishEntry(); } bool HadError() const override { @@ -191,6 +197,7 @@ class ZipFileWriter : public IArchiveWriter { } if (in->HadError()) { + error_ = in->GetError(); return false; } diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp new file mode 100644 index 000000000000..ceed3740f37a --- /dev/null +++ b/tools/aapt2/format/Archive_test.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test/Test.h" + +namespace aapt { + +using ArchiveTest = TestDirectoryFixture; + +constexpr size_t kTestDataLength = 100; + +class TestData : public io::MallocData { + public: + TestData(std::unique_ptr<uint8_t[]>& data, size_t size) + : MallocData(std::move(data), size) {} + + bool HadError() const override { return !error_.empty(); } + + std::string GetError() const override { return error_; } + + std::string error_; +}; + +std::unique_ptr<uint8_t[]> MakeTestArray() { + auto array = std::make_unique<uint8_t[]>(kTestDataLength); + for (int index = 0; index < kTestDataLength; ++index) { + array[index] = static_cast<uint8_t>(rand()); + } + return array; +} + +std::unique_ptr<IArchiveWriter> MakeDirectoryWriter(const std::string& output_path) { + file::mkdirs(output_path); + + StdErrDiagnostics diag; + return CreateDirectoryArchiveWriter(&diag, output_path); +} + +std::unique_ptr<IArchiveWriter> MakeZipFileWriter(const std::string& output_path) { + file::mkdirs(file::GetStem(output_path).to_string()); + std::remove(output_path.c_str()); + + StdErrDiagnostics diag; + return CreateZipFileArchiveWriter(&diag, output_path); +} + +void VerifyDirectory(const std::string& path, const std::string& file, const uint8_t array[]) { + std::string file_path = file::BuildPath({path, file}); + auto buffer = std::make_unique<char[]>(kTestDataLength); + std::ifstream stream(file_path); + stream.read(buffer.get(), kTestDataLength); + + for (int index = 0; index < kTestDataLength; ++index) { + ASSERT_EQ(array[index], static_cast<uint8_t>(buffer[index])); + } +} + +void VerifyZipFile(const std::string& output_path, const std::string& file, const uint8_t array[]) { + std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr); + std::unique_ptr<io::InputStream> stream = zip->FindFile(file)->OpenInputStream(); + + std::vector<uint8_t> buffer; + const void* data; + size_t size; + + while (stream->Next(&data, &size)) { + auto pointer = static_cast<const uint8_t*>(data); + buffer.insert(buffer.end(), pointer, pointer + size); + } + + for (int index = 0; index < kTestDataLength; ++index) { + ASSERT_EQ(array[index], buffer[index]); + } +} + +TEST_F(ArchiveTest, DirectoryWriteEntrySuccess) { + std::string output_path = GetTestPath("output"); + std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path); + std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); + std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); + + ASSERT_TRUE(writer->StartEntry("test1", 0)); + ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); + ASSERT_TRUE(writer->FinishEntry()); + ASSERT_FALSE(writer->HadError()); + + ASSERT_TRUE(writer->StartEntry("test2", 0)); + ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); + ASSERT_TRUE(writer->FinishEntry()); + ASSERT_FALSE(writer->HadError()); + + writer.reset(); + + VerifyDirectory(output_path, "test1", data1.get()); + VerifyDirectory(output_path, "test2", data2.get()); +} + +TEST_F(ArchiveTest, DirectoryWriteFileSuccess) { + std::string output_path = GetTestPath("output"); + std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path); + + std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); + auto data1_copy = std::make_unique<uint8_t[]>(kTestDataLength); + std::copy(data1.get(), data1.get() + kTestDataLength, data1_copy.get()); + + std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); + auto data2_copy = std::make_unique<uint8_t[]>(kTestDataLength); + std::copy(data2.get(), data2.get() + kTestDataLength, data2_copy.get()); + + auto input1 = std::make_unique<TestData>(data1_copy, kTestDataLength); + auto input2 = std::make_unique<TestData>(data2_copy, kTestDataLength); + + ASSERT_TRUE(writer->WriteFile("test1", 0, input1.get())); + ASSERT_FALSE(writer->HadError()); + ASSERT_TRUE(writer->WriteFile("test2", 0, input2.get())); + ASSERT_FALSE(writer->HadError()); + + writer.reset(); + + VerifyDirectory(output_path, "test1", data1.get()); + VerifyDirectory(output_path, "test2", data2.get()); +} + +TEST_F(ArchiveTest, DirectoryWriteFileError) { + std::string output_path = GetTestPath("output"); + std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path); + std::unique_ptr<uint8_t[]> data = MakeTestArray(); + auto input = std::make_unique<TestData>(data, kTestDataLength); + input->error_ = "DirectoryWriteFileError"; + + ASSERT_FALSE(writer->WriteFile("test", 0, input.get())); + ASSERT_TRUE(writer->HadError()); + ASSERT_EQ("DirectoryWriteFileError", writer->GetError()); +} + +TEST_F(ArchiveTest, ZipFileWriteEntrySuccess) { + std::string output_path = GetTestPath("output.apk"); + std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); + std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); + std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); + + ASSERT_TRUE(writer->StartEntry("test1", 0)); + ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); + ASSERT_TRUE(writer->FinishEntry()); + ASSERT_FALSE(writer->HadError()); + + ASSERT_TRUE(writer->StartEntry("test2", 0)); + ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); + ASSERT_TRUE(writer->FinishEntry()); + ASSERT_FALSE(writer->HadError()); + + writer.reset(); + + VerifyZipFile(output_path, "test1", data1.get()); + VerifyZipFile(output_path, "test2", data2.get()); +} + +TEST_F(ArchiveTest, ZipFileWriteFileSuccess) { + std::string output_path = GetTestPath("output.apk"); + std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); + + std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); + auto data1_copy = std::make_unique<uint8_t[]>(kTestDataLength); + std::copy(data1.get(), data1.get() + kTestDataLength, data1_copy.get()); + + std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); + auto data2_copy = std::make_unique<uint8_t[]>(kTestDataLength); + std::copy(data2.get(), data2.get() + kTestDataLength, data2_copy.get()); + + auto input1 = std::make_unique<TestData>(data1_copy, kTestDataLength); + auto input2 = std::make_unique<TestData>(data2_copy, kTestDataLength); + + ASSERT_TRUE(writer->WriteFile("test1", 0, input1.get())); + ASSERT_FALSE(writer->HadError()); + ASSERT_TRUE(writer->WriteFile("test2", 0, input2.get())); + ASSERT_FALSE(writer->HadError()); + + writer.reset(); + + VerifyZipFile(output_path, "test1", data1.get()); + VerifyZipFile(output_path, "test2", data2.get()); +} + +TEST_F(ArchiveTest, ZipFileWriteFileError) { + std::string output_path = GetTestPath("output.apk"); + std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); + std::unique_ptr<uint8_t[]> data = MakeTestArray(); + auto input = std::make_unique<TestData>(data, kTestDataLength); + input->error_ = "ZipFileWriteFileError"; + + ASSERT_FALSE(writer->WriteFile("test", 0, input.get())); + ASSERT_TRUE(writer->HadError()); + ASSERT_EQ("ZipFileWriteFileError", writer->GetError()); +} + +} // namespace aapt diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index fd8e36ebf823..f362744c0942 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -455,35 +455,6 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { const ResTable_overlayable_policy_header* policy_header = ConvertTo<ResTable_overlayable_policy_header>(parser.chunk()); - OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone; - if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) { - policies |= OverlayableItem::Policy::kPublic; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) { - policies |= OverlayableItem::Policy::kSystem; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) { - policies |= OverlayableItem::Policy::kVendor; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) { - policies |= OverlayableItem::Policy::kProduct; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_SIGNATURE) { - policies |= OverlayableItem::Policy::kSignature; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_ODM_PARTITION) { - policies |= OverlayableItem::Policy::kOdm; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_OEM_PARTITION) { - policies |= OverlayableItem::Policy::kOem; - } - const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>( ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize)); const ResTable_ref* const ref_end = ref_begin @@ -501,7 +472,7 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { } OverlayableItem overlayable_item(overlayable); - overlayable_item.policies = policies; + overlayable_item.policies = policy_header->policy_flags; if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) { return false; } @@ -614,6 +585,7 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) { Attribute::Symbol symbol; symbol.value = util::DeviceToHost32(map_entry.value.data); + symbol.type = map_entry.value.dataType; symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident)); attr->symbols.push_back(std::move(symbol)); } diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index f2e72da4056a..4784ecf3d12c 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -59,10 +59,22 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) { dst[i] = 0; } +static bool cmp_style_ids(ResourceId a, ResourceId b) { + // If one of a and b is from the framework package (package ID 0x01), and the + // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the + // framework ID. This ensures that when AssetManager resolves the dynamic IDs, + // they will be in sorted order as expected by AssetManager. + if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) || + (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) { + return b < a; + } + return a < b; +} + static bool cmp_style_entries(const Style::Entry& a, const Style::Entry& b) { if (a.key.id) { if (b.key.id) { - return a.key.id.value() < b.key.id.value(); + return cmp_style_ids(a.key.id.value(), b.key.id.value()); } return true; } else if (!b.key.id) { @@ -107,7 +119,7 @@ class MapFlattenVisitor : public ValueVisitor { } for (Attribute::Symbol& s : attr->symbols) { - BinaryPrimitive val(Res_value::TYPE_INT_DEC, s.value); + BinaryPrimitive val(s.type, s.value); FlattenEntry(&s.symbol, &val); } } @@ -221,21 +233,22 @@ class MapFlattenVisitor : public ValueVisitor { struct OverlayableChunk { std::string actor; Source source; - std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids; + std::map<PolicyFlags, std::set<ResourceId>> policy_ids; }; class PackageFlattener { public: PackageFlattener(IAaptContext* context, ResourceTablePackage* package, const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries, - bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources) + bool collapse_key_stringpool, + const std::set<ResourceName>& name_collapse_exemptions) : context_(context), diag_(context->GetDiagnostics()), package_(package), shared_libs_(shared_libs), use_sparse_entries_(use_sparse_entries), collapse_key_stringpool_(collapse_key_stringpool), - whitelisted_resources_(whitelisted_resources) { + name_collapse_exemptions_(name_collapse_exemptions) { } bool FlattenPackage(BigBuffer* buffer) { @@ -480,35 +493,12 @@ class PackageFlattener { return false; } - uint32_t policy_flags = 0; - if (item.policies & OverlayableItem::Policy::kPublic) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - if (item.policies & OverlayableItem::Policy::kSystem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kVendor) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kProduct) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kSignature) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE; - } - if (item.policies & OverlayableItem::Policy::kOdm) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_ODM_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kOem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_OEM_PARTITION; - } - - auto policy = overlayable_chunk->policy_ids.find(policy_flags); + auto policy = overlayable_chunk->policy_ids.find(item.policies); if (policy != overlayable_chunk->policy_ids.end()) { policy->second.insert(id); } else { overlayable_chunk->policy_ids.insert( - std::make_pair(policy_flags, std::set<ResourceId>{id})); + std::make_pair(item.policies, std::set<ResourceId>{id})); } } } @@ -546,7 +536,8 @@ class PackageFlattener { ChunkWriter policy_writer(buffer); auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>( RES_TABLE_OVERLAYABLE_POLICY_TYPE); - policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)); + policy_type->policy_flags = + static_cast<PolicyFlags>(util::HostToDevice32(static_cast<uint32_t>(policy_ids.first))); policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>( policy_ids.second.size())); // Write the ids after the policy header @@ -652,11 +643,12 @@ class PackageFlattener { for (ResourceEntry* entry : sorted_entries) { uint32_t local_key_index; + ResourceName resource_name({}, type->type, entry->name); if (!collapse_key_stringpool_ || - whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) { + name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) { local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); } else { - // resource isn't whitelisted, add it as obfuscated value + // resource isn't exempt from collapse, add it as obfuscated value local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } // Group values by configuration. @@ -712,7 +704,7 @@ class PackageFlattener { StringPool type_pool_; StringPool key_pool_; bool collapse_key_stringpool_; - const std::set<std::string>& whitelisted_resources_; + const std::set<ResourceName>& name_collapse_exemptions_; }; } // namespace @@ -760,7 +752,7 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { PackageFlattener flattener(context, package.get(), &table->included_packages_, options_.use_sparse_entries, options_.collapse_key_stringpool, - options_.whitelisted_resources); + options_.name_collapse_exemptions); if (!flattener.FlattenPackage(&package_buffer)) { return false; } diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h index 73c17295556b..4360db190146 100644 --- a/tools/aapt2/format/binary/TableFlattener.h +++ b/tools/aapt2/format/binary/TableFlattener.h @@ -19,6 +19,7 @@ #include "android-base/macros.h" +#include "Resource.h" #include "ResourceTable.h" #include "process/IResourceTableConsumer.h" #include "util/BigBuffer.h" @@ -41,8 +42,8 @@ struct TableFlattenerOptions { // have name indices that point to this single value bool collapse_key_stringpool = false; - // Set of whitelisted resource names to avoid altering in key stringpool - std::set<std::string> whitelisted_resources; + // Set of resources to avoid collapsing to a single entry in key stringpool. + std::set<ResourceName> name_collapse_exemptions; // Map from original resource paths to shortened resource paths. std::map<std::string, std::string> shortened_path_map; diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index a9409235e07a..59627ce579af 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -32,6 +32,8 @@ using ::testing::Gt; using ::testing::IsNull; using ::testing::NotNull; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { class TableFlattenerTest : public ::testing::Test { @@ -431,6 +433,47 @@ TEST_F(TableFlattenerTest, FlattenSharedLibrary) { EXPECT_EQ("lib", iter->second); } +TEST_F(TableFlattenerTest, FlattenSharedLibraryWithStyle) { + std::unique_ptr<IAaptContext> context = + test::ContextBuilder().SetCompilationPackage("lib").SetPackageId(0x00).Build(); + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .SetPackageId("lib", 0x00) + .AddValue("lib:style/Theme", + ResourceId(0x00030001), + test::StyleBuilder() + .AddItem("lib:attr/bar", ResourceId(0x00010002), + ResourceUtils::TryParseInt("2")) + .AddItem("lib:attr/foo", ResourceId(0x00010001), + ResourceUtils::TryParseInt("1")) + .AddItem("android:attr/bar", ResourceId(0x01010002), + ResourceUtils::TryParseInt("4")) + .AddItem("android:attr/foo", ResourceId(0x01010001), + ResourceUtils::TryParseInt("3")) + .Build()) + .Build(); + ResourceTable result; + ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result)); + + Maybe<ResourceTable::SearchResult> search_result = + result.FindResource(test::ParseNameOrDie("lib:style/Theme")); + ASSERT_TRUE(search_result); + EXPECT_EQ(0x00u, search_result.value().package->id.value()); + EXPECT_EQ(0x03u, search_result.value().type->id.value()); + EXPECT_EQ(0x01u, search_result.value().entry->id.value()); + ASSERT_EQ(1u, search_result.value().entry->values.size()); + Value* value = search_result.value().entry->values[0]->value.get(); + Style* style = ValueCast<Style>(value); + ASSERT_TRUE(style); + ASSERT_EQ(4u, style->entries.size()); + // Ensure the attributes from the shared library come after the items from + // android. + EXPECT_EQ(0x01010001, style->entries[0].key.id.value()); + EXPECT_EQ(0x01010002, style->entries[1].key.id.value()); + EXPECT_EQ(0x00010001, style->entries[2].key.id.value()); + EXPECT_EQ(0x00010002, style->entries[3].key.id.value()); +} + TEST_F(TableFlattenerTest, FlattenTableReferencingSharedLibraries) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build(); @@ -518,7 +561,7 @@ TEST_F(TableFlattenerTest, LongSharedLibraryPackageNameIsIllegal) { ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result)); } -TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { +TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -572,7 +615,7 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } -TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { +TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -591,21 +634,22 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { TableFlattenerOptions options; options.collapse_key_stringpool = true; - options.whitelisted_resources.insert("test"); - options.whitelisted_resources.insert("three"); + options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one")); + options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test")); ResTable res_table; ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table)); - EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", + EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); - EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020002), {}, - Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); + EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", + ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); + // Note that this resource is also named "one", but it's a different type, so gets obfuscated. EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION)); @@ -629,9 +673,9 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { TEST_F(TableFlattenerTest, FlattenOverlayable) { OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme")); - overlayable_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_item.policies |= OverlayableItem::Policy::kVendor; + overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION; std::string name = "com.app.test:integer/overlayable"; std::unique_ptr<ResourceTable> table = @@ -649,27 +693,27 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) { ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(result_overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kVendor - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(result_overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::VENDOR_PARTITION + | PolicyFlags::PRODUCT_PARTITION); } TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero_item"; OverlayableItem overlayable_item_zero(overlayable); - overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION; std::string name_one = "com.app.test:integer/overlayable_one_item"; OverlayableItem overlayable_item_one(overlayable); - overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= PolicyFlags::PUBLIC; std::string name_two = "com.app.test:integer/overlayable_two_item"; OverlayableItem overlayable_item_two(overlayable); - overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_two.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_two.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -690,47 +734,48 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::PUBLIC); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kVendor); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION + | PolicyFlags::VENDOR_PARTITION); } TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { auto group = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero"; OverlayableItem overlayable_item_zero(group); - overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION; auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization"); std::string name_one = "com.app.test:integer/overlayable_one"; OverlayableItem overlayable_item_one(group_one); - overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= PolicyFlags::PUBLIC; std::string name_two = "com.app.test:integer/overlayable_two"; OverlayableItem overlayable_item_two(group); - overlayable_item_two.policies |= OverlayableItem::Policy::kOdm; - overlayable_item_two.policies |= OverlayableItem::Policy::kOem; - overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_two.policies |= PolicyFlags::ODM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::OEM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION; std::string name_three = "com.app.test:integer/overlayable_three"; OverlayableItem overlayable_item_three(group_one); - overlayable_item_three.policies |= OverlayableItem::Policy::kSignature; + overlayable_item_three.policies |= PolicyFlags::SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -754,8 +799,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); @@ -764,7 +809,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::PUBLIC); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); @@ -773,9 +818,9 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kOdm - | OverlayableItem::Policy::kOem - | OverlayableItem::Policy::kVendor); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::ODM_PARTITION + | PolicyFlags::OEM_PARTITION + | PolicyFlags::VENDOR_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_three)); ASSERT_TRUE(search_result); @@ -784,7 +829,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp index 1dac493359e4..c24488b16153 100644 --- a/tools/aapt2/format/binary/XmlFlattener_test.cpp +++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp @@ -226,10 +226,10 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); // The tree needs a custom DynamicRefTable since it is not using a standard app ID (0x7f). - android::DynamicRefTable dynamic_ref_table; - dynamic_ref_table.addMapping(0x80, 0x80); + auto dynamic_ref_table = std::make_shared<android::DynamicRefTable>(); + dynamic_ref_table->addMapping(0x80, 0x80); - android::ResXMLTree tree(&dynamic_ref_table); + auto tree = android::ResXMLTree(std::move(dynamic_ref_table)); ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index bb21c1c539fb..2fd01d7f3dee 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -30,6 +30,8 @@ using ::android::ConfigDescription; using ::android::LocaleValue; using ::android::ResStringPool; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { namespace { @@ -379,25 +381,28 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, for (const int policy : pb_overlayable.policy()) { switch (policy) { case pb::OverlayableItem::PUBLIC: - out_overlayable->policies |= OverlayableItem::Policy::kPublic; + out_overlayable->policies |= PolicyFlags::PUBLIC; break; case pb::OverlayableItem::SYSTEM: - out_overlayable->policies |= OverlayableItem::Policy::kSystem; + out_overlayable->policies |= PolicyFlags::SYSTEM_PARTITION; break; case pb::OverlayableItem::VENDOR: - out_overlayable->policies |= OverlayableItem::Policy::kVendor; + out_overlayable->policies |= PolicyFlags::VENDOR_PARTITION; break; case pb::OverlayableItem::PRODUCT: - out_overlayable->policies |= OverlayableItem::Policy::kProduct; + out_overlayable->policies |= PolicyFlags::PRODUCT_PARTITION; break; case pb::OverlayableItem::SIGNATURE: - out_overlayable->policies |= OverlayableItem::Policy::kSignature; + out_overlayable->policies |= PolicyFlags::SIGNATURE; break; case pb::OverlayableItem::ODM: - out_overlayable->policies |= OverlayableItem::Policy::kOdm; + out_overlayable->policies |= PolicyFlags::ODM_PARTITION; break; case pb::OverlayableItem::OEM: - out_overlayable->policies |= OverlayableItem::Policy::kOem; + out_overlayable->policies |= PolicyFlags::OEM_PARTITION; + break; + case pb::OverlayableItem::ACTOR: + out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; break; default: *out_error = "unknown overlayable policy"; @@ -634,6 +639,7 @@ static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* o std::string* out_error) { out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); out_ref->private_reference = pb_ref.private_(); + out_ref->is_dynamic = pb_ref.is_dynamic().value(); if (pb_ref.id() != 0) { out_ref->id = ResourceId(pb_ref.id()); @@ -708,6 +714,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, return {}; } symbol.value = pb_symbol.value(); + symbol.type = pb_symbol.type() != 0U ? pb_symbol.type() + : android::Res_value::TYPE_INT_DEC; attr->symbols.push_back(std::move(symbol)); } value = std::move(attr); diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index a54822b20302..ba6df22af9d3 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -21,6 +21,8 @@ using android::ConfigDescription; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) { @@ -290,43 +292,51 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item pb::Overlayable* pb_overlayable = pb_table->add_overlayable(); pb_overlayable->set_name(overlayable_item.overlayable->name); pb_overlayable->set_actor(overlayable_item.overlayable->actor); - SerializeSourceToPb(overlayable_item.overlayable->source, source_pool, - pb_overlayable->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(overlayable_item.overlayable->source, source_pool, + pb_overlayable->mutable_source()); + } } pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item(); pb_overlayable_item->set_overlayable_idx(i); - if (overlayable_item.policies & OverlayableItem::Policy::kPublic) { + if (overlayable_item.policies & PolicyFlags::PUBLIC) { pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC); } - if (overlayable_item.policies & OverlayableItem::Policy::kProduct) { + if (overlayable_item.policies & PolicyFlags::PRODUCT_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT); } - if (overlayable_item.policies & OverlayableItem::Policy::kSystem) { + if (overlayable_item.policies & PolicyFlags::SYSTEM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM); } - if (overlayable_item.policies & OverlayableItem::Policy::kVendor) { + if (overlayable_item.policies & PolicyFlags::VENDOR_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR); } - if (overlayable_item.policies & OverlayableItem::Policy::kSignature) { + if (overlayable_item.policies & PolicyFlags::SIGNATURE) { pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE); } - if (overlayable_item.policies & OverlayableItem::Policy::kOdm) { + if (overlayable_item.policies & PolicyFlags::ODM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::ODM); } - if (overlayable_item.policies & OverlayableItem::Policy::kOem) { + if (overlayable_item.policies & PolicyFlags::OEM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::OEM); } + if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); + } - SerializeSourceToPb(overlayable_item.source, source_pool, - pb_overlayable_item->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(overlayable_item.source, source_pool, + pb_overlayable_item->mutable_source()); + } pb_overlayable_item->set_comment(overlayable_item.comment); } void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, - IDiagnostics* diag) { - StringPool source_pool; + IDiagnostics* diag, SerializeTableOptions options) { + auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>(); + pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint(); pb_fingerprint->set_tool(util::GetToolName()); pb_fingerprint->set_version(util::GetToolFingerprint()); @@ -356,32 +366,40 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level)); - SerializeSourceToPb(entry->visibility.source, &source_pool, - pb_visibility->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(entry->visibility.source, source_pool.get(), + pb_visibility->mutable_source()); + } pb_visibility->set_comment(entry->visibility.comment); if (entry->allow_new) { pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new(); - SerializeSourceToPb(entry->allow_new.value().source, &source_pool, - pb_allow_new->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(entry->allow_new.value().source, source_pool.get(), + pb_allow_new->mutable_source()); + } pb_allow_new->set_comment(entry->allow_new.value().comment); } if (entry->overlayable_item) { - SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool, - pb_entry, out_table); + SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, + source_pool.get(), pb_entry, out_table); } for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) { pb::ConfigValue* pb_config_value = pb_entry->add_config_value(); SerializeConfig(config_value->config, pb_config_value->mutable_config()); pb_config_value->mutable_config()->set_product(config_value->product); - SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool); + SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), + source_pool.get()); } } } } - SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool(), diag); + + if (source_pool != nullptr) { + SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag); + } } static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) { @@ -405,6 +423,9 @@ static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) pb_ref->set_private_(ref.private_reference); pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type)); + if (ref.is_dynamic) { + pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic); + } } template <typename T> @@ -552,6 +573,7 @@ class ValueSerializer : public ConstValueVisitor { SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_); SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name()); pb_symbol->set_value(symbol.value); + pb_symbol->set_type(symbol.type); } } diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h index 33ffd182435b..7a3ea9903732 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.h +++ b/tools/aapt2/format/proto/ProtoSerialize.h @@ -35,6 +35,11 @@ struct SerializeXmlOptions { bool remove_empty_text_nodes = false; }; +struct SerializeTableOptions { + /** Prevent serializing the source pool and source protos. */ + bool exclude_sources = false; +}; + // Serializes a Value to its protobuf representation. An optional StringPool will hold the // source path string. void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr); @@ -59,7 +64,8 @@ void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config); // Serializes a ResourceTable into its protobuf representation. -void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, IDiagnostics* diag); +void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, + IDiagnostics* diag, SerializeTableOptions options = {}); // Serializes a ResourceFile into its protobuf representation. void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file); diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index f252f33f44fb..1a7de6dc1c48 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -28,6 +28,8 @@ using ::testing::NotNull; using ::testing::SizeIs; using ::testing::StrEq; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { class MockFileCollection : public io::IFileCollection { @@ -80,7 +82,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics())); ASSERT_TRUE(table->AddResource( test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet", - test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics())); + test::BuildPrimitive(android::Res_value::TYPE_INT_HEX, 321u), context->GetDiagnostics())); // Make a reference with both resource name and resource ID. // The reference should point to a resource outside of this table to test that both name and id @@ -133,11 +135,13 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), ""); ASSERT_THAT(prim, NotNull()); EXPECT_THAT(prim->value.data, Eq(123u)); + EXPECT_THAT(prim->value.dataType, Eq(0x10)); prim = test::GetValueForConfigAndProduct<BinaryPrimitive>( &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet"); ASSERT_THAT(prim, NotNull()); EXPECT_THAT(prim->value.data, Eq(321u)); + EXPECT_THAT(prim->value.dataType, Eq(0x11)); Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc"); ASSERT_THAT(actual_ref, NotNull()); @@ -169,7 +173,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40)); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::NONE)); EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.source.line, Eq(42)); } @@ -514,23 +518,28 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) { TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>( "CustomizableResources", "overlay://customization")); - overlayable_item_foo.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_foo.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_foo.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item_foo.policies |= PolicyFlags::PRODUCT_PARTITION; OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>( "TaskBar", "overlay://theme")); - overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic; - overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_bar.policies |= PolicyFlags::PUBLIC; + overlayable_item_bar.policies |= PolicyFlags::VENDOR_PARTITION; OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>( "FontPack", "overlay://theme")); - overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_baz.policies |= PolicyFlags::PUBLIC; OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>( "IconPack", "overlay://theme")); - overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature; - overlayable_item_boz.policies |= OverlayableItem::Policy::kOdm; - overlayable_item_boz.policies |= OverlayableItem::Policy::kOem; + overlayable_item_boz.policies |= PolicyFlags::SIGNATURE; + overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION; + overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION; + + OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>( + "ActorConfig", "overlay://theme")); + overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE; + overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE; OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>( "Other", "overlay://customization")); @@ -544,6 +553,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz) .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz) .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz) + .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config) .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true")) .Build(); @@ -563,8 +573,8 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar")); ASSERT_TRUE(search_result); @@ -572,8 +582,8 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kVendor)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC + | PolicyFlags::VENDOR_PARTITION)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz")); ASSERT_TRUE(search_result); @@ -581,7 +591,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz")); ASSERT_TRUE(search_result); @@ -589,16 +599,25 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature - | OverlayableItem::Policy::kOdm - | OverlayableItem::Policy::kOem)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE + | PolicyFlags::ODM_PARTITION + | PolicyFlags::OEM_PARTITION)); + + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config")); + ASSERT_TRUE(search_result); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig")); + EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz")); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::NONE)); EXPECT_THAT(overlayable_item.comment, Eq("comment")); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz")); @@ -606,4 +625,41 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { ASSERT_FALSE(search_result.value().entry->overlayable_item); } +TEST(ProtoSerializeTest, SerializeAndDeserializeDynamicReference) { + Reference ref(ResourceId(0x00010001)); + ref.is_dynamic = true; + + pb::Item pb_item; + SerializeItemToPb(ref, &pb_item); + + ASSERT_TRUE(pb_item.has_ref()); + EXPECT_EQ(pb_item.ref().id(), ref.id.value().id); + EXPECT_TRUE(pb_item.ref().is_dynamic().value()); + + std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(), + android::ConfigDescription(), nullptr, + nullptr, nullptr); + Reference* actual_ref = ValueCast<Reference>(item.get()); + EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id); + EXPECT_TRUE(actual_ref->is_dynamic); +} + +TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) { + Reference ref(ResourceId(0x00010001)); + + pb::Item pb_item; + SerializeItemToPb(ref, &pb_item); + + ASSERT_TRUE(pb_item.has_ref()); + EXPECT_EQ(pb_item.ref().id(), ref.id.value().id); + EXPECT_FALSE(pb_item.ref().has_is_dynamic()); + + std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(), + android::ConfigDescription(), nullptr, + nullptr, nullptr); + Reference* actual_ref = ValueCast<Reference>(item.get()); + EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id); + EXPECT_FALSE(actual_ref->is_dynamic); +} + } // namespace aapt |