Search code examples
androidc++kotlinjava-native-interfacejnienv

Calling a Kotlin function asynchronously from C++ with JNI


I'm trying to call the function initializationCallback which is implemented in the Kotlin class NativeConnector from C++. I read that I first need to attach the current thread to the JVM, since the thread this code is executed from was not created by the JVM.

The attaching itself seems to be working/is not generating an error, but getting the method id fails with an error:

JNI DETECTED ERROR IN APPLICATION: JNI GetMethodID called with pending exception java.lang.ClassNotFoundException

Running the code from a JVM created thread and without attaching it to the JVM again works perfectly fine, so it seems to me the problem is occurring during attachment.

JNIEnv *env;
int envStatus = javaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
if (envStatus == JNI_EDETACHED) {
    if (javaVM->AttachCurrentThread(&env, nullptr) != 0) {
        Log::instance->logError(LOG_TAG, "AttachCurrentThread: failed.");
    }
}

auto clazz = env->FindClass("*/*/*/NativeConnector");
auto methodId = env->GetMethodID(clazz, "initializationCallback", "()V");
env->CallVoidMethod(m_connectorObject, methodId);

if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
}

javaVM->DetachCurrentThread();

Solution

  • Answered by Michael in a comment:

    Calling FindClass from a thread that you've attached yourself can be problematic. One solution to this is to resolve all necessary class references at startup (e.g. in JNI_OnLoad) and save them as global references for later use.

    See https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class for more info.