Port the Runtime.nativeLoad change to art.

Also improve the diagnostics when RegisterNatives fails.

Change-Id: I1000e2e240ce71fbcb4dbc42168253ef8a15c565
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 8c0c1ec..84b5144 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -57,17 +57,6 @@
 static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
 static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check.
 
-void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
-                           size_t method_count) {
-  ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
-  if (c.get() == NULL) {
-    LOG(FATAL) << "Couldn't find class: " << jni_class_name;
-  }
-  if (env->RegisterNatives(c.get(), methods, method_count) != JNI_OK) {
-    LOG(FATAL) << "Failed to register natives methods: " << jni_class_name;
-  }
-}
-
 void SetJniGlobalsMax(size_t max) {
   if (max != 0) {
     gGlobalsMax = max;
@@ -2021,10 +2010,14 @@
   }
 
   static jint RegisterNatives(JNIEnv* env, jclass java_class, const JNINativeMethod* methods, jint method_count) {
+    return RegisterNativeMethods(env, java_class, methods, method_count, true);
+  }
+
+  static jint RegisterNativeMethods(JNIEnv* env, jclass java_class, const JNINativeMethod* methods, size_t method_count, bool return_errors) {
     ScopedObjectAccess soa(env);
     Class* c = soa.Decode<Class*>(java_class);
 
-    for (int i = 0; i < method_count; i++) {
+    for (size_t i = 0; i < method_count; ++i) {
       const char* name = methods[i].name;
       const char* sig = methods[i].signature;
 
@@ -2038,11 +2031,14 @@
         m = c->FindVirtualMethod(name, sig);
       }
       if (m == NULL) {
-        LOG(INFO) << "Failed to register native method " << name << sig;
+        LOG(return_errors ? ERROR : FATAL) << "Failed to register native method "
+                                           << PrettyDescriptor(c) << "." << name << sig;
         ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
-        LOG(INFO) << "Failed to register non-native method " << name << sig << " as native";
+        LOG(return_errors ? ERROR : FATAL) << "Failed to register non-native method "
+                                           << PrettyDescriptor(c) << "." << name << sig
+                                           << " as native";
         ThrowNoSuchMethodError(soa, c, name, sig, "native");
         return JNI_ERR;
       }
@@ -2877,6 +2873,15 @@
   // The weak_globals table is visited by the GC itself (because it mutates the table).
 }
 
+void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
+                           size_t method_count) {
+  ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
+  if (c.get() == NULL) {
+    LOG(FATAL) << "Couldn't find class: " << jni_class_name;
+  }
+  JNI::RegisterNativeMethods(env, c.get(), methods, method_count, false);
+}
+
 }  // namespace art
 
 std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs) {
diff --git a/src/native/java_lang_Runtime.cc b/src/native/java_lang_Runtime.cc
index 6dc850e..d197b73 100644
--- a/src/native/java_lang_Runtime.cc
+++ b/src/native/java_lang_Runtime.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <dlfcn.h>
 #include <limits.h>
 #include <unistd.h>
 
@@ -36,20 +37,28 @@
   exit(status);
 }
 
-/*
- * static String nativeLoad(String filename, ClassLoader loader)
- *
- * Load the specified full path as a dynamic library filled with
- * JNI-compatible methods. Returns null on success, or a failure
- * message on failure.
- */
-static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader) {
+static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader, jstring javaLdLibraryPath) {
   ScopedObjectAccess soa(env);
   ScopedUtfChars filename(env, javaFilename);
   if (filename.c_str() == NULL) {
     return NULL;
   }
 
+  if (javaLdLibraryPath != NULL) {
+    ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath);
+    if (ldLibraryPath.c_str() == NULL) {
+      return NULL;
+    }
+    void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH");
+    if (sym != NULL) {
+      typedef void (*Fn)(const char*);
+      Fn android_update_LD_LIBRARY_PATH = reinterpret_cast<Fn>(sym);
+      (*android_update_LD_LIBRARY_PATH)(ldLibraryPath.c_str());
+    } else {
+      LOG(ERROR) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!";
+    }
+  }
+
   ClassLoader* classLoader = soa.Decode<ClassLoader*>(javaLoader);
   std::string detail;
   JavaVMExt* vm = Runtime::Current()->GetJavaVM();
@@ -78,7 +87,7 @@
   NATIVE_METHOD(Runtime, gc, "()V"),
   NATIVE_METHOD(Runtime, maxMemory, "()J"),
   NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
-  NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;"),
+  NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),
   NATIVE_METHOD(Runtime, totalMemory, "()J"),
 };
 
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index afe6dcd..2c16be9 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -197,7 +197,7 @@
 
 void WellKnownClasses::LateInit(JNIEnv* env) {
   ScopedLocalRef<jclass> java_lang_Runtime(env, env->FindClass("java/lang/Runtime"));
-  java_lang_Runtime_nativeLoad = CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;");
+  java_lang_Runtime_nativeLoad = CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;");
 }
 
 Class* WellKnownClasses::ToClass(jclass global_jclass) {