Make dt_runpath work for libraries opened from apk

This patch also fixes realpath for libraries opened directly
from apks.

Bug: http://b/21960914
Bug: http://b/21961857
Change-Id: I35ade661c87f1d448191f385811f6e9fd3cacf11
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 9d8b71d..d5a5e56 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -59,6 +59,7 @@
 
 #define LIBPATH LIBPATH_PREFIX "libdlext_test_fd/libdlext_test_fd.so"
 #define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
+#define LIBZIPPATH_WITH_RUNPATH LIBPATH_PREFIX "libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
 
 #define LIBZIP_OFFSET PAGE_SIZE
 
@@ -228,6 +229,24 @@
   dlclose(handle);
 }
 
+TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
+
+  void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
+
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr) << dlerror();
+
+  dlclose(p);
+  dlclose(handle);
+}
+
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
 
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 93df213..c06f4a9 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -34,8 +34,49 @@
   $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libatest_simple_zip.so
 
 $(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
-	@echo "Zipalign $(PRIVATE_ALIGNMENT): $@"
+	@echo "Zipalign: $@"
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir
 	$(hide) cp $^ $(dir $@)/libdir
 	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
 	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned
+LOCAL_MODULE_SUFFIX := .zip
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_runpath_zip
+LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+my_shared_libs := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
+	@echo "Zipalign: $@"
+	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir && \
+    mkdir -p $(dir $@)/libdir/dt_runpath_a && mkdir -p $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_D) $(dir $@)/libdir
+	$(hide) cp $(PRIVATE_LIB_A) $(dir $@)/libdir/dt_runpath_a
+	$(hide) cp $(PRIVATE_LIB_B) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_C) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_X) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir)
+	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk
index 44c8125..4544bb1 100644
--- a/tests/libs/Android.build.dt_runpath.mk
+++ b/tests/libs/Android.build.dt_runpath.mk
@@ -18,6 +18,19 @@
 # Libraries used by dt_runpath tests.
 # -----------------------------------------------------------------------------
 
+#
+# Dependencies
+#
+# libtest_dt_runpath_d.so                       runpath: ${ORIGIN}/dt_runpath_b_c_x
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_b.so  runpath: ${ORIGIN}/../dt_runpath_a
+# |   |-> dt_runpath_a/libtest_dt_runpath_a.so
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_c.so  runpath: ${ORIGIN}/invalid_dt_runpath
+# |   |-> libtest_dt_runpath_a.so (soname)
+#
+# This one is used to test dlopen
+# dt_runpath_b_c_x/libtest_dt_runpath_x.so
+#
+
 # A leaf library in a non-standard directory.
 libtest_dt_runpath_a_src_files := \
     empty.cpp
@@ -57,6 +70,20 @@
 module := libtest_dt_runpath_d
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
+# D version for open-from-zip test with runpath
+libtest_dt_runpath_d_zip_src_files := \
+    dlopen_b.cpp
+
+libtest_dt_runpath_d_zip_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
+libtest_dt_runpath_d_zip_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+libtest_dt_runpath_d_zip_install_to_out_data := true
+module := libtest_dt_runpath_d_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+
 # A leaf library in a directory library D has DT_RUNPATH for.
 libtest_dt_runpath_x_src_files := \
     empty.cpp
@@ -64,3 +91,4 @@
 libtest_dt_runpath_x_relative_path := dt_runpath_b_c_x
 module := libtest_dt_runpath_x
 include $(LOCAL_PATH)/Android.build.testlib.mk
+
diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp
index 5291d81..cd81e16 100644
--- a/tests/libs/dlopen_b.cpp
+++ b/tests/libs/dlopen_b.cpp
@@ -4,8 +4,9 @@
   // remove once it is fixed
   static int dummy = 0;
 
-  // This is not supposed to succeed. Even though this library has DT_RUNPATH
-  // for libtest_dt_runpath_x.so, it is not taked into account for dlopen.
+  // This is supposed to succeed because this library has DT_RUNPATH
+  // for libtest_dt_runpath_x.so which should be taken into account
+  // by dlopen.
   void *handle = dlopen("libtest_dt_runpath_x.so", RTLD_NOW);
   if (handle != nullptr) {
     dummy++;