diff options
| -rw-r--r-- | compiler/jni/jni_compiler_test.cc | 6 | ||||
| -rw-r--r-- | openjdkjvm/OpenjdkJvm.cc | 4 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 29 | ||||
| -rw-r--r-- | runtime/java_vm_ext.cc | 19 | ||||
| -rw-r--r-- | runtime/java_vm_ext.h | 6 | ||||
| -rw-r--r-- | runtime/runtime.cc | 4 | ||||
| -rw-r--r-- | runtime/well_known_classes.cc | 5 | ||||
| -rw-r--r-- | runtime/well_known_classes.h | 1 | ||||
| -rw-r--r-- | test/150-loadlibrary/src/Main.java | 2 |
9 files changed, 59 insertions, 17 deletions
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index daf64d1298..d1a42aac0f 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -299,7 +299,6 @@ class JniCompilerTest : public CommonCompilerTest { } // 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 @@ class JniCompilerTest : public CommonCompilerTest { void CriticalNativeImpl(); JNIEnv* env_; - jstring library_search_path_; jmethodID jmethod_; private: @@ -660,7 +658,7 @@ void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() { 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 @@ void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() { 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 ff839f5126..3c87fe2303 100644 --- a/openjdkjvm/OpenjdkJvm.cc +++ b/openjdkjvm/OpenjdkJvm.cc @@ -322,8 +322,7 @@ JNIEXPORT __attribute__((noreturn)) void JVM_Exit(jint status) { 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 @@ JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env, 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 727dd14d6a..3f06d18350 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -8706,9 +8706,9 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { } 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 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, 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 e15943646d..579552d6ab 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 @@ void JavaVMExt::UnloadNativeLibraries() { 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 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, // 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 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, runtime_->GetTargetSdkVersion(), path_str, class_loader, - library_path, + library_path.get(), &needs_native_bridge, error_msg); @@ -1119,6 +1122,18 @@ void JavaVMExt::VisitRoots(RootVisitor* visitor) { // 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 7c2755fc58..8c81c2565d 100644 --- a/runtime/java_vm_ext.h +++ b/runtime/java_vm_ext.h @@ -101,7 +101,6 @@ class JavaVMExt : public JavaVM { 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 @@ class JavaVMExt : public JavaVM { 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 37ba9e473d..441cd98522 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1614,7 +1614,7 @@ void Runtime::InitNativeMethods() { // 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; } } @@ -1623,7 +1623,7 @@ void Runtime::InitNativeMethods() { ? "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 5fef7dfd83..dc57f81a67 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -81,6 +81,7 @@ jclass WellKnownClasses::libcore_util_EmptyArray; 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 @@ void WellKnownClasses::Init(JNIEnv* env) { 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 @@ void WellKnownClasses::LateInit(JNIEnv* env) { // 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 @@ void WellKnownClasses::Clear() { 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 3ebcc33171..024971ae3d 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -92,6 +92,7 @@ struct WellKnownClasses { 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 908693760f..ec96221d1e 100644 --- a/test/150-loadlibrary/src/Main.java +++ b/test/150-loadlibrary/src/Main.java @@ -47,7 +47,7 @@ public class Main { // 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) { |