Inject shim libs as if they were DT_NEEDED.

The previous separate approach had one flaw: If the shim lib requires
another lib that's already loaded, find_library_internal() would return
the previously loaded copy, but the later load action would fail as the
ELF reader map of the initial loading round was already discarded and
thus a new ElfReader instance for the soinfo instance was created, which
didn't know about the previous reading/loading state.

Change-Id: Ib224dbd35d114197097e3dee14a077cc9130fedb
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 9084e92..eb7692f 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1238,14 +1238,15 @@
 // g_ld_all_shim_libs maintains the references to memory as it used
 // in the soinfo structures and in the g_active_shim_libs list.
 
-static std::vector<std::string> g_ld_all_shim_libs;
+typedef std::pair<std::string, std::string> ShimDescriptor;
+static std::vector<ShimDescriptor> g_ld_all_shim_libs;
 
 // g_active_shim_libs are all shim libs that are still eligible
 // to be loaded.  We must remove a shim lib from the list before
 // we load the library to avoid recursive loops (load shim libA
 // for libB where libA also links against libB).
 
-static linked_list_t<const std::string> g_active_shim_libs;
+static linked_list_t<const ShimDescriptor> g_active_shim_libs;
 
 static void reset_g_active_shim_libs(void) {
   g_active_shim_libs.clear();
@@ -1258,47 +1259,36 @@
   g_ld_all_shim_libs.clear();
   if (path != nullptr) {
     // We have historically supported ':' as well as ' ' in LD_SHIM_LIBS.
-    g_ld_all_shim_libs = android::base::Split(path, " :");
-    std::remove_if(g_ld_all_shim_libs.begin(),
-                   g_ld_all_shim_libs.end(),
-                   [] (const std::string& s) { return s.empty(); });
+    for (const auto& pair : android::base::Split(path, " :")) {
+      size_t pos = pair.find('|');
+      if (pos > 0 && pos < pair.length() - 1) {
+        auto desc = std::pair<std::string, std::string>(pair.substr(0, pos), pair.substr(pos + 1));
+        g_ld_all_shim_libs.push_back(desc);
+      }
+    }
   }
   reset_g_active_shim_libs();
 }
 
-static bool shim_lib_matches(const char *shim_lib, const char *realpath) {
-  const char *sep = strchr(shim_lib, '|');
-  return sep != nullptr && strncmp(realpath, shim_lib, sep - shim_lib) == 0;
-}
-
 template<typename F>
-static void shim_libs_for_each(const char *const path, F action) {
+static void for_each_matching_shim(const char *const path, F action) {
   if (path == nullptr) return;
   INFO("Finding shim libs for \"%s\"\n", path);
-  std::vector<const std::string *> matched;
+  std::vector<const ShimDescriptor *> matched;
 
-  g_active_shim_libs.for_each([&](const std::string *a_pair) {
-    const char *pair = a_pair->c_str();
-    if (shim_lib_matches(pair, path)) {
+  g_active_shim_libs.for_each([&](const ShimDescriptor *a_pair) {
+    if (a_pair->first == path) {
       matched.push_back(a_pair);
     }
   });
 
-  g_active_shim_libs.remove_if([&](const std::string *a_pair) {
-    const char *pair = a_pair->c_str();
-    return shim_lib_matches(pair, path);
+  g_active_shim_libs.remove_if([&](const ShimDescriptor *a_pair) {
+    return a_pair->first == path;
   });
 
   for (const auto& one_pair : matched) {
-    const char* const pair = one_pair->c_str();
-    const char* sep = strchr(pair, '|');
-    soinfo *child = find_library(&g_default_namespace, sep+1, RTLD_GLOBAL, nullptr, nullptr);
-    if (child) {
-      INFO("Using shim lib \"%s\"\n", sep+1);
-      action(child);
-    } else {
-      PRINT("Shim lib \"%s\" can not be loaded, ignoring.", sep+1);
-    }
+    INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path);
+    action(one_pair->second.c_str());
   }
 }
 
@@ -1310,7 +1300,7 @@
 // walk_dependencies_tree returns false if walk was terminated
 // by the action and true otherwise.
 template<typename F>
-static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, bool do_shims, F action) {
+static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
   SoinfoLinkedList visit_list;
   SoinfoLinkedList visited;
 
@@ -1330,13 +1320,6 @@
 
     visited.push_back(si);
 
-    if (do_shims) {
-      shim_libs_for_each(si->get_realpath(), [&](soinfo* child) {
-        si->add_child(child);
-        visit_list.push_back(child);
-      });
-    }
-
     si->get_children().for_each([&](soinfo* child) {
       visit_list.push_back(child);
     });
@@ -1352,7 +1335,7 @@
   const ElfW(Sym)* result = nullptr;
   bool skip_lookup = skip_until != nullptr;
 
-  walk_dependencies_tree(&root, 1, false, [&](soinfo* current_soinfo) {
+  walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
     if (skip_lookup) {
       skip_lookup = current_soinfo != skip_until;
       return true;
@@ -1751,6 +1734,7 @@
       action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
     }
   }
+  for_each_matching_shim(si->get_realpath(), action);
 }
 
 template<typename F>
@@ -1760,6 +1744,7 @@
       action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
     }
   }
+  for_each_matching_shim(elf_reader.name(), action);
 }
 
 static bool load_library(android_namespace_t* ns,
@@ -2205,7 +2190,6 @@
   walk_dependencies_tree(
       (start_with != nullptr && add_as_children) ? &start_with : soinfos,
       (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
-      true,
       [&] (soinfo* si) {
     local_group.push_back(si);
     return true;