Merge "loader: fix d-tor call order"
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 092e831..b0dd4ce 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -136,6 +136,10 @@
     tail_ = nullptr;
   }
 
+  bool empty() {
+    return (head_ == nullptr);
+  }
+
   template<typename F>
   void for_each(F action) const {
     visit([&] (T* si) {
@@ -179,6 +183,12 @@
     }
   }
 
+  void remove(T* element) {
+    remove_if([&](T* e) {
+      return e == element;
+    });
+  }
+
   template<typename F>
   T* find_if(F predicate) const {
     for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 522d5dc..ece6187 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1661,12 +1661,14 @@
         TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
             child->get_realpath(), child);
 
+        child->get_parents().remove(si);
+
         if (local_unload_list.contains(child)) {
           continue;
         } else if (child->is_linked() && child->get_local_group_root() != root) {
           external_unload_list.push_back(child);
-        } else {
-          unload_list.push_front(child);
+        } else if (child->get_parents().empty()) {
+          unload_list.push_back(child);
         }
       }
     } else {
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 3e9e85e..48fb6d1 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1142,8 +1142,9 @@
   g_fini_call_order_str += s;
 }
 
-TEST(dlfcn, init_fini_call_order) {
-  void* handle = dlopen("libtest_init_fini_order_root.so", RTLD_NOW);
+static void test_init_fini_call_order_for(const char* libname) {
+  g_fini_call_order_str.clear();
+  void* handle = dlopen(libname, RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
   typedef int (*get_init_order_number_t)();
   get_init_order_number_t get_init_order_number =
@@ -1158,6 +1159,11 @@
   ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
 }
 
+TEST(dlfcn, init_fini_call_order) {
+  test_init_fini_call_order_for("libtest_init_fini_order_root.so");
+  test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
+}
+
 TEST(dlfcn, symbol_versioning_use_v1) {
   void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 31a0916..5eb16c5 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -448,13 +448,26 @@
 }
 
 // -----------------------------------------------------------------------------
-// Library used to check init/fini call order
+// Libraries used to check init/fini call order
 // -----------------------------------------------------------------------------
 cc_test_library {
     name: "libtest_init_fini_order_root",
     defaults: ["bionic_testlib_defaults"],
     srcs: ["dlopen_check_init_fini_root.cpp"],
-    shared_libs: ["libtest_init_fini_order_child"],
+    shared_libs: [
+        "libtest_init_fini_order_child",
+        "libtest_init_fini_order_grand_child",
+    ],
+}
+
+cc_test_library {
+    name: "libtest_init_fini_order_root2",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["dlopen_check_init_fini_root.cpp"],
+    shared_libs: [
+        "libtest_init_fini_order_grand_child",
+        "libtest_init_fini_order_child",
+    ],
 }
 
 cc_test_library {