Allows features to link to other feature splits without namespacing.

Add uses-split dependencies to AppInfo. At link time, this is used
and allows features to reference other features, before
resource namespacing is implemented in Android Studio.

bug:135681292
Test: Link_test, ReferenceLinker_test, and integration tests.
Change-Id: Ifdf0067e7370552b6b9d4d6d4713d4484b6ea154
diff --git a/tests/FeatureSplit/feature1/Android.bp b/tests/FeatureSplit/feature1/Android.bp
index 1a93e84..706a4f5 100644
--- a/tests/FeatureSplit/feature1/Android.bp
+++ b/tests/FeatureSplit/feature1/Android.bp
@@ -18,7 +18,7 @@
     name: "FeatureSplit1",
     srcs: ["**/*.java"],
     sdk_version: "current",
-    libs: ["FeatureSplitBase"],
+    libs: ["FeatureSplitBase", "FeatureSplit2"],
     aaptflags: [
         "--package-id",
         "0x80",
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index b87361f..086c2c3 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -19,6 +19,7 @@
     featureSplit="feature1">
 
     <uses-sdk android:minSdkVersion="21" />
+    <uses-split android:name="feature2" />
 
     <application>
         <activity android:name=".one.One" android:label="Feature One">
diff --git a/tests/FeatureSplit/feature1/res/layout/included.xml b/tests/FeatureSplit/feature1/res/layout/included.xml
index c64bdb7..f0c56f8 100644
--- a/tests/FeatureSplit/feature1/res/layout/included.xml
+++ b/tests/FeatureSplit/feature1/res/layout/included.xml
@@ -2,4 +2,5 @@
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/text"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content" />
+    android:layout_height="wrap_content"
+    android:text="@string/feature2_string" />
diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml
index 7d58865..6a840df 100644
--- a/tests/FeatureSplit/feature1/res/values/values.xml
+++ b/tests/FeatureSplit/feature1/res/values/values.xml
@@ -20,7 +20,8 @@
     <integer name="test_integer2">200</integer>
     <color name="test_color2">#00ff00</color>
     <string-array name="string_array2">
-        <item>@string/app_title</item>
+      <item>@string/app_title</item>
+      <item>@string/feature2_string</item>
     </string-array>
 </resources>
 
diff --git a/tests/FeatureSplit/feature2/res/values/values.xml b/tests/FeatureSplit/feature2/res/values/values.xml
index af5ed1b..70e772c 100644
--- a/tests/FeatureSplit/feature2/res/values/values.xml
+++ b/tests/FeatureSplit/feature2/res/values/values.xml
@@ -15,10 +15,11 @@
 -->
 
 <resources>
+    <string name="feature2_string">feature 2 string referenced from feature 1</string>
     <integer name="test_integer3">300</integer>
     <color name="test_color3">#0000ff</color>
     <string-array name="string_array3">
-        <item>@string/app_title</item>
+      <item>@string/app_title</item>
     </string-array>
 </resources>
 
diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h
index 7512353..d3ca357 100644
--- a/tools/aapt2/AppInfo.h
+++ b/tools/aapt2/AppInfo.h
@@ -17,6 +17,7 @@
 #ifndef AAPT_APP_INFO_H
 #define AAPT_APP_INFO_H
 
+#include <set>
 #include <string>
 
 #include "util/Maybe.h"
@@ -42,6 +43,9 @@
 
   // The app's split name, if it is a split.
   Maybe<std::string> split_name;
+
+  // The split names that this split depends on.
+  std::set<std::string> split_name_dependencies;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 9b81369f..c7ac438 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -629,6 +629,12 @@
     return 0;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    UNIMPLEMENTED(FATAL) << "No Split Name Dependencies be needed in compile phase";
+    static std::set<std::string> empty;
+    return empty;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(CompileContext);
 
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 0cf86cc..22bcd85 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -243,6 +243,12 @@
     return 0u;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
+    static std::set<std::string> empty;
+    return empty;
+  }
+
   bool verbose_ = false;
   std::string package_;
 
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 262f4fc4e..d56994e 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -65,6 +65,12 @@
     return 0;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
+    static std::set<std::string> empty;
+    return empty;
+  }
+
  private:
   std::string empty_;
   StdErrDiagnostics diagnostics_;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index a23a6a4..429aff1 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -118,6 +118,12 @@
     return 0;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
+    static std::set<std::string> empty;
+    return empty;
+  }
+
  private:
   StdErrDiagnostics diagnostics_;
   bool verbose_ = false;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index b8be21c..ed2d0c1 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -140,6 +140,14 @@
     min_sdk_version_ = minSdk;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    return split_name_dependencies_;
+  }
+
+  void SetSplitNameDependencies(const std::set<std::string>& split_name_dependencies) {
+    split_name_dependencies_ = split_name_dependencies;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LinkContext);
 
@@ -151,6 +159,7 @@
   SymbolTable symbols_;
   bool verbose_ = false;
   int min_sdk_version_ = 0;
+  std::set<std::string> split_name_dependencies_;
 };
 
 // A custom delegate that generates compatible pre-O IDs for use with feature splits.
@@ -963,6 +972,17 @@
         app_info.min_sdk_version = ResourceUtils::ParseSdkVersion(min_sdk->value);
       }
     }
+
+    for (const xml::Element* child_el : manifest_el->GetChildElements()) {
+      if (child_el->namespace_uri.empty() && child_el->name == "uses-split") {
+        if (const xml::Attribute* split_name =
+            child_el->FindAttribute(xml::kSchemaAndroid, "name")) {
+          if (!split_name->value.empty()) {
+            app_info.split_name_dependencies.insert(split_name->value);
+          }
+        }
+      }
+    }
     return app_info;
   }
 
@@ -1770,6 +1790,7 @@
     context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0));
 
     context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
+    context_->SetSplitNameDependencies(app_info_.split_name_dependencies);
 
     // Override the package ID when it is "android".
     if (context_->GetCompilationPackage() == "android") {
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index bf8f043..062dd8e 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "AppInfo.h"
 #include "Link.h"
 
 #include "LoadedApk.h"
@@ -253,4 +254,67 @@
   EXPECT_EQ(actual_style->entries[0].key.id, 0x010100d4);  // android:background
 }
 
+TEST_F(LinkTest, AppInfoWithUsesSplit) {
+  StdErrDiagnostics diag;
+  const std::string base_files_dir = GetTestPath("base");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+                          R"(<resources>
+                               <string name="bar">bar</string>
+                             </resources>)",
+                          base_files_dir, &diag));
+  const std::string base_apk = GetTestPath("base.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest("com.aapt2.app"),
+      "-o", base_apk,
+  };
+  ASSERT_TRUE(Link(link_args, base_files_dir, &diag));
+
+  const std::string feature_manifest = GetTestPath("feature_manifest.xml");
+  WriteFile(feature_manifest, android::base::StringPrintf(R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.aapt2.app" split="feature1">
+      </manifest>)"));
+  const std::string feature_files_dir = GetTestPath("feature");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+                          R"(<resources>
+                               <string name="foo">foo</string>
+                             </resources>)",
+                          feature_files_dir, &diag));
+  const std::string feature_apk = GetTestPath("feature.apk");
+  const std::string feature_package_id = "0x80";
+  link_args = {
+      "--manifest", feature_manifest,
+      "-I", base_apk,
+      "--package-id", feature_package_id,
+      "-o", feature_apk,
+  };
+  ASSERT_TRUE(Link(link_args, feature_files_dir, &diag));
+
+  const std::string feature2_manifest = GetTestPath("feature2_manifest.xml");
+  WriteFile(feature2_manifest, android::base::StringPrintf(R"(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+            package="com.aapt2.app" split="feature2">
+          <uses-split android:name="feature1"/>
+        </manifest>)"));
+  const std::string feature2_files_dir = GetTestPath("feature2");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+                          R"(<resources>
+                               <string-array name="string_array">
+                                 <item>@string/bar</item>
+                                 <item>@string/foo</item>
+                               </string-array>
+                             </resources>)",
+                          feature2_files_dir, &diag));
+  const std::string feature2_apk = GetTestPath("feature2.apk");
+  const std::string feature2_package_id = "0x81";
+  link_args = {
+      "--manifest", feature2_manifest,
+      "-I", base_apk,
+      "-I", feature_apk,
+      "--package-id", feature2_package_id,
+      "-o", feature2_apk,
+  };
+  ASSERT_TRUE(Link(link_args, feature2_files_dir, &diag));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 2e6af18..5e06818 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -108,6 +108,12 @@
     return sdk_version_;
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
+    static std::set<std::string> empty;
+    return empty;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OptimizeContext);
 
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 28f09aa..8e49fab 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -17,6 +17,7 @@
 #include "link/ReferenceLinker.h"
 
 #include "android-base/logging.h"
+#include "android-base/stringprintf.h"
 #include "androidfw/ResourceTypes.h"
 
 #include "Diagnostics.h"
@@ -33,6 +34,7 @@
 
 using ::aapt::ResourceUtils::StringBuilder;
 using ::android::StringPiece;
+using ::android::base::StringPrintf;
 
 namespace aapt {
 
@@ -81,7 +83,7 @@
 
       // Find the attribute in the symbol table and check if it is visible from this callsite.
       const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
-          transformed_reference, callsite_, symbols_, &err_str);
+          transformed_reference, callsite_, context_, symbols_, &err_str);
       if (symbol) {
         // Assign our style key the correct ID. The ID may not exist.
         entry.key.id = symbol->id;
@@ -203,12 +205,35 @@
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
                                                           const CallSite& callsite,
+                                                          IAaptContext* context,
                                                           SymbolTable* symbols) {
   if (reference.name) {
     const ResourceName& name = reference.name.value();
     if (name.package.empty()) {
       // Use the callsite's package name if no package name was defined.
-      return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
+      const SymbolTable::Symbol* symbol = symbols->FindByName(
+          ResourceName(callsite.package, name.type, name.entry));
+      if (symbol) {
+        return symbol;
+      }
+
+      // If the callsite package is the same as the current compilation package,
+      // check the feature split dependencies as well. Feature split resources
+      // can be referenced without a namespace, just like the base package.
+      // TODO: modify the package name of included splits instead of having the
+      // symbol table look up the resource in in every package. b/136105066
+      if (callsite.package == context->GetCompilationPackage()) {
+        const auto& split_name_dependencies = context->GetSplitNameDependencies();
+        for (const std::string& split_name : split_name_dependencies) {
+          std::string split_package =
+              StringPrintf("%s.%s", callsite.package.c_str(), split_name.c_str());
+          symbol = symbols->FindByName(ResourceName(split_package, name.type, name.entry));
+          if (symbol) {
+            return symbol;
+          }
+        }
+      }
+      return nullptr;
     }
     return symbols->FindByName(name);
   } else if (reference.id) {
@@ -220,9 +245,10 @@
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
                                                                          const CallSite& callsite,
+                                                                         IAaptContext* context,
                                                                          SymbolTable* symbols,
                                                                          std::string* out_error) {
-  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols);
+  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, context, symbols);
   if (!symbol) {
     if (out_error) *out_error = "not found";
     return nullptr;
@@ -236,10 +262,10 @@
 }
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
-    const Reference& reference, const CallSite& callsite, SymbolTable* symbols,
-    std::string* out_error) {
+    const Reference& reference, const CallSite& callsite, IAaptContext* context,
+    SymbolTable* symbols, std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveSymbolCheckVisibility(reference, callsite, symbols, out_error);
+      ResolveSymbolCheckVisibility(reference, callsite, context, symbols, out_error);
   if (!symbol) {
     return nullptr;
   }
@@ -253,10 +279,11 @@
 
 Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
                                                                const CallSite& callsite,
+                                                               IAaptContext* context,
                                                                SymbolTable* symbols,
                                                                std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveAttributeCheckVisibility(reference, callsite, symbols, out_error);
+      ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error);
   if (!symbol) {
     return {};
   }
@@ -335,7 +362,7 @@
 
   std::string err_str;
   const SymbolTable::Symbol* s =
-      ResolveSymbolCheckVisibility(transformed_reference, callsite, symbols, &err_str);
+      ResolveSymbolCheckVisibility(transformed_reference, callsite, context, symbols, &err_str);
   if (s) {
     // The ID may not exist. This is fine because of the possibility of building
     // against libraries without assigned IDs.
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index b0b4945..1256709 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -39,13 +39,16 @@
   // package if the reference has no package name defined (implicit).
   // Returns nullptr if the symbol was not found.
   static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference,
-                                                  const CallSite& callsite, SymbolTable* symbols);
+                                                  const CallSite& callsite,
+                                                  IAaptContext* context,
+                                                  SymbolTable* symbols);
 
   // Performs name mangling and looks up the resource in the symbol table. If the symbol is not
   // visible by the reference at the callsite, nullptr is returned.
   // `out_error` holds the error message.
   static const SymbolTable::Symbol* ResolveSymbolCheckVisibility(const Reference& reference,
                                                                  const CallSite& callsite,
+                                                                 IAaptContext* context,
                                                                  SymbolTable* symbols,
                                                                  std::string* out_error);
 
@@ -53,6 +56,7 @@
   // That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute.
   static const SymbolTable::Symbol* ResolveAttributeCheckVisibility(const Reference& reference,
                                                                     const CallSite& callsite,
+                                                                    IAaptContext* context,
                                                                     SymbolTable* symbols,
                                                                     std::string* out_error);
 
@@ -60,6 +64,7 @@
   // If resolution fails, outError holds the error message.
   static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference,
                                                        const CallSite& callsite,
+                                                       IAaptContext* context,
                                                        SymbolTable* symbols,
                                                        std::string* out_error);
 
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index be38b96..a31ce94 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -266,8 +266,13 @@
 
   std::string error;
   const CallSite call_site{"com.app.test"};
+  std::unique_ptr<IAaptContext> context =
+    test::ContextBuilder()
+        .SetCompilationPackage("com.app.test")
+        .SetPackageId(0x7f)
+        .Build();
   const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
-      *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error);
+      *test::BuildReference("com.app.test:string/foo"), call_site, context.get(), &table, &error);
   ASSERT_THAT(symbol, NotNull());
   EXPECT_TRUE(error.empty());
 }
@@ -281,17 +286,23 @@
                          .AddPublicSymbol("com.app.test:attr/public_foo", ResourceId(0x7f010001),
                                           test::AttributeBuilder().Build())
                          .Build());
+  std::unique_ptr<IAaptContext> context =
+    test::ContextBuilder()
+        .SetCompilationPackage("com.app.ext")
+        .SetPackageId(0x7f)
+        .Build();
 
   std::string error;
   const CallSite call_site{"com.app.ext"};
 
   EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
-      *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error));
+      *test::BuildReference("com.app.test:attr/foo"), call_site, context.get(), &table, &error));
   EXPECT_FALSE(error.empty());
 
   error = "";
   ASSERT_TRUE(ReferenceLinker::CompileXmlAttribute(
-      *test::BuildReference("com.app.test:attr/public_foo"), call_site, &table, &error));
+      *test::BuildReference("com.app.test:attr/public_foo"), call_site, context.get(), &table,
+      &error));
   EXPECT_TRUE(error.empty());
 }
 
@@ -302,20 +313,62 @@
                          .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
                          .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001))
                          .Build());
+  std::unique_ptr<IAaptContext> context =
+    test::ContextBuilder()
+        .SetCompilationPackage("com.app.test")
+        .SetPackageId(0x7f)
+        .Build();
 
   const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
-                                                                CallSite{"com.app.test"}, &table);
+                                                                CallSite{"com.app.test"},
+                                                                context.get(), &table);
   ASSERT_THAT(s, NotNull());
   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
 
   s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
-                                     &table);
+                                     context.get(), &table);
   ASSERT_THAT(s, NotNull());
   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
 
   EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
-                                             CallSite{"com.app.bad"}, &table),
+                                             CallSite{"com.app.bad"}, context.get(), &table),
               IsNull());
 }
 
+TEST(ReferenceLinkerTest, ReferenceSymbolFromOtherSplit) {
+  NameMangler mangler(NameManglerPolicy{"com.app.test"});
+  SymbolTable table(&mangler);
+  table.AppendSource(test::StaticSymbolSourceBuilder()
+                         .AddSymbol("com.app.test.feature:string/bar", ResourceId(0x80010000))
+                         .Build());
+  std::set<std::string> split_name_dependencies;
+  split_name_dependencies.insert("feature");
+  std::unique_ptr<IAaptContext> context =
+      test::ContextBuilder()
+          .SetCompilationPackage("com.app.test")
+          .SetPackageId(0x81)
+          .SetSplitNameDependencies(split_name_dependencies)
+          .Build();
+
+  const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/bar"),
+                                                                CallSite{"com.app.test"},
+                                                                context.get(), &table);
+  ASSERT_THAT(s, NotNull());
+  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x80010000)));
+
+  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
+                                     context.get(), &table);
+  EXPECT_THAT(s, IsNull());
+
+  context =
+    test::ContextBuilder()
+        .SetCompilationPackage("com.app.test")
+        .SetPackageId(0x81)
+        .Build();
+  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/bar"),CallSite{"com.app.test"},
+                                     context.get(), &table);
+
+  EXPECT_THAT(s, IsNull());
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index d68f7dd..f3be483 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -99,7 +99,7 @@
 
         std::string err_str;
         attr.compiled_attribute =
-            ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, symbols_, &err_str);
+            ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, context_, symbols_, &err_str);
 
         if (!attr.compiled_attribute) {
           DiagMessage error_msg(source);
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 8c9c434..c686a10 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -101,6 +101,10 @@
         util::make_unique<SourcePathDiagnostics>(Source{source}, context_->GetDiagnostics());
   }
 
+  const std::set<std::string>& GetSplitNameDependencies() override {
+    return context_->GetSplitNameDependencies();
+  }
+
  private:
   IAaptContext* context_;
   std::unique_ptr<SourcePathDiagnostics> source_diag_;
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 30dad802..9c4b323 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -19,6 +19,7 @@
 
 #include <iostream>
 #include <list>
+#include <set>
 #include <sstream>
 
 #include "Diagnostics.h"
@@ -50,6 +51,7 @@
   virtual NameMangler* GetNameMangler() = 0;
   virtual bool IsVerbose() = 0;
   virtual int GetMinSdkVersion() = 0;
+  virtual const std::set<std::string>& GetSplitNameDependencies() = 0;
 };
 
 struct IResourceTableConsumer {
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 0564db0..7e10a59 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -81,6 +81,10 @@
     return min_sdk_version_;
   }
 
+ const std::set<std::string>& GetSplitNameDependencies() override {
+    return split_name_dependencies_;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Context);
 
@@ -93,6 +97,7 @@
   NameMangler name_mangler_;
   SymbolTable symbols_;
   int min_sdk_version_;
+  std::set<std::string> split_name_dependencies_;
 };
 
 class ContextBuilder {
@@ -127,6 +132,11 @@
     return *this;
   }
 
+  ContextBuilder& SetSplitNameDependencies(const std::set<std::string>& split_name_dependencies) {
+    context_->split_name_dependencies_ = split_name_dependencies;
+    return *this;
+  }
+
   std::unique_ptr<Context> Build() { return std::move(context_); }
 
  private: