Merge "ART: Clean up library loading"
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index daf64d1..d1a42aa 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -299,7 +299,6 @@
}
// JNI operations after runtime start.
env_ = Thread::Current()->GetJniEnv();
- library_search_path_ = env_->NewStringUTF("");
jklass_ = env_->FindClass("MyClassNatives");
ASSERT_TRUE(jklass_ != nullptr) << method_name << " " << method_sig;
@@ -380,7 +379,6 @@
void CriticalNativeImpl();
JNIEnv* env_;
- jstring library_search_path_;
jmethodID jmethod_;
private:
@@ -660,7 +658,7 @@
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, &reason))
<< reason;
jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24);
@@ -676,7 +674,7 @@
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, &reason))
<< reason;
jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 42);
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index ff839f5..3c87fe2 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -322,8 +322,7 @@
JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
jstring javaFilename,
- jobject javaLoader,
- jstring javaLibrarySearchPath) {
+ jobject javaLoader) {
ScopedUtfChars filename(env, javaFilename);
if (filename.c_str() == NULL) {
return NULL;
@@ -335,7 +334,6 @@
bool success = vm->LoadNativeLibrary(env,
filename.c_str(),
javaLoader,
- javaLibrarySearchPath,
&error_msg);
if (success) {
return nullptr;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7c0c68a..d18feae 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8706,9 +8706,9 @@
}
jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader) {
CHECK(self->GetJniEnv()->IsSameObject(loader_class,
WellKnownClasses::dalvik_system_PathClassLoader) ||
self->GetJniEnv()->IsSameObject(loader_class,
@@ -8784,6 +8784,29 @@
DCHECK(h_dex_path_list != nullptr);
// Set elements.
dex_elements_field->SetObject<false>(h_dex_path_list.Get(), h_dex_elements.Get());
+ // Create an empty List for the "nativeLibraryDirectories," required for native tests.
+ // Note: this code is uncommon(oatdump)/testing-only, so don't add further WellKnownClasses
+ // elements.
+ {
+ ArtField* native_lib_dirs = dex_elements_field->GetDeclaringClass()->
+ FindDeclaredInstanceField("nativeLibraryDirectories", "Ljava/util/List;");
+ DCHECK(native_lib_dirs != nullptr);
+ ObjPtr<mirror::Class> list_class = FindSystemClass(self, "Ljava/util/ArrayList;");
+ DCHECK(list_class != nullptr);
+ {
+ StackHandleScope<1> h_list_scope(self);
+ Handle<mirror::Class> h_list_class(h_list_scope.NewHandle<mirror::Class>(list_class));
+ bool list_init = EnsureInitialized(self, h_list_class, true, true);
+ DCHECK(list_init);
+ list_class = h_list_class.Get();
+ }
+ ObjPtr<mirror::Object> list_object = list_class->AllocObject(self);
+ // Note: we leave the object uninitialized. This must never leak into any non-testing code, but
+ // is fine for testing. While it violates a Java-code invariant (the elementData field is
+ // normally never null), as long as one does not try to add elements, this will still
+ // work.
+ native_lib_dirs->SetObject<false>(h_dex_path_list.Get(), list_object);
+ }
// Create the class loader..
Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index e159436..579552d 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -48,6 +48,7 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "ti/agent.h"
+#include "well_known_classes.h"
namespace art {
@@ -853,7 +854,6 @@
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
const std::string& path,
jobject class_loader,
- jstring library_path,
std::string* error_msg) {
error_msg->clear();
@@ -950,6 +950,9 @@
// class unloading. Libraries will only be unloaded when the reference count (incremented by
// dlopen) becomes zero from dlclose.
+ // Retrieve the library path from the classloader, if necessary.
+ ScopedLocalRef<jstring> library_path(env, GetLibrarySearchPath(env, class_loader));
+
Locks::mutator_lock_->AssertNotHeld(self);
const char* path_str = path.empty() ? nullptr : path.c_str();
bool needs_native_bridge = false;
@@ -957,7 +960,7 @@
runtime_->GetTargetSdkVersion(),
path_str,
class_loader,
- library_path,
+ library_path.get(),
&needs_native_bridge,
error_msg);
@@ -1119,6 +1122,18 @@
// The weak_globals table is visited by the GC itself (because it mutates the table).
}
+jstring JavaVMExt::GetLibrarySearchPath(JNIEnv* env, jobject class_loader) {
+ if (class_loader == nullptr) {
+ return nullptr;
+ }
+ if (!env->IsInstanceOf(class_loader, WellKnownClasses::dalvik_system_BaseDexClassLoader)) {
+ return nullptr;
+ }
+ return reinterpret_cast<jstring>(env->CallObjectMethod(
+ class_loader,
+ WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath));
+}
+
// JNI Invocation interface.
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 7c2755f..8c81c25 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -101,7 +101,6 @@
bool LoadNativeLibrary(JNIEnv* env,
const std::string& path,
jobject class_loader,
- jstring library_path,
std::string* error_msg);
// Unload native libraries with cleared class loaders.
@@ -200,6 +199,11 @@
static bool IsBadJniVersion(int version);
+ // Return the library search path for the given classloader, if the classloader is of a
+ // well-known type. The jobject will be a local reference and is expected to be managed by the
+ // caller.
+ static jstring GetLibrarySearchPath(JNIEnv* env, jobject class_loader);
+
private:
// The constructor should not be called directly. It may leave the object in
// an erroneous state, and the result needs to be checked.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 42f724a..e1610ab 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1619,7 +1619,7 @@
// libcore can't because it's the library that implements System.loadLibrary!
{
std::string error_msg;
- if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, &error_msg)) {
+ if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, &error_msg)) {
LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg;
}
}
@@ -1628,7 +1628,7 @@
? "libopenjdkd.so"
: "libopenjdk.so";
std::string error_msg;
- if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, nullptr, &error_msg)) {
+ if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, &error_msg)) {
LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg;
}
}
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5fef7df..dc57f81 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -81,6 +81,7 @@
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer;
+jmethodID WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath;
jmethodID WellKnownClasses::dalvik_system_VMRuntime_runFinalization;
jmethodID WellKnownClasses::java_lang_Boolean_valueOf;
jmethodID WellKnownClasses::java_lang_Byte_valueOf;
@@ -325,6 +326,7 @@
org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
org_apache_harmony_dalvik_ddmc_DdmServer = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
+ dalvik_system_BaseDexClassLoader_getLdLibraryPath = CacheMethod(env, dalvik_system_BaseDexClassLoader, false, "getLdLibraryPath", "()Ljava/lang/String;");
dalvik_system_VMRuntime_runFinalization = CacheMethod(env, dalvik_system_VMRuntime, true, "runFinalization", "(J)V");
java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
@@ -406,7 +408,7 @@
// to make sure these JNI methods are available.
java_lang_Runtime_nativeLoad =
CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad",
- "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)"
+ "(Ljava/lang/String;Ljava/lang/ClassLoader;)"
"Ljava/lang/String;");
java_lang_reflect_Proxy_invoke =
CacheMethod(env, java_lang_reflect_Proxy, true, "invoke",
@@ -465,6 +467,7 @@
org_apache_harmony_dalvik_ddmc_Chunk = nullptr;
org_apache_harmony_dalvik_ddmc_DdmServer = nullptr;
+ dalvik_system_BaseDexClassLoader_getLdLibraryPath = nullptr;
dalvik_system_VMRuntime_runFinalization = nullptr;
java_lang_Boolean_valueOf = nullptr;
java_lang_Byte_valueOf = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 3ebcc33..024971a 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -92,6 +92,7 @@
static jclass org_apache_harmony_dalvik_ddmc_Chunk;
static jclass org_apache_harmony_dalvik_ddmc_DdmServer;
+ static jmethodID dalvik_system_BaseDexClassLoader_getLdLibraryPath;
static jmethodID dalvik_system_VMRuntime_runFinalization;
static jmethodID java_lang_Boolean_valueOf;
static jmethodID java_lang_Byte_valueOf;
diff --git a/test/150-loadlibrary/src/Main.java b/test/150-loadlibrary/src/Main.java
index 9086937..ec96221 100644
--- a/test/150-loadlibrary/src/Main.java
+++ b/test/150-loadlibrary/src/Main.java
@@ -47,7 +47,7 @@
// Then call an internal function that accepts the classloader. Do not use load(), as it
// is deprecated and only there for backwards compatibility, and prints a warning to the
// log that we'd have to strip (it contains the pid).
- Method m = Runtime.class.getDeclaredMethod("doLoad", String.class, ClassLoader.class);
+ Method m = Runtime.class.getDeclaredMethod("nativeLoad", String.class, ClassLoader.class);
m.setAccessible(true);
Object result = m.invoke(Runtime.getRuntime(), fileName, bootClassLoader);
if (result != null) {