Support loading shared libraries from zip files
Add code to support loading shared libraries directly from within
APK files.
Extends the linker's handling of LD_LIBRARY_PATH, DT_RUNPATH, etc
to allow elements to be either directories as normal, or ZIP
format files. For ZIP, the ZIP subdirectory string is separated
from the path to file by '!'.
For example, if DT_NEEDED is libchrome.so and Chrome.apk is the
Android ARM APK then the path element
/system/app/Chrome.apk!lib/armeabi-v7a
would cause the linker to load lib/armeabi-v7a/libchrome.so
directly from inside Chrome.apk. For loading to succeed,
libchrome.so must be 'stored' and not compressed in Chrome.apk,
and must be page aligned within the file.
Motivation:
Chromium tracking issue:
https://code.google.com/p/chromium/issues/detail?id=390618
Bug: 8076853
Change-Id: Ic49046600b1417eae3ee8f37ee98c8ac1ecc19e7
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index dfb5e54..ef4ff20 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -29,6 +29,14 @@
#define ASSERT_SUBSTR(needle, haystack) \
ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
+#if defined(__LP64__)
+#define LIBPATH_PREFIX "/nativetest64/libdlext_test_fd/"
+#else
+#define LIBPATH_PREFIX "/nativetest/libdlext_test_fd/"
+#endif
+
+#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
+
static bool g_called = false;
extern "C" void DlSymTestFunction() {
g_called = true;
@@ -844,6 +852,46 @@
dlclose(handle2);
}
+TEST(dlfcn, dlopen_from_zip_absolute_path) {
+ const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
+
+ void* handle = dlopen((lib_path + "!libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ int (*fn)(void);
+ fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
+ ASSERT_TRUE(fn != nullptr);
+ EXPECT_EQ(4, fn());
+
+ dlclose(handle);
+}
+
+TEST(dlfcn, dlopen_from_zip_ld_library_path) {
+ const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!libdir";
+
+ typedef void (*fn_t)(const char*);
+ fn_t android_update_LD_LIBRARY_PATH =
+ reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
+
+ ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
+
+ void* handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+ ASSERT_TRUE(handle == nullptr);
+
+ android_update_LD_LIBRARY_PATH(lib_path.c_str());
+
+ handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ int (*fn)(void);
+ fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
+ ASSERT_TRUE(fn != nullptr);
+ EXPECT_EQ(4, fn());
+
+ dlclose(handle);
+}
+
+
// libtest_dlopen_from_ctor_main.so depends on
// libtest_dlopen_from_ctor.so which has a constructor
// that calls dlopen(libc...). This is to test the situation