Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 424db431 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

AAPT: Only print last uses-sdk tag

When an APK defines multiple "uses-sdk" tags, the Android runtime only
uses the minSdkVersion and targetSdkVersion values from the last
occurrence of the "uses-sdk" tag.

For example an application with the following tags:
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<uses-sdk android:maxSdkVersion="28"/>

Will have the following version codes at runtime:
minSdk=1 targetSdk=1

Another example:
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="28"/>
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="19"/>

Will have the following version codes at runtime:
minSdk=5 targetSdk=19

AAPT must print the version data from only the last tag, skipping other
occurrences of the tag.

Bug: 175789289
Test: manual
Change-Id: Ic855ff920d0b7abedd250d977bfa55189f4c8946
parent ff68a9ad
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -816,6 +816,11 @@ private:
    uint32_t                    mSourceResourceId;
};

static inline bool operator==(const android::ResXMLParser::ResXMLPosition& lhs,
                              const android::ResXMLParser::ResXMLPosition& rhs) {
  return lhs.curNode == rhs.curNode;
}

class DynamicRefTable;

/**
+55 −0
Original line number Diff line number Diff line
@@ -969,6 +969,8 @@ int doDump(Bundle* bundle)
                densities.add(dens);
            }

            std::vector<ResXMLParser::ResXMLPosition> tagsToSkip;

            size_t len;
            ResXMLTree::event_code_t code;
            int depth = 0;
@@ -1091,6 +1093,42 @@ int doDump(Bundle* bundle)
            Vector<FeatureGroup> featureGroups;
            KeyedVector<String8, ImpliedFeature> impliedFeatures;

            {
                int curDepth = 0;
                ResXMLParser::ResXMLPosition initialPos;
                tree.getPosition(&initialPos);

                // Find all of the "uses-sdk" tags within the "manifest" tag.
                std::vector<ResXMLParser::ResXMLPosition> usesSdkTagPositions;
                ResXMLParser::ResXMLPosition curPos;
                while ((code = tree.next()) != ResXMLTree::END_DOCUMENT &&
                       code != ResXMLTree::BAD_DOCUMENT) {
                    if (code == ResXMLTree::END_TAG) {
                        curDepth--;
                        continue;
                    }
                    if (code == ResXMLTree::START_TAG) {
                        curDepth++;
                    }
                    const char16_t* ctag16 = tree.getElementName(&len);
                    if (ctag16 == NULL || String8(ctag16) != "uses-sdk" || curDepth != 2) {
                        continue;
                    }

                    tree.getPosition(&curPos);
                    usesSdkTagPositions.emplace_back(curPos);
                }

                // Skip all "uses-sdk" tags besides the very last tag. The android runtime only uses
                // the attribute values from the last defined tag.
                for (size_t i = 0; i < usesSdkTagPositions.size() - 1; i++) {
                    tagsToSkip.emplace_back(usesSdkTagPositions[i]);
                }

                // Reset the position before parsing.
                tree.setPosition(initialPos);
            }

            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
                    code != ResXMLTree::BAD_DOCUMENT) {
                if (code == ResXMLTree::END_TAG) {
@@ -1202,8 +1240,25 @@ int doDump(Bundle* bundle)
                if (code != ResXMLTree::START_TAG) {
                    continue;
                }

                depth++;

                // If this tag should be skipped, skip to the end of this tag.
                ResXMLParser::ResXMLPosition curPos;
                tree.getPosition(&curPos);
                if (std::find(tagsToSkip.begin(), tagsToSkip.end(), curPos) != tagsToSkip.end()) {
                    const int breakDepth = depth - 1;
                    while ((code = tree.next()) != ResXMLTree::END_DOCUMENT &&
                           code != ResXMLTree::BAD_DOCUMENT) {
                        if (code == ResXMLTree::END_TAG && --depth == breakDepth) {
                            break;
                        } else if (code == ResXMLTree::START_TAG) {
                            depth++;
                        }
                    }
                    continue;
                }

                const char16_t* ctag16 = tree.getElementName(&len);
                if (ctag16 == NULL) {
                    SourcePos(manifestFile, tree.getLineNumber()).error(