diff options
author | Dmitriy Ivanov <dimitry@google.com> | 2015-06-16 15:38:21 -0700 |
---|---|---|
committer | Dmitriy Ivanov <dimitry@google.com> | 2015-06-17 16:36:03 -0700 |
commit | 28154f5c56dc4a64270cae2374b47a168d1bd7fa (patch) | |
tree | 5f369e0af05ead74aa603f4b3195dd465cd4caae /linker | |
parent | 4d0d31475f1584ed7bf4a52ce784c62c30ad522c (diff) | |
download | bionic-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.cpp | 49 | ||||
-rw-r--r-- | linker/linker_sdk_versions.cpp | 4 |
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; } |