Encoding of <overlayable> and <policy>
This change defines two new chunks for encoding overlayable information.
RES_TABLE_OVERLAYABLE_POLICY_TYPE contains flags that represent
restrictions enforced on overlays that try to overlay a specific set of
resource ids. The chunk header is followed by ResTable_ref for each id
that belongs to the policy type. A policy chunk will be created for
every unique combination of policies that are defined in overlayable
declarations.
RES_TABLE_OVERLAYABLE_TYPE holds policy blocks. Since <overlayable>
does not currently have any attributes, only one overlayable block is
encoded in an APK.
This change also removes the SPEC_OVERLAYABLE flag because the runtime
does not use the flag, and the overlayable chunk encoding renders it
obsolete.
Bug: 110869880
Bug: 117545186
Test: libandroidfw_tests and aapt2_tests
Change-Id: I45ae9bf4176699f14c85e2b7a2e8560185d8a0b8
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 68d216d..c20c720 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -583,7 +583,65 @@
loaded_package->dynamic_package_map_.emplace_back(std::move(package_name),
dtohl(entry_iter->packageId));
}
+ } break;
+ case RES_TABLE_OVERLAYABLE_TYPE: {
+ const ResTable_overlayable_header* header =
+ child_chunk.header<ResTable_overlayable_header>();
+ if (header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_TYPE too small.";
+ return {};
+ }
+
+ // Iterate over the overlayable policy chunks
+ ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
+ while (overlayable_iter.HasNext()) {
+ const Chunk overlayable_child_chunk = overlayable_iter.Next();
+
+ switch (overlayable_child_chunk.type()) {
+ case RES_TABLE_OVERLAYABLE_POLICY_TYPE: {
+ const ResTable_overlayable_policy_header* policy_header =
+ overlayable_child_chunk.header<ResTable_overlayable_policy_header>();
+ if (policy_header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
+ return {};
+ }
+
+ if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
+ < dtohl(policy_header->entry_count)) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
+ return {};
+ }
+
+ // Retrieve all the ids belonging to this policy
+ std::unordered_set<uint32_t> ids;
+ const auto ids_begin =
+ reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
+ const auto ids_end = ids_begin + dtohl(policy_header->entry_count);
+ for (auto id_iter = ids_begin; id_iter != ids_end; ++id_iter) {
+ ids.insert(dtohl(id_iter->ident));
+ }
+
+ // Add the pairing of overlayable properties to resource ids to the package
+ OverlayableInfo overlayable_info;
+ overlayable_info.policy_flags = policy_header->policy_flags;
+ loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
+ break;
+ }
+
+ default:
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ break;
+ }
+ }
+
+ if (overlayable_iter.HadError()) {
+ LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+ overlayable_iter.GetLastError().c_str());
+ if (overlayable_iter.HadFatalError()) {
+ return {};
+ }
+ }
} break;
default: