OSDN Git Service

Improve library lookup logic
authorDmitriy Ivanov <dimitry@google.com>
Tue, 16 Jun 2015 22:38:21 +0000 (15:38 -0700)
committerDmitriy Ivanov <dimitry@google.com>
Wed, 17 Jun 2015 23:36:03 +0000 (16:36 -0700)
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

linker/linker.cpp
linker/linker_sdk_versions.cpp

index bbdd1b0..2c51ed9 100644 (file)
@@ -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;
index e9ad3dc..9aebb06 100644 (file)
 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;
 }