diff options
author | 2022-09-09 15:46:14 -0700 | |
---|---|---|
committer | 2022-11-15 12:12:33 -0800 | |
commit | 368cd19d031f5a0b219ea92531d11ccb0ee66c4d (patch) | |
tree | ea6aa74fa746c043112705fdb08438abf782717b /libs/androidfw/AssetManager2.cpp | |
parent | b0d0974aeba2b0498f5f576ff38012ac94b909a8 (diff) |
androidfw: Add support for compact resource entries
Bug: 237583012
Given the large number of simple resources such as strings in
Android resources, their ResTable_entry and Res_value can be
encoded together in a compact way. This allows a significant
saving in both storage and memory footprint.
The basic observations for simple resources are:
* ResTable_entry.size will always be sizeof(ResTable_entry)
unless it's a complex entry
* ResTable_entry.key is unlikely to exceed 16-bit
* ResTable_entry.flags only uses 3 bits for now
* Res_value.size will always be sizeof(Res_value)
Given the above, we could well encode the information into
a compact/compatible structure.
struct compact {
uint16_t key;
uint16_t flags;
uint32_t data;
};
The layout of this structure will allow maximum backward
compatibility. e.g. the flags will be at the same offset,
and a
`dtohs((ResTable_entry *)entry->flags) & FLAG_COMPACT`
would tell if this entry is a compact one or not. For a
compact entry:
struct compact *entry;
entry_size == sizeof(*entry)
entry_key == static_cast<uint32_t>(dtohs(entry->key))
entry_flags == dtohs(entry->flags) & 0xff // low 8-bit
data_type == dtohs(entry->flags) >> 8 // high 8-bit
data_size == sizeof(Res_value)
data_value == dtohl(entry->data)
To allow minimum code change and backward compatibility,
we change 'struct ResTable_entry' to 'union ResTable_entry',
with an anonymous structure inside that's fully backward
compatible. Thus, any existing reference such as:
ResTable_entry *entry = ...
if (dtohs(entry->flags) & ResTable_entry::FLAG_COMPLEX) ...
would still work.
However, special care needs to be taken after an entry is
obtained, and when value needs to be extracted.
A compact entry will not encode a complex value, and hence
complex entries/values are handled the same way.
Change-Id: I15d97a4f5e85fab28c075496f7f0cf6b1fcd73e3
Diffstat (limited to 'libs/androidfw/AssetManager2.cpp')
-rw-r--r-- | libs/androidfw/AssetManager2.cpp | 38 |
1 files changed, 12 insertions, 26 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 1381bdd6a50d..06ffb72d183b 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -43,28 +43,19 @@ namespace { using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>; +/* NOTE: table_entry has been verified in LoadedPackage::GetEntryFromOffset(), + * and so access to ->value() and ->map_entry() are safe here + */ base::expected<EntryValue, IOError> GetEntryValue( incfs::verified_map_ptr<ResTable_entry> table_entry) { - const uint16_t entry_size = dtohs(table_entry->size); + const uint16_t entry_size = table_entry->size(); // Check if the entry represents a bag value. - if (entry_size >= sizeof(ResTable_map_entry) && - (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX)) { - const auto map_entry = table_entry.convert<ResTable_map_entry>(); - if (!map_entry) { - return base::unexpected(IOError::PAGES_MISSING); - } - return map_entry.verified(); + if (entry_size >= sizeof(ResTable_map_entry) && table_entry->is_complex()) { + return table_entry.convert<ResTable_map_entry>().verified(); } - // The entry represents a non-bag value. - const auto entry_value = table_entry.offset(entry_size).convert<Res_value>(); - if (!entry_value) { - return base::unexpected(IOError::PAGES_MISSING); - } - Res_value value; - value.copyFrom_dtoh(entry_value.value()); - return value; + return table_entry->value(); } } // namespace @@ -814,17 +805,12 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal( return base::unexpected(std::nullopt); } - auto best_entry_result = LoadedPackage::GetEntryFromOffset(best_type, best_offset); - if (!best_entry_result.has_value()) { - return base::unexpected(best_entry_result.error()); - } - - const incfs::map_ptr<ResTable_entry> best_entry = *best_entry_result; - if (!best_entry) { - return base::unexpected(IOError::PAGES_MISSING); + auto best_entry_verified = LoadedPackage::GetEntryFromOffset(best_type, best_offset); + if (!best_entry_verified.has_value()) { + return base::unexpected(best_entry_verified.error()); } - const auto entry = GetEntryValue(best_entry.verified()); + const auto entry = GetEntryValue(*best_entry_verified); if (!entry.has_value()) { return base::unexpected(entry.error()); } @@ -837,7 +823,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal( .package_name = &best_package->GetPackageName(), .type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1), .entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), - best_entry->key.index), + (*best_entry_verified)->key()), .dynamic_ref_table = package_group.dynamic_ref_table.get(), }; } |