summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2013-10-10 00:32:58 -0700
committerBrian Carlstrom <bdc@google.com>2013-10-10 17:37:23 -0700
commitce88853ab316c70ef7b598978a3609611db60552 (patch)
tree4388d3d8faa16943f9f5718a3bd74c8ef7e2df77
parent3a22361a4d7bb7ae5558640873c375692f1e242a (diff)
downloadart-ce88853ab316c70ef7b598978a3609611db60552.tar.gz
art-ce88853ab316c70ef7b598978a3609611db60552.tar.bz2
art-ce88853ab316c70ef7b598978a3609611db60552.zip
Have JNI FindClass fall back to system ClassLoader
Bug: 10994325 Change-Id: Id0a46e78eecfe8a9eb91008765c4fff48697cc58
-rw-r--r--build/Android.libarttest.mk1
-rw-r--r--runtime/jni_internal.cc30
-rw-r--r--runtime/runtime.cc21
-rw-r--r--runtime/runtime.h9
-rw-r--r--test/Android.mk1
-rw-r--r--test/JniTest/JniTest.java24
-rw-r--r--test/JniTest/jni_test.cc67
7 files changed, 139 insertions, 14 deletions
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk
index f7b4d1e817..f946d919cf 100644
--- a/build/Android.libarttest.mk
+++ b/build/Android.libarttest.mk
@@ -15,6 +15,7 @@
#
LIBARTTEST_COMMON_SRC_FILES := \
+ test/JniTest/jni_test.cc \
test/ReferenceMap/stack_walk_refmap_jni.cc \
test/StackWalk/stack_walk_jni.cc
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 0a0028462d..6a0990eec6 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -255,11 +255,28 @@ static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ArtMethod* method = soa.Self()->GetCurrentMethod(NULL);
- if (method == NULL ||
- method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
+ // If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
+ if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
return soa.Self()->GetClassLoaderOverride();
}
- return method->GetDeclaringClass()->GetClassLoader();
+ // If we have a method, use its ClassLoader for context.
+ if (method != NULL) {
+ return method->GetDeclaringClass()->GetClassLoader();
+ }
+ // We don't have a method, so try to use the system ClassLoader.
+ ClassLoader* class_loader = soa.Decode<ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+ if (class_loader != NULL) {
+ return class_loader;
+ }
+ // See if the override ClassLoader is set for gtests.
+ class_loader = soa.Self()->GetClassLoaderOverride();
+ if (class_loader != NULL) {
+ // If so, CommonTest should have set UseCompileTimeClassPath.
+ CHECK(Runtime::Current()->UseCompileTimeClassPath());
+ return class_loader;
+ }
+ // Use the BOOTCLASSPATH.
+ return NULL;
}
static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
@@ -2101,13 +2118,14 @@ class JNI {
descriptor += ClassHelper(element_class).GetDescriptor();
// Find the class.
- ScopedLocalRef<jclass> java_array_class(env, FindClass(env, descriptor.c_str()));
- if (java_array_class.get() == NULL) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* array_class = class_linker->FindClass(descriptor.c_str(),
+ element_class->GetClassLoader());
+ if (array_class == NULL) {
return NULL;
}
// Allocate and initialize if necessary.
- Class* array_class = soa.Decode<Class*>(java_array_class.get());
ObjectArray<Object>* result = ObjectArray<Object>::Alloc(soa.Self(), array_class, length);
if (initial_element != NULL) {
Object* initial_object = soa.Decode<Object*>(initial_element);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 09d1447d7b..b9f54e5836 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -83,7 +83,6 @@ Runtime::Runtime()
java_vm_(NULL),
pre_allocated_OutOfMemoryError_(NULL),
resolution_method_(NULL),
- system_class_loader_(NULL),
threads_being_born_(0),
shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
shutting_down_(false),
@@ -99,7 +98,8 @@ Runtime::Runtime()
instrumentation_(),
use_compile_time_class_path_(false),
main_thread_group_(NULL),
- system_thread_group_(NULL) {
+ system_thread_group_(NULL),
+ system_class_loader_(NULL) {
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
callee_save_methods_[i] = NULL;
}
@@ -666,9 +666,9 @@ bool Runtime::Create(const Options& options, bool ignore_unrecognized) {
return true;
}
-static void CreateSystemClassLoader() {
+jobject CreateSystemClassLoader() {
if (Runtime::Current()->UseCompileTimeClassPath()) {
- return;
+ return NULL;
}
ScopedObjectAccess soa(Thread::Current());
@@ -687,6 +687,10 @@ static void CreateSystemClassLoader() {
mirror::ClassLoader* class_loader = down_cast<mirror::ClassLoader*>(result.GetL());
CHECK(class_loader != NULL);
+ JNIEnv* env = soa.Self()->GetJniEnv();
+ ScopedLocalRef<jobject> system_class_loader(env, soa.AddLocalReference<jobject>(class_loader));
+ CHECK(system_class_loader.get() != NULL);
+
soa.Self()->SetClassLoaderOverride(class_loader);
mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
@@ -697,6 +701,8 @@ static void CreateSystemClassLoader() {
CHECK(contextClassLoader != NULL);
contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader);
+
+ return env->NewGlobalRef(system_class_loader.get());
}
bool Runtime::Start() {
@@ -729,7 +735,7 @@ bool Runtime::Start() {
StartDaemonThreads();
- CreateSystemClassLoader();
+ system_class_loader_ = CreateSystemClassLoader();
self->GetJniEnv()->locals.AssertEmpty();
@@ -991,6 +997,11 @@ jobject Runtime::GetSystemThreadGroup() const {
return system_thread_group_;
}
+jobject Runtime::GetSystemClassLoader() const {
+ CHECK(system_class_loader_ != NULL || IsCompiler());
+ return system_class_loader_;
+}
+
void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
// Register Throwable first so that registration of other native methods can throw exceptions
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 365d2d860b..bc5c8b00a8 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -240,6 +240,9 @@ class Runtime {
// Returns the "system" ThreadGroup, used when attaching our internal threads.
jobject GetSystemThreadGroup() const;
+ // Returns the system ClassLoader which represents the CLASSPATH.
+ jobject GetSystemClassLoader() const;
+
// Attaches the calling native thread to the runtime.
bool AttachCurrentThread(const char* thread_name, bool as_daemon, jobject thread_group,
bool create_peer);
@@ -467,9 +470,6 @@ class Runtime {
mirror::ArtMethod* resolution_method_;
- // As returned by ClassLoader.getSystemClassLoader()
- mirror::ClassLoader* system_class_loader_;
-
// A non-zero value indicates that a thread has been created but not yet initialized. Guarded by
// the shutdown lock so that threads aren't born while we're shutting down.
size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_);
@@ -510,6 +510,9 @@ class Runtime {
jobject main_thread_group_;
jobject system_thread_group_;
+ // As returned by ClassLoader.getSystemClassLoader().
+ jobject system_class_loader_;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
diff --git a/test/Android.mk b/test/Android.mk
index 6f498e8c02..da469d75d7 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -44,6 +44,7 @@ TEST_OAT_DIRECTORIES := \
Main \
HelloWorld \
\
+ JniTest \
NativeAllocations \
ParallelGC \
ReferenceMap \
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
new file mode 100644
index 0000000000..431056ae32
--- /dev/null
+++ b/test/JniTest/JniTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class JniTest {
+ public static void main(String[] args) {
+ System.loadLibrary("arttest");
+ testFindClassOnAttachedNativeThread();
+ }
+
+ private static native void testFindClassOnAttachedNativeThread();
+}
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
new file mode 100644
index 0000000000..ed69d39d27
--- /dev/null
+++ b/test/JniTest/jni_test.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include "jni.h"
+
+#if defined(NDEBUG)
+#error test code compiled without NDEBUG
+#endif
+
+static JavaVM* jvm = NULL;
+
+extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
+ assert(vm != NULL);
+ assert(jvm == NULL);
+ jvm = vm;
+ return JNI_VERSION_1_6;
+}
+
+static void* testFindClassOnAttachedNativeThread(void*) {
+ assert(jvm != NULL);
+
+ JNIEnv* env = NULL;
+ JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL };
+ int attach_result = jvm->AttachCurrentThread(&env, &args);
+ assert(attach_result == 0);
+
+ jclass clazz = env->FindClass("JniTest");
+ assert(clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jobjectArray array = env->NewObjectArray(0, clazz, NULL);
+ assert(array != NULL);
+ assert(!env->ExceptionCheck());
+
+ int detach_result = jvm->DetachCurrentThread();
+ assert(detach_result == 0);
+ return NULL;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindClassOnAttachedNativeThread(JNIEnv*,
+ jclass) {
+ pthread_t pthread;
+ int pthread_create_result = pthread_create(&pthread,
+ NULL,
+ testFindClassOnAttachedNativeThread,
+ NULL);
+ assert(pthread_create_result == 0);
+ int pthread_join_result = pthread_join(pthread, NULL);
+ assert(pthread_join_result == 0);
+}