Add test checking init/fini call order

This test is checking that loader complies with the order described in
http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini

Bug: http://b/35201832
Test: bionic-unit-tests --gtest_filter=dl*:Dl*
Test: bionic-unit-tests-glibc --gtest_filter=dl*
Change-Id: I4cdf878c043112442c191e82aa9f5d5077e4d8c4
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index a56e3a7..3e9e85e 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1136,6 +1136,28 @@
 #endif
 }
 
+static std::string g_fini_call_order_str;
+
+static void register_fini_call(const char* s) {
+  g_fini_call_order_str += s;
+}
+
+TEST(dlfcn, init_fini_call_order) {
+  void* handle = dlopen("libtest_init_fini_order_root.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*get_init_order_number_t)();
+  get_init_order_number_t get_init_order_number =
+          reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number"));
+  ASSERT_EQ(321, get_init_order_number());
+
+  typedef void (*set_fini_callback_t)(void (*f)(const char*));
+  set_fini_callback_t set_fini_callback =
+          reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback"));
+  set_fini_callback(register_fini_call);
+  dlclose(handle);
+  ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
+}
+
 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 7802727..31a0916 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -448,6 +448,29 @@
 }
 
 // -----------------------------------------------------------------------------
+// Library 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"],
+}
+
+cc_test_library {
+    name: "libtest_init_fini_order_child",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["dlopen_check_init_fini_child.cpp"],
+    shared_libs: ["libtest_init_fini_order_grand_child"],
+}
+
+cc_test_library {
+    name: "libtest_init_fini_order_grand_child",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["dlopen_check_init_fini_grand_child.cpp"],
+}
+
+// -----------------------------------------------------------------------------
 // Library that depends on the library with constructor that calls dlopen() b/7941716
 // -----------------------------------------------------------------------------
 cc_test_library {
diff --git a/tests/libs/dlopen_check_init_fini_child.cpp b/tests/libs/dlopen_check_init_fini_child.cpp
new file mode 100644
index 0000000..bdb5f06
--- /dev/null
+++ b/tests/libs/dlopen_check_init_fini_child.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+
+// These two function are called by local group's constructors and destructors
+extern "C" __attribute__((weak)) void record_init(int digit);
+extern "C" __attribute__((weak)) void record_fini(const char* s);
+
+static void __attribute__((constructor)) init() {
+  record_init(2);
+}
+
+static void __attribute__((destructor)) fini() {
+  record_fini("(child)");
+}
diff --git a/tests/libs/dlopen_check_init_fini_grand_child.cpp b/tests/libs/dlopen_check_init_fini_grand_child.cpp
new file mode 100644
index 0000000..7900f39
--- /dev/null
+++ b/tests/libs/dlopen_check_init_fini_grand_child.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+
+// These two function are called by local group's constructors and destructors
+extern "C" __attribute__((weak)) void record_init(int digit);
+extern "C" __attribute__((weak)) void record_fini(const char* s);
+
+static void __attribute__((constructor)) init() {
+  record_init(3);
+}
+
+static void __attribute__((destructor)) fini() {
+  record_fini("(grandchild)");
+}
diff --git a/tests/libs/dlopen_check_init_fini_root.cpp b/tests/libs/dlopen_check_init_fini_root.cpp
new file mode 100644
index 0000000..45394ec
--- /dev/null
+++ b/tests/libs/dlopen_check_init_fini_root.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+
+static int volatile g_initialization_order_code;
+
+void (*g_fini_callback)(const char*) = nullptr;
+
+// These two function are called by local group's constructors and destructors
+extern "C" void record_init(int digit) {
+  g_initialization_order_code = g_initialization_order_code*10 + digit;
+}
+
+extern "C" void record_fini(const char* s) {
+  g_fini_callback(s);
+}
+
+// these 2 functions are used by the test
+extern "C" int get_init_order_number() {
+  return g_initialization_order_code;
+}
+
+extern "C" void set_fini_callback(void (*f)(const char*)) {
+  g_fini_callback = f;
+}
+
+static void __attribute__((constructor)) init() {
+  record_init(1);
+}
+
+static void __attribute__((destructor)) fini() {
+  record_fini("(root)");
+}