diff options
Diffstat (limited to 'tools/aapt2/optimize')
-rw-r--r-- | tools/aapt2/optimize/MultiApkGenerator.cpp | 94 | ||||
-rw-r--r-- | tools/aapt2/optimize/MultiApkGenerator_test.cpp | 62 |
2 files changed, 72 insertions, 84 deletions
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; |