Loading tools/aapt2/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ sources := \ link/ReferenceLinker.cpp \ link/TableMerger.cpp \ link/VersionCollapser.cpp \ link/XmlNamespaceRemover.cpp \ link/XmlReferenceLinker.cpp \ process/SymbolTable.cpp \ proto/ProtoHelpers.cpp \ Loading Loading @@ -89,6 +90,7 @@ testSources := \ link/ReferenceLinker_test.cpp \ link/TableMerger_test.cpp \ link/VersionCollapser_test.cpp \ link/XmlNamespaceRemover_test.cpp \ link/XmlReferenceLinker_test.cpp \ process/SymbolTable_test.cpp \ proto/TableProtoSerializer_test.cpp \ Loading tools/aapt2/link/Link.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ struct LinkOptions { bool generateNonFinalIds = false; std::vector<std::string> javadocAnnotations; bool outputToDirectory = false; bool noXmlNamespaces = false; bool autoAddOverlay = false; bool doNotCompressAnything = false; std::unordered_set<std::string> extensionsToNotCompress; Loading Loading @@ -293,6 +294,7 @@ static std::unique_ptr<ResourceFile> loadFileExportHeader(const Source& source, struct ResourceFileFlattenerOptions { bool noAutoVersion = false; bool noVersionVectors = false; bool noXmlNamespaces = false; bool keepRawValues = false; bool doNotCompressAnything = false; bool updateProguardSpec = false; Loading Loading @@ -382,6 +384,13 @@ bool ResourceFileFlattener::linkAndVersionXmlFile(const ResourceEntry* entry, return false; } if (mOptions.noXmlNamespaces) { XmlNamespaceRemover namespaceRemover; if (!namespaceRemover.consume(mContext, outFileOp->xmlToFlatten.get())) { return false; } } if (!mOptions.noAutoVersion) { if (mOptions.noVersionVectors) { // Skip this if it is a vector or animated-vector. Loading Loading @@ -1296,6 +1305,7 @@ public: fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress; fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion; fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors; fileFlattenerOptions.noXmlNamespaces = mOptions.noXmlNamespaces; fileFlattenerOptions.updateProguardSpec = static_cast<bool>(mOptions.generateProguardRulesPath); Loading Loading @@ -1594,6 +1604,14 @@ public: error = true; } } if (mOptions.noXmlNamespaces) { // PackageParser will fail if URIs are removed from AndroidManifest.xml. XmlNamespaceRemover namespaceRemover(true /* keepUris */); if (!namespaceRemover.consume(mContext, manifestXml.get())) { error = true; } } } else { error = true; } Loading Loading @@ -1732,6 +1750,9 @@ int link(const std::vector<StringPiece>& args) { .optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified " "by -o", &options.outputToDirectory) .optionalSwitch("--no-xml-namespaces", "Removes XML namespace prefix and URI " "information from AndroidManifest.xml\nand XML binaries in res/*.", &options.noXmlNamespaces) .optionalFlag("--min-sdk-version", "Default minimum SDK version to use for " "AndroidManifest.xml", &options.manifestFixerOptions.minSdkVersionDefault) Loading tools/aapt2/link/Linkers.h +17 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,23 @@ struct PrivateAttributeMover : public IResourceTableConsumer { bool consume(IAaptContext* context, ResourceTable* table) override; }; /** * Removes namespace nodes and URI information from the XmlResource. * * Once an XmlResource is processed by this consumer, it is no longer able to have its attributes * parsed. As such, this XmlResource must have already been processed by XmlReferenceLinker. */ class XmlNamespaceRemover : public IXmlResourceConsumer { private: bool mKeepUris; public: XmlNamespaceRemover(bool keepUris = false) : mKeepUris(keepUris) { }; bool consume(IAaptContext* context, xml::XmlResource* resource) override; }; /** * Resolves attributes in the XmlResource and compiles string values to resource values. * Once an XmlResource is processed by this linker, it is ready to be flattened. Loading tools/aapt2/link/XmlNamespaceRemover.cpp 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ResourceTable.h" #include "link/Linkers.h" #include <algorithm> namespace aapt { namespace { /** * Visits each xml Node, removing URI references and nested namespaces. */ class XmlVisitor : public xml::Visitor { public: XmlVisitor(bool keepUris) : mKeepUris(keepUris) { } void visit(xml::Element* el) override { // Strip namespaces for (auto& child : el->children) { while (child && xml::nodeCast<xml::Namespace>(child.get())) { if (child->children.empty()) { child = {}; } else { child = std::move(child->children.front()); child->parent = el; } } } el->children.erase(std::remove_if(el->children.begin(), el->children.end(), [](const std::unique_ptr<xml::Node>& child) -> bool { return child == nullptr; }), el->children.end()); if (!mKeepUris) { for (xml::Attribute& attr : el->attributes) { attr.namespaceUri = std::string(); } el->namespaceUri = std::string(); } xml::Visitor::visit(el); } private: bool mKeepUris; }; } // namespace bool XmlNamespaceRemover::consume(IAaptContext* context, xml::XmlResource* resource) { if (!resource->root) { return false; } // Replace any root namespaces until the root is a non-namespace node while (xml::nodeCast<xml::Namespace>(resource->root.get())) { if (resource->root->children.empty()) { break; } resource->root = std::move(resource->root->children.front()); resource->root->parent = nullptr; } XmlVisitor visitor(mKeepUris); resource->root->accept(&visitor); return true; } } // namespace aapt tools/aapt2/link/XmlNamespaceRemover_test.cpp 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "link/Linkers.h" #include "test/Test.h" namespace aapt { class XmlUriTestVisitor : public xml::Visitor { public: void visit(xml::Element* el) override { for (const auto& attr : el->attributes) { EXPECT_EQ(std::string(), attr.namespaceUri); } EXPECT_EQ(std::string(), el->namespaceUri); xml::Visitor::visit(el); } void visit(xml::Namespace* ns) override { EXPECT_EQ(std::string(), ns->namespaceUri); xml::Visitor::visit(ns); } }; class XmlNamespaceTestVisitor : public xml::Visitor { public: void visit(xml::Namespace* ns) override { ADD_FAILURE() << "Detected namespace: " << ns->namespacePrefix << "=\"" << ns->namespaceUri << "\""; xml::Visitor::visit(ns); } }; class XmlNamespaceRemoverTest : public ::testing::Test { public: void SetUp() override { mContext = test::ContextBuilder() .setCompilationPackage("com.app.test") .build(); } protected: std::unique_ptr<IAaptContext> mContext; }; TEST_F(XmlNamespaceRemoverTest, RemoveUris) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" android:text="hello" />)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlUriTestVisitor visitor; root->accept(&visitor); } TEST_F(XmlNamespaceRemoverTest, RemoveNamespaces) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" xmlns:foo="http://schemas.android.com/apk/res/foo" foo:bar="foobar" android:text="hello" />)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlNamespaceTestVisitor visitor; root->accept(&visitor); } TEST_F(XmlNamespaceRemoverTest, RemoveNestedNamespaces) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" android:text="hello"> <View xmlns:foo="http://schemas.example.com/foo" android:text="foo"/> </View>)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlNamespaceTestVisitor visitor; root->accept(&visitor); } } // namespace aapt Loading
tools/aapt2/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ sources := \ link/ReferenceLinker.cpp \ link/TableMerger.cpp \ link/VersionCollapser.cpp \ link/XmlNamespaceRemover.cpp \ link/XmlReferenceLinker.cpp \ process/SymbolTable.cpp \ proto/ProtoHelpers.cpp \ Loading Loading @@ -89,6 +90,7 @@ testSources := \ link/ReferenceLinker_test.cpp \ link/TableMerger_test.cpp \ link/VersionCollapser_test.cpp \ link/XmlNamespaceRemover_test.cpp \ link/XmlReferenceLinker_test.cpp \ process/SymbolTable_test.cpp \ proto/TableProtoSerializer_test.cpp \ Loading
tools/aapt2/link/Link.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ struct LinkOptions { bool generateNonFinalIds = false; std::vector<std::string> javadocAnnotations; bool outputToDirectory = false; bool noXmlNamespaces = false; bool autoAddOverlay = false; bool doNotCompressAnything = false; std::unordered_set<std::string> extensionsToNotCompress; Loading Loading @@ -293,6 +294,7 @@ static std::unique_ptr<ResourceFile> loadFileExportHeader(const Source& source, struct ResourceFileFlattenerOptions { bool noAutoVersion = false; bool noVersionVectors = false; bool noXmlNamespaces = false; bool keepRawValues = false; bool doNotCompressAnything = false; bool updateProguardSpec = false; Loading Loading @@ -382,6 +384,13 @@ bool ResourceFileFlattener::linkAndVersionXmlFile(const ResourceEntry* entry, return false; } if (mOptions.noXmlNamespaces) { XmlNamespaceRemover namespaceRemover; if (!namespaceRemover.consume(mContext, outFileOp->xmlToFlatten.get())) { return false; } } if (!mOptions.noAutoVersion) { if (mOptions.noVersionVectors) { // Skip this if it is a vector or animated-vector. Loading Loading @@ -1296,6 +1305,7 @@ public: fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress; fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion; fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors; fileFlattenerOptions.noXmlNamespaces = mOptions.noXmlNamespaces; fileFlattenerOptions.updateProguardSpec = static_cast<bool>(mOptions.generateProguardRulesPath); Loading Loading @@ -1594,6 +1604,14 @@ public: error = true; } } if (mOptions.noXmlNamespaces) { // PackageParser will fail if URIs are removed from AndroidManifest.xml. XmlNamespaceRemover namespaceRemover(true /* keepUris */); if (!namespaceRemover.consume(mContext, manifestXml.get())) { error = true; } } } else { error = true; } Loading Loading @@ -1732,6 +1750,9 @@ int link(const std::vector<StringPiece>& args) { .optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified " "by -o", &options.outputToDirectory) .optionalSwitch("--no-xml-namespaces", "Removes XML namespace prefix and URI " "information from AndroidManifest.xml\nand XML binaries in res/*.", &options.noXmlNamespaces) .optionalFlag("--min-sdk-version", "Default minimum SDK version to use for " "AndroidManifest.xml", &options.manifestFixerOptions.minSdkVersionDefault) Loading
tools/aapt2/link/Linkers.h +17 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,23 @@ struct PrivateAttributeMover : public IResourceTableConsumer { bool consume(IAaptContext* context, ResourceTable* table) override; }; /** * Removes namespace nodes and URI information from the XmlResource. * * Once an XmlResource is processed by this consumer, it is no longer able to have its attributes * parsed. As such, this XmlResource must have already been processed by XmlReferenceLinker. */ class XmlNamespaceRemover : public IXmlResourceConsumer { private: bool mKeepUris; public: XmlNamespaceRemover(bool keepUris = false) : mKeepUris(keepUris) { }; bool consume(IAaptContext* context, xml::XmlResource* resource) override; }; /** * Resolves attributes in the XmlResource and compiles string values to resource values. * Once an XmlResource is processed by this linker, it is ready to be flattened. Loading
tools/aapt2/link/XmlNamespaceRemover.cpp 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ResourceTable.h" #include "link/Linkers.h" #include <algorithm> namespace aapt { namespace { /** * Visits each xml Node, removing URI references and nested namespaces. */ class XmlVisitor : public xml::Visitor { public: XmlVisitor(bool keepUris) : mKeepUris(keepUris) { } void visit(xml::Element* el) override { // Strip namespaces for (auto& child : el->children) { while (child && xml::nodeCast<xml::Namespace>(child.get())) { if (child->children.empty()) { child = {}; } else { child = std::move(child->children.front()); child->parent = el; } } } el->children.erase(std::remove_if(el->children.begin(), el->children.end(), [](const std::unique_ptr<xml::Node>& child) -> bool { return child == nullptr; }), el->children.end()); if (!mKeepUris) { for (xml::Attribute& attr : el->attributes) { attr.namespaceUri = std::string(); } el->namespaceUri = std::string(); } xml::Visitor::visit(el); } private: bool mKeepUris; }; } // namespace bool XmlNamespaceRemover::consume(IAaptContext* context, xml::XmlResource* resource) { if (!resource->root) { return false; } // Replace any root namespaces until the root is a non-namespace node while (xml::nodeCast<xml::Namespace>(resource->root.get())) { if (resource->root->children.empty()) { break; } resource->root = std::move(resource->root->children.front()); resource->root->parent = nullptr; } XmlVisitor visitor(mKeepUris); resource->root->accept(&visitor); return true; } } // namespace aapt
tools/aapt2/link/XmlNamespaceRemover_test.cpp 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "link/Linkers.h" #include "test/Test.h" namespace aapt { class XmlUriTestVisitor : public xml::Visitor { public: void visit(xml::Element* el) override { for (const auto& attr : el->attributes) { EXPECT_EQ(std::string(), attr.namespaceUri); } EXPECT_EQ(std::string(), el->namespaceUri); xml::Visitor::visit(el); } void visit(xml::Namespace* ns) override { EXPECT_EQ(std::string(), ns->namespaceUri); xml::Visitor::visit(ns); } }; class XmlNamespaceTestVisitor : public xml::Visitor { public: void visit(xml::Namespace* ns) override { ADD_FAILURE() << "Detected namespace: " << ns->namespacePrefix << "=\"" << ns->namespaceUri << "\""; xml::Visitor::visit(ns); } }; class XmlNamespaceRemoverTest : public ::testing::Test { public: void SetUp() override { mContext = test::ContextBuilder() .setCompilationPackage("com.app.test") .build(); } protected: std::unique_ptr<IAaptContext> mContext; }; TEST_F(XmlNamespaceRemoverTest, RemoveUris) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" android:text="hello" />)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlUriTestVisitor visitor; root->accept(&visitor); } TEST_F(XmlNamespaceRemoverTest, RemoveNamespaces) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" xmlns:foo="http://schemas.android.com/apk/res/foo" foo:bar="foobar" android:text="hello" />)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlNamespaceTestVisitor visitor; root->accept(&visitor); } TEST_F(XmlNamespaceRemoverTest, RemoveNestedNamespaces) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( <View xmlns:android="http://schemas.android.com/apk/res/android" android:text="hello"> <View xmlns:foo="http://schemas.example.com/foo" android:text="foo"/> </View>)EOF"); XmlNamespaceRemover remover; ASSERT_TRUE(remover.consume(mContext.get(), doc.get())); xml::Node* root = doc.get()->root.get(); ASSERT_NE(root, nullptr); XmlNamespaceTestVisitor visitor; root->accept(&visitor); } } // namespace aapt