From a1f2bce0e56185d8a3ddbbb75cf9daacdcb5a3d2 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 12 Sep 2022 11:37:37 -0700 Subject: androidfw: Add support for 16-bit entry offsets Bug: 237583012 Most offsets to the entries can be well encoded in 16-bit, and given entries are 4-byte aligned, this gives us a range of entry offsets from 0x00000 to 0xfffe * 4u, with 0xffffu to represent ResTable_type::NO_ENTRY. For now, 16-bit entry offset will be enabled only when: * all the entry offsets can be represented in 16-bit * --enable-compact-entries switch is turned on Change-Id: I1c815c052aa5fba6eab2529434d31d7714c13694 --- libs/androidfw/LoadedArsc.cpp | 61 +++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 20 deletions(-) (limited to 'libs/androidfw/LoadedArsc.cpp') diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index e78f91ee3f46..386f718208b3 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -88,7 +88,9 @@ static bool VerifyResTableType(incfs::map_ptr 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 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().iterator(); + auto sparse_indices = offsets.convert().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& entry, @@ -289,17 +290,26 @@ base::expected LoadedPackage::GetEntryOffset( return base::unexpected(std::nullopt); } - const auto entry_offset_ptr = type_chunk.offset(offsets_offset).convert() + entry_index; - if (UNLIKELY(!entry_offset_ptr)) { - return base::unexpected(IOError::PAGES_MISSING); + uint32_t result; + + if (type_chunk->flags & ResTable_type::FLAG_OFFSET16) { + const auto entry_offset_ptr = offsets.convert() + 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() + 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, NullOrIOError> @@ -382,24 +392,35 @@ base::expected LoadedPackage::FindEntryByName( for (const auto& type_entry : type_spec->type_entries) { const incfs::verified_map_ptr& 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() + - 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(); + auto sparse_entry = entry_offsets.convert() + 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() + 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() + 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(); if (!entry) { -- cgit v1.2.3-59-g8ed1b