summaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorDmitriy Ivanov <dimitry@google.com>2015-06-16 15:38:21 -0700
committerDmitriy Ivanov <dimitry@google.com>2015-06-17 16:36:03 -0700
commit28154f5c56dc4a64270cae2374b47a168d1bd7fa (patch)
tree5f369e0af05ead74aa603f4b3195dd465cd4caae /linker
parent4d0d31475f1584ed7bf4a52ce784c62c30ad522c (diff)
downloadbionic-28154f5c56dc4a64270cae2374b47a168d1bd7fa.zip
bionic-28154f5c56dc4a64270cae2374b47a168d1bd7fa.tar.gz
bionic-28154f5c56dc4a64270cae2374b47a168d1bd7fa.tar.bz2
Improve library lookup logic
Linker tries to open a library even if it can be found by soname. This only happens if the library was previously opened under different target sdk version. Bug: http://b/21876587 Bug: http://b/21153477 Bug: http://b/21171302 Bug: https://code.google.com/p/android/issues/detail?id=160921 Change-Id: I7dbbcc3b49933bffd89ca0af55371e1a1f2bf4c2
Diffstat (limited to 'linker')
-rw-r--r--linker/linker.cpp49
-rw-r--r--linker/linker_sdk_versions.cpp4
2 files changed, 45 insertions, 8 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index bbdd1b0..2c51ed9 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1343,30 +1343,63 @@ static soinfo* load_library(LoadTaskList& load_tasks,
return result;
}
-static soinfo *find_loaded_library_by_soname(const char* name) {
+// Returns true if library was found and false in 2 cases
+// 1. The library was found but loaded under different target_sdk_version
+// (*candidate != nullptr)
+// 2. The library was not found by soname (*candidate is nullptr)
+static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
+ *candidate = nullptr;
+
// Ignore filename with path.
if (strchr(name, '/') != nullptr) {
- return nullptr;
+ return false;
}
+ uint32_t target_sdk_version = get_application_target_sdk_version();
+
for (soinfo* si = solist; si != nullptr; si = si->next) {
const char* soname = si->get_soname();
if (soname != nullptr && (strcmp(name, soname) == 0)) {
- return si;
+ // If the library was opened under different target sdk version
+ // skip this step and try to reopen it. The exceptions are
+ // "libdl.so" and global group. There is no point in skipping
+ // them because relocation process is going to use them
+ // in any case.
+ bool is_libdl = si == solist;
+ if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
+ !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
+ *candidate = si;
+ return true;
+ } else if (*candidate == nullptr) {
+ // for the different sdk version - remember the first library.
+ *candidate = si;
+ }
}
}
- return nullptr;
+
+ return false;
}
static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
int rtld_flags, const android_dlextinfo* extinfo) {
- soinfo* si = find_loaded_library_by_soname(name);
+ soinfo* candidate;
+
+ if (find_loaded_library_by_soname(name, &candidate)) {
+ return candidate;
+ }
// Library might still be loaded, the accurate detection
// of this fact is done by load_library.
- if (si == nullptr) {
- TRACE("[ '%s' has not been found by soname. Trying harder...]", name);
- si = load_library(load_tasks, name, rtld_flags, extinfo);
+ TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
+ name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
+
+ soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
+
+ // In case we were unable to load the library but there
+ // is a candidate loaded under the same soname but different
+ // sdk level - return it anyways.
+ if (si == nullptr && candidate != nullptr) {
+ si = candidate;
}
return si;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index e9ad3dc..9aebb06 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -21,6 +21,10 @@
static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
void set_application_target_sdk_version(uint32_t target) {
+ // translate current sdk_version to platform sdk_version
+ if (target == 0) {
+ target = __ANDROID_API__;
+ }
g_target_sdk_version = target;
}