18c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "ManifestMerger.h" 28c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "Maybe.h" 38c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "ResourceParser.h" 48c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "Source.h" 58c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "Util.h" 68c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include "XmlPullParser.h" 78c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 88c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include <iostream> 98c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include <memory> 108c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include <set> 118c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski#include <string> 128c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 138c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskinamespace aapt { 148c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 158c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskiconstexpr const char16_t* kSchemaAndroid = u"http://schemas.android.com/apk/res/android"; 168c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 178c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic xml::Element* findManifest(xml::Node* root) { 188c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!root) { 198c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return nullptr; 208c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 218c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 228c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski while (root->type == xml::NodeType::kNamespace) { 238c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (root->children.empty()) { 248c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski break; 258c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 268c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski root = root->children[0].get(); 278c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 288c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 298c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (root && root->type == xml::NodeType::kElement) { 308c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* el = static_cast<xml::Element*>(root); 318c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (el->namespaceUri.empty() && el->name == u"manifest") { 328c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return el; 338c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 348c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 358c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return nullptr; 368c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 378c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 388c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic xml::Element* findChildWithSameName(xml::Element* parent, xml::Element* src) { 398c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* attrKey = src->findAttribute(kSchemaAndroid, u"name"); 408c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!attrKey) { 418c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return nullptr; 428c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 438c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return parent->findChildWithAttribute(src->namespaceUri, src->name, attrKey); 448c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 458c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 468c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic bool attrLess(const xml::Attribute& lhs, const xml::Attribute& rhs) { 478c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return std::tie(lhs.namespaceUri, lhs.name, lhs.value) 488c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski < std::tie(rhs.namespaceUri, rhs.name, rhs.value); 498c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 508c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 518c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic int compare(xml::Element* lhs, xml::Element* rhs) { 528c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski int diff = lhs->attributes.size() - rhs->attributes.size(); 538c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (diff != 0) { 548c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return diff; 558c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 568c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 578c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::set<xml::Attribute, decltype(&attrLess)> lhsAttrs(&attrLess); 588c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski lhsAttrs.insert(lhs->attributes.begin(), lhs->attributes.end()); 598c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (auto& attr : rhs->attributes) { 608c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (lhsAttrs.erase(attr) == 0) { 618c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // The rhs attribute is not in the left. 628c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return -1; 638c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 648c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 658c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 668c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!lhsAttrs.empty()) { 678c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // The lhs has attributes not in the rhs. 688c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return 1; 698c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 708c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return 0; 718c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 728c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 738c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam LesinskiManifestMerger::ManifestMerger(const Options& options) : 748c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mOptions(options), mAppLogger({}), mLogger({}) { 758c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 768c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 778c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::setAppManifest(const Source& source, const std::u16string& package, 788c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::unique_ptr<xml::Node> root) { 798c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 808c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mAppLogger = SourceLogger{ source }; 818c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mRoot = std::move(root); 828c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 838c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 848c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 858c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::checkEqual(xml::Element* elA, xml::Element* elB) { 868c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (compare(elA, elB) != 0) { 878c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.error(elB->lineNumber) 888c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "library tag '" << elB->name << "' conflicts with app tag." 898c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 908c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mAppLogger.note(elA->lineNumber) 918c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "app tag '" << elA->name << "' defined here." 928c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 938c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 948c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 958c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 968c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::vector<xml::Element*> childrenA = elA->getChildElements(); 978c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::vector<xml::Element*> childrenB = elB->getChildElements(); 988c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 998c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (childrenA.size() != childrenB.size()) { 1008c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.error(elB->lineNumber) 1018c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "library tag '" << elB->name << "' children conflict with app tag." 1028c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 1038c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mAppLogger.note(elA->lineNumber) 1048c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "app tag '" << elA->name << "' defined here." 1058c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 1068c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 1078c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1088c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1098c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski auto cmp = [](xml::Element* lhs, xml::Element* rhs) -> bool { 1108c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return compare(lhs, rhs) < 0; 1118c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski }; 1128c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1138c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::sort(childrenA.begin(), childrenA.end(), cmp); 1148c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::sort(childrenB.begin(), childrenB.end(), cmp); 1158c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1168c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (size_t i = 0; i < childrenA.size(); i++) { 1178c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!checkEqual(childrenA[i], childrenB[i])) { 1188c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 1198c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1208c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1218c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 1228c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 1238c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1248c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::mergeNewOrEqual(xml::Element* parentA, xml::Element* elA, xml::Element* elB) { 1258c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!elA) { 1268c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski parentA->addChild(elB->clone()); 1278c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 1288c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1298c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return checkEqual(elA, elB); 1308c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 1318c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1328c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::mergePreferRequired(xml::Element* parentA, xml::Element* elA, 1338c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elB) { 1348c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!elA) { 1358c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski parentA->addChild(elB->clone()); 1368c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 1378c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1388c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1398c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* reqA = elA->findAttribute(kSchemaAndroid, u"required"); 1408c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* reqB = elB->findAttribute(kSchemaAndroid, u"required"); 1418c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski bool requiredA = !reqA || (reqA->value != u"false" && reqA->value != u"FALSE"); 1428c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski bool requiredB = !reqB || (reqB->value != u"false" && reqB->value != u"FALSE"); 1438c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!requiredA && requiredB) { 1448c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (reqA) { 1458c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski *reqA = xml::Attribute{ kSchemaAndroid, u"required", u"true" }; 1468c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else { 1478c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski elA->attributes.push_back(xml::Attribute{ kSchemaAndroid, u"required", u"true" }); 1488c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1498c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1508c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 1518c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 1528c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1538c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic int findIntegerValue(xml::Attribute* attr, int defaultValue) { 1548c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (attr) { 1558c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::unique_ptr<BinaryPrimitive> integer = ResourceParser::tryParseInt(attr->value); 1568c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (integer) { 1578c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return integer->value.data; 1588c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1598c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1608c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return defaultValue; 1618c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 1628c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1638c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::mergeUsesSdk(xml::Element* elA, xml::Element* elB) { 1648c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski bool error = false; 1658c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* minAttrA = nullptr; 1668c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* minAttrB = nullptr; 1678c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elA) { 1688c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski minAttrA = elA->findAttribute(kSchemaAndroid, u"minSdkVersion"); 1698c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1708c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1718c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elB) { 1728c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski minAttrB = elB->findAttribute(kSchemaAndroid, u"minSdkVersion"); 1738c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1748c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1758c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski int minSdkA = findIntegerValue(minAttrA, 1); 1768c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski int minSdkB = findIntegerValue(minAttrB, 1); 1778c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1788c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (minSdkA < minSdkB) { 1798c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::ostream* out; 1808c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (minAttrA) { 1818c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.error(elA->lineNumber) << "app declares "); 1828c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (elA) { 1838c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.error(elA->lineNumber) << "app has implied "); 1848c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else { 1858c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.error() << "app has implied "); 1868c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1878c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1888c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski *out << "minSdkVersion=" << minSdkA << " but library expects a higher SDK version." 1898c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 1908c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1918c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // elB is valid because minSdkB wouldn't be greater than minSdkA if it wasn't. 1928c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.note(elB->lineNumber) 1938c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "library declares minSdkVersion=" << minSdkB << "." 1948c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 1958c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error = true; 1968c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 1978c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 1988c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* targetAttrA = nullptr; 1998c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* targetAttrB = nullptr; 2008c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2018c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elA) { 2028c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski targetAttrA = elA->findAttribute(kSchemaAndroid, u"targetSdkVersion"); 2038c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2048c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2058c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elB) { 2068c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski targetAttrB = elB->findAttribute(kSchemaAndroid, u"targetSdkVersion"); 2078c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2088c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2098c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski int targetSdkA = findIntegerValue(targetAttrA, minSdkA); 2108c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski int targetSdkB = findIntegerValue(targetAttrB, minSdkB); 2118c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2128c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (targetSdkA < targetSdkB) { 2138c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::ostream* out; 2148c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (targetAttrA) { 2158c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.warn(elA->lineNumber) << "app declares "); 2168c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (elA) { 2178c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.warn(elA->lineNumber) << "app has implied "); 2188c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else { 2198c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski out = &(mAppLogger.warn() << "app has implied "); 2208c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2218c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2228c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski *out << "targetSdkVerion=" << targetSdkA << " but library expects target SDK " 2238c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << targetSdkB << "." << std::endl; 2248c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2258c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.note(elB->lineNumber) 2268c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "library declares targetSdkVersion=" << targetSdkB << "." 2278c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << std::endl; 2288c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error = true; 2298c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2308c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return !error; 2318c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 2328c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2338c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::mergeApplication(xml::Element* applicationA, xml::Element* applicationB) { 2348c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!applicationA || !applicationB) { 2358c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 2368c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2378c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2388c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski bool error = false; 2398c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2408c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // First make sure that the names are identical. 2418c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* nameA = applicationA->findAttribute(kSchemaAndroid, u"name"); 2428c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Attribute* nameB = applicationB->findAttribute(kSchemaAndroid, u"name"); 2438c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (nameB) { 2448c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!nameA) { 2458c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski applicationA->attributes.push_back(*nameB); 2468c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (nameA->value != nameB->value) { 2478c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.error(applicationB->lineNumber) 2488c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "conflicting application name '" 2498c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << nameB->value 2508c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "'." << std::endl; 2518c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mAppLogger.note(applicationA->lineNumber) 2528c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "application defines application name '" 2538c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << nameA->value 2548c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "'." << std::endl; 2558c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error = true; 2568c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2578c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2588c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2598c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // Now we descend into the activity/receiver/service/provider tags 2608c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (xml::Element* elB : applicationB->getChildElements()) { 2618c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!elB->namespaceUri.empty()) { 2628c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski continue; 2638c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2648c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2658c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elB->name == u"activity" || elB->name == u"activity-alias" 2668c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski || elB->name == u"service" || elB->name == u"receiver" 2678c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski || elB->name == u"provider" || elB->name == u"meta-data") { 2688c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elA = findChildWithSameName(applicationA, elB); 2698c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergeNewOrEqual(applicationA, elA, elB); 2708c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (elB->name == u"uses-library") { 2718c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elA = findChildWithSameName(applicationA, elB); 2728c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergePreferRequired(applicationA, elA, elB); 2738c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2748c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2758c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return !error; 2768c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 2778c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2788c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::mergeLibraryManifest(const Source& source, const std::u16string& package, 2798c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::unique_ptr<xml::Node> libRoot) { 2808c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger = SourceLogger{ source }; 2818c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* manifestA = findManifest(mRoot.get()); 2828c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* manifestB = findManifest(libRoot.get()); 2838c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!manifestA) { 2848c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mAppLogger.error() << "missing manifest tag." << std::endl; 2858c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 2868c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2878c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2888c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!manifestB) { 2898c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski mLogger.error() << "library missing manifest tag." << std::endl; 2908c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 2918c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 2928c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2938c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski bool error = false; 2948c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 2958c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // Do <application> first. 2968c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* applicationA = manifestA->findChild({}, u"application"); 2978c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* applicationB = manifestB->findChild({}, u"application"); 2988c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergeApplication(applicationA, applicationB); 2998c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3008c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski // Do <uses-sdk> next. 3018c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* usesSdkA = manifestA->findChild({}, u"uses-sdk"); 3028c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* usesSdkB = manifestB->findChild({}, u"uses-sdk"); 3038c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergeUsesSdk(usesSdkA, usesSdkB); 3048c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3058c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (xml::Element* elB : manifestB->getChildElements()) { 3068c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!elB->namespaceUri.empty()) { 3078c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski continue; 3088c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3098c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3108c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (elB->name == u"uses-permission" || elB->name == u"permission" 3118c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski || elB->name == u"permission-group" || elB->name == u"permission-tree") { 3128c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elA = findChildWithSameName(manifestA, elB); 3138c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergeNewOrEqual(manifestA, elA, elB); 3148c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (elB->name == u"uses-feature") { 3158c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elA = findChildWithSameName(manifestA, elB); 3168c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !mergePreferRequired(manifestA, elA, elB); 3178c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } else if (elB->name == u"uses-configuration" || elB->name == u"supports-screen" 3188c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski || elB->name == u"compatible-screens" || elB->name == u"supports-gl-texture") { 3198c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski xml::Element* elA = findChildWithSameName(manifestA, elB); 3208c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski error |= !checkEqual(elA, elB); 3218c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3228c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3238c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return !error; 3248c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 3258c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3268c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskistatic void printMerged(xml::Node* node, int depth) { 3278c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::string indent; 3288c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (int i = 0; i < depth; i++) { 3298c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski indent += " "; 3308c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3318c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3328c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski switch (node->type) { 3338c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski case xml::NodeType::kNamespace: 3348c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::cerr << indent << "N: " 3358c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "xmlns:" << static_cast<xml::Namespace*>(node)->namespacePrefix 3368c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "=\"" << static_cast<xml::Namespace*>(node)->namespaceUri 3378c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "\"\n"; 3388c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski break; 3398c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3408c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski case xml::NodeType::kElement: 3418c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::cerr << indent << "E: " 3428c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << static_cast<xml::Element*>(node)->namespaceUri 3438c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << ":" << static_cast<xml::Element*>(node)->name 3448c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "\n"; 3458c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (const auto& attr : static_cast<xml::Element*>(node)->attributes) { 3468c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::cerr << indent << " A: " 3478c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << attr.namespaceUri 3488c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << ":" << attr.name 3498c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski << "=\"" << attr.value << "\"\n"; 3508c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3518c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski break; 3528c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3538c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski case xml::NodeType::kText: 3548c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski std::cerr << indent << "T: \"" << static_cast<xml::Text*>(node)->text << "\"\n"; 3558c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski break; 3568c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3578c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3588c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski for (auto& child : node->children) { 3598c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski printMerged(child.get(), depth + 1); 3608c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3618c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 3628c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3638c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskixml::Node* ManifestMerger::getMergedXml() { 3648c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return mRoot.get(); 3658c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 3668c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3678c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinskibool ManifestMerger::printMerged() { 3688c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski if (!mRoot) { 3698c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return false; 3708c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski } 3718c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3728c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski ::aapt::printMerged(mRoot.get(), 0); 3738c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski return true; 3748c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} 3758c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski 3768c831ca87bb7c8699b2a5cb34b8d35deedf9ce4eAdam Lesinski} // namespace aapt 377