1

I try to call a java function from my c++ code, but the app keeps 'crashing'.

At first, I start the c++ code through JNI call, which works without any problem. Then I let the function which is called executing the callback:

#include <jni.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_net_example_folder_Service_startSomething(JNIEnv *env, jobject obj) {
    invoke_class(env);
    return env->NewStringUTF("The End.\n");    //works if I only use this line
}

Trying to follow http://www.inonit.com/cygwin/jni/invocationApi/c.html (and a lot of other guides/tips etc.), I use this to call the java function:

void invoke_class(JNIEnv* env) {
    jclass helloWorldClass;
    jmethodID mainMethod;

    helloWorldClass = env->FindClass("Java/net/example/folder/helloWorldClass");

    mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "()V");

    env->CallStaticVoidMethod(helloWorldClass, mainMethod);
}

To call the java code:

package net.example.folder;

import android.util.Log;

public class helloWorldClass {
    public static void helloWorld() {
        Log.e("helloWorldCLass", "Hello World!");
    }
}

The c++ code is called by a background service. Here is the function of the Activity that starts it:

public void startService() {
    Intent i = new Intent(this, Service.class);
    startService(i);
}

And this is a part of the Service:

public class SimService extends IntentService {

    ...

    @Override
    protected void onHandleIntent(Intent intent) {
        System.loadLibrary("native-lib");
        startSomething();
    }
}

That all works, but when I now change the function 'invoke_class' to:

void invoke_class(JNIEnv* env) {
    jclass helloWorldClass;
    jmethodID mainMethod;

    helloWorldClass = env->FindClass("net/example/folder/helloWorldClass");

    mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "([Ljava/lang/String;)V");

    env->CallStaticVoidMethod(helloWorldClass, mainMethod, env->NewStringUTF("some text"));
}

and of course the java part to:

package net.example.folder;

import android.util.Log;

public class helloWorldClass {
    public static void helloWorld(String msg) {
        Log.e("helloWorldCLass", msg);
    }
}

With that, I'll get the earlier mentioned crash.

Why is that? How do I pass arguments correctly?

3
  • 1
    [ is used to represent arrays (as if you had String[] msg), remove that from your GetStaticMethodID method. Commented Apr 1, 2018 at 7:41
  • 1
    And of course add error checking for all JNI calls. Do not just assume that they will succeed. Commented Apr 1, 2018 at 11:12
  • Thanks, without [ it works. Error checking like if(mainMethod != 0) and running the code only then? It will still cause crashing my application, because of some "JNI Error" Commented Apr 1, 2018 at 12:25

1 Answer 1

3

Symbol [ is used to represent arrays (as if you had String[] msg), remove that from your GetStaticMethodID method.

You can see more information about JNI Types and Data Structures here

Also as Michael said - you should check for java exceptions in your native code, because otherwise your app will crash. You can do it using Exception jni functions. For example:

jclass exClass = env->FindClass("some/random/class");
if (exClass == nullptr || env->ExceptionOccurred()) {
    env->ExceptionClear();
    // do smth in case of failure
}
Sign up to request clarification or add additional context in comments.

1 Comment

exClass will have the value NULL if the class/method does not exist or can not be found. At least in my case. So if (exClass == NULL || ...) for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.