Loading tools/aapt2/cmd/Optimize.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <memory> #include <vector> #include "android-base/file.h" #include "android-base/stringprintf.h" #include "androidfw/ResourceTypes.h" Loading Loading @@ -47,6 +48,7 @@ using ::aapt::configuration::Artifact; using ::aapt::configuration::PostProcessingConfiguration; using ::android::ResTable_config; using ::android::StringPiece; using ::android::base::ReadFileToString; using ::android::base::StringAppendF; using ::android::base::StringPrintf; Loading Loading @@ -279,6 +281,20 @@ class OptimizeCommand { OptimizeContext* context_; }; bool ExtractWhitelistFromConfig(const std::string& path, OptimizeContext* context, OptimizeOptions* options) { std::string contents; if (!ReadFileToString(path, &contents, true)) { context->GetDiagnostics()->Error(DiagMessage() << "failed to parse whitelist from config file: " << path); return false; } for (const StringPiece& resource_name : util::Tokenize(contents, ',')) { options->table_flattener_options.whitelisted_resources.insert(resource_name.to_string()); } return true; } bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, OptimizeOptions* out_options) { const xml::XmlResource* manifest = apk->GetManifest(); Loading @@ -302,6 +318,7 @@ int Optimize(const std::vector<StringPiece>& args) { OptimizeContext context; OptimizeOptions options; Maybe<std::string> config_path; Maybe<std::string> whitelist_path; Maybe<std::string> target_densities; Maybe<std::string> target_abis; std::vector<std::string> configs; Loading @@ -320,6 +337,10 @@ int Optimize(const std::vector<StringPiece>& args) { "All the resources that would be unused on devices of the given densities will be \n" "removed from the APK.", &target_densities) .OptionalFlag("--whitelist-config-path", "Path to the whitelist.cfg file containing whitelisted resources \n" "whose names should not be altered in final resource tables.", &whitelist_path) .OptionalFlag( "--target-abis", "Comma separated list of the CPU ABIs that the APK will be optimized for.\n" Loading @@ -339,6 +360,9 @@ int Optimize(const std::vector<StringPiece>& args) { "Enables encoding sparse entries using a binary search tree.\n" "This decreases APK size at the cost of resource retrieval performance.", &options.table_flattener_options.use_sparse_entries) .OptionalSwitch("--enable-resource-obfuscation", "Enables obfuscation of key string pool to single value", &options.table_flattener_options.collapse_key_stringpool) .OptionalSwitch("-v", "Enables verbose logging", &verbose); if (!flags.Parse("aapt2 optimize", args, &std::cerr)) { Loading Loading @@ -425,6 +449,15 @@ int Optimize(const std::vector<StringPiece>& args) { return 1; } if (options.table_flattener_options.collapse_key_stringpool) { if (whitelist_path) { std::string& path = whitelist_path.value(); if (!ExtractWhitelistFromConfig(path, &context, &options)) { return 1; } } } if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) { return 1; } Loading tools/aapt2/format/binary/TableFlattener.cpp +22 −6 Original line number Diff line number Diff line Loading @@ -220,12 +220,15 @@ class MapFlattenVisitor : public ValueVisitor { class PackageFlattener { public: PackageFlattener(IAaptContext* context, ResourceTablePackage* package, const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries) const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries, bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources) : context_(context), diag_(context->GetDiagnostics()), package_(package), shared_libs_(shared_libs), use_sparse_entries_(use_sparse_entries) { use_sparse_entries_(use_sparse_entries), collapse_key_stringpool_(collapse_key_stringpool), whitelisted_resources_(whitelisted_resources) { } bool FlattenPackage(BigBuffer* buffer) { Loading Loading @@ -494,13 +497,23 @@ class PackageFlattener { // configuration available. Here we reverse this to match the binary // table. std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map; for (ResourceEntry* entry : sorted_entries) { const uint32_t key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); // hardcoded string uses characters which make it an invalid resource name const std::string obfuscated_resource_name = "0_resource_name_obfuscated"; for (ResourceEntry* entry : sorted_entries) { uint32_t local_key_index; if (!collapse_key_stringpool_ || whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) { local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); } else { // resource isn't whitelisted, add it as obfuscated value local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } // Group values by configuration. for (auto& config_value : entry->values) { config_to_entry_list_map[config_value->config].push_back( FlatEntry{entry, config_value->value.get(), key_index}); FlatEntry{entry, config_value->value.get(), local_key_index}); } } Loading Loading @@ -549,6 +562,8 @@ class PackageFlattener { bool use_sparse_entries_; StringPool type_pool_; StringPool key_pool_; bool collapse_key_stringpool_; const std::set<std::string>& whitelisted_resources_; }; } // namespace Loading Loading @@ -593,7 +608,8 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { } PackageFlattener flattener(context, package.get(), &table->included_packages_, options_.use_sparse_entries); options_.use_sparse_entries, options_.collapse_key_stringpool, options_.whitelisted_resources); if (!flattener.FlattenPackage(&package_buffer)) { return false; } Loading tools/aapt2/format/binary/TableFlattener.h +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ struct TableFlattenerOptions { // This is only available on platforms O+ and will only be respected when // minSdk is O+. bool use_sparse_entries = false; // When true, the key string pool in the final ResTable // 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 whitelisted resource names to avoid altering in key stringpool std::set<std::string> whitelisted_resources; }; class TableFlattener : public IResourceTableConsumer { Loading tools/aapt2/format/binary/TableFlattener_test.cpp +118 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,15 @@ class TableFlattenerTest : public ::testing::Test { << StringPiece16(actual_name.name, actual_name.nameLen) << "'"; } ResourceName actual_res_name(resName.value()); if (expected_res_name.entry != actual_res_name.entry || expected_res_name.package != actual_res_name.package || expected_res_name.type != actual_res_name.type) { return ::testing::AssertionFailure() << "expected resource '" << expected_res_name.to_string() << "' but got '" << actual_res_name.to_string() << "'"; } if (expected_config != config) { return ::testing::AssertionFailure() << "expected config '" << expected_config << "' but got '" << ConfigDescription(config) << "'"; Loading Loading @@ -450,4 +459,113 @@ TEST_F(TableFlattenerTest, LongSharedLibraryPackageNameIsIllegal) { ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result)); } TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(0x7f020000)) .AddSimple("com.app.test:id/two", ResourceId(0x7f020001)) .AddValue("com.app.test:id/three", ResourceId(0x7f020002), test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000))) .AddValue("com.app.test:integer/one", ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo") .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml") .Build(); TableFlattenerOptions options; options.collapse_key_stringpool = true; 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", 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/0_resource_name_obfuscated", ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); 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)); EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated", ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(0x7f020000)) .AddSimple("com.app.test:id/two", ResourceId(0x7f020001)) .AddValue("com.app.test:id/three", ResourceId(0x7f020002), test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000))) .AddValue("com.app.test:integer/one", ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo") .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml") .Build(); TableFlattenerOptions options; options.collapse_key_stringpool = true; options.whitelisted_resources.insert("test"); options.whitelisted_resources.insert("three"); 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", 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:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION)); EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } } // namespace aapt tools/aapt2/text/Unicode_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ TEST(UnicodeTest, IsValidResourceEntryName) { EXPECT_FALSE(IsValidResourceEntryName("Føø/Bar")); EXPECT_FALSE(IsValidResourceEntryName("Føø:Bar")); EXPECT_FALSE(IsValidResourceEntryName("Føø;Bar")); EXPECT_FALSE(IsValidResourceEntryName("0_resource_name_obfuscated")); } } // namespace text Loading Loading
tools/aapt2/cmd/Optimize.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <memory> #include <vector> #include "android-base/file.h" #include "android-base/stringprintf.h" #include "androidfw/ResourceTypes.h" Loading Loading @@ -47,6 +48,7 @@ using ::aapt::configuration::Artifact; using ::aapt::configuration::PostProcessingConfiguration; using ::android::ResTable_config; using ::android::StringPiece; using ::android::base::ReadFileToString; using ::android::base::StringAppendF; using ::android::base::StringPrintf; Loading Loading @@ -279,6 +281,20 @@ class OptimizeCommand { OptimizeContext* context_; }; bool ExtractWhitelistFromConfig(const std::string& path, OptimizeContext* context, OptimizeOptions* options) { std::string contents; if (!ReadFileToString(path, &contents, true)) { context->GetDiagnostics()->Error(DiagMessage() << "failed to parse whitelist from config file: " << path); return false; } for (const StringPiece& resource_name : util::Tokenize(contents, ',')) { options->table_flattener_options.whitelisted_resources.insert(resource_name.to_string()); } return true; } bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, OptimizeOptions* out_options) { const xml::XmlResource* manifest = apk->GetManifest(); Loading @@ -302,6 +318,7 @@ int Optimize(const std::vector<StringPiece>& args) { OptimizeContext context; OptimizeOptions options; Maybe<std::string> config_path; Maybe<std::string> whitelist_path; Maybe<std::string> target_densities; Maybe<std::string> target_abis; std::vector<std::string> configs; Loading @@ -320,6 +337,10 @@ int Optimize(const std::vector<StringPiece>& args) { "All the resources that would be unused on devices of the given densities will be \n" "removed from the APK.", &target_densities) .OptionalFlag("--whitelist-config-path", "Path to the whitelist.cfg file containing whitelisted resources \n" "whose names should not be altered in final resource tables.", &whitelist_path) .OptionalFlag( "--target-abis", "Comma separated list of the CPU ABIs that the APK will be optimized for.\n" Loading @@ -339,6 +360,9 @@ int Optimize(const std::vector<StringPiece>& args) { "Enables encoding sparse entries using a binary search tree.\n" "This decreases APK size at the cost of resource retrieval performance.", &options.table_flattener_options.use_sparse_entries) .OptionalSwitch("--enable-resource-obfuscation", "Enables obfuscation of key string pool to single value", &options.table_flattener_options.collapse_key_stringpool) .OptionalSwitch("-v", "Enables verbose logging", &verbose); if (!flags.Parse("aapt2 optimize", args, &std::cerr)) { Loading Loading @@ -425,6 +449,15 @@ int Optimize(const std::vector<StringPiece>& args) { return 1; } if (options.table_flattener_options.collapse_key_stringpool) { if (whitelist_path) { std::string& path = whitelist_path.value(); if (!ExtractWhitelistFromConfig(path, &context, &options)) { return 1; } } } if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) { return 1; } Loading
tools/aapt2/format/binary/TableFlattener.cpp +22 −6 Original line number Diff line number Diff line Loading @@ -220,12 +220,15 @@ class MapFlattenVisitor : public ValueVisitor { class PackageFlattener { public: PackageFlattener(IAaptContext* context, ResourceTablePackage* package, const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries) const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries, bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources) : context_(context), diag_(context->GetDiagnostics()), package_(package), shared_libs_(shared_libs), use_sparse_entries_(use_sparse_entries) { use_sparse_entries_(use_sparse_entries), collapse_key_stringpool_(collapse_key_stringpool), whitelisted_resources_(whitelisted_resources) { } bool FlattenPackage(BigBuffer* buffer) { Loading Loading @@ -494,13 +497,23 @@ class PackageFlattener { // configuration available. Here we reverse this to match the binary // table. std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map; for (ResourceEntry* entry : sorted_entries) { const uint32_t key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); // hardcoded string uses characters which make it an invalid resource name const std::string obfuscated_resource_name = "0_resource_name_obfuscated"; for (ResourceEntry* entry : sorted_entries) { uint32_t local_key_index; if (!collapse_key_stringpool_ || whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) { local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); } else { // resource isn't whitelisted, add it as obfuscated value local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } // Group values by configuration. for (auto& config_value : entry->values) { config_to_entry_list_map[config_value->config].push_back( FlatEntry{entry, config_value->value.get(), key_index}); FlatEntry{entry, config_value->value.get(), local_key_index}); } } Loading Loading @@ -549,6 +562,8 @@ class PackageFlattener { bool use_sparse_entries_; StringPool type_pool_; StringPool key_pool_; bool collapse_key_stringpool_; const std::set<std::string>& whitelisted_resources_; }; } // namespace Loading Loading @@ -593,7 +608,8 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { } PackageFlattener flattener(context, package.get(), &table->included_packages_, options_.use_sparse_entries); options_.use_sparse_entries, options_.collapse_key_stringpool, options_.whitelisted_resources); if (!flattener.FlattenPackage(&package_buffer)) { return false; } Loading
tools/aapt2/format/binary/TableFlattener.h +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ struct TableFlattenerOptions { // This is only available on platforms O+ and will only be respected when // minSdk is O+. bool use_sparse_entries = false; // When true, the key string pool in the final ResTable // 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 whitelisted resource names to avoid altering in key stringpool std::set<std::string> whitelisted_resources; }; class TableFlattener : public IResourceTableConsumer { Loading
tools/aapt2/format/binary/TableFlattener_test.cpp +118 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,15 @@ class TableFlattenerTest : public ::testing::Test { << StringPiece16(actual_name.name, actual_name.nameLen) << "'"; } ResourceName actual_res_name(resName.value()); if (expected_res_name.entry != actual_res_name.entry || expected_res_name.package != actual_res_name.package || expected_res_name.type != actual_res_name.type) { return ::testing::AssertionFailure() << "expected resource '" << expected_res_name.to_string() << "' but got '" << actual_res_name.to_string() << "'"; } if (expected_config != config) { return ::testing::AssertionFailure() << "expected config '" << expected_config << "' but got '" << ConfigDescription(config) << "'"; Loading Loading @@ -450,4 +459,113 @@ TEST_F(TableFlattenerTest, LongSharedLibraryPackageNameIsIllegal) { ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result)); } TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(0x7f020000)) .AddSimple("com.app.test:id/two", ResourceId(0x7f020001)) .AddValue("com.app.test:id/three", ResourceId(0x7f020002), test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000))) .AddValue("com.app.test:integer/one", ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo") .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml") .Build(); TableFlattenerOptions options; options.collapse_key_stringpool = true; 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", 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/0_resource_name_obfuscated", ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); 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)); EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated", ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple("com.app.test:id/one", ResourceId(0x7f020000)) .AddSimple("com.app.test:id/two", ResourceId(0x7f020001)) .AddValue("com.app.test:id/three", ResourceId(0x7f020002), test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000))) .AddValue("com.app.test:integer/one", ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u)) .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"), ResourceId(0x7f030000), util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u)) .AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo") .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml") .Build(); TableFlattenerOptions options; options.collapse_key_stringpool = true; options.whitelisted_resources.insert("test"); options.whitelisted_resources.insert("three"); 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", 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:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION)); EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); ASSERT_GE(idx, 0); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } } // namespace aapt
tools/aapt2/text/Unicode_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ TEST(UnicodeTest, IsValidResourceEntryName) { EXPECT_FALSE(IsValidResourceEntryName("Føø/Bar")); EXPECT_FALSE(IsValidResourceEntryName("Føø:Bar")); EXPECT_FALSE(IsValidResourceEntryName("Føø;Bar")); EXPECT_FALSE(IsValidResourceEntryName("0_resource_name_obfuscated")); } } // namespace text Loading