From fd03f1ef004b194a3408f52a8812e1f47b21b6cc Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Tue, 19 Sep 2017 17:10:10 -0700 Subject: 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 --- runtime/java_vm_ext.cc | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'runtime/java_vm_ext.cc') 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 local_ref(env, env->NewLocalRef(obj)); + if (local_ref != nullptr) { + ScopedLocalRef 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 local_string(env, + env->CallObjectMethod(local_ref.get(), to_string)); + if (local_string != nullptr) { + ScopedUtfChars utf(env, reinterpret_cast(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; } -- cgit v1.2.3-59-g8ed1b