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

Commit 7a378b26 authored by Eric Miao's avatar Eric Miao Committed by Android (Google) Code Review
Browse files

Merge "androidfw: Add support for 16-bit entry offsets"

parents a485aa6f a1f2bce0
Loading
Loading
Loading
Loading
+41 −20
Original line number Diff line number Diff line
@@ -88,7 +88,9 @@ static bool VerifyResTableType(incfs::map_ptr<ResTable_type> header) {
  // Make sure that there is enough room for the entry offsets.
  const size_t offsets_offset = dtohs(header->header.headerSize);
  const size_t entries_offset = dtohl(header->entriesStart);
  const size_t offsets_length = sizeof(uint32_t) * entry_count;
  const size_t offsets_length = header->flags & ResTable_type::FLAG_OFFSET16
                                    ? sizeof(uint16_t) * entry_count
                                    : sizeof(uint32_t) * entry_count;

  if (offsets_offset > entries_offset || entries_offset - offsets_offset < offsets_length) {
    LOG(ERROR) << "RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data.";
@@ -247,14 +249,13 @@ base::expected<uint32_t, NullOrIOError> LoadedPackage::GetEntryOffset(
  // The configuration matches and is better than the previous selection.
  // Find the entry value if it exists for this configuration.
  const size_t entry_count = dtohl(type_chunk->entryCount);
  const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
  const auto offsets = type_chunk.offset(dtohs(type_chunk->header.headerSize));

  // Check if there is the desired entry in this type.
  if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
    // This is encoded as a sparse map, so perform a binary search.
    bool error = false;
    auto sparse_indices = type_chunk.offset(offsets_offset)
                                    .convert<ResTable_sparseTypeEntry>().iterator();
    auto sparse_indices = offsets.convert<ResTable_sparseTypeEntry>().iterator();
    auto sparse_indices_end = sparse_indices + entry_count;
    auto result = std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
                                   [&error](const incfs::map_ptr<ResTable_sparseTypeEntry>& entry,
@@ -289,17 +290,26 @@ base::expected<uint32_t, NullOrIOError> LoadedPackage::GetEntryOffset(
    return base::unexpected(std::nullopt);
  }

  const auto entry_offset_ptr = type_chunk.offset(offsets_offset).convert<uint32_t>() + entry_index;
  uint32_t result;

  if (type_chunk->flags & ResTable_type::FLAG_OFFSET16) {
    const auto entry_offset_ptr = offsets.convert<uint16_t>() + entry_index;
    if (UNLIKELY(!entry_offset_ptr)) {
      return base::unexpected(IOError::PAGES_MISSING);
    }
    result = offset_from16(entry_offset_ptr.value());
  } else {
    const auto entry_offset_ptr = offsets.convert<uint32_t>() + entry_index;
    if (UNLIKELY(!entry_offset_ptr)) {
      return base::unexpected(IOError::PAGES_MISSING);
    }
    result = dtohl(entry_offset_ptr.value());
  }

  const uint32_t value = dtohl(entry_offset_ptr.value());
  if (value == ResTable_type::NO_ENTRY) {
  if (result == ResTable_type::NO_ENTRY) {
    return base::unexpected(std::nullopt);
  }

  return value;
  return result;
}

base::expected<incfs::verified_map_ptr<ResTable_entry>, NullOrIOError>
@@ -382,24 +392,35 @@ base::expected<uint32_t, NullOrIOError> LoadedPackage::FindEntryByName(
  for (const auto& type_entry : type_spec->type_entries) {
    const incfs::verified_map_ptr<ResTable_type>& type = type_entry.type;

    size_t entry_count = dtohl(type->entryCount);
    for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
      auto entry_offset_ptr = type.offset(dtohs(type->header.headerSize)).convert<uint32_t>() +
          entry_idx;
      if (!entry_offset_ptr) {
        return base::unexpected(IOError::PAGES_MISSING);
      }
    const size_t entry_count = dtohl(type->entryCount);
    const auto entry_offsets = type.offset(dtohs(type->header.headerSize));

    for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
      uint32_t offset;
      uint16_t res_idx;
      if (type->flags & ResTable_type::FLAG_SPARSE) {
        auto sparse_entry = entry_offset_ptr.convert<ResTable_sparseTypeEntry>();
        auto sparse_entry = entry_offsets.convert<ResTable_sparseTypeEntry>() + entry_idx;
        if (!sparse_entry) {
          return base::unexpected(IOError::PAGES_MISSING);
        }
        offset = dtohs(sparse_entry->offset) * 4u;
        res_idx  = dtohs(sparse_entry->idx);
      } else if (type->flags & ResTable_type::FLAG_OFFSET16) {
        auto entry = entry_offsets.convert<uint16_t>() + entry_idx;
        if (!entry) {
          return base::unexpected(IOError::PAGES_MISSING);
        }
        offset = offset_from16(entry.value());
        res_idx = entry_idx;
      } else {
        offset = dtohl(entry_offset_ptr.value());
        auto entry = entry_offsets.convert<uint32_t>() + entry_idx;
        if (!entry) {
          return base::unexpected(IOError::PAGES_MISSING);
        }
        offset = dtohl(entry.value());
        res_idx = entry_idx;
      }

      if (offset != ResTable_type::NO_ENTRY) {
        auto entry = type.offset(dtohl(type->entriesStart) + offset).convert<ResTable_entry>();
        if (!entry) {
+16 −3
Original line number Diff line number Diff line
@@ -6593,9 +6593,13 @@ status_t ResTable::getEntry(
                    // Entry does not exist.
                    continue;
                }

                if (thisType->flags & ResTable_type::FLAG_OFFSET16) {
                    auto eindex16 = reinterpret_cast<const uint16_t*>(eindex);
                    thisOffset = offset_from16(eindex16[realEntryIndex]);
                } else {
                    thisOffset = dtohl(eindex[realEntryIndex]);
                }
            }

            if (thisOffset == ResTable_type::NO_ENTRY) {
                // There is no entry for this index and configuration.
@@ -7646,6 +7650,9 @@ void ResTable::print(bool inclValues) const
                        if (type->flags & ResTable_type::FLAG_SPARSE) {
                            printf(" [sparse]");
                        }
                        if (type->flags & ResTable_type::FLAG_OFFSET16) {
                            printf(" [offset16]");
                        }
                    }

                    printf(":\n");
@@ -7677,7 +7684,13 @@ void ResTable::print(bool inclValues) const
                            thisOffset = static_cast<uint32_t>(dtohs(entry->offset)) * 4u;
                        } else {
                            entryId = entryIndex;
                            if (type->flags & ResTable_type::FLAG_OFFSET16) {
                                const auto eindex16 =
                                    reinterpret_cast<const uint16_t*>(eindex);
                                thisOffset = offset_from16(eindex16[entryIndex]);
                            } else {
                                thisOffset = dtohl(eindex[entryIndex]);
                            }
                            if (thisOffset == ResTable_type::NO_ENTRY) {
                                continue;
                            }
+6 −1
Original line number Diff line number Diff line
@@ -59,7 +59,9 @@ const ResTable_entry* TypeVariant::iterator::operator*() const {
            + dtohl(type->header.size);
    const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
            reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
    if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount) > containerEnd) {
    const size_t indexSize = type->flags & ResTable_type::FLAG_OFFSET16 ?
                                    sizeof(uint16_t) : sizeof(uint32_t);
    if (reinterpret_cast<uintptr_t>(entryIndices) + (indexSize * entryCount) > containerEnd) {
        ALOGE("Type's entry indices extend beyond its boundaries");
        return NULL;
    }
@@ -73,6 +75,9 @@ const ResTable_entry* TypeVariant::iterator::operator*() const {
      }

      entryOffset = static_cast<uint32_t>(dtohs(ResTable_sparseTypeEntry{*iter}.offset)) * 4u;
    } else if (type->flags & ResTable_type::FLAG_OFFSET16) {
      auto entryIndices16 = reinterpret_cast<const uint16_t*>(entryIndices);
      entryOffset = offset_from16(entryIndices16[mIndex]);
    } else {
      entryOffset = dtohl(entryIndices[mIndex]);
    }
+9 −0
Original line number Diff line number Diff line
@@ -1438,6 +1438,10 @@ struct ResTable_type
        // Mark any types that use this with a v26 qualifier to prevent runtime issues on older
        // platforms.
        FLAG_SPARSE = 0x01,

        // If set, the offsets to the entries are encoded in 16-bit, real_offset = offset * 4u
        // An 16-bit offset of 0xffffu means a NO_ENTRY
        FLAG_OFFSET16 = 0x02,
    };
    uint8_t flags;

@@ -1454,6 +1458,11 @@ struct ResTable_type
    ResTable_config config;
};

// Convert a 16-bit offset to 32-bit if FLAG_OFFSET16 is set
static inline uint32_t offset_from16(uint16_t off16) {
    return dtohs(off16) == 0xffffu ? ResTable_type::NO_ENTRY : dtohs(off16) * 4u;
}

// The minimum size required to read any version of ResTable_type.
constexpr size_t kResTableTypeMinSize =
    sizeof(ResTable_type) - sizeof(ResTable_config) + sizeof(ResTable_config::size);
+18 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "format/binary/TableFlattener.h"

#include <limits>
#include <sstream>
#include <type_traits>
#include <variant>
@@ -191,6 +192,9 @@ class PackageFlattener {
      offsets[flat_entry.entry->id.value()] = res_entry_writer->Write(&flat_entry);
    }

    // whether the offsets can be represented in 2 bytes
    bool short_offsets = (values_buffer.size() / 4u) < std::numeric_limits<uint16_t>::max();

    bool sparse_encode = sparse_entries_ == SparseEntriesMode::Enabled ||
                         sparse_entries_ == SparseEntriesMode::Forced;

@@ -203,8 +207,7 @@ class PackageFlattener {
    }

    // Only sparse encode if the offsets are representable in 2 bytes.
    sparse_encode =
        sparse_encode && (values_buffer.size() / 4u) <= std::numeric_limits<uint16_t>::max();
    sparse_encode = sparse_encode && short_offsets;

    // Only sparse encode if the ratio of populated entries to total entries is below some
    // threshold.
@@ -226,12 +229,22 @@ class PackageFlattener {
      }
    } else {
      type_header->entryCount = android::util::HostToDevice32(num_total_entries);
      if (compact_entry && short_offsets) {
        // use 16-bit offset only when compact_entry is true
        type_header->flags |= ResTable_type::FLAG_OFFSET16;
        uint16_t* indices = type_writer.NextBlock<uint16_t>(num_total_entries);
        for (size_t i = 0; i < num_total_entries; i++) {
          indices[i] = android::util::HostToDevice16(offsets[i] / 4u);
        }
      } else {
        uint32_t* indices = type_writer.NextBlock<uint32_t>(num_total_entries);
        for (size_t i = 0; i < num_total_entries; i++) {
          indices[i] = android::util::HostToDevice32(offsets[i]);
        }
      }
    }

    type_writer.buffer()->Align4();
    type_header->entriesStart = android::util::HostToDevice32(type_writer.size());
    type_writer.buffer()->AppendBuffer(std::move(values_buffer));
    type_writer.Finish();