diff options
-rw-r--r-- | tools/aapt2/LoadedApk.cpp | 43 | ||||
-rw-r--r-- | tools/aapt2/LoadedApk.h | 25 | ||||
-rw-r--r-- | tools/aapt2/cmd/Optimize.cpp | 18 | ||||
-rw-r--r-- | tools/aapt2/configuration/ConfigurationParser.cpp | 7 | ||||
-rw-r--r-- | tools/aapt2/configuration/ConfigurationParser.h | 10 | ||||
-rw-r--r-- | tools/aapt2/configuration/ConfigurationParser_test.cpp | 58 | ||||
-rw-r--r-- | tools/aapt2/optimize/MultiApkGenerator.cpp | 94 | ||||
-rw-r--r-- | tools/aapt2/optimize/MultiApkGenerator_test.cpp | 62 |
8 files changed, 188 insertions, 129 deletions
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index b80780e33dfa..6f2b86528b5b 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -20,11 +20,15 @@ #include "ValueVisitor.h" #include "flatten/Archive.h" #include "flatten/TableFlattener.h" +#include "flatten/XmlFlattener.h" #include "io/BigBufferInputStream.h" #include "io/Util.h" +#include "xml/XmlDom.h" namespace aapt { +using xml::XmlResource; + std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context, const android::StringPiece& path) { Source source(path); @@ -52,6 +56,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context, if (!parser.Parse()) { return {}; } + return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table)); } @@ -63,7 +68,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOption bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table, const TableFlattenerOptions& options, FilterChain* filters, - IArchiveWriter* writer) { + IArchiveWriter* writer, XmlResource* manifest) { std::set<std::string> referenced_resources; // List the files being referenced in the resource table. for (auto& pkg : split_table->packages) { @@ -119,6 +124,20 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return false; } + } else if (manifest != nullptr && path == "AndroidManifest.xml") { + BigBuffer buffer(8192); + XmlFlattener xml_flattener(&buffer, {}); + if (!xml_flattener.Consume(context, manifest)) { + context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed"); + return false; + } + + uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u; + io::BigBufferInputStream manifest_buffer_in(&buffer); + if (!io::CopyInputStreamToArchive(context, &manifest_buffer_in, path, compression_flags, + writer)) { + return false; + } } else { uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u; if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) { @@ -129,4 +148,26 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return true; } +std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) { + IDiagnostics* diag = context->GetDiagnostics(); + + io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml"); + if (manifest_file == nullptr) { + diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found"); + return {}; + } + + std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData(); + if (manifest_data == nullptr) { + diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml"); + return {}; + } + + std::unique_ptr<xml::XmlResource> manifest = + xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource()); + if (manifest == nullptr) { + diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml"); + } + return manifest; +} } // namespace aapt diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h index dacd0c2130a9..d779b7e7663f 100644 --- a/tools/aapt2/LoadedApk.h +++ b/tools/aapt2/LoadedApk.h @@ -25,17 +25,17 @@ #include "flatten/TableFlattener.h" #include "io/ZipArchive.h" #include "unflatten/BinaryResourceParser.h" +#include "xml/XmlDom.h" namespace aapt { /** Info about an APK loaded in memory. */ class LoadedApk { public: - LoadedApk( - const Source& source, - std::unique_ptr<io::IFileCollection> apk, - std::unique_ptr<ResourceTable> table) - : source_(source), apk_(std::move(apk)), table_(std::move(table)) {} + LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk, + std::unique_ptr<ResourceTable> table) + : source_(source), apk_(std::move(apk)), table_(std::move(table)) { + } io::IFileCollection* GetFileCollection() { return apk_.get(); } @@ -51,13 +51,20 @@ class LoadedApk { IArchiveWriter* writer); /** - * Writes the APK on disk at the given path, while also removing the resource - * files that are not referenced in the resource table. The provided filter - * chain is applied to each entry in the APK file. + * Writes the APK on disk at the given path, while also removing the resource files that are not + * referenced in the resource table. The provided filter chain is applied to each entry in the APK + * file. + * + * If the manifest is also provided, it will be written to the new APK file, otherwise the + * original manifest will be written. The manifest is only required if the contents of the new APK + * have been modified in a way that require the AndroidManifest.xml to also be modified. */ virtual bool WriteToArchive(IAaptContext* context, ResourceTable* split_table, const TableFlattenerOptions& options, FilterChain* filters, - IArchiveWriter* writer); + IArchiveWriter* writer, xml::XmlResource* manifest = nullptr); + + /** Inflates the AndroidManifest.xml file from the APK. */ + std::unique_ptr<xml::XmlResource> InflateManifest(IAaptContext* context); static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context, const android::StringPiece& path); diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 704faee35ced..56b61d04ff9e 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -283,24 +283,8 @@ class OptimizeCommand { bool ExtractAppDataFromManifest(OptimizeContext* context, LoadedApk* apk, OptimizeOptions* out_options) { - io::IFile* manifest_file = apk->GetFileCollection()->FindFile("AndroidManifest.xml"); - if (manifest_file == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(apk->GetSource()) - << "missing AndroidManifest.xml"); - return false; - } - - std::unique_ptr<io::IData> data = manifest_file->OpenAsData(); - if (data == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(manifest_file->GetSource()) - << "failed to open file"); - return false; - } - - std::unique_ptr<xml::XmlResource> manifest = xml::Inflate( - data->data(), data->size(), context->GetDiagnostics(), manifest_file->GetSource()); + std::unique_ptr<xml::XmlResource> manifest = apk->InflateManifest(context); if (manifest == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to read binary AndroidManifest.xml"); return false; } diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp index 9d6d3286f0ef..d2b4d725c416 100644 --- a/tools/aapt2/configuration/ConfigurationParser.cpp +++ b/tools/aapt2/configuration/ConfigurationParser.cpp @@ -27,6 +27,7 @@ #include "ConfigDescription.h" #include "Diagnostics.h" +#include "ResourceUtils.h" #include "io/File.h" #include "io/FileSystem.h" #include "io/StringInputStream.h" @@ -499,11 +500,11 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle AndroidSdk entry; for (const auto& attr : child->attributes) { if (attr.name == "minSdkVersion") { - entry.min_sdk_version = {attr.value}; + entry.min_sdk_version = ResourceUtils::ParseSdkVersion(attr.value); } else if (attr.name == "targetSdkVersion") { - entry.target_sdk_version = {attr.value}; + entry.target_sdk_version = ResourceUtils::ParseSdkVersion(attr.value); } else if (attr.name == "maxSdkVersion") { - entry.max_sdk_version = {attr.value}; + entry.max_sdk_version = ResourceUtils::ParseSdkVersion(attr.value); } else { diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value); } diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h index 9bc9081b8ae4..ebf1c986a980 100644 --- a/tools/aapt2/configuration/ConfigurationParser.h +++ b/tools/aapt2/configuration/ConfigurationParser.h @@ -103,14 +103,14 @@ struct AndroidManifest { }; struct AndroidSdk { - Maybe<std::string> min_sdk_version; - Maybe<std::string> target_sdk_version; - Maybe<std::string> max_sdk_version; + Maybe<int> min_sdk_version; + Maybe<int> target_sdk_version; + Maybe<int> max_sdk_version; Maybe<AndroidManifest> manifest; - static AndroidSdk ForMinSdk(std::string min_sdk) { + static AndroidSdk ForMinSdk(int min_sdk) { AndroidSdk sdk; - sdk.min_sdk_version = {std::move(min_sdk)}; + sdk.min_sdk_version = min_sdk; return sdk; } diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp index 7ffb3d515079..6bb168f15b1e 100644 --- a/tools/aapt2/configuration/ConfigurationParser_test.cpp +++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp @@ -24,6 +24,15 @@ #include "xml/XmlDom.h" namespace aapt { + +namespace configuration { +void PrintTo(const AndroidSdk& sdk, std::ostream* os) { + *os << "SDK: min=" << sdk.min_sdk_version.value_or_default(-1) + << ", target=" << sdk.target_sdk_version.value_or_default(-1) + << ", max=" << sdk.max_sdk_version.value_or_default(-1); +} +} // namespace configuration + namespace { using ::android::ResTable_config; @@ -76,9 +85,9 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> </locale-group> <android-sdk-group label="v19"> <android-sdk - minSdkVersion="v19" - targetSdkVersion="v24" - maxSdkVersion="v25"> + minSdkVersion="19" + targetSdkVersion="24" + maxSdkVersion="25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> @@ -156,7 +165,7 @@ TEST_F(ConfigurationParserTest, ValidateFile) { EXPECT_EQ(1ul, value.android_sdk_groups.size()); EXPECT_TRUE(value.android_sdk_groups["v19"].min_sdk_version); - EXPECT_EQ("v19", value.android_sdk_groups["v19"].min_sdk_version.value()); + EXPECT_EQ(19, value.android_sdk_groups["v19"].min_sdk_version.value()); EXPECT_EQ(1ul, value.gl_texture_groups.size()); EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size()); @@ -321,9 +330,9 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { static constexpr const char* xml = R"xml( <android-sdk-group label="v19"> <android-sdk - minSdkVersion="v19" - targetSdkVersion="v24" - maxSdkVersion="v25"> + minSdkVersion="19" + targetSdkVersion="24" + maxSdkVersion="25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> @@ -342,14 +351,43 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { auto& out = config.android_sdk_groups["v19"]; AndroidSdk sdk; - sdk.min_sdk_version = std::string("v19"); - sdk.target_sdk_version = std::string("v24"); - sdk.max_sdk_version = std::string("v25"); + sdk.min_sdk_version = 19; + sdk.target_sdk_version = 24; + sdk.max_sdk_version = 25; sdk.manifest = AndroidManifest(); ASSERT_EQ(sdk, out); } +TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) { + static constexpr const char* xml = R"xml( + <android-sdk-group label="O"> + <android-sdk + minSdkVersion="M" + targetSdkVersion="O" + maxSdkVersion="O"> + </android-sdk> + </android-sdk-group>)xml"; + + auto doc = test::BuildXmlDom(xml); + + PostProcessingConfiguration config; + bool ok = android_sdk_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); + ASSERT_TRUE(ok); + + ASSERT_EQ(1ul, config.android_sdk_groups.size()); + ASSERT_EQ(1u, config.android_sdk_groups.count("O")); + + auto& out = config.android_sdk_groups["O"]; + + AndroidSdk sdk; + sdk.min_sdk_version = {}; // Only the latest development version is supported. + sdk.target_sdk_version = 26; + sdk.max_sdk_version = 26; + + ASSERT_EQ(sdk, out); +} + TEST_F(ConfigurationParserTest, GlTextureGroupAction) { static constexpr const char* xml = R"xml( <gl-texture-group label="dxt1"> diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp index 5ff890832371..563c46df26d1 100644 --- a/tools/aapt2/optimize/MultiApkGenerator.cpp +++ b/tools/aapt2/optimize/MultiApkGenerator.cpp @@ -22,22 +22,47 @@ #include "androidfw/StringPiece.h" #include "LoadedApk.h" +#include "ResourceUtils.h" #include "configuration/ConfigurationParser.h" #include "filter/AbiFilter.h" #include "filter/Filter.h" #include "flatten/Archive.h" +#include "flatten/XmlFlattener.h" #include "optimize/VersionCollapser.h" #include "process/IResourceTableConsumer.h" #include "split/TableSplitter.h" #include "util/Files.h" +#include "xml/XmlDom.h" namespace aapt { using ::aapt::configuration::AndroidSdk; using ::aapt::configuration::Artifact; using ::aapt::configuration::PostProcessingConfiguration; +using ::aapt::xml::XmlResource; using ::android::StringPiece; +namespace { + +Maybe<AndroidSdk> GetAndroidSdk(const Artifact& artifact, const PostProcessingConfiguration& config, + IDiagnostics* diag) { + if (!artifact.android_sdk_group) { + return {}; + } + + const std::string& group_name = artifact.android_sdk_group.value(); + auto group = config.android_sdk_groups.find(group_name); + // TODO: Remove validation when configuration parser ensures referential integrity. + if (group == config.android_sdk_groups.end()) { + diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); + return {}; + } + + return group->second; +} + +} // namespace + /** * Context wrapper that allows the min Android SDK value to be overridden. */ @@ -127,6 +152,43 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) { return false; } + std::unique_ptr<XmlResource> manifest; + + Maybe<AndroidSdk> maybe_sdk = GetAndroidSdk(artifact, config, diag); + if (maybe_sdk) { + // TODO(safarmer): Handle the rest of the Android SDK. + const AndroidSdk& android_sdk = maybe_sdk.value(); + + manifest = apk_->InflateManifest(context_); + if (!manifest) { + return false; + } + + // Make sure the first element is <manifest> with package attribute. + xml::Element* manifest_el = manifest->root.get(); + if (manifest_el == nullptr) { + return {}; + } + + if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") { + diag->Error(DiagMessage(manifest->file.source) << "root tag must be <manifest>"); + return {}; + } + + if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) { + if (xml::Attribute* min_sdk_attr = + uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) { + if (min_sdk_attr == nullptr) { + diag->Error(DiagMessage(manifest->file.source.WithLine(uses_sdk_el->line_number)) + << "missing android:minSdkVersion"); + return {}; + } + const std::string& min_sdk_str = std::to_string(android_sdk.min_sdk_version.value()); + min_sdk_attr->compiled_value = ResourceUtils::TryParseInt(min_sdk_str); + } + } + } + std::string out = options.out_dir; if (!file::mkdirs(out)) { context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out); @@ -145,7 +207,7 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) { } if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters, - writer.get())) { + writer.get(), manifest.get())) { return false; } } @@ -208,37 +270,15 @@ std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable( splits.config_filter = &axis_filter; } - if (artifact.android_sdk_group) { - const std::string& group_name = artifact.android_sdk_group.value(); - auto group = config.android_sdk_groups.find(group_name); - // TODO: Remove validation when configuration parser ensures referential integrity. - if (group == config.android_sdk_groups.end()) { - context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '" - << group_name << "'"); - return {}; - } - - const AndroidSdk& sdk = group->second; - if (!sdk.min_sdk_version) { - context_->GetDiagnostics()->Error(DiagMessage() - << "skipping SDK version. No min SDK: " << group_name); - return {}; - } - - ConfigDescription c; - const std::string& version = sdk.min_sdk_version.value(); - if (!ConfigDescription::Parse(version, &c)) { - context_->GetDiagnostics()->Error(DiagMessage() << "could not parse min SDK: " << version); - return {}; - } - - wrappedContext.SetMinSdkVersion(c.sdkVersion); + Maybe<AndroidSdk> sdk = GetAndroidSdk(artifact, config, context_->GetDiagnostics()); + if (sdk && sdk.value().min_sdk_version) { + wrappedContext.SetMinSdkVersion(sdk.value().min_sdk_version.value()); } std::unique_ptr<ResourceTable> table = old_table.Clone(); VersionCollapser collapser; - if (!collapser.Consume(context_, table.get())) { + if (!collapser.Consume(&wrappedContext, table.get())) { context_->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources"); return {}; } diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp index 23f573cd52a5..e8e6adc490e9 100644 --- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp +++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp @@ -50,14 +50,6 @@ using ::testing::Return; using ::testing::Test; using ::testing::_; -/** Subclass the LoadedApk class so that we can mock the WriteToArchive method. */ -class MockApk : public LoadedApk { - public: - MockApk(std::unique_ptr<ResourceTable> table) : LoadedApk({"test.apk"}, {}, std::move(table)){}; - MOCK_METHOD5(WriteToArchive, bool(IAaptContext*, ResourceTable*, const TableFlattenerOptions&, - FilterChain*, IArchiveWriter*)); -}; - /** * Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to * directly test table filter. @@ -111,54 +103,10 @@ class MultiApkGeneratorTest : public ::testing::Test { ConfigDescription v21_ = ParseConfigOrDie("v21"); }; -TEST_F(MultiApkGeneratorTest, FromBaseApk) { - std::unique_ptr<ResourceTable> table = BuildTable(); - - MockApk apk{std::move(table)}; - - EXPECT_CALL(apk, WriteToArchive(_, _, _, _, _)).Times(0); - - test::Context ctx; - PostProcessingConfiguration empty_config; - TableFlattenerOptions table_flattener_options; - - MultiApkGenerator generator{&apk, &ctx}; - EXPECT_TRUE(generator.FromBaseApk({"out", empty_config, table_flattener_options})); - - Artifact x64 = test::ArtifactBuilder() - .SetName("${basename}.x64.apk") - .SetAbiGroup("x64") - .SetLocaleGroup("en") - .SetDensityGroup("xhdpi") - .Build(); - - Artifact intel = test::ArtifactBuilder() - .SetName("${basename}.intel.apk") - .SetAbiGroup("intel") - .SetLocaleGroup("europe") - .SetDensityGroup("large") - .Build(); - - auto config = test::PostProcessingConfigurationBuilder() - .SetLocaleGroup("en", {"en"}) - .SetLocaleGroup("europe", {"en", "fr", "de", "es"}) - .SetAbiGroup("x64", {Abi::kX86_64}) - .SetAbiGroup("intel", {Abi::kX86_64, Abi::kX86}) - .SetDensityGroup("xhdpi", {"xhdpi"}) - .SetDensityGroup("large", {"xhdpi", "xxhdpi", "xxxhdpi"}) - .AddArtifact(x64) - .AddArtifact(intel) - .Build(); - - // Called once for each artifact. - EXPECT_CALL(apk, WriteToArchive(Eq(&ctx), _, _, _, _)).Times(2).WillRepeatedly(Return(true)); - EXPECT_TRUE(generator.FromBaseApk({"out", config, table_flattener_options})); -} - TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) { std::unique_ptr<ResourceTable> table = BuildTable(); - MockApk apk{std::move(table)}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table)}; std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build(); PostProcessingConfiguration empty_config; TableFlattenerOptions table_flattener_options; @@ -174,7 +122,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) { .SetLocaleGroup("en", {"en"}) .SetAbiGroup("x64", {Abi::kX86_64}) .SetDensityGroup("xhdpi", {"xhdpi"}) - .SetAndroidSdk("v23", AndroidSdk::ForMinSdk("v23")) + .SetAndroidSdk("v23", AndroidSdk::ForMinSdk(23)) .AddArtifact(x64) .Build(); @@ -199,7 +147,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) { TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) { std::unique_ptr<ResourceTable> table = BuildTable(); - MockApk apk{std::move(table)}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table)}; std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build(); PostProcessingConfiguration empty_config; TableFlattenerOptions table_flattener_options; @@ -215,7 +163,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) { .SetLocaleGroup("en", {"en"}) .SetAbiGroup("x64", {Abi::kX86_64}) .SetDensityGroup("xhdpi", {"xhdpi"}) - .SetAndroidSdk("v4", AndroidSdk::ForMinSdk("v4")) + .SetAndroidSdk("v4", AndroidSdk::ForMinSdk(4)) .AddArtifact(x64) .Build(); @@ -238,7 +186,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) { TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) { std::unique_ptr<ResourceTable> table = BuildTable(); - MockApk apk{std::move(table)}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table)}; std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build(); PostProcessingConfiguration empty_config; TableFlattenerOptions table_flattener_options; |