summaryrefslogtreecommitdiff
path: root/libs/androidfw/AssetManager2.cpp
diff options
context:
space:
mode:
author Eric Miao <ericymiao@google.com> 2022-09-09 15:46:14 -0700
committer Eric Miao <ericymiao@google.com> 2022-11-15 12:12:33 -0800
commit368cd19d031f5a0b219ea92531d11ccb0ee66c4d (patch)
treeea6aa74fa746c043112705fdb08438abf782717b /libs/androidfw/AssetManager2.cpp
parentb0d0974aeba2b0498f5f576ff38012ac94b909a8 (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.cpp38
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(),
};
}