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/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);