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