diff options
author | Brian Carlstrom <bdc@google.com> | 2013-10-10 00:32:58 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2013-10-10 17:37:23 -0700 |
commit | ce88853ab316c70ef7b598978a3609611db60552 (patch) | |
tree | 4388d3d8faa16943f9f5718a3bd74c8ef7e2df77 | |
parent | 3a22361a4d7bb7ae5558640873c375692f1e242a (diff) | |
download | art-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.mk | 1 | ||||
-rw-r--r-- | runtime/jni_internal.cc | 30 | ||||
-rw-r--r-- | runtime/runtime.cc | 21 | ||||
-rw-r--r-- | runtime/runtime.h | 9 | ||||
-rw-r--r-- | test/Android.mk | 1 | ||||
-rw-r--r-- | test/JniTest/JniTest.java | 24 | ||||
-rw-r--r-- | test/JniTest/jni_test.cc | 67 |
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); +} |