Backward compatibility for dlsym(RTLD_DEFAULT, ...)

 Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
 if the library is opened by application with target api level <= 22

Bug: http://b/21565766
Bug: http://b/17512583
Change-Id: Ic45ed1e4f53e84cba9d74cab6b0049c0c7aa8423
(cherry picked from commit 04f7e3e955ba7de5f449c995e667659319dc1cce)
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 8705d9a..a70abf5 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <android/dlext.h>
+#include <android/api-level.h>
 
 #include <bionic/pthread_internal.h>
 #include "private/bionic_tls.h"
@@ -260,6 +261,7 @@
     __libdl_info->strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
     __libdl_info->local_group_root_ = __libdl_info;
     __libdl_info->soname_ = "libdl.so";
+    __libdl_info->target_sdk_version_ = __ANDROID_API__;
 #if defined(__arm__)
     strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
 #endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6a1d84f..b1bf091 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <android/api-level.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -986,7 +987,10 @@
 
   const ElfW(Sym)* s = nullptr;
   for (soinfo* si = start; si != nullptr; si = si->next) {
-    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+    // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
+    // if the library is opened by application with target api level <= 22
+    // See http://b/21565766
+    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
       continue;
     }
 
@@ -1215,8 +1219,7 @@
 static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
 #if !defined(__LP64__)
   // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
-  uint32_t target_sdk_version = get_application_target_sdk_version();
-  if (target_sdk_version != 0 && target_sdk_version <= 22) {
+  if (get_application_target_sdk_version() <= 22) {
     const char* bname = basename(dt_needed);
     if (bname != dt_needed) {
       DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
@@ -2391,6 +2394,17 @@
   return local_group_root_;
 }
 
+// This function returns api-level at the time of
+// dlopen/load. Note that libraries opened by system
+// will always have 'current' api level.
+uint32_t soinfo::get_target_sdk_version() const {
+  if (!has_min_version(2)) {
+    return __ANDROID_API__;
+  }
+
+  return local_group_root_->target_sdk_version_;
+}
+
 /* Force any of the closed stdin, stdout and stderr to be associated with
    /dev/null. */
 static int nullify_closed_stdio() {
@@ -2862,13 +2876,13 @@
   }
 
   // Before M release linker was using basename in place of soname.
-  // In the case when dt_soname is absent some apps stop working:
+  // In the case when dt_soname is absent some apps stop working
   // because they can't find dt_needed library by soname.
   // This workaround should keep them working. (applies only
-  // for apps targeting sdk version <=22). Make an exception for main
-  // executable which does not need dt_soname.
-  uint32_t target_sdk_version = get_application_target_sdk_version();
-  if (soname_ == nullptr && this != somain && target_sdk_version != 0 && target_sdk_version <= 22) {
+  // for apps targeting sdk version <=22). Make an exception for
+  // the main executable and linker; they do not need to have dt_soname
+  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
+      get_application_target_sdk_version() <= 22) {
     soname_ = basename(realpath_.c_str());
     DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
         get_realpath(), soname_);
@@ -2884,6 +2898,10 @@
     local_group_root_ = this;
   }
 
+  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
+    target_sdk_version_ = get_application_target_sdk_version();
+  }
+
   VersionTracker version_tracker;
 
   if (!version_tracker.init(this)) {
diff --git a/linker/linker.h b/linker/linker.h
index 04b584e..6042cb8 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -334,6 +334,8 @@
 
   bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
 
+  uint32_t get_target_sdk_version() const;
+
  private:
   bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* elf_addr_lookup(const void* addr);
@@ -393,6 +395,8 @@
   ElfW(Addr) verneed_ptr_;
   size_t verneed_cnt_;
 
+  uint32_t target_sdk_version_;
+
   friend soinfo* get_libdl_info();
 };
 
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index c73eb38..e9ad3dc 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -15,9 +15,10 @@
  */
 
 #include "linker.h"
+#include <android/api-level.h>
 #include <atomic>
 
-static std::atomic<uint32_t> g_target_sdk_version;
+static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
 
 void set_application_target_sdk_version(uint32_t target) {
   g_target_sdk_version = target;