Add file_offset parameter to android_extinfo

Bug: 17762003
Change-Id: I8fb267a3155acef3dba534038cf5d1ef00d7154b
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 7bd59c8..7585e9b 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -31,7 +31,7 @@
 
 
 #define ASSERT_DL_NOTNULL(ptr) \
-    ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror()
+    ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
 
 #define ASSERT_DL_ZERO(i) \
     ASSERT_EQ(0, i) << "dlerror: " << dlerror()
@@ -46,23 +46,31 @@
 #define LIBSIZE 1024*1024 // how much address space to reserve for it
 
 #if defined(__LP64__)
-#define LIBPATH "%s/nativetest64/libdlext_test_fd/libdlext_test_fd.so"
+#define LIBPATH_PREFIX "%s/nativetest64/libdlext_test_fd/"
 #else
-#define LIBPATH "%s/nativetest/libdlext_test_fd/libdlext_test_fd.so"
+#define LIBPATH_PREFIX "%s/nativetest/libdlext_test_fd/"
 #endif
 
+#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so"
+#define LIBZIPPATH LIBPATH_PREFIX "dlext_test.zip"
+
+#define LIBZIP_OFFSET 2*PAGE_SIZE
+
 class DlExtTest : public ::testing::Test {
 protected:
   virtual void SetUp() {
-    handle_ = NULL;
+    handle_ = nullptr;
     // verify that we don't have the library loaded already
-    ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber"));
+    void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD);
+    ASSERT_TRUE(h == nullptr);
+    h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD);
+    ASSERT_TRUE(h == nullptr);
     // call dlerror() to swallow the error, and check it was the one we wanted
-    ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror());
+    ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
   }
 
   virtual void TearDown() {
-    if (handle_ != NULL) {
+    if (handle_ != nullptr) {
       ASSERT_DL_ZERO(dlclose(handle_));
     }
   }
@@ -71,7 +79,7 @@
 };
 
 TEST_F(DlExtTest, ExtInfoNull) {
-  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL);
+  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr);
   ASSERT_DL_NOTNULL(handle_);
   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
   ASSERT_DL_NOTNULL(f);
@@ -90,7 +98,7 @@
 
 TEST_F(DlExtTest, ExtInfoUseFd) {
   const char* android_data = getenv("ANDROID_DATA");
-  ASSERT_TRUE(android_data != NULL);
+  ASSERT_TRUE(android_data != nullptr);
   char lib_path[PATH_MAX];
   snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data);
 
@@ -105,8 +113,55 @@
   EXPECT_EQ(4, f());
 }
 
+TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
+  const char* android_data = getenv("ANDROID_DATA");
+  ASSERT_TRUE(android_data != nullptr);
+
+  char lib_path[PATH_MAX];
+  snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET;
+  extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
+  extinfo.library_offset = LIBZIP_OFFSET;
+
+  handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo);
+  ASSERT_DL_NOTNULL(handle_);
+
+  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
+  ASSERT_DL_NOTNULL(f);
+  EXPECT_EQ(4, f());
+}
+
+TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
+  const char* android_data = getenv("ANDROID_DATA");
+  ASSERT_TRUE(android_data != nullptr);
+
+  char lib_path[PATH_MAX];
+  snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_OFFSET;
+  extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
+  extinfo.library_offset = 17;
+
+  handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle_ == nullptr);
+  ASSERT_STREQ("dlopen failed: file offset for the library libname_placeholder is not page-aligned: 17", dlerror());
+}
+
+TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) {
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_OFFSET;
+  extinfo.library_offset = LIBZIP_OFFSET;
+
+  handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle_ == nullptr);
+  ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
+}
+
 TEST_F(DlExtTest, Reserved) {
-  void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
                      -1, 0);
   ASSERT_TRUE(start != MAP_FAILED);
   android_dlextinfo extinfo;
@@ -124,7 +179,7 @@
 }
 
 TEST_F(DlExtTest, ReservedTooSmall) {
-  void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+  void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
                      -1, 0);
   ASSERT_TRUE(start != MAP_FAILED);
   android_dlextinfo extinfo;
@@ -132,11 +187,11 @@
   extinfo.reserved_addr = start;
   extinfo.reserved_size = PAGE_SIZE;
   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
-  EXPECT_EQ(NULL, handle_);
+  EXPECT_EQ(nullptr, handle_);
 }
 
 TEST_F(DlExtTest, ReservedHint) {
-  void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
                      -1, 0);
   ASSERT_TRUE(start != MAP_FAILED);
   android_dlextinfo extinfo;
@@ -154,7 +209,7 @@
 }
 
 TEST_F(DlExtTest, ReservedHintTooSmall) {
-  void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+  void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
                      -1, 0);
   ASSERT_TRUE(start != MAP_FAILED);
   android_dlextinfo extinfo;
@@ -175,7 +230,7 @@
 protected:
   virtual void SetUp() {
     DlExtTest::SetUp();
-    void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+    void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
                        -1, 0);
     ASSERT_TRUE(start != MAP_FAILED);
     extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
@@ -184,7 +239,7 @@
     extinfo_.relro_fd = -1;
 
     const char* android_data = getenv("ANDROID_DATA");
-    ASSERT_TRUE(android_data != NULL);
+    ASSERT_TRUE(android_data != nullptr);
     snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data);
   }
 
@@ -205,7 +260,7 @@
       extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
       extinfo_.relro_fd = relro_fd;
       void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
-      if (handle == NULL) {
+      if (handle == nullptr) {
         fprintf(stderr, "in child: %s\n", dlerror());
         exit(1);
       }
@@ -333,7 +388,7 @@
       } else {
         handle = dlopen(lib, RTLD_NOW);
       }
-      if (handle == NULL) {
+      if (handle == nullptr) {
         fprintf(stderr, "in child: %s\n", dlerror());
         exit(1);
       }
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
new file mode 100644
index 0000000..e672091
--- /dev/null
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2014 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.
+#
+
+# -----------------------------------------------------------------------------
+# Library used by dlext tests - zipped and aligned
+# -----------------------------------------------------------------------------
+
+# TODO: It there simple way to do this?
+$(bionic_2nd_arch_prefix)bionic_dlext_test_zip := \
+    $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATES)/libdlext_test_fd/dlext_test_origin.zip
+$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned := \
+    $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd/dlext_test.zip
+ALL_MODULES += $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned)
+
+$(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries := \
+    $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so
+
+bionic_dlext_test_zip_alignment := 4096 # PAGE_SIZE
+
+$(bionic_2nd_arch_prefix)bionic_dlext_test_zip_tmpdir := $(dir $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip))
+
+$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare: $($(bionic_2nd_arch_prefix)bionic_dlext_built_shared_libraries)
+	$(hide) mkdir -p $(dir $@)
+	$(hide) cp -p $< $(dir $@)
+
+$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip)_prepare
+	@echo "Zip: $@"
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@) empty_file.txt libdlext_test_fd.so)
+
+$($(bionic_2nd_arch_prefix)bionic_dlext_test_zip_aligned): $($(bionic_2nd_arch_prefix)bionic_dlext_test_zip) | $(ZIPALIGN)
+	$(hide) rm -rf $@
+	$(hide) mkdir -p $(dir $@)
+	@echo "Zipalign $(bionic_dlext_test_zip_alignment): $@"
+	$(hide) zipalign $(bionic_dlext_test_zip_alignment) $< $@
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index c98fea8..0cff660 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -95,6 +95,17 @@
 include $(TEST_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
+# Library used by dlext tests - zipped and aligned
+# -----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+bionic_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX)
+include $(LOCAL_PATH)/Android.build.dlext_testzip.mk
+ifneq ($(TARGET_2ND_ARCH),)
+  bionic_2nd_arch_prefix :=
+  include $(LOCAL_PATH)/Android.build.dlext_testzip.mk
+endif
+
+# -----------------------------------------------------------------------------
 # Library used by dlfcn tests
 # -----------------------------------------------------------------------------
 libtest_simple_src_files := \
@@ -338,4 +349,8 @@
 module := libtest_dlsym_weak_func
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/Android.build.testlib.mk $(TEST_PATH)/Android.build.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(LOCAL_PATH)/Android.mk \
+    $(LOCAL_PATH)/Android.build.dlext_testzip.mk \
+    $(LOCAL_PATH)/Android.build.testlib.mk \
+    $(TEST_PATH)/Android.build.mk