FindClass from any thread in Android JNI

前端 未结 2 1282
孤独总比滥情好
孤独总比滥情好 2020-11-28 02:42

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:

<
相关标签:
2条回答
  • 2020-11-28 03:25

    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;
    }
    
    0 讨论(0)
  • 2020-11-28 03:28

    Try attaching your native thread to the JVM first.

    The pointer to jvm you can obtain first thing in JNI_OnLoad

    env->GetJavaVM(&jvm);
    

    Then from your native thread

    JNIEnv *env;
    jvm->AttachCurrentThread((void **)&env, NULL);
    

    Then use that env for FindClass

    0 讨论(0)
提交回复
热议问题