findClass的从Android的JNI任何线程 [英] FindClass from any thread in Android JNI

查看:1361
本文介绍了findClass的从Android的JNI任何线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Android的JNI提示页提到了这一点常见问题:为什么没有findClass的发现我的课 他们提到的多个解决方案,并在最后一个选项有这样一句:

Android's JNI tips page mentions this FAQ: Why didn't FindClass find my class? They mention multiple solutions and the last option there is this one:

缓存一个参考的ClassLoader对象的地方方便,并发出   loadClass的直接调用。这需要一些努力。

Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.

所以,我试图得到它的工作,似乎无论怎样,这种方法根本不适合我。最后,我想通了如何使用类加载器,但如果从本地线程我尝试尚未触及/尚未加载的loadClass将无法正常工作。本质上,这是相同的ENV-> findClass的行为从本地线程调用时,不同之处在于它不会返回0为在该应用已经使用的类。任何想法,如果我没有得到它的权利,也不可能从本地线程访问类未使用的/加载呢。

So, I tried to get it working and it seems that no matter what, this method simply does not work for me. Eventually, I figured how to use ClassLoader but it won't work if from a native thread I try to loadClass that hasn't been touched/loaded yet. Essentially, it's the identical to env->FindClass in behavior when called from a native thread, with the exception that it won't return 0 for classes that were already use in the app. Any idea if I didn't get it right, or it's impossible to access classes from a native thread that weren't used/loaded yet.






编辑:我会给更多的信息来解释究竟是什么我的意思。有定期的JNI ENV->的findClass(类名),另外一个,我写了 myFindClass(ENV,类名)使用缓存 ClassLoader->的loadClass






I'll give more info to explain what exactly I mean. There is regular JNI env->FindClass(className), and another one that I wrote myFindClass(env, className) that uses cached ClassLoader->loadClass.

这是我想从本地C / C ++是COM / NONAME / TestClient的访问类。里面myFindClass我也用ENV->的findClass和日志的价值,它返回:

The class that I'm trying to access from native c/c++ is "com/noname/TestClient". Inside myFindClass I also use env->FindClass and log value that it returns:

jclass myFindClass(JNIEnv * env, const char* name)
{
    ...
    jclass c0 = env->FindClass(name);
    jclass c1 = (jclass)env->CallObjectMethod(ClassLoader,
        MID_loadClass, envNewStringUTF(name));
    dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 are same: %d",
        name, c0, c1, env->IsSameObject(c0, c1));
    ...
}

然后,我有这3个组合来解释这个问题。

Then, I have these 3 combinations to explain the issue.

1)

//inside JNI_OnLoad thread
myFindClass(env, "com/noname/TestClient");
...

//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");

我得到这个logcat的:

I get this logcat:

myFindClass(COM / NONAME / TestClent)=> C0:0x41b64558,C1:0x41b64558,   C0和C1是一样的:1
...
myFindClass(COM / NONAME / TestClent)=> C0:0,   C1:0x41b64558,C0和C1相同:0

myFindClass("com/noname/TestClent") => c0:0x41b64558, c1:0x41b64558, c0 and c1 are same: 1
...
myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0 and c1 are same: 0

2)

//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...

//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");

我得到这个logcat的:

I get this logcat:

myFindClass(COM / NONAME / TestClent)=> C0:0,C1:0x41b64558,C0和C1相同:0

myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0 and c1 are same: 0

3)

//inside JNI_OnLoad thread
//"com/noname/TestClient" isn't touched from JNI_OnLoad.
...

//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");

我得到这个logcat的:

I get this logcat:

myFindClass(COM / NONAME / TestClent)=> C0:0,C1:0,C0和C1是一样的:1

myFindClass("com/noname/TestClent") => c0:0, c1:0, c0 and c1 are same: 1

基本上,我的问题是,类装入器不会找到我的班在第三的情况下。是不是一个错误?可以做些什么来解决这个问题?

Basically, my issue is that ClassLoader doesn't find my class in the 3rd case. Is it a bug? What can be done to fix the problem?

EDIT2: 最重要的是,它似乎的ClassLoader :: loadClass的显然是越野车。如果我问myFindClass(NONAME / TestClent),那么它会返回一些垃圾,当我用任何方式返回JCLASS应用程序崩溃。

On top of that, it seems that ClassLoader::loadClass is plainly buggy. If I ask myFindClass("noname/TestClent") then it returns some garbage, and when I use that returned jclass in any way the app crashes.

推荐答案

经过多次尝试和崩溃我的应用程序,一个同事和我设法缓存,并成功地使用了类加载器的另一个人,线程。我们使用了code如下所示(C ++ 11,但很容易转换为C ++ 2003),贴在这里,因为我们找不到任何例子前面提到的高速缓存引用的ClassLoader对象的地方方便,而问题的loadClass直接调用。这需要一些努力。调用的findClass工作完全由一个线程JNI_OnLoad的一个不同的调用时。我希望这有助于。

After much trying and crashing of my app, a colleague and I managed to cache and succesfully use the class loader in another, native, thread. The code we used is shown below (C++11, but easily converted to C++2003), posted here since we couldn't find any examples of the aforementioned "Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.". Calling findClass worked perfectly when called from a thread different from the one of JNI_OnLoad. I hope this helps.

JavaVM* gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
    gJvm = pjvm;  // cache the JavaVM pointer
    auto env = getEnv();
    //replace with one of your classes in the line below
    auto randomClass = env->FindClass("com/example/RandomClass");
    jclass classClass = env->GetObjectClass(randomClass);
    auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
    auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
                                             "()Ljava/lang/ClassLoader;");
    gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
    gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
                                    "(Ljava/lang/String;)Ljava/lang/Class;");

    return JNI_VERSION_1_6;
}

jclass findClass(const char* name) {
    return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));
}

JNIEnv* getEnv() {
    JNIEnv *env;
    int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
    if(status < 0) {    
        status = gJvm->AttachCurrentThread(&env, NULL);
        if(status < 0) {        
            return nullptr;
        }
    }
    return env;
}

这篇关于findClass的从Android的JNI任何线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆