Loading tools/aapt2/link/ManifestFixer.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -214,6 +214,33 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) { return true; } // Ensure that 'ns_decls' contains a declaration for 'uri', using 'prefix' as // the xmlns prefix if possible. static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::string& uri, std::vector<xml::NamespaceDecl>* ns_decls) { if (std::find_if(ns_decls->begin(), ns_decls->end(), [&](const xml::NamespaceDecl& ns_decl) { return ns_decl.uri == uri; }) != ns_decls->end()) { return; } std::set<std::string> used_prefixes; for (const auto& ns_decl : *ns_decls) { used_prefixes.insert(ns_decl.prefix); } // Make multiple attempts in the unlikely event that 'prefix' is already taken. std::string disambiguator; for (int i = 0; i < used_prefixes.size() + 1; i++) { std::string attempted_prefix = prefix + disambiguator; if (used_prefixes.find(attempted_prefix) == used_prefixes.end()) { ns_decls->push_back(xml::NamespaceDecl{attempted_prefix, uri}); return; } disambiguator = std::to_string(i); } } bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) { // First verify some options. Loading Loading @@ -262,6 +289,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action.Action(VerifyManifest); manifest_action.Action(FixCoreAppAttribute); manifest_action.Action([&](xml::Element* el) -> bool { EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls); if (options_.version_name_default) { if (options_.replace_version) { el->RemoveAttribute(xml::kSchemaAndroid, "versionName"); Loading tools/aapt2/link/ManifestFixer_test.cpp +28 −2 Original line number Diff line number Diff line Loading @@ -727,8 +727,7 @@ TEST_F(ManifestFixerTest, SupportKeySets) { } TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)"; std::string input = R"(<manifest package="com.pkg" />)"; ManifestFixerOptions options; options.compile_sdk_version = {"28"}; options.compile_sdk_version_codename = {"P"}; Loading @@ -736,6 +735,12 @@ TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // There should be a declaration of kSchemaAndroid, even when the input // didn't have one. EXPECT_EQ(manifest->root->namespace_decls.size(), 1); EXPECT_EQ(manifest->root->namespace_decls[0].prefix, "android"); EXPECT_EQ(manifest->root->namespace_decls[0].uri, xml::kSchemaAndroid); xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("28")); Loading Loading @@ -782,6 +787,27 @@ TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) { EXPECT_THAT(attr->value, StrEq("P")); } TEST_F(ManifestFixerTest, AndroidPrefixAlreadyUsed) { std::string input = R"(<manifest package="com.pkg" xmlns:android="http://schemas.android.com/apk/prv/res/android" android:private_attr="foo" />)"; ManifestFixerOptions options; options.compile_sdk_version = {"28"}; options.compile_sdk_version_codename = {"P"}; std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // Make sure that we don't redefine "android". EXPECT_EQ(manifest->root->namespace_decls.size(), 2); EXPECT_EQ(manifest->root->namespace_decls[0].prefix, "android"); EXPECT_EQ(manifest->root->namespace_decls[0].uri, "http://schemas.android.com/apk/prv/res/android"); EXPECT_EQ(manifest->root->namespace_decls[1].prefix, "android0"); EXPECT_EQ(manifest->root->namespace_decls[1].uri, xml::kSchemaAndroid); } TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" Loading Loading
tools/aapt2/link/ManifestFixer.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -214,6 +214,33 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) { return true; } // Ensure that 'ns_decls' contains a declaration for 'uri', using 'prefix' as // the xmlns prefix if possible. static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::string& uri, std::vector<xml::NamespaceDecl>* ns_decls) { if (std::find_if(ns_decls->begin(), ns_decls->end(), [&](const xml::NamespaceDecl& ns_decl) { return ns_decl.uri == uri; }) != ns_decls->end()) { return; } std::set<std::string> used_prefixes; for (const auto& ns_decl : *ns_decls) { used_prefixes.insert(ns_decl.prefix); } // Make multiple attempts in the unlikely event that 'prefix' is already taken. std::string disambiguator; for (int i = 0; i < used_prefixes.size() + 1; i++) { std::string attempted_prefix = prefix + disambiguator; if (used_prefixes.find(attempted_prefix) == used_prefixes.end()) { ns_decls->push_back(xml::NamespaceDecl{attempted_prefix, uri}); return; } disambiguator = std::to_string(i); } } bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) { // First verify some options. Loading Loading @@ -262,6 +289,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action.Action(VerifyManifest); manifest_action.Action(FixCoreAppAttribute); manifest_action.Action([&](xml::Element* el) -> bool { EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls); if (options_.version_name_default) { if (options_.replace_version) { el->RemoveAttribute(xml::kSchemaAndroid, "versionName"); Loading
tools/aapt2/link/ManifestFixer_test.cpp +28 −2 Original line number Diff line number Diff line Loading @@ -727,8 +727,7 @@ TEST_F(ManifestFixerTest, SupportKeySets) { } TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)"; std::string input = R"(<manifest package="com.pkg" />)"; ManifestFixerOptions options; options.compile_sdk_version = {"28"}; options.compile_sdk_version_codename = {"P"}; Loading @@ -736,6 +735,12 @@ TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // There should be a declaration of kSchemaAndroid, even when the input // didn't have one. EXPECT_EQ(manifest->root->namespace_decls.size(), 1); EXPECT_EQ(manifest->root->namespace_decls[0].prefix, "android"); EXPECT_EQ(manifest->root->namespace_decls[0].uri, xml::kSchemaAndroid); xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("28")); Loading Loading @@ -782,6 +787,27 @@ TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) { EXPECT_THAT(attr->value, StrEq("P")); } TEST_F(ManifestFixerTest, AndroidPrefixAlreadyUsed) { std::string input = R"(<manifest package="com.pkg" xmlns:android="http://schemas.android.com/apk/prv/res/android" android:private_attr="foo" />)"; ManifestFixerOptions options; options.compile_sdk_version = {"28"}; options.compile_sdk_version_codename = {"P"}; std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // Make sure that we don't redefine "android". EXPECT_EQ(manifest->root->namespace_decls.size(), 2); EXPECT_EQ(manifest->root->namespace_decls[0].prefix, "android"); EXPECT_EQ(manifest->root->namespace_decls[0].uri, "http://schemas.android.com/apk/prv/res/android"); EXPECT_EQ(manifest->root->namespace_decls[1].prefix, "android0"); EXPECT_EQ(manifest->root->namespace_decls[1].uri, xml::kSchemaAndroid); } TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" Loading