Loading tools/aapt2/cmd/Compile.cpp +22 −0 Original line number Diff line number Diff line Loading @@ -836,6 +836,28 @@ int CompileCommand::Action(const std::vector<std::string>& args) { return 1; } // Parse the feature flag values. An argument that starts with '@' points to a file to read flag // values from. std::vector<std::string> all_feature_flags_args; for (const std::string& arg : feature_flags_args_) { if (util::StartsWith(arg, "@")) { const std::string path = arg.substr(1, arg.size() - 1); std::string error; if (!file::AppendArgsFromFile(path, &all_feature_flags_args, &error)) { context.GetDiagnostics()->Error(android::DiagMessage(path) << error); return 1; } } else { all_feature_flags_args.push_back(arg); } } for (const std::string& arg : all_feature_flags_args) { if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { return 1; } } return Compile(&context, file_collection.get(), archive_writer.get(), options_); } Loading tools/aapt2/cmd/Compile.h +9 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "Command.h" #include "ResourceTable.h" #include "androidfw/IDiagnostics.h" #include "cmd/Util.h" #include "format/Archive.h" #include "process/IResourceTableConsumer.h" Loading @@ -45,6 +46,7 @@ struct CompileOptions { bool preserve_visibility_of_styleables = false; bool verbose = false; std::optional<std::string> product_; FeatureFlagValues feature_flag_values; }; /** Parses flags and compiles resources to be used in linking. */ Loading Loading @@ -92,6 +94,12 @@ class CompileCommand : public Command { "Leave only resources specific to the given product. All " "other resources (including defaults) are removed.", &options_.product_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' the name is separated from the value by '='.\n" "The name can have a suffix of ':ro' to indicate it is read only." "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); } int Action(const std::vector<std::string>& args) override; Loading @@ -101,6 +109,7 @@ class CompileCommand : public Command { CompileOptions options_; std::optional<std::string> visibility_; std::optional<std::string> trace_folder_; std::vector<std::string> feature_flags_args_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, Loading tools/aapt2/cmd/Link.h +3 −2 Original line number Diff line number Diff line Loading @@ -332,8 +332,9 @@ class LinkCommand : public Command { AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' and the name is separated from the value by '='.\n" "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).", "are separated by ',' the name is separated from the value by '='.\n" "The name can have a suffix of ':ro' to indicate it is read only." "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); AddOptionalSwitch("--non-updatable-system", "Mark the app as a non-updatable system app. This inserts\n" Loading tools/aapt2/cmd/Util.cpp +23 −4 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, if (parts.size() > 2) { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[=true|false]"); << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } Loading @@ -137,6 +137,25 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, diag->Error(android::DiagMessage() << "No name given for one or more flags in: " << arg); return false; } std::vector<std::string> name_parts = util::Split(flag_name, ':'); if (name_parts.size() > 2) { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } flag_name = name_parts[0]; bool read_only = false; if (name_parts.size() == 2) { if (name_parts[1] == "ro") { read_only = true; } else { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } } std::optional<bool> flag_value = {}; if (parts.size() == 2) { Loading @@ -151,13 +170,13 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, } } if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), flag_value); auto ffp = FeatureFlagProperties{read_only, flag_value}; if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), ffp); !inserted) { // We are allowing the same flag to appear multiple times, last value wins. diag->Note(android::DiagMessage() << "Value for feature flag '" << flag_name << "' was given more than once"); it->second = flag_value; it->second = ffp; } } return true; Loading tools/aapt2/cmd/Util.h +11 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,17 @@ namespace aapt { using FeatureFlagValues = std::map<std::string, std::optional<bool>, std::less<>>; struct FeatureFlagProperties { bool read_only; std::optional<bool> enabled; FeatureFlagProperties(bool ro, std::optional<bool> e) : read_only(ro), enabled(e) { } bool operator==(const FeatureFlagProperties&) const = default; }; using FeatureFlagValues = std::map<std::string, FeatureFlagProperties, std::less<>>; // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc). // Returns Nothing and logs a human friendly error message if the string was not legal. Loading Loading
tools/aapt2/cmd/Compile.cpp +22 −0 Original line number Diff line number Diff line Loading @@ -836,6 +836,28 @@ int CompileCommand::Action(const std::vector<std::string>& args) { return 1; } // Parse the feature flag values. An argument that starts with '@' points to a file to read flag // values from. std::vector<std::string> all_feature_flags_args; for (const std::string& arg : feature_flags_args_) { if (util::StartsWith(arg, "@")) { const std::string path = arg.substr(1, arg.size() - 1); std::string error; if (!file::AppendArgsFromFile(path, &all_feature_flags_args, &error)) { context.GetDiagnostics()->Error(android::DiagMessage(path) << error); return 1; } } else { all_feature_flags_args.push_back(arg); } } for (const std::string& arg : all_feature_flags_args) { if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { return 1; } } return Compile(&context, file_collection.get(), archive_writer.get(), options_); } Loading
tools/aapt2/cmd/Compile.h +9 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "Command.h" #include "ResourceTable.h" #include "androidfw/IDiagnostics.h" #include "cmd/Util.h" #include "format/Archive.h" #include "process/IResourceTableConsumer.h" Loading @@ -45,6 +46,7 @@ struct CompileOptions { bool preserve_visibility_of_styleables = false; bool verbose = false; std::optional<std::string> product_; FeatureFlagValues feature_flag_values; }; /** Parses flags and compiles resources to be used in linking. */ Loading Loading @@ -92,6 +94,12 @@ class CompileCommand : public Command { "Leave only resources specific to the given product. All " "other resources (including defaults) are removed.", &options_.product_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' the name is separated from the value by '='.\n" "The name can have a suffix of ':ro' to indicate it is read only." "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); } int Action(const std::vector<std::string>& args) override; Loading @@ -101,6 +109,7 @@ class CompileCommand : public Command { CompileOptions options_; std::optional<std::string> visibility_; std::optional<std::string> trace_folder_; std::vector<std::string> feature_flags_args_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, Loading
tools/aapt2/cmd/Link.h +3 −2 Original line number Diff line number Diff line Loading @@ -332,8 +332,9 @@ class LinkCommand : public Command { AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' and the name is separated from the value by '='.\n" "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).", "are separated by ',' the name is separated from the value by '='.\n" "The name can have a suffix of ':ro' to indicate it is read only." "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); AddOptionalSwitch("--non-updatable-system", "Mark the app as a non-updatable system app. This inserts\n" Loading
tools/aapt2/cmd/Util.cpp +23 −4 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, if (parts.size() > 2) { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[=true|false]"); << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } Loading @@ -137,6 +137,25 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, diag->Error(android::DiagMessage() << "No name given for one or more flags in: " << arg); return false; } std::vector<std::string> name_parts = util::Split(flag_name, ':'); if (name_parts.size() > 2) { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } flag_name = name_parts[0]; bool read_only = false; if (name_parts.size() == 2) { if (name_parts[1] == "ro") { read_only = true; } else { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } } std::optional<bool> flag_value = {}; if (parts.size() == 2) { Loading @@ -151,13 +170,13 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, } } if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), flag_value); auto ffp = FeatureFlagProperties{read_only, flag_value}; if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), ffp); !inserted) { // We are allowing the same flag to appear multiple times, last value wins. diag->Note(android::DiagMessage() << "Value for feature flag '" << flag_name << "' was given more than once"); it->second = flag_value; it->second = ffp; } } return true; Loading
tools/aapt2/cmd/Util.h +11 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,17 @@ namespace aapt { using FeatureFlagValues = std::map<std::string, std::optional<bool>, std::less<>>; struct FeatureFlagProperties { bool read_only; std::optional<bool> enabled; FeatureFlagProperties(bool ro, std::optional<bool> e) : read_only(ro), enabled(e) { } bool operator==(const FeatureFlagProperties&) const = default; }; using FeatureFlagValues = std::map<std::string, FeatureFlagProperties, std::less<>>; // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc). // Returns Nothing and logs a human friendly error message if the string was not legal. Loading