Support System.loadLibrary for libraries with transitive dependencies.

Also fix the FLAG_ERROR annoyance --- it's not helpful to cache failures.

Bug: 7896159
Bug: http://code.google.com/p/android/issues/detail?id=34416
Bug: http://code.google.com/p/android/issues/detail?id=22143
Change-Id: I60f235edb4ea4756e1f7ce56f7739f18e8a50789
diff --git a/libdl/libdl.c b/libdl/libdl.c
index e8b01be..378f521 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -24,6 +24,8 @@
 int dladdr(const void *addr, Dl_info *info) { return 0; }
 int dlclose(void *handle) { return 0; }
 
+void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { }
+
 #if defined(__arm__)
 
 void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; }
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 2184f3a..a5f8944 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -55,6 +55,11 @@
   return old_value;
 }
 
+void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
+  ScopedPthreadMutexLocker locker(&gDlMutex);
+  do_android_update_LD_LIBRARY_PATH(ld_library_path);
+}
+
 void* dlopen(const char* filename, int flags) {
   ScopedPthreadMutexLocker locker(&gDlMutex);
   soinfo* result = do_dlopen(filename, flags);
@@ -141,16 +146,16 @@
 }
 
 #if defined(ANDROID_ARM_LINKER)
-//                     0000000 00011111 111112 22222222 2333333 333344444444445555555
-//                     0123456 78901234 567890 12345678 9012345 678901234567890123456
+//   0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
+//   0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
+    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_unwind_find_exidx\0"
 
 #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
-//                     0000000 00011111 111112 22222222 2333333 3333444444444455
-//                     0123456 78901234 567890 12345678 9012345 6789012345678901
+//   0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
+//   0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
+    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0"
 #else
 #error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported.
 #endif
@@ -175,10 +180,11 @@
   ELF32_SYM_INITIALIZER(15, &dlsym, 1),
   ELF32_SYM_INITIALIZER(21, &dlerror, 1),
   ELF32_SYM_INITIALIZER(29, &dladdr, 1),
+  ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1),
 #if defined(ANDROID_ARM_LINKER)
-  ELF32_SYM_INITIALIZER(36, &dl_unwind_find_exidx, 1),
+  ELF32_SYM_INITIALIZER(67, &dl_unwind_find_exidx, 1),
 #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
-  ELF32_SYM_INITIALIZER(36, &dl_iterate_phdr, 1),
+  ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1),
 #endif
 };
 
@@ -201,7 +207,7 @@
 // Note that adding any new symbols here requires
 // stubbing them out in libdl.
 static unsigned gLibDlBuckets[1] = { 1 };
-static unsigned gLibDlChains[7] = { 0, 2, 3, 4, 5, 6, 0 };
+static unsigned gLibDlChains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 };
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
 soinfo libdl_info = {
@@ -218,7 +224,7 @@
     symtab: gLibDlSymtab,
 
     nbucket: 1,
-    nchain: 7,
+    nchain: 8,
     bucket: gLibDlBuckets,
     chain: gLibDlChains,
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0bdff99..6a2a958 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -351,6 +351,43 @@
     gSoInfoFreeList = si;
 }
 
+
+static void parse_path(const char* path, const char* delimiters,
+                       const char** array, char* buf, size_t buf_size, size_t max_count) {
+  if (path == NULL) {
+    return;
+  }
+
+  size_t len = strlcpy(buf, path, buf_size);
+
+  size_t i = 0;
+  char* buf_p = buf;
+  while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
+    if (*array[i] != '\0') {
+      ++i;
+    }
+  }
+
+  // Forget the last path if we had to truncate; this occurs if the 2nd to
+  // last char isn't '\0' (i.e. wasn't originally a delimiter).
+  if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
+    array[i - 1] = NULL;
+  } else {
+    array[i] = NULL;
+  }
+}
+
+static void parse_LD_LIBRARY_PATH(const char* path) {
+  parse_path(path, ":", gLdPaths,
+             gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX);
+}
+
+static void parse_LD_PRELOAD(const char* path) {
+  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
+  parse_path(path, " :", gLdPreloadNames,
+             gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX);
+}
+
 #ifdef ANDROID_ARM_LINKER
 
 /* For a given PC, find the .so that it belongs to.
@@ -561,34 +598,28 @@
 
 /* This is used by dl_sym().  It performs a global symbol lookup.
  */
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
-{
-    unsigned elf_hash = elfhash(name);
-    Elf32_Sym *s = NULL;
-    soinfo *si;
+Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) {
+  unsigned elf_hash = elfhash(name);
 
-    if(start == NULL) {
-        start = solist;
+  if (start == NULL) {
+    start = solist;
+  }
+
+  Elf32_Sym* s = NULL;
+  for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
+    s = soinfo_elf_lookup(si, elf_hash, name);
+    if (s != NULL) {
+      *found = si;
+      break;
     }
+  }
 
-    for(si = start; (s == NULL) && (si != NULL); si = si->next)
-    {
-        if(si->flags & FLAG_ERROR)
-            continue;
-        s = soinfo_elf_lookup(si, elf_hash, name);
-        if (s != NULL) {
-            *found = si;
-            break;
-        }
-    }
+  if (s != NULL) {
+    TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, found->base = 0x%08x\n",
+               name, s->st_value, (*found)->base);
+  }
 
-    if(s != NULL) {
-        TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, si->base = 0x%08x\n",
-                   name, s->st_value, si->base);
-        return s;
-    }
-
-    return NULL;
+  return s;
 }
 
 soinfo *find_containing_library(const void *addr)
@@ -869,20 +900,6 @@
     return si.release();
 }
 
-static soinfo* init_library(soinfo* si) {
-  // At this point we know that whatever is loaded @ base is a valid ELF
-  // shared library whose segments are properly mapped in.
-  TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n",
-        si->base, si->size, si->name);
-
-  if (!soinfo_link_image(si)) {
-    munmap((void *)si->base, si->size);
-    return NULL;
-  }
-
-  return si;
-}
-
 static soinfo *find_loaded_library(const char *name)
 {
     soinfo *si;
@@ -909,10 +926,6 @@
 
   soinfo* si = find_loaded_library(name);
   if (si != NULL) {
-    if (si->flags & FLAG_ERROR) {
-      DL_ERR("\"%s\" failed to load previously", name);
-      return NULL;
-    }
     if (si->flags & FLAG_LINKED) {
       return si;
     }
@@ -922,8 +935,19 @@
 
   TRACE("[ '%s' has not been loaded yet.  Locating...]\n", name);
   si = load_library(name);
-  if (si != NULL) {
-    si = init_library(si);
+  if (si == NULL) {
+    return NULL;
+  }
+
+  // At this point we know that whatever is loaded @ base is a valid ELF
+  // shared library whose segments are properly mapped in.
+  TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n",
+        si->base, si->size, si->name);
+
+  if (!soinfo_link_image(si)) {
+    munmap(reinterpret_cast<void*>(si->base), si->size);
+    soinfo_free(si);
+    return NULL;
   }
 
   return si;
@@ -966,6 +990,12 @@
   return 0;
 }
 
+void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
+  if (!get_AT_SECURE()) {
+    parse_LD_LIBRARY_PATH(ld_library_path);
+  }
+}
+
 soinfo* do_dlopen(const char* name, int flags) {
   if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
     DL_ERR("invalid flags to dlopen: %x", flags);
@@ -1466,8 +1496,6 @@
 }
 
 static bool soinfo_link_image(soinfo* si) {
-    si->flags |= FLAG_ERROR;
-
     /* "base" might wrap around UINT32_MAX. */
     Elf32_Addr base = si->load_bias;
     const Elf32_Phdr *phdr = si->phdr;
@@ -1747,47 +1775,9 @@
         nullify_closed_stdio();
     }
     notify_gdb_of_load(si);
-    si->flags &= ~FLAG_ERROR;
     return true;
 }
 
-static void parse_path(const char* path, const char* delimiters,
-                       const char** array, char* buf, size_t buf_size, size_t max_count)
-{
-    if (path == NULL) {
-        return;
-    }
-
-    size_t len = strlcpy(buf, path, buf_size);
-
-    size_t i = 0;
-    char* buf_p = buf;
-    while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
-        if (*array[i] != '\0') {
-            ++i;
-        }
-    }
-
-    // Forget the last path if we had to truncate; this occurs if the 2nd to
-    // last char isn't '\0' (i.e. wasn't originally a delimiter).
-    if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
-        array[i - 1] = NULL;
-    } else {
-        array[i] = NULL;
-    }
-}
-
-static void parse_LD_LIBRARY_PATH(const char* path) {
-    parse_path(path, ":", gLdPaths,
-               gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX);
-}
-
-static void parse_LD_PRELOAD(const char* path) {
-    // We have historically supported ':' as well as ' ' in LD_PRELOAD.
-    parse_path(path, " :", gLdPreloadNames,
-               gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX);
-}
-
 /*
  * This code is called after the linker has linked itself and
  * fixed it's own GOT. It is safe to make references to externs
diff --git a/linker/linker.h b/linker/linker.h
index 60c76fa..377ba15 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -72,7 +72,6 @@
 };
 
 #define FLAG_LINKED     0x00000001
-#define FLAG_ERROR      0x00000002
 #define FLAG_EXE        0x00000004 // The main executable
 #define FLAG_LINKER     0x00000010 // The linker itself
 
@@ -207,6 +206,7 @@
 #define DT_PREINIT_ARRAYSZ 33
 #endif
 
+void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
 soinfo* do_dlopen(const char* name, int flags);
 int do_dlclose(soinfo* si);