diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 116dcd641bc11..a8d229956b731 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1085,6 +1085,10 @@ class Linker {
const auto localeconfig_entry =
ResolveTableEntry(context_, &final_table_, localeconfig_reference);
if (!localeconfig_entry) {
+ // If locale config is resolved from external symbols - skip validation.
+ if (context_->GetExternalSymbols()->FindByReference(*localeconfig_reference)) {
+ return true;
+ }
context_->GetDiagnostics()->Error(
android::DiagMessage(localeConfig->compiled_value->GetSource())
<< "no localeConfig entry");
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 254f3a546f99a..28fcc1a4800ec 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -840,6 +840,43 @@ TEST_F(LinkTest, LocaleConfigVerification) {
ASSERT_TRUE(Link(link1_args, &diag));
}
+TEST_F(LinkTest, LocaleConfigVerificationExternalSymbol) {
+ StdErrDiagnostics diag;
+ const std::string base_files_dir = GetTestPath("base");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/locales_config.xml"), R"(
+
+
+
+
+
+ )",
+ base_files_dir, &diag));
+ const std::string base_apk = GetTestPath("base.apk");
+ std::vector link_args = {
+ "--manifest",
+ GetDefaultManifest("com.aapt2.app"),
+ "-o",
+ base_apk,
+ };
+ ASSERT_TRUE(Link(link_args, base_files_dir, &diag));
+
+ const std::string localeconfig_manifest = GetTestPath("localeconfig_manifest.xml");
+ const std::string out_apk = GetTestPath("out.apk");
+ WriteFile(localeconfig_manifest, android::base::StringPrintf(R"(
+
+
+
+
+ )"));
+ link_args = LinkCommandBuilder(this)
+ .SetManifestFile(localeconfig_manifest)
+ .AddParameter("-I", base_apk)
+ .Build(out_apk);
+ ASSERT_TRUE(Link(link_args, &diag));
+}
+
TEST_F(LinkTest, LocaleConfigWrongTag) {
StdErrDiagnostics diag;
const std::string compiled_files_dir = GetTestPath("compiled");