0

I have jni cpp class similar to this

JNIEXPORT void JNICALL Java_com_my_package_GameBridge_startGame(JNIEnv *env, 
                                                                    jobject obj)) 
{
    GameBridge_Android gameBridge;
    JavaVM* jvm;
    int status = env->GetJavaVM(&jvm);
    // global reference
    jobject globalRef = env->NewGlobalRef(obj)
    gameBridge.setCallback(globalRef);
    gameBridge.startGame();
}

I'm trying storing reference to jobject as a global reference and whenever I need I will be able to call java methods on that object.

I decided to create pure c++ class - GameBridge_Android
C++ header looks similar to this

GameBridge_Android.h:

class GameBridge_Android : public GameBridge
{
public:
    GameBridge_Android();
    virtual void startGame();
    virtual void restartGame();
    virtual void pauseGame();
    virtual void resumeGame();
    virtual void setCallback(jobject obj);

protected:
    jobject mCallback;
};

And its realization

GameBridge_Android.cpp:

void GameBridge_Android::restartGame(){//....}
void GameBridge_Android::resumeGame(){//....}
void GameBridge_Android::setCallback(jobject callback)
{
     mCallback = callback;
}

void GameBridge_Android::pauseGame()
{
    JavaVM* vm = JniHelper::getJavaVM();
    JNIEnv* env;
    jint rs = vm->AttachCurrentThread(&env, NULL); 

    jclass cls = env->FindClass("com/my/package/GameBridge");
    jmethodID onPause = env->GetMethodID(cls, "onPause", "()V");
    env->CallVoidMethod(mCallback, onPause);
}

And simple java GameBridge class

public class GameBridge {
    public native void startGame();

    public void onPause() {
        Log.d("JAVA_GameBridge", "onPause called ");
    }
}

I'm getting an error

 art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: native          code passing in reference to invalid global reference: 0x736c6576

 04-08 16:33:57.889  25537-29355/com.my.package A/art﹕  art/runtime/check_jni.cc:65]  in call to CallVoidMethodV

I've tried to change jobject reference to global reference but no success (probably I'm doing smth wrong here) However, when I invoke static java method, everything works perfectly ok.

P.S. I'm not C++ developer, so any suggestions and correction also on that part would be very appreciated.

NazarK
  • 1,221
  • 2
  • 14
  • 16
  • why is gameBridge a local variable in Java_com_my_package_GameBridge_startGame()? When the function finishes it will be destroyed – samgak Apr 10 '15 at 02:55
  • @samgak you're right, it is probably better to have game bridge as static variable. – NazarK Apr 14 '15 at 07:59
  • So, did you find a solution to this problem? – RenatoUtsch Jan 08 '16 at 18:43
  • @RenatoUtsch Do not keep reference to the non static java objects in the native memory. Android's VM ( Dalvik or ART) can do whatever they want with objects (moving them, garbage them etc) so there are no guarantee that the reference would point to the object that you expect. – NazarK Feb 08 '16 at 10:34

1 Answers1

0

First, check EVERY result from calls such as FindClass() and GetMethodID() against NULL. If you get a NULL, use something like "cerr..." or "fprintf( stderr, ...)" to immediately emit a very descriptive error message.

Second, it's been a few years since I tried doing something very close to what you're doing, so I'm not sure, but I don't think you can reference the jobject passed to a native non-static method call outside of the context of the call it was passed to. You may need to use a global reference from NewGlobalRef().

JNI is very unforgiving.

Here's another method for attaching a thread to the JVM: How to obtain JNI interface pointer (JNIEnv *) for asynchronous calls

I seem to remember that's more like the one I had success with.

Community
  • 1
  • 1
Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Checking is done, everything at this point is good. I've tryed to make pointer to jobject as global but I it did not do a trick. – NazarK Apr 14 '15 at 08:06