Sort bag by attribute key when using libs

When shared libraries are assigned package ids in a different order
than compile order, bag resources that use attributes from both
multiple libraries will not be sorted in ascending attribute id order.
This change detects when the attribute ids are not in order and sorts
the bag entries accordingly.

The change is designed to be less invasive. Deduping the GetBag logic
should probably be spun off in a separate bug.

Bug: 147674078
Test: libandroidfw_tests
Change-Id: Id8ce8e9c7ef294fcc312b77468136067d392dbd0
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 8cfd2d8..3208662 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -992,6 +992,11 @@
   return bag;
 }
 
+static bool compare_bag_entries(const ResolvedBag::Entry& entry1,
+    const ResolvedBag::Entry& entry2) {
+  return entry1.key < entry2.key;
+}
+
 const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
   auto cached_iter = cached_bags_.find(resid);
   if (cached_iter != cached_bags_.end()) {
@@ -1027,13 +1032,15 @@
   child_resids.push_back(resid);
 
   uint32_t parent_resid = dtohl(map->parent.ident);
-  if (parent_resid == 0 || std::find(child_resids.begin(), child_resids.end(), parent_resid)
+  if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid)
       != child_resids.end()) {
-    // There is no parent or that a circular dependency exist, meaning there is nothing to
-    // inherit and we can do a simple copy of the entries in the map.
+    // There is no parent or a circular dependency exist, meaning there is nothing to inherit and
+    // we can do a simple copy of the entries in the map.
     const size_t entry_count = map_entry_end - map_entry;
     util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
         malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
+
+    bool sort_entries = false;
     ResolvedBag::Entry* new_entry = new_bag->entries;
     for (; map_entry != map_entry_end; ++map_entry) {
       uint32_t new_key = dtohl(map_entry->name.ident);
@@ -1059,8 +1066,15 @@
             new_entry->value.data, new_key);
         return nullptr;
       }
+      sort_entries = sort_entries ||
+          (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
       ++new_entry;
     }
+
+    if (sort_entries) {
+      std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries);
+    }
+
     new_bag->type_spec_flags = entry.type_flags;
     new_bag->entry_count = static_cast<uint32_t>(entry_count);
     ResolvedBag* result = new_bag.get();
@@ -1091,6 +1105,7 @@
   const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
 
   // The keys are expected to be in sorted order. Merge the two bags.
+  bool sort_entries = false;
   while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
     uint32_t child_key = dtohl(map_entry->name.ident);
     if (!is_internal_resid(child_key)) {
@@ -1123,6 +1138,8 @@
       memcpy(new_entry, parent_entry, sizeof(*new_entry));
     }
 
+    sort_entries = sort_entries ||
+        (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
     if (child_key >= parent_entry->key) {
       // Move to the next parent entry if we used it or it was overridden.
       ++parent_entry;
@@ -1153,6 +1170,8 @@
                                        new_entry->value.dataType, new_entry->value.data, new_key);
       return nullptr;
     }
+    sort_entries = sort_entries ||
+        (new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
     ++map_entry;
     ++new_entry;
   }
@@ -1172,6 +1191,10 @@
         new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))));
   }
 
+  if (sort_entries) {
+    std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries);
+  }
+
   // Combine flags from the parent and our own bag.
   new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags;
   new_bag->entry_count = static_cast<uint32_t>(actual_count);