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

Commit 59d5a5a9 authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Todd Kennedy
Browse files

idmap: use more robust data structures

The problem of creating idmap data consists of three steps:

  1. create the mapping overlay resid -> target resid
  2. fix the padding between the target resids
  3. write the mapping as a binary stream

Because we iterate over the resources in the overlay package, there are
no guarantees on the order in which target resources are processed. This
means we can't fix the padding until after step 1. On the other hand,
after step 2 the mapping should be immutable.

Introduce new data structures that help enforce immutability and
ownership of data, as outlined above.

Bug: 80150169
Test: make libandroidfw_tests
Test: atest OverlayHostTests OverlayDeviceTests
Change-Id: I45689e8003c96d251a63a758f77609972ae963df
parent 19b3c371
Loading
Loading
Loading
Loading
+62 −30
Original line number Diff line number Diff line
@@ -7035,40 +7035,70 @@ status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
    return NO_ERROR;
}

struct IdmapMatchingResources {
    void Add(uint32_t targetResId, uint32_t overlayResId) {
        uint8_t targetTypeid = Res_GETTYPE(targetResId);
        if (typeMappings.find(targetTypeid) == typeMappings.end()) {
            typeMappings.emplace(targetTypeid, std::set<std::pair<uint32_t, uint32_t>>());
class IdmapMatchingResources;

class IdmapTypeMapping {
public:
    void add(uint32_t targetResId, uint32_t overlayResId) {
        uint8_t targetTypeId = Res_GETTYPE(targetResId);
        if (mData.find(targetTypeId) == mData.end()) {
            mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>());
        }
        auto& entries = typeMappings[targetTypeid];
        auto& entries = mData[targetTypeId];
        entries.insert(std::make_pair(targetResId, overlayResId));
    }

    void FixPadding() {
        for (auto ti = typeMappings.cbegin(); ti != typeMappings.cend(); ++ti) {
            uint32_t last_seen = 0xffffffff;
            size_t total_entries = 0;
    bool empty() const {
        return mData.empty();
    }

private:
    // resource type ID in context of target -> set of resource entries mapping target -> overlay
    std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> mData;

    friend IdmapMatchingResources;
};

class IdmapMatchingResources {
public:
    IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm) : mTypeMapping(std::move(tm)) {
        assert(mTypeMapping);
        for (auto ti = mTypeMapping->mData.cbegin(); ti != mTypeMapping->mData.cend(); ++ti) {
            uint32_t lastSeen = 0xffffffff;
            size_t totalEntries = 0;
            for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) {
                assert(last_seen == 0xffffffff || last_seen < ei->first);
                entryPadding[ei->first] = (last_seen == 0xffffffff) ? 0 : ei->first - last_seen - 1;
                last_seen = ei->first;
                total_entries += 1 + entryPadding[ei->first];
                assert(lastSeen == 0xffffffff || lastSeen < ei->first);
                mEntryPadding[ei->first] = (lastSeen == 0xffffffff) ? 0 : ei->first - lastSeen - 1;
                lastSeen = ei->first;
                totalEntries += 1 + mEntryPadding[ei->first];
            }
            mNumberOfEntriesIncludingPadding[ti->first] = totalEntries;
        }
    }

    const auto& getTypeMapping() const {
        return mTypeMapping->mData;
    }
            numberOfEntriesIncludingPadding[ti->first] = total_entries;

    size_t getNumberOfEntriesIncludingPadding(uint8_t type) const {
        return mNumberOfEntriesIncludingPadding.at(type);
    }

    size_t getPadding(uint32_t resid) const {
        return mEntryPadding.at(resid);
    }

private:
    // resource type ID in context of target -> set of resource entries mapping target -> overlay
    std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> typeMappings;
    const std::unique_ptr<IdmapTypeMapping> mTypeMapping;

    // resource ID in context of target -> trailing padding for that resource (call FixPadding
    // before use)
    std::map<uint32_t, size_t> entryPadding;
    std::map<uint32_t, size_t> mEntryPadding;

    // resource type ID in context of target -> total number of entries, including padding entries,
    // for that type (call FixPadding before use)
    std::map<uint8_t, size_t> numberOfEntriesIncludingPadding;
    std::map<uint8_t, size_t> mNumberOfEntriesIncludingPadding;
};

status_t ResTable::createIdmap(const ResTable& targetResTable,
@@ -7098,7 +7128,8 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
        return UNKNOWN_ERROR;
    }

    const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package;
    const ResTable_package* targetPackageStruct =
        targetResTable.mPackageGroups[0]->packages[0]->package;
    const size_t tmpNameSize = arraysize(targetPackageStruct->name);
    char16_t tmpName[tmpNameSize];
    strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize);
@@ -7110,7 +7141,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
    size_t forcedOverlayCount = 0u;

    // find the resources that exist in both packages
    IdmapMatchingResources matchingResources;
    auto typeMapping = std::make_unique<IdmapTypeMapping>();
    for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
        const TypeList& typeList = packageGroup->types[typeIndex];
        if (typeList.isEmpty()) {
@@ -7144,24 +7175,25 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
                ++forcedOverlayCount;
            }

            matchingResources.Add(target_resid, overlay_resid);
            typeMapping->add(target_resid, overlay_resid);
        }
    }

    if (matchingResources.typeMappings.empty()) {
    if (typeMapping->empty()) {
        ALOGE("idmap: no matching resources");
        return UNKNOWN_ERROR;
    }

    matchingResources.FixPadding();
    const IdmapMatchingResources matchingResources(std::move(typeMapping));

    // write idmap
    *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc
    *outSize += 2 * sizeof(uint16_t); // target package id, type count
    const auto typesEnd = matchingResources.typeMappings.cend();
    for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) {
    auto fixedTypeMapping = matchingResources.getTypeMapping();
    const auto typesEnd = fixedTypeMapping.cend();
    for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
        *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset
        *outSize += matchingResources.numberOfEntriesIncludingPadding[ti->first] *
        *outSize += matchingResources.getNumberOfEntriesIncludingPadding(ti->first) *
            sizeof(uint32_t); // entries
    }
    if ((*outData = malloc(*outSize)) == NULL) {
@@ -7190,11 +7222,11 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
    uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
    *typeData++ = htods(targetPackageStruct->id); // write: target package id
    *typeData++ =
        htods(static_cast<uint16_t>(matchingResources.typeMappings.size())); // write: type count
        htods(static_cast<uint16_t>(fixedTypeMapping.size())); // write: type count

    // write idmap data
    for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) {
        const size_t entryCount = matchingResources.numberOfEntriesIncludingPadding[ti->first];
    for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
        const size_t entryCount = matchingResources.getNumberOfEntriesIncludingPadding(ti->first);
        auto ei = ti->second.cbegin();
        *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id
        *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id
@@ -7202,7 +7234,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
        *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset
        uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData);
        for (; ei != ti->second.cend(); ++ei) {
            const size_t padding = matchingResources.entryPadding[ei->first];
            const size_t padding = matchingResources.getPadding(ei->first);
            for (size_t i = 0; i < padding; ++i) {
                *entryData++ = htodl(0xffffffff); // write: padding
            }