FindClass strangeness on created threads

712 views
Skip to first unread message

CrewNerd

unread,
Apr 19, 2010, 4:33:17 PM4/19/10
to android-ndk
In threads that I create directly (via pthread_create) calls to
FindClass are failing in some cases. After studying the docs and other
messages on this topic, I still can't spot any problems in my code.

To reduce complexity, I put a simple test call to FindClass right up
front in my thread proc. I find that FindClass calls on system classes
like java.lang.String will work on any thread, but if I refer to my
own application classes, then FindClass will only work on threads
created by the Java VM. Here's the relevant section of my thread proc.
Any suggestions?

Thanks


void *ThreadType::startProc(void *param)
{
JNIEnv *env;
jint rv = cachedJVM->AttachCurrentThread(&env, NULL); // cachedJVM
set in JNI_OnLoad
if (rv != 0) {
__android_log_print(ANDROID_LOG_DEBUG, "Trace", "Failed to attach
VM: AttachCurrentThread returns %d", rv);
return (void*) 1;
}

__android_log_print(ANDROID_LOG_DEBUG, "Trace",
"ThreadType::startProc - testing FindClass");

//jclass foo = jniEnv()->FindClass("java/lang/String"); // works!
jclass foo = jniEnv()->FindClass("<my app class path>"); //
fails!
if (foo == NULL) {
__android_log_print(ANDROID_LOG_DEBUG, "Trace",
"ThreadType::startProc - FindClass failed");
if (jniEnv()->ExceptionCheck())
jniEnv()->ExceptionDescribe();
return;
}
__android_log_print(ANDROID_LOG_DEBUG, "Trace",
"ThreadType::startProc - FindClass succeeded");

...


--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.

Fergus Henderson

unread,
Apr 20, 2010, 11:01:20 AM4/20/10
to andro...@googlegroups.com

The default class loader for native threads won't load non-system classes.

You can call System.setClassLoader(MyClass.class.GetClassLoader()) before FindClass("MyClass").
You may have to pass in the class loader from Java code to your C/C++ code, and you may need to call System.setClassLoader() via JNI calls e.g. FindClass("System"); Call...Method() etc.

Disclaimer: I may have some details wrong, and I have not tried exactly this, although I have done something similar.

fadden

unread,
Apr 20, 2010, 6:59:10 PM4/20/10
to android-ndk
On Apr 20, 8:01 am, Fergus Henderson <fergus.hender...@gmail.com>
wrote:
> The default class loader for native threads won't load non-system classes.

To be a little more specific: FindClass uses the class loader
associated with the calling method. If your app is running along,
calls into native code, and the native code calls FindClass, it will
use the class loader associated with whatever made the call to native
code.

If you have a newly attached thread, there is no "caller" on the
stack, and FindClass has to punt and use the system class loader.
Since Android apps use user-defined class loaders, your app classes
will not be found.

(There's a hack in place to make JNI_OnLoad find the app classes,
since the caller would otherwise be System.loadLibrary() and you
wouldn't be able to find anything.)

You can work around this by passing the class loader in and doing
things "the hard way". For an example, see AndroidRuntime::findClass
in frameworks/base/core/jni/AndroidRuntime.cpp:


http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/jni/AndroidRuntime.cpp;h=f61e2476c71191aa6eabc93bcb26b3c15ccf6136;hb=HEAD

(starts around line 365)

Alternatively, use FindClass on the interesting classes earlier, store
global refs to the class objects, and later on make them available to
the new thread through some other means (pass in a state block, read a
global variable, etc).

BlackTass

unread,
Apr 23, 2010, 4:01:22 AM4/23/10
to android-ndk


On Apr 21, 2:59 am, fadden <fad...@android.com> wrote:
> (There's a hack in place to make JNI_OnLoad find the app classes,
> since the caller would otherwise be System.loadLibrary() and you
> wouldn't be able to find anything.)
>
> You can work around this by passing the class loader in and doing
> things "the hard way".  For an example, see AndroidRuntime::findClass
> in frameworks/base/core/jni/AndroidRuntime.cpp:
>
> http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;...
>
> (starts around line 365)

Briefly tried it by copying code into my project, but it didn't help.
This class loader loads system classes well, but my custom classes
cannot be loaded (ClassNotFoundException). Did you tried it and it
helped you? If yes, maybe you changed something there or do something
more?

BlackTass

unread,
Apr 24, 2010, 2:54:45 PM4/24/10
to android-ndk


On Apr 21, 2:59 am, fadden <fad...@android.com> wrote:

> Alternatively, use FindClass on the interesting classes earlier, store
> global refs to the class objects, and later on make them available to
> the new thread through some other means (pass in a state block, read a
> global variable, etc).

Tried this way too. It crashes with JNI Warning about not valid JNI
reference.

BlackTass

unread,
Apr 25, 2010, 4:07:05 PM4/25/10
to android-ndk
Solved this issue. It was my error. Before it there was code with
exception (that was caught of course, but it didn't help). After
removing this code all works great.
Reply all
Reply to author
Forward
0 new messages