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

Commit 67ab8fa5 authored by Adam Lesinski's avatar Adam Lesinski Committed by Android Git Automerger
Browse files

am 863b1a90: am 19f9d54f: Merge "Fix backwards compat problem with AAPT public attrs" into lmp-dev

* commit '863b1a90e0b52683d3ed82af54431d247be1cab1':
  Fix backwards compat problem with AAPT public attrs
parents a706efac e2e58ef9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1521,6 +1521,8 @@ public:

    bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const;

    bool getResourceFlags(uint32_t resID, uint32_t* outFlags) const;

    /**
     * Retrieve the value of a resource.  If the resource is found, returns a
     * value >= 0 indicating the table it is in (for use with
+38 −0
Original line number Diff line number Diff line
@@ -5393,6 +5393,44 @@ const char16_t* StringPoolRef::string16(size_t* outLen) const {
    return NULL;
}

bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
    if (mError != NO_ERROR) {
        return false;
    }

    const ssize_t p = getResourcePackageIndex(resID);
    const int t = Res_GETTYPE(resID);
    const int e = Res_GETENTRY(resID);

    if (p < 0) {
        if (Res_GETPACKAGE(resID)+1 == 0) {
            ALOGW("No package identifier when getting flags for resource number 0x%08x", resID);
        } else {
            ALOGW("No known package when getting flags for resource number 0x%08x", resID);
        }
        return false;
    }
    if (t < 0) {
        ALOGW("No type identifier when getting flags for resource number 0x%08x", resID);
        return false;
    }

    const PackageGroup* const grp = mPackageGroups[p];
    if (grp == NULL) {
        ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID);
        return false;
    }

    Entry entry;
    status_t err = getEntry(grp, t, e, NULL, &entry);
    if (err != NO_ERROR) {
        return false;
    }

    *outFlags = entry.specFlags;
    return true;
}

status_t ResTable::getEntry(
        const PackageGroup* packageGroup, int typeIndex, int entryIndex,
        const ResTable_config* config,
+3 −1
Original line number Diff line number Diff line
#!/bin/bash

aapt package -M AndroidManifest.xml -S res --split fr,de -F bundle.apk -f && \
PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar

aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split fr,de -F bundle.apk -f && \
unzip bundle.apk resources.arsc && \
mv resources.arsc basic.arsc && \
xxd -i basic.arsc > basic_arsc.h && \
+21 −3
Original line number Diff line number Diff line
@@ -781,12 +781,18 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
    if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
            bundle->getVersionName(), errorOnFailedInsert, replaceVersion)) {
        return UNKNOWN_ERROR;
    } else {
        const XMLNode::attribute_entry* attr = root->getAttribute(
                String16(RESOURCES_ANDROID_NAMESPACE), String16("versionName"));
        if (attr != NULL) {
            bundle->setVersionName(strdup(String8(attr->string).string()));
        }
    }
    
    sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
    if (bundle->getMinSdkVersion() != NULL
            || bundle->getTargetSdkVersion() != NULL
            || bundle->getMaxSdkVersion() != NULL) {
        sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
        if (vers == NULL) {
            vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
            root->insertChildAt(vers, 0);
@@ -806,6 +812,14 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
        }
    }

    if (vers != NULL) {
        const XMLNode::attribute_entry* attr = vers->getAttribute(
                String16(RESOURCES_ANDROID_NAMESPACE), String16("minSdkVersion"));
        if (attr != NULL) {
            bundle->setMinSdkVersion(strdup(String8(attr->string).string()));
        }
    }

    if (bundle->getPlatformBuildVersionCode() != "") {
        if (!addTagAttribute(root, "", "platformBuildVersionCode",
                    bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) {
@@ -973,8 +987,8 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
static ssize_t extractPlatformBuildVersion(AssetManager& assets, Bundle* bundle) {
    int32_t cookie = getPlatformAssetCookie(assets);
    if (cookie == 0) {
        fprintf(stderr, "ERROR: Platform package not found\n");
        return UNKNOWN_ERROR;
        // No platform was loaded.
        return NO_ERROR;
    }

    ResXMLTree tree;
@@ -1500,6 +1514,10 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
        return err;
    }

    if (table.modifyForCompat(bundle) != NO_ERROR) {
        return UNKNOWN_ERROR;
    }

    //block.restart();
    //printXMLBlock(&block);

+196 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include <androidfw/ResourceTypes.h>
#include <utils/ByteOrder.h>
#include <utils/TypeHelpers.h>
#include <stdarg.h>

#define NOISY(x) //x
@@ -3287,6 +3288,18 @@ ResourceTable::Item::Item(const SourcePos& _sourcePos,
    }
}

ResourceTable::Entry::Entry(const Entry& entry)
    : RefBase()
    , mName(entry.mName)
    , mParent(entry.mParent)
    , mType(entry.mType)
    , mItem(entry.mItem)
    , mItemFormat(entry.mItemFormat)
    , mBag(entry.mBag)
    , mNameIndex(entry.mNameIndex)
    , mParentId(entry.mParentId)
    , mPos(entry.mPos) {}

status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
{
    if (mType == TYPE_BAG) {
@@ -3372,6 +3385,17 @@ status_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos,
    return NO_ERROR;
}

status_t ResourceTable::Entry::removeFromBag(const String16& key) {
    if (mType != Entry::TYPE_BAG) {
        return NO_ERROR;
    }

    if (mBag.removeItem(key) >= 0) {
        return NO_ERROR;
    }
    return UNKNOWN_ERROR;
}

status_t ResourceTable::Entry::emptyBag(const SourcePos& sourcePos)
{
    status_t err = makeItABag(sourcePos);
@@ -4113,3 +4137,175 @@ bool ResourceTable::getItemValue(
    }
    return res;
}

/**
 * Returns true if the given attribute ID comes from
 * a platform version from or after L.
 */
bool ResourceTable::isAttributeFromL(uint32_t attrId) {
    const uint32_t baseAttrId = 0x010103f7;
    if ((attrId & 0xffff0000) != (baseAttrId & 0xffff0000)) {
        return false;
    }

    uint32_t specFlags;
    if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
        return false;
    }

    return (specFlags & ResTable_typeSpec::SPEC_PUBLIC) != 0 &&
        (attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff);
}

/**
 * Modifies the entries in the resource table to account for compatibility
 * issues with older versions of Android.
 *
 * This primarily handles the issue of private/public attribute clashes
 * in framework resources.
 *
 * AAPT has traditionally assigned resource IDs to public attributes,
 * and then followed those public definitions with private attributes.
 *
 * --- PUBLIC ---
 * | 0x01010234 | attr/color
 * | 0x01010235 | attr/background
 *
 * --- PRIVATE ---
 * | 0x01010236 | attr/secret
 * | 0x01010237 | attr/shhh
 *
 * Each release, when attributes are added, they take the place of the private
 * attributes and the private attributes are shifted down again.
 *
 * --- PUBLIC ---
 * | 0x01010234 | attr/color
 * | 0x01010235 | attr/background
 * | 0x01010236 | attr/shinyNewAttr
 * | 0x01010237 | attr/highlyValuedFeature
 *
 * --- PRIVATE ---
 * | 0x01010238 | attr/secret
 * | 0x01010239 | attr/shhh
 *
 * Platform code may look for private attributes set in a theme. If an app
 * compiled against a newer version of the platform uses a new public
 * attribute that happens to have the same ID as the private attribute
 * the older platform is expecting, then the behavior is undefined.
 *
 * We get around this by detecting any newly defined attributes (in L),
 * copy the resource into a -v21 qualified resource, and delete the
 * attribute from the original resource. This ensures that older platforms
 * don't see the new attribute, but when running on L+ platforms, the
 * attribute will be respected.
 */
status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
    if (bundle->getMinSdkVersion() != NULL) {
        // If this app will only ever run on L+ devices,
        // we don't need to do any compatibility work.

        if (String8("L") == bundle->getMinSdkVersion()) {
            // Code-name for the v21 release.
            return NO_ERROR;
        }

        const int minSdk = atoi(bundle->getMinSdkVersion());
        if (minSdk >= SDK_L) {
            return NO_ERROR;
        }
    }

    const String16 attr16("attr");

    const size_t packageCount = mOrderedPackages.size();
    for (size_t pi = 0; pi < packageCount; pi++) {
        sp<Package> p = mOrderedPackages.itemAt(pi);
        if (p == NULL || p->getTypes().size() == 0) {
            // Empty, skip!
            continue;
        }

        const size_t typeCount = p->getOrderedTypes().size();
        for (size_t ti = 0; ti < typeCount; ti++) {
            sp<Type> t = p->getOrderedTypes().itemAt(ti);
            if (t == NULL) {
                continue;
            }

            const size_t configCount = t->getOrderedConfigs().size();
            for (size_t ci = 0; ci < configCount; ci++) {
                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
                if (c == NULL) {
                    continue;
                }

                Vector<key_value_pair_t<ConfigDescription, sp<Entry> > > entriesToAdd;
                const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries =
                        c->getEntries();
                const size_t entryCount = entries.size();
                for (size_t ei = 0; ei < entryCount; ei++) {
                    sp<Entry> e = entries.valueAt(ei);
                    if (e == NULL || e->getType() != Entry::TYPE_BAG) {
                        continue;
                    }

                    const ConfigDescription& config = entries.keyAt(ei);
                    if (config.sdkVersion >= SDK_L) {
                        // We don't need to do anything if the resource is
                        // already qualified for version 21 or higher.
                        continue;
                    }

                    Vector<String16> attributesToRemove;
                    const KeyedVector<String16, Item>& bag = e->getBag();
                    const size_t bagCount = bag.size();
                    for (size_t bi = 0; bi < bagCount; bi++) {
                        const Item& item = bag.valueAt(bi);
                        const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
                        if (isAttributeFromL(attrId)) {
                            attributesToRemove.add(bag.keyAt(bi));
                        }
                    }

                    if (attributesToRemove.isEmpty()) {
                        continue;
                    }

                    // Duplicate the entry under the same configuration
                    // but with sdkVersion == SDK_L.
                    ConfigDescription newConfig(config);
                    newConfig.sdkVersion = SDK_L;
                    entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
                            newConfig, new Entry(*e)));

                    // Remove the attribute from the original.
                    for (size_t i = 0; i < attributesToRemove.size(); i++) {
                        e->removeFromBag(attributesToRemove[i]);
                    }
                }

                const size_t entriesToAddCount = entriesToAdd.size();
                for (size_t i = 0; i < entriesToAddCount; i++) {
                    if (entries.indexOfKey(entriesToAdd[i].key) >= 0) {
                        // An entry already exists for this config.
                        // That means that any attributes that were
                        // defined in L in the original bag will be overriden
                        // anyways on L devices, so we do nothing.
                        continue;
                    }

                    entriesToAdd[i].value->getPos()
                            .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
                                    SDK_L,
                                    String8(p->getName()).string(),
                                    String8(t->getName()).string(),
                                    String8(entriesToAdd[i].value->getName()).string(),
                                    entriesToAdd[i].key.toString().string());

                    c->addEntry(entriesToAdd[i].key, entriesToAdd[i].value);
                }
            }
        }
    }
    return NO_ERROR;
}
Loading