Search code examples
javaandroidcallbackjava-native-interface

Accessed stale local reference passing short[] from JNI to Java


Hello I'm writing a program for Android with Java and JNI.

I'm caching JavaVM*, a global ref jclass and 2 methodsID in the onLoad().

Then from myCallback(), which is running on a separate thread, I get the ref to the environment using AttachCurrentThread() and the cashed JavaVM*. Then I want to pass a short[] back to Java.

I'm getting the error: "accessed stale local reference"

here's my code:

JavaVM* mVm = NULL;
static jclass globalJavaReceiver = NULL;
jmethodID updatePlayerStatus = NULL;
jmethodID sendWaveData = NULL;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

    mVm = vm;

    JNIEnv* env;
    jclass nativeReceiver = NULL;

    if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    nativeReceiver = (*env)->FindClass(env,
            "com/example/customviewcircles/nativeaudio/NativeReceiver");

    if (nativeReceiver != NULL) {

        globalJavaReceiver = (jclass)(*env)->NewGlobalRef(env, nativeReceiver);

        if (globalJavaReceiver != NULL) {

            updatePlayerStatus = (*env)->GetMethodID(env, globalJavaReceiver,
                    "myMethodName", "(I)V");

            sendWaveData = (*env)->GetMethodID(env, globalJavaReceiver,
                    "mySecondMethosName", "([S)V");
        }
    }
    return JNI_VERSION_1_6;
}

void myCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {

        JNIEnv* env;

        (*mVm)->AttachCurrentThread(mVm, &env, NULL);

        jshortArray javaArray = (*env)->NewShortArray(env, myBufferSize);
        if (javaArray != NULL) {

            (*env)->SetShortArrayRegion(env, javaArray, 0, myBufferSize,
                    myNativeShortArray);

        } 

        jobject myObject = NULL;

        if (globalJavaReceiver != NULL) {

            if (sendWaveData != NULL) {

                myObject = (*env)->NewObject(env, globalJavaReceiver,
                        sendWaveData);

                if (myObject != NULL) {

                    (*env)->CallVoidMethod(env, myObject, sendWaveData,
                            javaArray);

                    // getting error 
                    // JNI ERROR (app bug): accessed stale local reference 0x40995ec1 (index 22448 in a table of size 2)
                    // VM aborting
                    // A/libc(9813): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 9840 (AudioRecord)
                }
            }
        }
        (*mVm)->DetachCurrentThread(mVm);

}

what am I doing wrong?

thank you for your time


Solution

  • The problem here was that in :

      myObject = (*env)->NewObject(env, globalJavaReceiver,
                        sendWaveData);
    

    I was trying to create an object from a wrong class function, not from the constructor

    So then I change this part in:

    myObject = (*env)->NewObject(env, globalJavaReceiver,
                    nativeReceiverConstructor);
    

    where nativeReceiverConstructor is the jmethodID from the class constructor. Then finally I've been able to do:

    (*env)->CallVoidMethod(env, myObject, sendWaveData, javaArray);
    

    where sendWaveData is the jmethodID from the function I want to call.

    To pass the array I've then create a jshortArray and SetShortArrayRegion

    Hope it helps