Merge "Add encoding of name and actor overlayable fields"
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 5a26780..70ce9bc 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -593,7 +593,12 @@
           return {};
         }
 
-        // Iterate over the overlayable policy chunks
+        std::string name;
+        util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+        std::string actor;
+        util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+
+        // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
         while (overlayable_iter.HasNext()) {
           const Chunk overlayable_child_chunk = overlayable_iter.Next();
@@ -613,7 +618,7 @@
                 return {};
               }
 
-              // Retrieve all the ids belonging to this policy
+              // Retrieve all the resource ids belonging to this policy chunk
               std::unordered_set<uint32_t> ids;
               const auto ids_begin =
                   reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
@@ -622,8 +627,10 @@
                 ids.insert(dtohl(id_iter->ident));
               }
 
-              // Add the pairing of overlayable properties to resource ids to the package
+              // Add the pairing of overlayable properties and resource ids to the package
               OverlayableInfo overlayable_info{};
+              overlayable_info.name = name;
+              overlayable_info.actor = actor;
               overlayable_info.policy_flags = policy_header->policy_flags;
               loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
               break;
@@ -636,7 +643,7 @@
         }
 
         if (overlayable_iter.HadError()) {
-          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s",
                                      overlayable_iter.GetLastError().c_str());
           if (overlayable_iter.HadFatalError()) {
             return {};
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8c5c3b7..be62f30 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,8 @@
 using TypeSpecPtr = util::unique_cptr<TypeSpec>;
 
 struct OverlayableInfo {
+  std::string name;
+  std::string actor;
   uint32_t policy_flags;
 };
 
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 9b05d1f..6b9ebd3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1611,6 +1611,12 @@
 struct ResTable_overlayable_header
 {
   struct ResChunk_header header;
+
+  // The name of the overlayable set of resources that overlays target.
+  uint16_t name[256];
+
+ // The component responsible for enabling and disabling overlays targeting this chunk.
+  uint16_t actor[256];
 };
 
 /**
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 22d587a..2e386a0 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -294,22 +294,30 @@
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources2"));
+  EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 }
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 85ab4be..8634747 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index 11aa735..dba7b08 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-<overlayable>
+<overlayable name="OverlayableResources1" actor="overlay://theme">
     <!-- Any overlay can overlay the value of @string/overlayable1 -->
     <item type="string" name="overlayable1" />
 
@@ -31,9 +31,9 @@
     </policy>
 </overlayable>
 
-<overlayable>
+<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
     <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
-   @string/overlayable3 -->
+        @string/overlayable3 -->
     <policy type="product_services|vendor|product">
         <item type="string" name="overlayable3" />
     </policy>
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c496ff0..7d4c6f3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -42,6 +42,19 @@
 
 namespace {
 
+static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
+  size_t utf16_len = strnlen16(src, len);
+  if (utf16_len == 0) {
+    return {};
+  }
+  std::u16string dst;
+  dst.resize(utf16_len);
+  for (size_t i = 0; i < utf16_len; i++) {
+    dst[i] = util::DeviceToHost16(src[i]);
+  }
+  return dst;
+}
+
 // Visitor that converts a reference's resource ID to a resource name, given a mapping from
 // resource ID to resource name.
 class ReferenceIdToNameVisitor : public DescendingValueVisitor {
@@ -176,12 +189,8 @@
   }
 
   // Extract the package name.
-  size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
-  std::u16string package_name;
-  package_name.resize(len);
-  for (size_t i = 0; i < len; i++) {
-    package_name[i] = util::DeviceToHost16(package_header->name[i]);
-  }
+  std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
+                                              arraysize(package_header->name));
 
   ResourceTablePackage* package =
       table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
@@ -435,6 +444,11 @@
   }
 
   auto overlayable = std::make_shared<Overlayable>();
+  overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
+                                                      arraysize(header->name)));
+  overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
+                                                       arraysize(header->name)));
+  overlayable->source = source_.WithLine(0);
 
   ResChunkPullParser parser(GetChunkData(chunk),
                             GetChunkDataLen(chunk));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 931d57b..c4ecbaf 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -217,9 +217,10 @@
   size_t entry_count_ = 0;
 };
 
-struct PolicyChunk {
-  uint32_t policy_flags;
-  std::set<ResourceId> ids;
+struct OverlayableChunk {
+  std::string actor;
+  Source source;
+  std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
 };
 
 class PackageFlattener {
@@ -421,8 +422,9 @@
     return sorted_entries;
   }
 
-  void FlattenOverlayable(BigBuffer* buffer) {
-    std::vector<PolicyChunk> policies;
+  bool FlattenOverlayable(BigBuffer* buffer) {
+    std::set<ResourceId> seen_ids;
+    std::map<std::string, OverlayableChunk> overlayable_chunks;
 
     CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
     for (auto& type : package_->types) {
@@ -433,79 +435,119 @@
           continue;
         }
 
-        OverlayableItem& overlayable = entry->overlayable_item.value();
-        uint32_t policy_flags = OverlayableItem::Policy::kNone;
-        if (overlayable.policies & OverlayableItem::Policy::kPublic) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kSystem) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kVendor) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProduct) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+        OverlayableItem& item = entry->overlayable_item.value();
+
+        // Resource ids should only appear once in the resource table
+        ResourceId id = android::make_resid(package_->id.value(), type->id.value(),
+                                            entry->id.value());
+        CHECK(seen_ids.find(id) == seen_ids.end())
+            << "multiple overlayable definitions found for resource "
+            << ResourceName(package_->name, type->type, entry->name).to_string();
+        seen_ids.insert(id);
+
+        // Find the overlayable chunk with the specified name
+        OverlayableChunk* overlayable_chunk = nullptr;
+        auto iter = overlayable_chunks.find(item.overlayable->name);
+        if (iter == overlayable_chunks.end()) {
+          OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source};
+          overlayable_chunk =
+              &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second;
+        } else {
+          OverlayableChunk& chunk = iter->second;
+          if (!(chunk.source == item.overlayable->source)) {
+            // The name of an overlayable set of resources must be unique
+            context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+                                                  << "duplicate overlayable name"
+                                                  << item.overlayable->name << "'");
+            context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
+                                                  << "previous declaration here");
+            return false;
+          }
+
+          CHECK(chunk.actor == item.overlayable->actor);
+          overlayable_chunk = &chunk;
         }
 
-        if (overlayable.policies == OverlayableItem::Policy::kNone) {
+        uint32_t policy_flags = 0;
+        if (item.policies == OverlayableItem::Policy::kNone) {
           // Encode overlayable entries defined without a policy as publicly overlayable
           policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-
-        // Find the overlayable policy chunk with the same policies as the entry
-        PolicyChunk* policy_chunk = nullptr;
-        for (PolicyChunk& policy : policies) {
-          if (policy.policy_flags == policy_flags) {
-            policy_chunk = &policy;
-            break;
+        } else {
+          if (item.policies & OverlayableItem::Policy::kPublic) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+          }
+          if (item.policies & OverlayableItem::Policy::kSystem) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kVendor) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kProduct) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kProductServices) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
           }
         }
 
-        // Create a new policy chunk if an existing one with the same policy cannot be found
-        if (policy_chunk == nullptr) {
-          PolicyChunk p;
-          p.policy_flags = policy_flags;
-          policies.push_back(p);
-          policy_chunk = &policies.back();
+        auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+        if (policy != overlayable_chunk->policy_ids.end()) {
+          policy->second.insert(id);
+        } else {
+          overlayable_chunk->policy_ids.insert(
+              std::make_pair(policy_flags, std::set<ResourceId>{id}));
         }
-
-        policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
-                                                     entry->id.value()));
       }
     }
 
-    if (policies.empty()) {
-      // Only write the overlayable chunk if the APK has overlayable entries
-      return;
-    }
+    for (auto& overlayable_pair : overlayable_chunks) {
+      std::string name = overlayable_pair.first;
+      OverlayableChunk& overlayable = overlayable_pair.second;
 
-    ChunkWriter writer(buffer);
-    writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
-
-    // Write each policy block for the overlayable
-    for (PolicyChunk& policy : policies) {
-      ChunkWriter policy_writer(buffer);
-      ResTable_overlayable_policy_header* policy_type =
-          policy_writer.StartChunk<ResTable_overlayable_policy_header>(
-              RES_TABLE_OVERLAYABLE_POLICY_TYPE);
-      policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
-      policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
-
-      // Write the ids after the policy header
-      ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
-      for (const ResourceId& id : policy.ids) {
-        id_block->ident = util::HostToDevice32(id.id);
-        id_block++;
+      // Write the header of the overlayable chunk
+      ChunkWriter overlayable_writer(buffer);
+      auto* overlayable_type =
+          overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+      if (name.size() >= arraysize(overlayable_type->name)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << name
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->name)
+                                   << " utf16 characters)");
+        return false;
       }
+      strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
+                    util::Utf8ToUtf16(name));
 
-      policy_writer.Finish();
+      if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->actor)
+                                   << " utf16 characters)");
+        return false;
+      }
+      strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
+                    util::Utf8ToUtf16(overlayable.actor));
+
+      // Write each policy block for the overlayable
+      for (auto& policy_ids : overlayable.policy_ids) {
+        ChunkWriter policy_writer(buffer);
+        auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+            RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+        policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+        policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
+                                                            policy_ids.second.size()));
+        // Write the ids after the policy header
+        auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
+        for (const ResourceId& id : policy_ids.second) {
+          id_block->ident = util::HostToDevice32(id.id);
+          id_block++;
+        }
+        policy_writer.Finish();
+      }
+      overlayable_writer.Finish();
     }
 
-    writer.Finish();
+    return true;
   }
 
   bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a5fb6fd..18fecf6 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -657,36 +657,36 @@
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
   auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
   std::string name_zero = "com.app.test:integer/overlayable_zero_item";
-  OverlayableItem overlayable_zero_item(overlayable);
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_zero(overlayable);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
 
   std::string name_one = "com.app.test:integer/overlayable_one_item";
-  OverlayableItem overlayable_one_item(overlayable);
-  overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_one(overlayable);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+  overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
 
   std::string name_two = "com.app.test:integer/overlayable_two_item";
-  OverlayableItem overlayable_two_item(overlayable);
-  overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
+  OverlayableItem overlayable_item_two(overlayable);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
 
   std::string name_three = "com.app.test:integer/overlayable_three_item";
-  OverlayableItem overlayable_three_item(overlayable);
+  OverlayableItem overlayable_item_three(overlayable);
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
           .AddSimple(name_zero, ResourceId(0x7f020000))
-          .SetOverlayable(name_zero, overlayable_zero_item)
+          .SetOverlayable(name_zero, overlayable_item_zero)
           .AddSimple(name_one, ResourceId(0x7f020001))
-          .SetOverlayable(name_one, overlayable_one_item)
+          .SetOverlayable(name_one, overlayable_item_one)
           .AddSimple(name_two, ResourceId(0x7f020002))
-          .SetOverlayable(name_two, overlayable_two_item)
+          .SetOverlayable(name_two, overlayable_item_two)
           .AddSimple(name_three, ResourceId(0x7f020003))
-          .SetOverlayable(name_three, overlayable_three_item)
+          .SetOverlayable(name_three, overlayable_item_three)
           .Build();
 
   ResourceTable output_table;
@@ -724,6 +724,84 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
+  EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
+  auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+  std::string name_zero = "com.app.test:integer/overlayable_zero";
+  OverlayableItem overlayable_item_zero(group);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
+
+  auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
+  std::string name_one = "com.app.test:integer/overlayable_one";
+  OverlayableItem overlayable_item_one(group_one);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+  overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
+
+  std::string name_two = "com.app.test:integer/overlayable_two";
+  OverlayableItem overlayable_item_two(group);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+
+  std::string name_three = "com.app.test:integer/overlayable_three";
+  OverlayableItem overlayable_item_three(group_one);
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.test", 0x7f)
+          .AddSimple(name_zero, ResourceId(0x7f020000))
+          .SetOverlayable(name_zero, overlayable_item_zero)
+          .AddSimple(name_one, ResourceId(0x7f020001))
+          .SetOverlayable(name_one, overlayable_item_one)
+          .AddSimple(name_two, ResourceId(0x7f020002))
+          .SetOverlayable(name_two, overlayable_item_two)
+          .AddSimple(name_three, ResourceId(0x7f020003))
+          .SetOverlayable(name_three, overlayable_item_three)
+          .Build();
+  ResourceTable output_table;
+  ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+  auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct
+                                         | OverlayableItem::Policy::kProductServices);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic
+                                         | OverlayableItem::Policy::kProductServices);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct
+                                         | OverlayableItem::Policy::kVendor);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
 }
 
 }  // namespace aapt