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

Commit edb88a2b authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "Add ResTable_sparseTypeEntry support"

parents 18c527b9 c8f71aa6
Loading
Loading
Loading
Loading
+64 −16
Original line number Diff line number Diff line
@@ -6074,6 +6074,10 @@ bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
    return true;
}

static bool keyCompare(const ResTable_sparseTypeEntry& entry , uint16_t entryIdx) {
  return dtohs(entry.idx) < entryIdx;
}

status_t ResTable::getEntry(
        const PackageGroup* packageGroup, int typeIndex, int entryIndex,
        const ResTable_config* config,
@@ -6115,6 +6119,9 @@ status_t ResTable::getEntry(
            currentTypeIsOverlay = true;
        }

        // Check that the entry idx is within range of the declared entry count (ResTable_typeSpec).
        // Particular types (ResTable_type) may be encoded with sparse entries, and so their
        // entryCount do not need to match.
        if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
            ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
                    Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
@@ -6169,11 +6176,37 @@ status_t ResTable::getEntry(
                continue;
            }

            // Check if there is the desired entry in this type.
            const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
                    reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));

            uint32_t thisOffset = dtohl(eindex[realEntryIndex]);
            uint32_t thisOffset;

            // Check if there is the desired entry in this type.
            if (thisType->flags & ResTable_type::FLAG_SPARSE) {
                // This is encoded as a sparse map, so perform a binary search.
                const ResTable_sparseTypeEntry* sparseIndices =
                        reinterpret_cast<const ResTable_sparseTypeEntry*>(eindex);
                const ResTable_sparseTypeEntry* result = std::lower_bound(
                        sparseIndices, sparseIndices + dtohl(thisType->entryCount), realEntryIndex,
                        keyCompare);
                if (result == sparseIndices + dtohl(thisType->entryCount)
                        || dtohs(result->idx) != realEntryIndex) {
                    // No entry found.
                    continue;
                }

                // Extract the offset from the entry. Each offset must be a multiple of 4
                // so we store it as the real offset divided by 4.
                thisOffset = dtohs(result->offset) * 4u;
            } else {
                if (static_cast<uint32_t>(realEntryIndex) >= dtohl(thisType->entryCount)) {
                    // Entry does not exist.
                    continue;
                }

                thisOffset = dtohl(eindex[realEntryIndex]);
            }

            if (thisOffset == ResTable_type::NO_ENTRY) {
                // There is no entry for this index and configuration.
                continue;
@@ -6480,12 +6513,6 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
                }

                Type* t = typeList.editItemAt(typeList.size() - 1);
                if (newEntryCount != t->entryCount) {
                    ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
                        (int)newEntryCount, (int)t->entryCount);
                    return (mError=BAD_TYPE);
                }

                if (t->package != package) {
                    ALOGE("No TypeSpec for type %d", type->id);
                    return (mError=BAD_TYPE);
@@ -7098,8 +7125,17 @@ void ResTable::print(bool inclValues) const
                thisConfig.copyFromDtoH(type->config);

                String8 configStr = thisConfig.toString();
                printf("      config %s:\n", configStr.size() > 0
                printf("      config %s", configStr.size() > 0
                        ? configStr.string() : "(default)");
                if (type->flags != 0u) {
                    printf(" flags=0x%02x", type->flags);
                    if (type->flags & ResTable_type::FLAG_SPARSE) {
                        printf(" [sparse]");
                    }
                }

                printf(":\n");

                size_t entryCount = dtohl(type->entryCount);
                uint32_t entriesStart = dtohl(type->entriesStart);
                if ((entriesStart&0x3) != 0) {
@@ -7111,18 +7147,30 @@ void ResTable::print(bool inclValues) const
                    printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
                    continue;
                }
                for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {

                const uint32_t* const eindex = (const uint32_t*)
                        (((const uint8_t*)type) + dtohs(type->header.headerSize));

                    uint32_t thisOffset = dtohl(eindex[entryIndex]);
                for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
                    size_t entryId;
                    uint32_t thisOffset;
                    if (type->flags & ResTable_type::FLAG_SPARSE) {
                        const ResTable_sparseTypeEntry* entry =
                                reinterpret_cast<const ResTable_sparseTypeEntry*>(
                                        eindex + entryIndex);
                        entryId = dtohs(entry->idx);
                        // Offsets are encoded as divided by 4.
                        thisOffset = static_cast<uint32_t>(dtohs(entry->offset)) * 4u;
                    } else {
                        entryId = entryIndex;
                        thisOffset = dtohl(eindex[entryIndex]);
                        if (thisOffset == ResTable_type::NO_ENTRY) {
                            continue;
                        }
                    }

                    uint32_t resID = (0xff000000 & ((packageId)<<24))
                                | (0x00ff0000 & ((typeIndex+1)<<16))
                                | (0x0000ffff & (entryIndex));
                                | (0x0000ffff & (entryId));
                    if (packageId == 0) {
                        pg->dynamicRefTable.lookupResourceId(&resID);
                    }
+39 −5
Original line number Diff line number Diff line
@@ -16,23 +16,45 @@

#include <androidfw/TypeWrappers.h>

#include <algorithm>

namespace android {

TypeVariant::TypeVariant(const ResTable_type* data) : data(data), mLength(dtohl(data->entryCount)) {
    if (data->flags & ResTable_type::FLAG_SPARSE) {
        const uint32_t entryCount = dtohl(data->entryCount);
        const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(data) + dtohl(data->header.size);
        const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
                reinterpret_cast<uintptr_t>(data) + dtohs(data->header.headerSize));
        if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount)
                > containerEnd) {
            ALOGE("Type's entry indices extend beyond its boundaries");
            mLength = 0;
        } else {
          mLength = ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx + 1;
        }
    }
}

TypeVariant::iterator& TypeVariant::iterator::operator++() {
    mIndex++;
    if (mIndex > dtohl(mTypeVariant->data->entryCount)) {
        mIndex = dtohl(mTypeVariant->data->entryCount);
    if (mIndex > mTypeVariant->mLength) {
        mIndex = mTypeVariant->mLength;
    }
    return *this;
}

static bool keyCompare(uint32_t entry, uint16_t index) {
  return dtohs(ResTable_sparseTypeEntry{entry}.idx) < index;
}

const ResTable_entry* TypeVariant::iterator::operator*() const {
    const ResTable_type* type = mTypeVariant->data;
    const uint32_t entryCount = dtohl(type->entryCount);
    if (mIndex >= entryCount) {
    if (mIndex >= mTypeVariant->mLength) {
        return NULL;
    }

    const uint32_t entryCount = dtohl(mTypeVariant->data->entryCount);
    const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
            + dtohl(type->header.size);
    const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
@@ -42,7 +64,19 @@ const ResTable_entry* TypeVariant::iterator::operator*() const {
        return NULL;
    }

    const uint32_t entryOffset = dtohl(entryIndices[mIndex]);
    uint32_t entryOffset;
    if (type->flags & ResTable_type::FLAG_SPARSE) {
      auto iter = std::lower_bound(entryIndices, entryIndices + entryCount, mIndex, keyCompare);
      if (iter == entryIndices + entryCount
              || dtohs(ResTable_sparseTypeEntry{*iter}.idx) != mIndex) {
        return NULL;
      }

      entryOffset = static_cast<uint32_t>(dtohs(ResTable_sparseTypeEntry{*iter}.offset)) * 4u;
    } else {
      entryOffset = dtohl(entryIndices[mIndex]);
    }

    if (entryOffset == ResTable_type::NO_ENTRY) {
        return NULL;
    }
+38 −4
Original line number Diff line number Diff line
@@ -1339,12 +1339,21 @@ struct ResTable_typeSpec

/**
 * A collection of resource entries for a particular resource data
 * type. Followed by an array of uint32_t defining the resource
 * type.
 *
 * If the flag FLAG_SPARSE is not set in `flags`, then this struct is
 * followed by an array of uint32_t defining the resource
 * values, corresponding to the array of type strings in the
 * ResTable_package::typeStrings string block. Each of these hold an
 * index from entriesStart; a value of NO_ENTRY means that entry is
 * not defined.
 *
 * If the flag FLAG_SPARSE is set in `flags`, then this struct is followed
 * by an array of ResTable_sparseTypeEntry defining only the entries that
 * have values for this type. Each entry is sorted by their entry ID such
 * that a binary search can be performed over the entries. The ID and offset
 * are encoded in a uint32_t. See ResTabe_sparseTypeEntry.
 *
 * There may be multiple of these chunks for a particular resource type,
 * supply different configuration variations for the resource values of
 * that type.
@@ -1365,10 +1374,17 @@ struct ResTable_type
    // resource identifier).  0 is invalid.
    uint8_t id;
    
    enum {
        // If set, the entry is sparse, and encodes both the entry ID and offset into each entry,
        // and a binary search is used to find the key. Only available on platforms >= O.
        // Mark any types that use this with a v26 qualifier to prevent runtime issues on older
        // platforms.
        FLAG_SPARSE = 0x01,
    };
    uint8_t flags;

    // Must be 0.
    uint8_t res0;
    // Must be 0.
    uint16_t res1;
    uint16_t reserved;
    
    // Number of uint32_t entry indices that follow.
    uint32_t entryCount;
@@ -1380,6 +1396,24 @@ struct ResTable_type
    ResTable_config config;
};

/**
 * An entry in a ResTable_type with the flag `FLAG_SPARSE` set.
 */
union ResTable_sparseTypeEntry {
    // Holds the raw uint32_t encoded value. Do not read this.
    uint32_t entry;
    struct {
        // The index of the entry.
        uint16_t idx;

        // The offset from ResTable_type::entriesStart, divided by 4.
        uint16_t offset;
    };
};

static_assert(sizeof(ResTable_sparseTypeEntry) == sizeof(uint32_t),
        "ResTable_sparseTypeEntry must be 4 bytes in size");

/**
 * This is the beginning of information about an entry in the resource
 * table.  It holds the reference to the name of this entry, and is
+5 −3
Original line number Diff line number Diff line
@@ -23,8 +23,7 @@
namespace android {

struct TypeVariant {
    TypeVariant(const ResTable_type* data)
        : data(data) {}
    TypeVariant(const ResTable_type* data);

    class iterator {
    public:
@@ -72,10 +71,13 @@ struct TypeVariant {
    }

    iterator endEntries() const {
        return iterator(this, dtohl(data->entryCount));
        return iterator(this, mLength);
    }

    const ResTable_type* data;

private:
    size_t mLength;
};

} // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ testFiles := \
benchmarkFiles := \
    AssetManager2_bench.cpp \
    BenchMain.cpp \
    BenchmarkHelpers.cpp \
    SparseEntry_bench.cpp \
    TestHelpers.cpp \
    Theme_bench.cpp

Loading