JNI Calling Java from Native C


#1

I’m trying to build a plugin to support a C library used within an Ionic Cordova app. So far the JavaScript -> Java and Java- > C portions of my code work. I can successfully debug C code from within Android Studio running on the phone. However, my C library has a callback method that needs to be passed up the stack (C -> Java -> JavaScript) and I’m having issues getting the JNI methods working properly. Here’s my code so far:

Java

package com.example;

import ...

public class AgentMgrService {

    private static final String TAG = "AgentMgrService";
    private boolean libLoaded = false;
    private static Context mContext;

    public CallbackContext jsCallback;

    // C-function interface
    public static native void startAgentMgr(String agentMgrConfig);
    public static native void stopAgentMgr();

    // load library
    static {
        System.loadLibrary("lib_agentmgr");
    }
    public AgentMgrService(Context context) {
        mContext = context;
    }

    public void startMobileAgentMgr(String agentmgrConfig) throws RemoteException {
        startAgentMgr(agentmgrConfig);

    public void testMe() {
        Log.d(TAG, "testMe!");
    }

    public String toString() {
        Log.d(TAG, "This is a string!");
        return "This is a string!";
    }

}

C

#include ...

static JavaVM* _jamgr_appVm = NULL;
static jobject _jamgr_appObj = NULL;

void
Java_com_exampler_AgentMgrService_startAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    if (_jamgr_appObj == NULL) {
      _jamgr_appObj = (*env)->NewGlobalRef(env, thiz);
    }
    jni_callback();

}

int
jni_callback()
{
    JNIEnv* env = NULL;
    jint retval = 0;
    jmethodID mid = NULL;
    jclass cls = NULL;

    retval = (*_jamgr_appVm)->GetEnv(_jamgr_appVm, (void**) &env, JNI_VERSION_1_6);

    cls = (*env)->GetObjectClass(env, _jamgr_appObj);


    //Try the toString() method
    mid = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;");
    jobject strObj = (*env)->CallObjectMethod(env, _jamgr_appObj, mid);
    const char* str = (*env)->GetStringUTFChars(env, strObj, NULL);
    printf("\nCalling class is: %s\n", str);
    //this prints "class com.example.AgentMgrService"

    mid = (*env)->GetMethodID(env, cls, "testMe", "()V");
    //this returns NULL and thus the below call fails
    (*env)->CallVoidMethod(env, _jamgr_appObj, mid, jstr);

    return retval;
}

When running the above code everything behaves fine until the first GetMethodID(). When calling toString() I get the boilerplate "class com.example.AgentMgrService" as a reply. But wait, I overloaded toString()! Additionally, attempting to get the testMe() returns NULL, so it couldn’t find that method. So I’m in the right class and can in fact call some Java methods from within C, but not methods that I have defined? I haven’t tried making everything static yet but I’m unsure if that would help.


#2

Would it not be somewhat easier to rewrite this library in Java, or even easier, Javascript?