AAPT2: Insert <uses-sdk> element before <application>

PackageParser on the device uses the targetSdkVersion of the
app while it parses <application>. That means that if the
<uses-sdk> tag comes after <application>, the targetSdkVersion
is assumed to be 0.

Test: make libaapt2_tests
Change-Id: I60f2179a7ff44e7419217afb53f3d24f8c030f6e
This commit is contained in:
Adam Lesinski 2016-10-27 16:31:58 -07:00
parent 584264f6af
commit e343eb145c
5 changed files with 64 additions and 11 deletions

View File

@ -1356,8 +1356,8 @@ class LinkCommand {
application_el->attributes.push_back(
xml::Attribute{xml::kSchemaAndroid, "hasCode", "false"});
manifest_el->AddChild(std::move(application_el));
namespace_android->AddChild(std::move(manifest_el));
manifest_el->AppendChild(std::move(application_el));
namespace_android->AppendChild(std::move(manifest_el));
doc->root = std::move(namespace_android);
return doc;
}

View File

@ -309,10 +309,12 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
if ((options_.min_sdk_version_default ||
options_.target_sdk_version_default) &&
root->FindChild({}, "uses-sdk") == nullptr) {
// Auto insert a <uses-sdk> element.
// Auto insert a <uses-sdk> element. This must be inserted before the
// <application> tag. The device runtime PackageParser will make SDK version
// decisions while parsing <application>.
std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
uses_sdk->name = "uses-sdk";
root->AddChild(std::move(uses_sdk));
root->InsertChild(0, std::move(uses_sdk));
}
xml::XmlActionExecutor executor;
@ -327,7 +329,8 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
if (options_.rename_manifest_package) {
// Rename manifest package outside of the XmlActionExecutor.
// We need to extract the old package name and FullyQualify all class names.
// We need to extract the old package name and FullyQualify all class
// names.
if (!RenameManifestPackage(options_.rename_manifest_package.value(),
root)) {
return false;

View File

@ -168,6 +168,50 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
EXPECT_EQ("22", attr->value);
}
TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
ManifestFixerOptions options = {std::string("8"), std::string("22")};
std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<application android:name=".MainApplication" />
</manifest>)EOF",
options);
ASSERT_NE(nullptr, doc);
xml::Element* manifest_el = xml::FindRootElement(doc.get());
ASSERT_NE(nullptr, manifest_el);
ASSERT_EQ("manifest", manifest_el->name);
xml::Element* application_el = manifest_el->FindChild("", "application");
ASSERT_NE(nullptr, application_el);
xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
ASSERT_NE(nullptr, uses_sdk_el);
// Check that the uses_sdk_el comes before application_el in the children
// vector.
// Since there are no namespaces here, these children are direct descendants
// of manifest.
auto uses_sdk_iter =
std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
[&](const std::unique_ptr<xml::Node>& child) {
return child.get() == uses_sdk_el;
});
auto application_iter =
std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
[&](const std::unique_ptr<xml::Node>& child) {
return child.get() == application_el;
});
ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
ASSERT_NE(manifest_el->children.end(), application_iter);
// The distance should be positive, meaning uses_sdk_iter comes before
// application_iter.
EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
}
TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
ManifestFixerOptions options;
options.rename_manifest_package = std::string("com.android");

View File

@ -66,7 +66,7 @@ static void AddToStack(Stack* stack, XML_Parser parser,
Node* this_node = node.get();
if (!stack->node_stack.empty()) {
stack->node_stack.top()->AddChild(std::move(node));
stack->node_stack.top()->AppendChild(std::move(node));
} else {
stack->root = std::move(node);
}
@ -325,7 +325,7 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len,
root = std::move(new_node);
} else {
CHECK(!node_stack.empty()) << "node stack should not be empty";
node_stack.top()->AddChild(std::move(new_node));
node_stack.top()->AppendChild(std::move(new_node));
}
if (!NodeCast<Text>(this_node)) {
@ -346,7 +346,7 @@ std::unique_ptr<Node> Namespace::Clone() {
ns->children.reserve(children.size());
for (const std::unique_ptr<xml::Node>& child : children) {
ns->AddChild(child->Clone());
ns->AppendChild(child->Clone());
}
return std::move(ns);
}
@ -372,11 +372,16 @@ Element* FindRootElement(Node* node) {
return el;
}
void Node::AddChild(std::unique_ptr<Node> child) {
void Node::AppendChild(std::unique_ptr<Node> child) {
child->parent = this;
children.push_back(std::move(child));
}
void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
child->parent = this;
children.insert(children.begin() + index, std::move(child));
}
Attribute* Element::FindAttribute(const StringPiece& ns,
const StringPiece& name) {
for (auto& attr : attributes) {
@ -456,7 +461,7 @@ std::unique_ptr<Node> Element::Clone() {
el->children.reserve(children.size());
for (const std::unique_ptr<xml::Node>& child : children) {
el->AddChild(child->Clone());
el->AppendChild(child->Clone());
}
return std::move(el);
}

View File

@ -47,7 +47,8 @@ class Node {
virtual ~Node() = default;
void AddChild(std::unique_ptr<Node> child);
void AppendChild(std::unique_ptr<Node> child);
void InsertChild(size_t index, std::unique_ptr<Node> child);
virtual void Accept(RawVisitor* visitor) = 0;
virtual std::unique_ptr<Node> Clone() = 0;
};