summaryrefslogtreecommitdiff
path: root/runtime/java_vm_ext.cc
diff options
context:
space:
mode:
author Andreas Gampe <agampe@google.com> 2017-09-19 17:10:10 -0700
committer Andreas Gampe <agampe@google.com> 2017-09-19 18:29:41 -0700
commitfd03f1ef004b194a3408f52a8812e1f47b21b6cc (patch)
tree82ac30f682c5d34a17fe178e7b85967b6340d824 /runtime/java_vm_ext.cc
parent335ee588ec4bc22be759f5e0fd4b972978e5ace6 (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.cc38
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;
}