diff options
author | 2017-09-19 17:10:10 -0700 | |
---|---|---|
committer | 2017-09-19 18:29:41 -0700 | |
commit | fd03f1ef004b194a3408f52a8812e1f47b21b6cc (patch) | |
tree | 82ac30f682c5d34a17fe178e7b85967b6340d824 /runtime/java_vm_ext.cc | |
parent | 335ee588ec4bc22be759f5e0fd4b972978e5ace6 (diff) |
ART: Improve double-JNI-load exception message
Try to print the involved classloaders. The code is suboptimal
and will not cache any intermediates, as this is an unexpected
failure - but aids in debugging application issues.
Add a test for the behavior of duplicate library loading in
separate classloaders. For ART, add a rough test for the pattern
of the error message.
Bug: 65574359
Test: m test-art-host
Test: art/test/testrunner/testrunner.py -b --host -t 004-JniTest
Change-Id: I6c6c7726a79172f39153d4a458eba4fb3e8e85b0
Diffstat (limited to 'runtime/java_vm_ext.cc')
-rw-r--r-- | runtime/java_vm_ext.cc | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index 1593577625..c0d1861a8e 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -35,6 +35,7 @@ #include "mirror/class_loader.h" #include "nativebridge/native_bridge.h" #include "nativehelper/ScopedLocalRef.h" +#include "nativehelper/ScopedUtfChars.h" #include "nativeloader/native_loader.h" #include "object_callbacks.h" #include "parsed_options.h" @@ -833,9 +834,42 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, // The library will be associated with class_loader. The JNI // spec says we can't load the same library into more than one // class loader. + // + // This isn't very common. So spend some time to get a readable message. + auto call_to_string = [&](jobject obj) -> std::string { + if (obj == nullptr) { + return "null"; + } + // Handle jweaks. Ignore double local-ref. + ScopedLocalRef<jobject> local_ref(env, env->NewLocalRef(obj)); + if (local_ref != nullptr) { + ScopedLocalRef<jclass> local_class(env, env->GetObjectClass(local_ref.get())); + jmethodID to_string = env->GetMethodID(local_class.get(), + "toString", + "()Ljava/lang/String;"); + DCHECK(to_string != nullptr); + ScopedLocalRef<jobject> local_string(env, + env->CallObjectMethod(local_ref.get(), to_string)); + if (local_string != nullptr) { + ScopedUtfChars utf(env, reinterpret_cast<jstring>(local_string.get())); + if (utf.c_str() != nullptr) { + return utf.c_str(); + } + } + env->ExceptionClear(); + return "(Error calling toString)"; + } + return "null"; + }; + std::string old_class_loader = call_to_string(library->GetClassLoader()); + std::string new_class_loader = call_to_string(class_loader); StringAppendF(error_msg, "Shared library \"%s\" already opened by " - "ClassLoader %p; can't open in ClassLoader %p", - path.c_str(), library->GetClassLoader(), class_loader); + "ClassLoader %p(%s); can't open in ClassLoader %p(%s)", + path.c_str(), + library->GetClassLoader(), + old_class_loader.c_str(), + class_loader, + new_class_loader.c_str()); LOG(WARNING) << *error_msg; return false; } |