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/linker/Android.mk b/linker/Android.mk
index a962c76..585a738 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -12,6 +12,7 @@
     linker_libc_support.c \
     linker_memory.cpp \
     linker_phdr.cpp \
+    linker_utils.cpp \
     rt.cpp \
 
 LOCAL_SRC_FILES_arm     := arch/arm/begin.S
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3e59218..39f618d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -58,6 +58,7 @@
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
+#include "linker_utils.h"
 
 #include "base/strings.h"
 #include "ziparchive/zip_archive.h"
@@ -360,13 +361,13 @@
 
 static bool realpath_fd(int fd, std::string* realpath) {
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
-  snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+  __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
     PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
   }
 
-  *realpath = std::string(&buf[0]);
+  *realpath = &buf[0];
   return true;
 }
 
@@ -1165,15 +1166,21 @@
 }
 
 static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
-                                   const char* const path,
-                                   off64_t* file_offset) {
-  TRACE("Trying zip file open from path '%s'", path);
+                                   const char* const input_path,
+                                   off64_t* file_offset, std::string* realpath) {
+  std::string normalized_path;
+  if (!normalize_path(input_path, &normalized_path)) {
+    return -1;
+  }
+
+  const char* const path = normalized_path.c_str();
+  TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
 
   // Treat an '!/' separator inside a path as the separator between the name
   // of the zip file on disk and the subdirectory to search within it.
   // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
   // "bar/bas/x.so" within "foo.zip".
-  const char* separator = strstr(path, kZipFileSeparator);
+  const char* const separator = strstr(path, kZipFileSeparator);
   if (separator == nullptr) {
     return -1;
   }
@@ -1215,6 +1222,15 @@
   }
 
   *file_offset = entry.offset;
+
+  if (realpath_fd(fd, realpath)) {
+    *realpath += separator;
+  } else {
+    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+          normalized_path.c_str());
+    *realpath = normalized_path;
+  }
+
   return fd;
 }
 
@@ -1228,7 +1244,7 @@
   return true;
 }
 
-static int open_library_on_default_path(const char* name, off64_t* file_offset) {
+static int open_library_on_default_path(const char* name, off64_t* file_offset, std::string* realpath) {
   for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
     char buf[512];
     if (!format_path(buf, sizeof(buf), g_default_ld_paths[i], name)) {
@@ -1238,6 +1254,10 @@
     int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
     if (fd != -1) {
       *file_offset = 0;
+      if (!realpath_fd(fd, realpath)) {
+        PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
+        *realpath = buf;
+      }
       return fd;
     }
   }
@@ -1247,7 +1267,8 @@
 
 static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
                                  const char* name, off64_t* file_offset,
-                                 const std::vector<std::string>& paths) {
+                                 const std::vector<std::string>& paths,
+                                 std::string* realpath) {
   for (const auto& path_str : paths) {
     char buf[512];
     const char* const path = path_str.c_str();
@@ -1257,13 +1278,17 @@
 
     int fd = -1;
     if (strstr(buf, kZipFileSeparator) != nullptr) {
-      fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset);
+      fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
     }
 
     if (fd == -1) {
       fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
       if (fd != -1) {
         *file_offset = 0;
+        if (!realpath_fd(fd, realpath)) {
+          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
+          *realpath = buf;
+        }
       }
     }
 
@@ -1277,13 +1302,13 @@
 
 static int open_library(ZipArchiveCache* zip_archive_cache,
                         const char* name, soinfo *needed_by,
-                        off64_t* file_offset) {
+                        off64_t* file_offset, std::string* realpath) {
   TRACE("[ opening %s ]", name);
 
   // If the name contains a slash, we should attempt to open it directly and not search the paths.
   if (strchr(name, '/') != nullptr) {
     if (strstr(name, kZipFileSeparator) != nullptr) {
-      int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset);
+      int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
       if (fd != -1) {
         return fd;
       }
@@ -1297,13 +1322,13 @@
   }
 
   // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
-  int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths);
+  int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath);
   if (fd == -1 && needed_by) {
-    fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath());
+    fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
   }
 
   if (fd == -1) {
-    fd = open_library_on_default_path(name, file_offset);
+    fd = open_library_on_default_path(name, file_offset, realpath);
   }
 
   return fd;
@@ -1336,7 +1361,8 @@
 static soinfo* load_library(int fd, off64_t file_offset,
                             LoadTaskList& load_tasks,
                             const char* name, int rtld_flags,
-                            const android_dlextinfo* extinfo) {
+                            const android_dlextinfo* extinfo,
+                            const std::string& realpath) {
   if ((file_offset % PAGE_SIZE) != 0) {
     DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
     return nullptr;
@@ -1378,12 +1404,6 @@
     return nullptr;
   }
 
-  std::string realpath = name;
-  if (!realpath_fd(fd, &realpath)) {
-    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
-    realpath = name;
-  }
-
   // Read the ELF header and load the segments.
   ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
   if (!elf_reader.Load(extinfo)) {
@@ -1416,22 +1436,29 @@
                             LoadTaskList& load_tasks, const char* name,
                             soinfo* needed_by, int rtld_flags,
                             const android_dlextinfo* extinfo) {
+  off64_t file_offset;
+  std::string realpath;
   if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
-    off64_t file_offset = 0;
+    file_offset = 0;
     if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
       file_offset = extinfo->library_fd_offset;
     }
-    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+
+    if (!realpath_fd(extinfo->library_fd, &realpath)) {
+      PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
+            "Will use given name.", name);
+      realpath = name;
+    }
+    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
   }
 
   // Open the file.
-  off64_t file_offset;
-  int fd = open_library(zip_archive_cache, name, needed_by, &file_offset);
+  int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath);
   if (fd == -1) {
     DL_ERR("library \"%s\" not found", name);
     return nullptr;
   }
-  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
   close(fd);
   return result;
 }
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
new file mode 100644
index 0000000..5d39d83
--- /dev/null
+++ b/linker/linker_utils.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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 "linker_utils.h"
+#include "linker_debug.h"
+
+bool normalize_path(const char* path, std::string* normalized_path) {
+  // Input should be an absolute path
+  if (path[0] != '/') {
+    PRINT("canonize_path - invalid input: '%s', the input path should be absolute", path);
+    return false;
+  }
+
+  const size_t len = strlen(path) + 1;
+  char buf[len];
+
+  const char* in_ptr = path;
+  char* out_ptr = buf;
+
+  while (*in_ptr != 0) {
+    if (*in_ptr == '/') {
+      char c1 = in_ptr[1];
+      if (c1 == '.') {
+        char c2 = in_ptr[2];
+        if (c2 == '/') {
+          in_ptr += 2;
+          continue;
+        } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
+          in_ptr += 3;
+          while (out_ptr > buf && *--out_ptr != '/') {
+          }
+          if (in_ptr[0] == 0) {
+            // retain '/'
+            out_ptr++;
+          }
+          continue;
+        }
+      } else if (c1 == '/') {
+        ++in_ptr;
+        continue;
+      }
+    }
+    *out_ptr++ = *in_ptr++;
+  }
+
+  *out_ptr = 0;
+  *normalized_path = buf;
+  return true;
+}
+
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
new file mode 100644
index 0000000..fc79fd1
--- /dev/null
+++ b/linker/linker_utils.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+#ifndef __LINKER_UTILS_H
+#define __LINKER_UTILS_H
+
+#include <string>
+
+bool normalize_path(const char* path, std::string* normalized_path);
+
+#endif
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 0aaee3e..a061877 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -27,11 +27,14 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
 
 LOCAL_SRC_FILES := \
+  linker_globals.cpp \
   linked_list_test.cpp \
   linker_block_allocator_test.cpp \
   ../linker_block_allocator.cpp \
   linker_memory_allocator_test.cpp \
-  ../linker_allocator.cpp
+  ../linker_allocator.cpp \
+  linker_utils_test.cpp \
+  ../linker_utils.cpp
 
 # for __libc_fatal
 LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
diff --git a/linker/tests/linker_globals.cpp b/linker/tests/linker_globals.cpp
new file mode 100644
index 0000000..7762a87
--- /dev/null
+++ b/linker/tests/linker_globals.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+// To enable logging
+int g_ld_debug_verbosity = 0;
+
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
new file mode 100644
index 0000000..458474e
--- /dev/null
+++ b/linker/tests/linker_utils_test.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include "../linker_utils.h"
+
+TEST(linker_utils, normalize_path_smoke) {
+  std::string output;
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/zipfile!/dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/.../zipfile!/.dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/somedir/.../zipfile!/.dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/root/..", &output));
+  ASSERT_EQ("/", output);
+
+  ASSERT_TRUE(normalize_path("/root/notroot/..", &output));
+  ASSERT_EQ("/root/", output);
+
+  ASSERT_TRUE(normalize_path("/a/../../b", &output));
+  ASSERT_EQ("/b", output);
+
+  output = "unchanged";
+  ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("unchanged", output);
+}
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++;