AAPT2: Automatic Static Library Namespacing.

Introduces a link flag --auto-namespace-static-lib for use when linking
static libraries.

When linking a static library with compiled sources that have references
to resources in provided libraries without an explicit package name,
the flag enables automatic inference of the package.

If a resource is present in the package that is being compiled, that is
used, otherwise the reference is rewritten to the highest precedence
resource with matching name and type.

Test: m out/host/linux-x86/nativetest64/aapt2_tests/aapt2_tests && \
      $ANDROID_HOST_OUT/nativetest64/aapt2_tests/aapt2_tests
Test: m frameworks/base/tools/aapt2/integration-tests
Change-Id: I6c6017e054654d1f60782d0a428a7a2a47f8952b
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 30dad802..a3a7719 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -50,6 +50,7 @@
   virtual NameMangler* GetNameMangler() = 0;
   virtual bool IsVerbose() = 0;
   virtual int GetMinSdkVersion() = 0;
+  virtual bool IsAutoNamespace() = 0;
 };
 
 struct IResourceTableConsumer {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 2e97a2f..f6f0a50 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -114,6 +114,16 @@
   return shared_symbol.get();
 }
 
+const SymbolTable::Symbol* SymbolTable::FindByNameInAnyPackage(const ResourceName& name) {
+  for (auto& source : sources_) {
+    std::string package = source->GetPackageForSymbol(name);
+    if (!package.empty()) {
+      return FindByName(ResourceName(package, name.type, name.entry));
+    }
+  }
+  return {};
+}
+
 const SymbolTable::Symbol* SymbolTable::FindById(const ResourceId& id) {
   if (const std::shared_ptr<Symbol>& s = id_cache_.get(id)) {
     return s.get();
@@ -211,6 +221,25 @@
   return symbol;
 }
 
+std::string ResourceTableSymbolSource::GetPackageForSymbol(const ResourceName& name) {
+  for (auto& package : table_->packages) {
+    ResourceTableType* type = package->FindType(name.type);
+    if (type == nullptr) {
+      continue;
+    }
+    ResourceEntry* entry = type->FindEntry(name.entry);
+    if (entry == nullptr) {
+      continue;
+    }
+    return package->name;
+  }
+  if (name.type == ResourceType::kAttr) {
+    // Recurse and try looking up a private attribute.
+    return GetPackageForSymbol(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
+  }
+  return {};
+}
+
 bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
   int32_t cookie = 0;
   return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie);
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index b676efb..c80e627 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -88,6 +88,13 @@
   // results are stored in a cache which may evict entries on subsequent calls.
   const Symbol* FindByName(const ResourceName& name);
 
+  // Finds the symbol from any package, for use as part of automatic conversion to namespaces.
+  // This returns the symbol from the highest priority package,
+  // which mimics the behavior of the resource merger and overlays.
+  // NOTE: Never hold on to the result between calls to FindByXXX. The
+  // results are stored in a cache which may evict entries on subsequent calls.
+  const Symbol* FindByNameInAnyPackage(const ResourceName& name);
+
   // NOTE: Never hold on to the result between calls to FindByXXX. The
   // results are stored in a cache which may evict entries on subsequent calls.
   const Symbol* FindById(const ResourceId& id);
@@ -152,6 +159,11 @@
 
   virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) = 0;
+  // Finds the name of a symbol from any package,
+  // for use as part of automatic conversion to namespaces.
+  // This returns the symbol from the highest priority package,
+  // which mimics the behavior of the resource merger and overlays.
+  virtual std::string GetPackageForSymbol(const ResourceName& name) = 0;
   virtual std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) = 0;
 
   // Default implementation tries the name if it exists, else the ID.
@@ -176,6 +188,7 @@
   std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) override;
 
+  std::string GetPackageForSymbol(const ResourceName& name) override;
   std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override {
     return {};
   }
@@ -195,6 +208,9 @@
 
   std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) override;
+  std::string GetPackageForSymbol(const ResourceName& name) override {
+    return {};
+  }
   std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override;
   std::unique_ptr<SymbolTable::Symbol> FindByReference(
       const Reference& ref) override;
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 1f59d70..df40b26 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -120,4 +120,39 @@
   EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.other:id/foo")), IsNull());
 }
 
+TEST(SymbolTableTest, FindByNameInAnyPackage) {
+  // This represents lib3 --depends-on--> lib2 --depends-on--> lib1
+
+  NameMangler mangler(NameManglerPolicy{"com.example.lib3"});
+  SymbolTable symbol_table(&mangler);
+  // Lib2 has higher precedence than lib1, as it is closer to the current library (lib3)
+  // in the dependency graph.
+
+  symbol_table.AppendSource(test::StaticSymbolSourceBuilder()
+                                .AddPublicSymbol("com.example.lib1:string/foo", ResourceId())
+                                .AddSymbol("com.example.lib1:attr/foo", ResourceId(),
+                                           test::AttributeBuilder()
+                                               .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
+                                               .AddItem("one", 0x01)
+                                               .AddItem("two", 0x02)
+                                               .Build())
+                                .Build());
+  symbol_table.PrependSource(test::StaticSymbolSourceBuilder()
+                                 .AddPublicSymbol("com.example.lib2:string/foo", ResourceId())
+                                 .Build());
+
+  // Sanity test
+  EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("string/foo")), IsNull());
+
+  // Test public symbol resolution
+  const SymbolTable::Symbol* const found_string =
+      symbol_table.FindByNameInAnyPackage(test::ParseNameOrDie("string/foo"));
+  ASSERT_THAT(found_string, NotNull());
+
+  // Test attr resolution
+  const SymbolTable::Symbol* const found_attr =
+      symbol_table.FindByNameInAnyPackage(test::ParseNameOrDie("attr/foo"));
+  ASSERT_THAT(found_attr, NotNull());
+}
+
 }  // namespace aapt