Merge "Pass the Java caller's location to Runtime.nativeLoad."
diff --git a/ojluni/annotations/hiddenapi/java/lang/Runtime.java b/ojluni/annotations/hiddenapi/java/lang/Runtime.java
index c9a364c..ca8c56c 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Runtime.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Runtime.java
@@ -154,7 +154,7 @@
     }
 
     @UnsupportedAppUsage
-    synchronized void loadLibrary0(java.lang.ClassLoader loader, java.lang.String libname) {
+    void loadLibrary0(java.lang.ClassLoader loader, java.lang.String libname) {
         throw new RuntimeException("Stub!");
     }
 
@@ -167,8 +167,10 @@
     }
 
     @UnsupportedAppUsage
-    private static native java.lang.String nativeLoad(
-            java.lang.String filename, java.lang.ClassLoader loader);
+    private static java.lang.String nativeLoad(
+            java.lang.String filename, java.lang.ClassLoader loader) {
+        throw new RuntimeException("Stub!");
+    }
 
     @Deprecated
     public java.io.InputStream getLocalizedInputStream(java.io.InputStream in) {
diff --git a/ojluni/src/main/java/java/lang/Runtime.java b/ojluni/src/main/java/java/lang/Runtime.java
index 2fc124c..bb0bcb4 100644
--- a/ojluni/src/main/java/java/lang/Runtime.java
+++ b/ojluni/src/main/java/java/lang/Runtime.java
@@ -1004,7 +1004,7 @@
     */
     void loadLibrary0(Class<?> fromClass, String libname) {
         ClassLoader classLoader = ClassLoader.getClassLoader(fromClass);
-        loadLibrary0(classLoader, libname);
+        loadLibrary0(classLoader, fromClass, libname);
     }
 
     /**
@@ -1021,10 +1021,33 @@
         checkTargetSdkVersionForLoad("java.lang.Runtime#loadLibrary(String, ClassLoader)");
         java.lang.System.logE("java.lang.Runtime#loadLibrary(String, ClassLoader)" +
                               " is private and will be removed in a future Android release");
-        loadLibrary0(classLoader, libname);
+        // Pass null for callerClass, we don't know it at this point. Passing null preserved
+        // the behavior when we used to not pass the class.
+        loadLibrary0(classLoader, null, libname);
     }
 
-    synchronized void loadLibrary0(ClassLoader loader, String libname) {
+    // This overload exists for @UnsupportedAppUsage
+    void loadLibrary0(ClassLoader loader, String libname) {
+        // Pass null for callerClass, we don't know it at this point. Passing null preserved
+        // the behavior when we used to not pass the class.
+        loadLibrary0(loader, null, libname);
+    }
+    
+    /**
+     * Loads the shared library {@code libname} in the context of {@code loader} and
+     * {@code callerClass}.
+     *
+     * @param      loader    the class loader that initiated the loading. Used by the
+     *                       underlying linker to determine linker namespace. A {@code null}
+     *                       value represents the boot class loader.
+     * @param      fromClass the class that initiated the loading. Used when loader is
+     *                       {@code null} and ignored in all other cases. When used, it 
+     *                       determines the linker namespace from the class's .dex location.
+     *                       {@code null} indicates the default namespace for the boot 
+     *                       class loader.
+     * @param      libname   the name of the library.
+     */
+    private synchronized void loadLibrary0(ClassLoader loader, Class<?> callerClass, String libname) {
         if (libname.indexOf((int)File.separatorChar) != -1) {
             throw new UnsatisfiedLinkError(
     "Directory separator should not appear in library name: " + libname);
@@ -1050,26 +1073,14 @@
             return;
         }
 
+        // We know some apps use mLibPaths directly, potentially assuming it's not null.
+        // Initialize it here to make sure apps see a non-null value.
+        getLibPaths();
         String filename = System.mapLibraryName(libraryName);
-        List<String> candidates = new ArrayList<String>();
-        String lastError = null;
-        for (String directory : getLibPaths()) {
-            String candidate = directory + filename;
-            candidates.add(candidate);
-
-            if (IoUtils.canOpenReadOnly(candidate)) {
-                String error = nativeLoad(candidate, loader);
-                if (error == null) {
-                    return; // We successfully loaded the library. Job done.
-                }
-                lastError = error;
-            }
+        String error = nativeLoad(filename, loader, callerClass);
+        if (error != null) {
+            throw new UnsatisfiedLinkError(error);
         }
-
-        if (lastError != null) {
-            throw new UnsatisfiedLinkError(lastError);
-        }
-        throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
     }
 
     private volatile String[] mLibPaths = null;
@@ -1100,7 +1111,11 @@
         return paths;
     }
 
-    private static native String nativeLoad(String filename, ClassLoader loader);
+    private static String nativeLoad(String filename, ClassLoader loader) {
+        return nativeLoad(filename, loader, null);
+    }
+
+    private static native String nativeLoad(String filename, ClassLoader loader, Class<?> caller);
     // END Android-changed: Different implementation of loadLibrary0(Class, String).
 
     /**
diff --git a/ojluni/src/main/native/Runtime.c b/ojluni/src/main/native/Runtime.c
index ad734fd..749511e 100644
--- a/ojluni/src/main/native/Runtime.c
+++ b/ojluni/src/main/native/Runtime.c
@@ -75,9 +75,9 @@
 
 JNIEXPORT jstring JNICALL
 Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,
-                   jobject javaLoader)
+                   jobject javaLoader, jclass caller)
 {
-    return JVM_NativeLoad(env, javaFilename, javaLoader);
+    return JVM_NativeLoad(env, javaFilename, javaLoader, caller);
 }
 
 static JNINativeMethod gMethods[] = {
@@ -87,7 +87,7 @@
   NATIVE_METHOD(Runtime, nativeGc, "()V"),
   NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
   NATIVE_METHOD(Runtime, nativeLoad,
-                "(Ljava/lang/String;Ljava/lang/ClassLoader;)"
+                "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Class;)"
                     "Ljava/lang/String;"),
 };
 
diff --git a/ojluni/src/main/native/jvm.h b/ojluni/src/main/native/jvm.h
index 83067ce..fd15abf 100644
--- a/ojluni/src/main/native/jvm.h
+++ b/ojluni/src/main/native/jvm.h
@@ -166,7 +166,7 @@
 JVM_ActiveProcessorCount(void);
 
 JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env, jstring javaFilename,
-                                 jobject javaLoader);
+                                 jobject javaLoader, jclass caller);
 
 JNIEXPORT void * JNICALL
 JVM_LoadLibrary(const char *name);