Loading tools/aapt2/cmd/Optimize.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -194,8 +194,10 @@ class OptimizeCommand { if (options_.configuration && options_.output_dir) { MultiApkGenerator generator{apk.get(), context_}; if (!generator.FromBaseApk(options_.output_dir.value(), options_.configuration.value(), options_.table_flattener_options)) { MultiApkGeneratorOptions generator_options = {options_.output_dir.value(), options_.configuration.value(), options_.table_flattener_options}; if (!generator.FromBaseApk(generator_options)) { return 1; } } Loading tools/aapt2/configuration/ConfigurationParser.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -488,8 +488,8 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle return false; } auto& group = config->android_sdk_groups[label]; bool valid = true; bool found = false; for (auto* child : root_element->GetChildElements()) { if (child->name != "android-sdk") { Loading Loading @@ -520,7 +520,11 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle } } group.push_back(entry); config->android_sdk_groups[label] = entry; if (found) { valid = false; } found = true; } } Loading tools/aapt2/configuration/ConfigurationParser.h +11 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,10 @@ namespace configuration { template<class T> using Group = std::unordered_map<std::string, std::vector<T>>; /** A mapping of group label to a single configuration item. */ template <class T> using Entry = std::unordered_map<std::string, T>; /** Output artifact configuration options. */ struct Artifact { /** Name to use for output of processing foo.apk -> foo.<name>.apk. */ Loading Loading @@ -104,6 +108,12 @@ struct AndroidSdk { Maybe<std::string> max_sdk_version; Maybe<AndroidManifest> manifest; static AndroidSdk ForMinSdk(std::string min_sdk) { AndroidSdk sdk; sdk.min_sdk_version = {std::move(min_sdk)}; return sdk; } inline friend bool operator==(const AndroidSdk& lhs, const AndroidSdk& rhs) { return lhs.min_sdk_version == rhs.min_sdk_version && lhs.target_sdk_version == rhs.target_sdk_version && Loading Loading @@ -134,7 +144,7 @@ struct PostProcessingConfiguration { Group<Abi> abi_groups; Group<ConfigDescription> screen_density_groups; Group<ConfigDescription> locale_groups; Group<AndroidSdk> android_sdk_groups; Entry<AndroidSdk> android_sdk_groups; Group<DeviceFeature> device_feature_groups; Group<GlTexture> gl_texture_groups; Loading tools/aapt2/configuration/ConfigurationParser_test.cpp +32 −32 Original line number Diff line number Diff line Loading @@ -74,11 +74,11 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> <locale>es-rMX</locale> <locale>fr-rCA</locale> </locale-group> <android-sdk-group label="19"> <android-sdk-group label="v19"> <android-sdk minSdkVersion="19" targetSdkVersion="24" maxSdkVersion="25"> minSdkVersion="v19" targetSdkVersion="v24" maxSdkVersion="v25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> Loading @@ -102,7 +102,7 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> abi-group="arm" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/> <artifact Loading @@ -110,7 +110,7 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> abi-group="other" screen-density-group="alldpi" locale-group="north-america" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/> </artifacts> Loading Loading @@ -155,7 +155,8 @@ TEST_F(ConfigurationParserTest, ValidateFile) { EXPECT_EQ(3ul, value.locale_groups["north-america"].size()); EXPECT_EQ(1ul, value.android_sdk_groups.size()); EXPECT_EQ(1ul, value.android_sdk_groups["19"].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(1ul, value.gl_texture_groups.size()); EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size()); Loading @@ -178,7 +179,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { abi-group="arm" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/>)xml"; Loading @@ -195,7 +196,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { EXPECT_EQ("arm", artifact.abi_group.value()); EXPECT_EQ("large", artifact.screen_density_group.value()); EXPECT_EQ("europe", artifact.locale_group.value()); EXPECT_EQ("19", artifact.android_sdk_group.value()); EXPECT_EQ("v19", artifact.android_sdk_group.value()); EXPECT_EQ("dxt1", artifact.gl_texture_group.value()); EXPECT_EQ("low-latency", artifact.device_feature_group.value()); Loading @@ -205,7 +206,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { abi-group="other" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/>)xml"; doc = test::BuildXmlDom(second); Loading Loading @@ -318,11 +319,11 @@ TEST_F(ConfigurationParserTest, LocaleGroupAction) { TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { static constexpr const char* xml = R"xml( <android-sdk-group label="19"> <android-sdk-group label="v19"> <android-sdk minSdkVersion="19" targetSdkVersion="24" maxSdkVersion="25"> minSdkVersion="v19" targetSdkVersion="v24" maxSdkVersion="v25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> Loading @@ -336,18 +337,17 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { ASSERT_TRUE(ok); ASSERT_EQ(1ul, config.android_sdk_groups.size()); ASSERT_EQ(1u, config.android_sdk_groups.count("19")); ASSERT_EQ(1u, config.android_sdk_groups.count("v19")); auto& out = config.android_sdk_groups["19"]; auto& out = config.android_sdk_groups["v19"]; AndroidSdk sdk; sdk.min_sdk_version = std::string("19"); sdk.target_sdk_version = std::string("24"); sdk.max_sdk_version = std::string("25"); sdk.min_sdk_version = std::string("v19"); sdk.target_sdk_version = std::string("v24"); sdk.max_sdk_version = std::string("v25"); sdk.manifest = AndroidManifest(); ASSERT_EQ(1ul, out.size()); ASSERT_EQ(sdk, out[0]); ASSERT_EQ(sdk, out); } TEST_F(ConfigurationParserTest, GlTextureGroupAction) { Loading Loading @@ -454,41 +454,41 @@ TEST(ArtifactTest, Complex) { artifact.device_feature_group = {"df1"}; artifact.gl_texture_group = {"glx1"}; artifact.locale_group = {"en-AU"}; artifact.android_sdk_group = {"26"}; artifact.android_sdk_group = {"v26"}; { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag); "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.${ext}", "app.apk", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.${ext}", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}", "app.apk", &diag); "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } } Loading tools/aapt2/optimize/MultiApkGenerator.cpp +160 −53 Original line number Diff line number Diff line Loading @@ -26,25 +26,77 @@ #include "filter/AbiFilter.h" #include "filter/Filter.h" #include "flatten/Archive.h" #include "optimize/VersionCollapser.h" #include "process/IResourceTableConsumer.h" #include "split/TableSplitter.h" #include "util/Files.h" namespace aapt { using ::aapt::configuration::AndroidSdk; using ::aapt::configuration::Artifact; using ::aapt::configuration::PostProcessingConfiguration; using ::android::StringPiece; /** * Context wrapper that allows the min Android SDK value to be overridden. */ class ContextWrapper : public IAaptContext { public: explicit ContextWrapper(IAaptContext* context) : context_(context), min_sdk_(context_->GetMinSdkVersion()) { } PackageType GetPackageType() override { return context_->GetPackageType(); } SymbolTable* GetExternalSymbols() override { return context_->GetExternalSymbols(); } IDiagnostics* GetDiagnostics() override { return context_->GetDiagnostics(); } const std::string& GetCompilationPackage() override { return context_->GetCompilationPackage(); } uint8_t GetPackageId() override { return context_->GetPackageId(); } NameMangler* GetNameMangler() override { return context_->GetNameMangler(); } bool IsVerbose() override { return context_->IsVerbose(); } int GetMinSdkVersion() override { return min_sdk_; } void SetMinSdkVersion(int min_sdk) { min_sdk_ = min_sdk; } private: IAaptContext* context_; int min_sdk_ = -1; }; MultiApkGenerator::MultiApkGenerator(LoadedApk* apk, IAaptContext* context) : apk_(apk), context_(context) { } bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, const PostProcessingConfiguration& config, const TableFlattenerOptions& table_flattener_options) { bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) { // TODO(safarmer): Handle APK version codes for the generated APKs. IDiagnostics* diag = context_->GetDiagnostics(); const PostProcessingConfiguration& config = options.config; const std::string& apk_name = file::GetFilename(apk_->GetSource().path).to_string(); const StringPiece ext = file::GetExtension(apk_name); Loading @@ -53,8 +105,6 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, // For now, just write out the stripped APK since ABI splitting doesn't modify anything else. for (const Artifact& artifact : config.artifacts) { FilterChain filters; TableSplitterOptions splits; AxisConfigFilter axis_filter; if (!artifact.name && !config.artifact_format) { diag->Error( Loading @@ -71,16 +121,57 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, return false; } std::unique_ptr<ResourceTable> table = FilterTable(artifact, config, *apk_->GetResourceTable(), &filters); if (!table) { return false; } std::string out = options.out_dir; if (!file::mkdirs(out)) { context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out); } file::AppendPath(&out, artifact_name.value()); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "Generating split: " << out); } std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(context_->GetDiagnostics(), out); if (context_->IsVerbose()) { diag->Note(DiagMessage() << "Writing output: " << out); } if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters, writer.get())) { return false; } } return true; } std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable( const configuration::Artifact& artifact, const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table, FilterChain* filters) { TableSplitterOptions splits; AxisConfigFilter axis_filter; ContextWrapper wrappedContext{context_}; if (artifact.abi_group) { const std::string& group_name = artifact.abi_group.value(); auto group = config.abi_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.abi_groups.end()) { diag->Error(DiagMessage() << "could not find referenced ABI group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced ABI group '" << group_name << "'"); return {}; } filters.AddFilter(AbiFilter::FromAbiList(group->second)); filters->AddFilter(AbiFilter::FromAbiList(group->second)); } if (artifact.screen_density_group) { Loading @@ -89,14 +180,15 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, auto group = config.screen_density_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.screen_density_groups.end()) { diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return {}; } const std::vector<ConfigDescription>& densities = group->second; std::for_each(densities.begin(), densities.end(), [&](const ConfigDescription& c) { splits.preferred_densities.push_back(c.density); }); for(const auto& density_config : densities) { splits.preferred_densities.push_back(density_config.density); } } if (artifact.locale_group) { Loading @@ -104,41 +196,56 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, auto group = config.locale_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.locale_groups.end()) { diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return {}; } const std::vector<ConfigDescription>& locales = group->second; std::for_each(locales.begin(), locales.end(), [&](const ConfigDescription& c) { axis_filter.AddConfig(c); }); for (const auto& locale : locales) { axis_filter.AddConfig(locale); } splits.config_filter = &axis_filter; } std::unique_ptr<ResourceTable> table = apk_->GetResourceTable()->Clone(); TableSplitter splitter{{}, splits}; splitter.SplitTable(table.get()); std::string out = out_dir; if (!file::mkdirs(out)) { context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out); 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 {}; } file::AppendPath(&out, artifact_name.value()); std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(diag, out); const AndroidSdk& sdk = group->second; if (!sdk.min_sdk_version) { context_->GetDiagnostics()->Error(DiagMessage() << "skipping SDK version. No min SDK: " << group_name); return {}; } if (context_->IsVerbose()) { diag->Note(DiagMessage() << "Writing output: " << out); 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 {}; } if (!apk_->WriteToArchive(context_, table.get(), table_flattener_options, &filters, writer.get())) { return false; wrappedContext.SetMinSdkVersion(c.sdkVersion); } std::unique_ptr<ResourceTable> table = old_table.Clone(); VersionCollapser collapser; if (!collapser.Consume(context_, table.get())) { context_->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources"); return {}; } return true; TableSplitter splitter{{}, splits}; splitter.SplitTable(table.get()); return table; } } // namespace aapt Loading
tools/aapt2/cmd/Optimize.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -194,8 +194,10 @@ class OptimizeCommand { if (options_.configuration && options_.output_dir) { MultiApkGenerator generator{apk.get(), context_}; if (!generator.FromBaseApk(options_.output_dir.value(), options_.configuration.value(), options_.table_flattener_options)) { MultiApkGeneratorOptions generator_options = {options_.output_dir.value(), options_.configuration.value(), options_.table_flattener_options}; if (!generator.FromBaseApk(generator_options)) { return 1; } } Loading
tools/aapt2/configuration/ConfigurationParser.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -488,8 +488,8 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle return false; } auto& group = config->android_sdk_groups[label]; bool valid = true; bool found = false; for (auto* child : root_element->GetChildElements()) { if (child->name != "android-sdk") { Loading Loading @@ -520,7 +520,11 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle } } group.push_back(entry); config->android_sdk_groups[label] = entry; if (found) { valid = false; } found = true; } } Loading
tools/aapt2/configuration/ConfigurationParser.h +11 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,10 @@ namespace configuration { template<class T> using Group = std::unordered_map<std::string, std::vector<T>>; /** A mapping of group label to a single configuration item. */ template <class T> using Entry = std::unordered_map<std::string, T>; /** Output artifact configuration options. */ struct Artifact { /** Name to use for output of processing foo.apk -> foo.<name>.apk. */ Loading Loading @@ -104,6 +108,12 @@ struct AndroidSdk { Maybe<std::string> max_sdk_version; Maybe<AndroidManifest> manifest; static AndroidSdk ForMinSdk(std::string min_sdk) { AndroidSdk sdk; sdk.min_sdk_version = {std::move(min_sdk)}; return sdk; } inline friend bool operator==(const AndroidSdk& lhs, const AndroidSdk& rhs) { return lhs.min_sdk_version == rhs.min_sdk_version && lhs.target_sdk_version == rhs.target_sdk_version && Loading Loading @@ -134,7 +144,7 @@ struct PostProcessingConfiguration { Group<Abi> abi_groups; Group<ConfigDescription> screen_density_groups; Group<ConfigDescription> locale_groups; Group<AndroidSdk> android_sdk_groups; Entry<AndroidSdk> android_sdk_groups; Group<DeviceFeature> device_feature_groups; Group<GlTexture> gl_texture_groups; Loading
tools/aapt2/configuration/ConfigurationParser_test.cpp +32 −32 Original line number Diff line number Diff line Loading @@ -74,11 +74,11 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> <locale>es-rMX</locale> <locale>fr-rCA</locale> </locale-group> <android-sdk-group label="19"> <android-sdk-group label="v19"> <android-sdk minSdkVersion="19" targetSdkVersion="24" maxSdkVersion="25"> minSdkVersion="v19" targetSdkVersion="v24" maxSdkVersion="v25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> Loading @@ -102,7 +102,7 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> abi-group="arm" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/> <artifact Loading @@ -110,7 +110,7 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?> abi-group="other" screen-density-group="alldpi" locale-group="north-america" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/> </artifacts> Loading Loading @@ -155,7 +155,8 @@ TEST_F(ConfigurationParserTest, ValidateFile) { EXPECT_EQ(3ul, value.locale_groups["north-america"].size()); EXPECT_EQ(1ul, value.android_sdk_groups.size()); EXPECT_EQ(1ul, value.android_sdk_groups["19"].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(1ul, value.gl_texture_groups.size()); EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size()); Loading @@ -178,7 +179,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { abi-group="arm" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/>)xml"; Loading @@ -195,7 +196,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { EXPECT_EQ("arm", artifact.abi_group.value()); EXPECT_EQ("large", artifact.screen_density_group.value()); EXPECT_EQ("europe", artifact.locale_group.value()); EXPECT_EQ("19", artifact.android_sdk_group.value()); EXPECT_EQ("v19", artifact.android_sdk_group.value()); EXPECT_EQ("dxt1", artifact.gl_texture_group.value()); EXPECT_EQ("low-latency", artifact.device_feature_group.value()); Loading @@ -205,7 +206,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { abi-group="other" screen-density-group="large" locale-group="europe" android-sdk-group="19" android-sdk-group="v19" gl-texture-group="dxt1" device-feature-group="low-latency"/>)xml"; doc = test::BuildXmlDom(second); Loading Loading @@ -318,11 +319,11 @@ TEST_F(ConfigurationParserTest, LocaleGroupAction) { TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { static constexpr const char* xml = R"xml( <android-sdk-group label="19"> <android-sdk-group label="v19"> <android-sdk minSdkVersion="19" targetSdkVersion="24" maxSdkVersion="25"> minSdkVersion="v19" targetSdkVersion="v24" maxSdkVersion="v25"> <manifest> <!--- manifest additions here XSLT? TODO --> </manifest> Loading @@ -336,18 +337,17 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { ASSERT_TRUE(ok); ASSERT_EQ(1ul, config.android_sdk_groups.size()); ASSERT_EQ(1u, config.android_sdk_groups.count("19")); ASSERT_EQ(1u, config.android_sdk_groups.count("v19")); auto& out = config.android_sdk_groups["19"]; auto& out = config.android_sdk_groups["v19"]; AndroidSdk sdk; sdk.min_sdk_version = std::string("19"); sdk.target_sdk_version = std::string("24"); sdk.max_sdk_version = std::string("25"); sdk.min_sdk_version = std::string("v19"); sdk.target_sdk_version = std::string("v24"); sdk.max_sdk_version = std::string("v25"); sdk.manifest = AndroidManifest(); ASSERT_EQ(1ul, out.size()); ASSERT_EQ(sdk, out[0]); ASSERT_EQ(sdk, out); } TEST_F(ConfigurationParserTest, GlTextureGroupAction) { Loading Loading @@ -454,41 +454,41 @@ TEST(ArtifactTest, Complex) { artifact.device_feature_group = {"df1"}; artifact.gl_texture_group = {"glx1"}; artifact.locale_group = {"en-AU"}; artifact.android_sdk_group = {"26"}; artifact.android_sdk_group = {"v26"}; { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag); "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.${ext}", "app.apk", &diag); "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.${ext}", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } { auto result = artifact.ToArtifactName( "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}", "app.apk", &diag); "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}", "app.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk"); } } Loading
tools/aapt2/optimize/MultiApkGenerator.cpp +160 −53 Original line number Diff line number Diff line Loading @@ -26,25 +26,77 @@ #include "filter/AbiFilter.h" #include "filter/Filter.h" #include "flatten/Archive.h" #include "optimize/VersionCollapser.h" #include "process/IResourceTableConsumer.h" #include "split/TableSplitter.h" #include "util/Files.h" namespace aapt { using ::aapt::configuration::AndroidSdk; using ::aapt::configuration::Artifact; using ::aapt::configuration::PostProcessingConfiguration; using ::android::StringPiece; /** * Context wrapper that allows the min Android SDK value to be overridden. */ class ContextWrapper : public IAaptContext { public: explicit ContextWrapper(IAaptContext* context) : context_(context), min_sdk_(context_->GetMinSdkVersion()) { } PackageType GetPackageType() override { return context_->GetPackageType(); } SymbolTable* GetExternalSymbols() override { return context_->GetExternalSymbols(); } IDiagnostics* GetDiagnostics() override { return context_->GetDiagnostics(); } const std::string& GetCompilationPackage() override { return context_->GetCompilationPackage(); } uint8_t GetPackageId() override { return context_->GetPackageId(); } NameMangler* GetNameMangler() override { return context_->GetNameMangler(); } bool IsVerbose() override { return context_->IsVerbose(); } int GetMinSdkVersion() override { return min_sdk_; } void SetMinSdkVersion(int min_sdk) { min_sdk_ = min_sdk; } private: IAaptContext* context_; int min_sdk_ = -1; }; MultiApkGenerator::MultiApkGenerator(LoadedApk* apk, IAaptContext* context) : apk_(apk), context_(context) { } bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, const PostProcessingConfiguration& config, const TableFlattenerOptions& table_flattener_options) { bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) { // TODO(safarmer): Handle APK version codes for the generated APKs. IDiagnostics* diag = context_->GetDiagnostics(); const PostProcessingConfiguration& config = options.config; const std::string& apk_name = file::GetFilename(apk_->GetSource().path).to_string(); const StringPiece ext = file::GetExtension(apk_name); Loading @@ -53,8 +105,6 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, // For now, just write out the stripped APK since ABI splitting doesn't modify anything else. for (const Artifact& artifact : config.artifacts) { FilterChain filters; TableSplitterOptions splits; AxisConfigFilter axis_filter; if (!artifact.name && !config.artifact_format) { diag->Error( Loading @@ -71,16 +121,57 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, return false; } std::unique_ptr<ResourceTable> table = FilterTable(artifact, config, *apk_->GetResourceTable(), &filters); if (!table) { return false; } std::string out = options.out_dir; if (!file::mkdirs(out)) { context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out); } file::AppendPath(&out, artifact_name.value()); if (context_->IsVerbose()) { context_->GetDiagnostics()->Note(DiagMessage() << "Generating split: " << out); } std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(context_->GetDiagnostics(), out); if (context_->IsVerbose()) { diag->Note(DiagMessage() << "Writing output: " << out); } if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters, writer.get())) { return false; } } return true; } std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable( const configuration::Artifact& artifact, const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table, FilterChain* filters) { TableSplitterOptions splits; AxisConfigFilter axis_filter; ContextWrapper wrappedContext{context_}; if (artifact.abi_group) { const std::string& group_name = artifact.abi_group.value(); auto group = config.abi_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.abi_groups.end()) { diag->Error(DiagMessage() << "could not find referenced ABI group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced ABI group '" << group_name << "'"); return {}; } filters.AddFilter(AbiFilter::FromAbiList(group->second)); filters->AddFilter(AbiFilter::FromAbiList(group->second)); } if (artifact.screen_density_group) { Loading @@ -89,14 +180,15 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, auto group = config.screen_density_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.screen_density_groups.end()) { diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return {}; } const std::vector<ConfigDescription>& densities = group->second; std::for_each(densities.begin(), densities.end(), [&](const ConfigDescription& c) { splits.preferred_densities.push_back(c.density); }); for(const auto& density_config : densities) { splits.preferred_densities.push_back(density_config.density); } } if (artifact.locale_group) { Loading @@ -104,41 +196,56 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir, auto group = config.locale_groups.find(group_name); // TODO: Remove validation when configuration parser ensures referential integrity. if (group == config.locale_groups.end()) { diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return false; context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '" << group_name << "'"); return {}; } const std::vector<ConfigDescription>& locales = group->second; std::for_each(locales.begin(), locales.end(), [&](const ConfigDescription& c) { axis_filter.AddConfig(c); }); for (const auto& locale : locales) { axis_filter.AddConfig(locale); } splits.config_filter = &axis_filter; } std::unique_ptr<ResourceTable> table = apk_->GetResourceTable()->Clone(); TableSplitter splitter{{}, splits}; splitter.SplitTable(table.get()); std::string out = out_dir; if (!file::mkdirs(out)) { context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out); 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 {}; } file::AppendPath(&out, artifact_name.value()); std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(diag, out); const AndroidSdk& sdk = group->second; if (!sdk.min_sdk_version) { context_->GetDiagnostics()->Error(DiagMessage() << "skipping SDK version. No min SDK: " << group_name); return {}; } if (context_->IsVerbose()) { diag->Note(DiagMessage() << "Writing output: " << out); 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 {}; } if (!apk_->WriteToArchive(context_, table.get(), table_flattener_options, &filters, writer.get())) { return false; wrappedContext.SetMinSdkVersion(c.sdkVersion); } std::unique_ptr<ResourceTable> table = old_table.Clone(); VersionCollapser collapser; if (!collapser.Consume(context_, table.get())) { context_->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources"); return {}; } return true; TableSplitter splitter{{}, splits}; splitter.SplitTable(table.get()); return table; } } // namespace aapt