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: