Store frro configs in idmap file

This also includes the change to use the configs to decide which (if
any) frros to use at runtime

Bug: 243066074
Test: Manual, updated and created automated tests
Change-Id: I3f1d23e2958ad170799880b9f5eb5bd8ceb1fa67
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 39c7d19..235700b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -601,10 +601,6 @@
     return base::unexpected(result.error());
   }
 
-  if (type_idx == 0x1c) {
-    LOG(ERROR) << base::StringPrintf("foobar first result %s", result->package_name->c_str());
-  }
-
   bool overlaid = false;
   if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
     for (const auto& id_map : package_group.overlays_) {
@@ -615,7 +611,21 @@
       }
       if (overlay_entry.IsInlineValue()) {
         // The target resource is overlaid by an inline value not represented by a resource.
-        result->entry = overlay_entry.GetInlineValue();
+        ConfigDescription best_frro_config;
+        Res_value best_frro_value;
+        bool frro_found = false;
+        for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+          if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
+              && config.match(*desired_config)) {
+            frro_found = true;
+            best_frro_config = config;
+            best_frro_value = value;
+          }
+        }
+        if (!frro_found) {
+          continue;
+        }
+        result->entry = best_frro_value;
         result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
         result->cookie = id_map.cookie;
 
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index efd1f6a..e122d48 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -56,6 +56,8 @@
 struct Idmap_data_header {
   uint32_t target_entry_count;
   uint32_t target_inline_entry_count;
+  uint32_t target_inline_entry_value_count;
+  uint32_t configuration_count;
   uint32_t overlay_entry_count;
 
   uint32_t string_pool_index_offset;
@@ -68,6 +70,12 @@
 
 struct Idmap_target_entry_inline {
   uint32_t target_id;
+  uint32_t start_value_index;
+  uint32_t value_count;
+};
+
+struct Idmap_target_entry_inline_value {
+  uint32_t config_index;
   Res_value value;
 };
 
@@ -138,11 +146,15 @@
 IdmapResMap::IdmapResMap(const Idmap_data_header* data_header,
                          const Idmap_target_entry* entries,
                          const Idmap_target_entry_inline* inline_entries,
+                         const Idmap_target_entry_inline_value* inline_entry_values,
+                         const ConfigDescription* configs,
                          uint8_t target_assigned_package_id,
                          const OverlayDynamicRefTable* overlay_ref_table)
     : data_header_(data_header),
       entries_(entries),
       inline_entries_(inline_entries),
+      inline_entry_values_(inline_entry_values),
+      configurations_(configs),
       target_assigned_package_id_(target_assigned_package_id),
       overlay_ref_table_(overlay_ref_table) { }
 
@@ -183,7 +195,13 @@
 
   if (inline_entry != end_inline_entry &&
       (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
-    return Result(inline_entry->value);
+    std::map<ConfigDescription, Res_value> values_map;
+    for (int i = 0; i < inline_entry->value_count; i++) {
+      const auto& value = inline_entry_values_[inline_entry->start_value_index + i];
+      const auto& config = configurations_[value.config_index];
+      values_map[config] = value.value;
+    }
+    return Result(values_map);
   }
   return {};
 }
@@ -237,6 +255,8 @@
                          const Idmap_data_header* data_header,
                          const Idmap_target_entry* target_entries,
                          const Idmap_target_entry_inline* target_inline_entries,
+                         const Idmap_target_entry_inline_value* inline_entry_values,
+                         const ConfigDescription* configs,
                          const Idmap_overlay_entry* overlay_entries,
                          std::unique_ptr<ResStringPool>&& string_pool,
                          std::string_view overlay_apk_path,
@@ -245,6 +265,8 @@
        data_header_(data_header),
        target_entries_(target_entries),
        target_inline_entries_(target_inline_entries),
+       inline_entry_values_(inline_entry_values),
+       configurations_(configs),
        overlay_entries_(overlay_entries),
        string_pool_(std::move(string_pool)),
        idmap_path_(std::move(idmap_path)),
@@ -303,6 +325,21 @@
   if (target_inline_entries == nullptr) {
     return {};
   }
+
+  auto target_inline_entry_values = ReadType<Idmap_target_entry_inline_value>(
+      &data_ptr, &data_size, "target inline values",
+      dtohl(data_header->target_inline_entry_value_count));
+  if (target_inline_entry_values == nullptr) {
+    return {};
+  }
+
+  auto configurations = ReadType<ConfigDescription>(
+      &data_ptr, &data_size, "configurations",
+      dtohl(data_header->configuration_count));
+  if (configurations == nullptr) {
+    return {};
+  }
+
   auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline",
                                                        dtohl(data_header->overlay_entry_count));
   if (overlay_entries == nullptr) {
@@ -329,8 +366,8 @@
   // Can't use make_unique because LoadedIdmap constructor is private.
   return std::unique_ptr<LoadedIdmap>(
       new LoadedIdmap(idmap_path.to_string(), header, data_header, target_entries,
-                      target_inline_entries, overlay_entries, std::move(idmap_string_pool),
-                      *target_path, *overlay_path));
+                      target_inline_entries, target_inline_entry_values, configurations,
+                      overlay_entries, std::move(idmap_string_pool), *target_path, *overlay_path));
 }
 
 bool LoadedIdmap::IsUpToDate() const {
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 6804472..a1cbbbf 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -23,6 +23,7 @@
 #include <variant>
 
 #include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
 #include "androidfw/StringPiece.h"
 #include "androidfw/ResourceTypes.h"
 #include "utils/ByteOrder.h"
@@ -35,6 +36,7 @@
 struct Idmap_data_header;
 struct Idmap_target_entry;
 struct Idmap_target_entry_inline;
+struct Idmap_target_entry_inline_value;
 struct Idmap_overlay_entry;
 
 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
@@ -91,7 +93,8 @@
    public:
     Result() = default;
     explicit Result(uint32_t value) : data_(value) {};
-    explicit Result(const Res_value& value) : data_(value) { };
+    explicit Result(const std::map<ConfigDescription, Res_value> &value)
+        : data_(value) { };
 
     // Returns `true` if the resource is overlaid.
     explicit operator bool() const {
@@ -107,15 +110,16 @@
     }
 
     bool IsInlineValue() const {
-      return std::get_if<Res_value>(&data_) != nullptr;
+      return std::get_if<2>(&data_) != nullptr;
     }
 
-    const Res_value& GetInlineValue() const {
-      return std::get<Res_value>(data_);
+    const std::map<ConfigDescription, Res_value>& GetInlineValue() const {
+      return std::get<2>(data_);
     }
 
    private:
-      std::variant<std::monostate, uint32_t, Res_value> data_;
+      std::variant<std::monostate, uint32_t,
+          std::map<ConfigDescription, Res_value> > data_;
   };
 
   // Looks up the value that overlays the target resource id.
@@ -129,12 +133,16 @@
   explicit IdmapResMap(const Idmap_data_header* data_header,
                        const Idmap_target_entry* entries,
                        const Idmap_target_entry_inline* inline_entries,
+                       const Idmap_target_entry_inline_value* inline_entry_values,
+                       const ConfigDescription* configs,
                        uint8_t target_assigned_package_id,
                        const OverlayDynamicRefTable* overlay_ref_table);
 
   const Idmap_data_header* data_header_;
   const Idmap_target_entry* entries_;
   const Idmap_target_entry_inline* inline_entries_;
+  const Idmap_target_entry_inline_value* inline_entry_values_;
+  const ConfigDescription* configurations_;
   const uint8_t target_assigned_package_id_;
   const OverlayDynamicRefTable* overlay_ref_table_;
 
@@ -170,8 +178,8 @@
   // Returns a mapping from target resource ids to overlay values.
   const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
                                           const OverlayDynamicRefTable* overlay_ref_table) const {
-    return IdmapResMap(data_header_, target_entries_, target_inline_entries_,
-                       target_assigned_package_id, overlay_ref_table);
+    return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_,
+                       configurations_, target_assigned_package_id, overlay_ref_table);
   }
 
   // Returns a dynamic reference table for a loaded overlay package.
@@ -191,6 +199,8 @@
   const Idmap_data_header* data_header_;
   const Idmap_target_entry* target_entries_;
   const Idmap_target_entry_inline* target_inline_entries_;
+  const Idmap_target_entry_inline_value* inline_entry_values_;
+  const ConfigDescription* configurations_;
   const Idmap_overlay_entry* overlay_entries_;
   const std::unique_ptr<ResStringPool> string_pool_;
 
@@ -207,6 +217,8 @@
                        const Idmap_data_header* data_header,
                        const Idmap_target_entry* target_entries,
                        const Idmap_target_entry_inline* target_inline_entries,
+                       const Idmap_target_entry_inline_value* inline_entry_values_,
+                       const ConfigDescription* configs,
                        const Idmap_overlay_entry* overlay_entries,
                        std::unique_ptr<ResStringPool>&& string_pool,
                        std::string_view overlay_apk_path,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 8c614bc..9309091 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -45,7 +45,7 @@
 namespace android {
 
 constexpr const uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const uint32_t kIdmapCurrentVersion = 0x00000008u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x00000009u;
 
 // This must never change.
 constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
@@ -1098,7 +1098,7 @@
         SDKVERSION_ANY = 0
     };
     
-  enum {
+    enum {
         MINORVERSION_ANY = 0
     };
     
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 88eadcc..8e847e8 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ