Option to exclude configs from AAPT2 Link

Adds --exclude-configs to remove matching configs from resulting APK. This matches on explicitness, so if the resource contains all the flags set by the option exactly, it will be removed, but not the other way around.

"--exclude-configs fr" with fr-land resource will remove.
"--exclude-configs fr-land" with fr resource will not remove.

Bug: 119678846

Test: aapt2_tests ResourceExcluder_test
Test: manually ran link on a test set of res

Change-Id: Ieccdecde4aea1fa0502abfd092dffa7da8f929ea
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 729447e..8463046 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -59,6 +59,7 @@
 #include "link/ManifestFixer.h"
 #include "link/NoDefaultResourceRemover.h"
 #include "link/ReferenceLinker.h"
+#include "link/ResourceExcluder.h"
 #include "link/TableMerger.h"
 #include "link/XmlCompatVersioner.h"
 #include "optimize/ResourceDeduper.h"
@@ -1828,6 +1829,29 @@
       }
     }
 
+    if (!options_.exclude_configs_.empty()) {
+      std::vector<ConfigDescription> excluded_configs;
+
+      for (auto& config_string : options_.exclude_configs_) {
+        ConfigDescription config_description;
+
+        if (!ConfigDescription::Parse(config_string, &config_description)) {
+          context_->GetDiagnostics()->Error(DiagMessage()
+                                                << "failed to parse --excluded-configs "
+                                                << config_string);
+          return 1;
+        }
+
+        excluded_configs.push_back(config_description);
+      }
+
+      ResourceExcluder excluder(excluded_configs);
+      if (!excluder.Consume(context_, &final_table_)) {
+        context_->GetDiagnostics()->Error(DiagMessage() << "failed excluding configurations");
+        return 1;
+      }
+    }
+
     if (!options_.no_resource_deduping) {
       ResourceDeduper deduper;
       if (!deduper.Consume(context_, &final_table_)) {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index f70470a..590a6bb 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -82,6 +82,9 @@
   std::vector<SplitConstraints> split_constraints;
   std::vector<std::string> split_paths;
 
+  // Configurations to exclude
+  std::vector<std::string> exclude_configs_;
+
   // Stable ID options.
   std::unordered_map<ResourceName, ResourceId> stable_id_map;
   Maybe<std::string> resource_id_map_path;
@@ -255,6 +258,9 @@
             "Syntax: path/to/output.apk:<config>[,<config>[...]].\n"
             "On Windows, use a semicolon ';' separator instead.",
         &split_args_);
+    AddOptionalFlagList("--exclude-configs",
+        "Excludes values of resources whose configs contain the specified qualifiers.",
+        &options_.exclude_configs_);
     AddOptionalSwitch("--debug-mode",
         "Inserts android:debuggable=\"true\" in to the application node of the\n"
             "manifest, making the application debuggable even on production devices.",