Implement filter-product

filter-product option is added to aapt2 compile, which filters values
with a given product and removes all other values (including default).
The motivation of this change is to generate product-specific RRO
automatically, making a main resource APK (e.g. framework-res.apk)
identical in all targets.

Bug: 294799593
Test: build
Change-Id: I42eb3e134c7aa120f6bbe2d26d311bd46b586595
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 44cd276..18165f7 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -20,12 +20,12 @@
 #include <set>
 #include <unordered_set>
 
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/StringPiece.h"
-
 #include "Resource.h"
 #include "SdkConstants.h"
+#include "android-base/macros.h"
+#include "android-base/result.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/StringPiece.h"
 #include "process/IResourceTableConsumer.h"
 #include "xml/XmlDom.h"
 
@@ -92,28 +92,6 @@
   DISALLOW_COPY_AND_ASSIGN(PrivateAttributeMover);
 };
 
-class ResourceConfigValue;
-
-class ProductFilter : public IResourceTableConsumer {
- public:
-  using ResourceConfigValueIter = std::vector<std::unique_ptr<ResourceConfigValue>>::iterator;
-
-  explicit ProductFilter(std::unordered_set<std::string> products) : products_(products) {
-  }
-
-  ResourceConfigValueIter SelectProductToKeep(const ResourceNameRef& name,
-                                              const ResourceConfigValueIter begin,
-                                              const ResourceConfigValueIter end,
-                                              android::IDiagnostics* diag);
-
-  bool Consume(IAaptContext* context, ResourceTable* table) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ProductFilter);
-
-  std::unordered_set<std::string> products_;
-};
-
 // Removes namespace nodes and URI information from the XmlResource.
 //
 // Once an XmlResource is processed by this consumer, it is no longer able to have its attributes
diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/link/ProductFilter.cpp
deleted file mode 100644
index 9544986..0000000
--- a/tools/aapt2/link/ProductFilter.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "link/Linkers.h"
-
-#include "ResourceTable.h"
-#include "trace/TraceBuffer.h"
-
-namespace aapt {
-
-ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
-    const ResourceNameRef& name, const ResourceConfigValueIter begin,
-    const ResourceConfigValueIter end, android::IDiagnostics* diag) {
-  ResourceConfigValueIter default_product_iter = end;
-  ResourceConfigValueIter selected_product_iter = end;
-
-  for (ResourceConfigValueIter iter = begin; iter != end; ++iter) {
-    ResourceConfigValue* config_value = iter->get();
-    if (products_.find(config_value->product) != products_.end()) {
-      if (selected_product_iter != end) {
-        // We have two possible values for this product!
-        diag->Error(android::DiagMessage(config_value->value->GetSource())
-                    << "selection of product '" << config_value->product << "' for resource "
-                    << name << " is ambiguous");
-
-        ResourceConfigValue* previously_selected_config_value =
-            selected_product_iter->get();
-        diag->Note(android::DiagMessage(previously_selected_config_value->value->GetSource())
-                   << "product '" << previously_selected_config_value->product
-                   << "' is also a candidate");
-        return end;
-      }
-
-      // Select this product.
-      selected_product_iter = iter;
-    }
-
-    if (config_value->product.empty() || config_value->product == "default") {
-      if (default_product_iter != end) {
-        // We have two possible default values.
-        diag->Error(android::DiagMessage(config_value->value->GetSource())
-                    << "multiple default products defined for resource " << name);
-
-        ResourceConfigValue* previously_default_config_value =
-            default_product_iter->get();
-        diag->Note(android::DiagMessage(previously_default_config_value->value->GetSource())
-                   << "default product also defined here");
-        return end;
-      }
-
-      // Mark the default.
-      default_product_iter = iter;
-    }
-  }
-
-  if (default_product_iter == end) {
-    diag->Error(android::DiagMessage() << "no default product defined for resource " << name);
-    return end;
-  }
-
-  if (selected_product_iter == end) {
-    selected_product_iter = default_product_iter;
-  }
-  return selected_product_iter;
-}
-
-bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) {
-  TRACE_NAME("ProductFilter::Consume");
-  bool error = false;
-  for (auto& pkg : table->packages) {
-    for (auto& type : pkg->types) {
-      for (auto& entry : type->entries) {
-        std::vector<std::unique_ptr<ResourceConfigValue>> new_values;
-
-        ResourceConfigValueIter iter = entry->values.begin();
-        ResourceConfigValueIter start_range_iter = iter;
-        while (iter != entry->values.end()) {
-          ++iter;
-          if (iter == entry->values.end() ||
-              (*iter)->config != (*start_range_iter)->config) {
-            // End of the array, or we saw a different config,
-            // so this must be the end of a range of products.
-            // Select the product to keep from the set of products defined.
-            ResourceNameRef name(pkg->name, type->named_type, entry->name);
-            auto value_to_keep = SelectProductToKeep(
-                name, start_range_iter, iter, context->GetDiagnostics());
-            if (value_to_keep == iter) {
-              // An error occurred, we could not pick a product.
-              error = true;
-            } else {
-              // We selected a product to keep. Move it to the new array.
-              new_values.push_back(std::move(*value_to_keep));
-            }
-
-            // Start the next range of products.
-            start_range_iter = iter;
-          }
-        }
-
-        // Now move the new values in to place.
-        entry->values = std::move(new_values);
-      }
-    }
-  }
-  return !error;
-}
-
-}  // namespace aapt
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
deleted file mode 100644
index 2cb9afa..0000000
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "link/Linkers.h"
-
-#include "test/Test.h"
-
-using ::android::ConfigDescription;
-
-namespace aapt {
-
-TEST(ProductFilterTest, SelectTwoProducts) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  const ConfigDescription land = test::ParseConfigOrDie("land");
-  const ConfigDescription port = test::ParseConfigOrDie("port");
-
-  ResourceTable table;
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/default.xml")).Build(),
-                    land)
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/tablet.xml")).Build(),
-                    land, "tablet")
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/default.xml")).Build(),
-                    port)
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/tablet.xml")).Build(),
-                    port, "tablet")
-          .Build(),
-      context->GetDiagnostics()));
-
-  ProductFilter filter({"tablet"});
-  ASSERT_TRUE(filter.Consume(context.get(), &table));
-
-  EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one", land, ""));
-  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one", land, "tablet"));
-  EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one", port, ""));
-  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one", port, "tablet"));
-}
-
-TEST(ProductFilterTest, SelectDefaultProduct) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  ResourceTable table;
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
-                    "tablet")
-          .Build(),
-      context->GetDiagnostics()));
-  ;
-
-  ProductFilter filter(std::unordered_set<std::string>{});
-  ASSERT_TRUE(filter.Consume(context.get(), &table));
-
-  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one",
-                         ConfigDescription::DefaultConfig(), ""));
-  EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(
-                         &table, "android:string/one",
-                         ConfigDescription::DefaultConfig(), "tablet"));
-}
-
-TEST(ProductFilterTest, FailOnAmbiguousProduct) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  ResourceTable table;
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
-                    "tablet")
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("no-sdcard.xml")).Build(),
-                    {}, "no-sdcard")
-          .Build(),
-      context->GetDiagnostics()));
-
-  ProductFilter filter({"tablet", "no-sdcard"});
-  ASSERT_FALSE(filter.Consume(context.get(), &table));
-}
-
-TEST(ProductFilterTest, FailOnMultipleDefaults) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  ResourceTable table;
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source(".xml")).Build())
-          .Build(),
-      context->GetDiagnostics()));
-
-  ASSERT_TRUE(table.AddResource(
-      NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
-          .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build(), {},
-                    "default")
-          .Build(),
-      context->GetDiagnostics()));
-
-  ProductFilter filter(std::unordered_set<std::string>{});
-  ASSERT_FALSE(filter.Consume(context.get(), &table));
-}
-
-}  // namespace aapt