0

I have a java buffer on which I need some c data manipulation. To do that I call a native function "SimpleFunction", which is calling java code to retrive the buffer value at a specific index (buffer_read_byte) and to save the modified value (buffer_byte_write).

Java side:

byte buffer = new byte[100];
public static byte getByte(int index) {
    return buffer[index];
}   
public static void writeByte(int in, int index) {
    buffer[index] = (byte)(in);
}
private native void SimpleFunction(int size);

for(int i=0;i<100;i++)
    setBufferModByteInt(0x55,i);
SimpleFunction(100);

C side:

#include <android/log.h>
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include "algorithms/global.h"
#define LOG_TAG "NDK"
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
static JavaVM* jvm;

void Java_com_App_SimpleFunction(JNIEnv * env, jobject this, jint size)
{
    int address=0;
    for(address=0;address<(int)(size);address++)
    {
        /*
        some data manipulation on ""value""
        */

        value=buffer_read_byte(env,this,address)&0xFF;
        buffer_byte_write(env,this,address,value);
    }
    return;
}

uint8_t buffer_read_byte(JNIEnv * env, jobject this, jint pos)
{
    uint8_t value=0;
    const char * ss="2";
    if ((*env)->ExceptionCheck(env)) {
     return;
    }

    jclass cls = (*env)->FindClass(env,"com/App/Class");
    if ((*env)->ExceptionCheck(env)) {
        return 0;
    }
    jmethodID method = (*env)->GetStaticMethodID(env, cls, "getByte", "(I)B");
    if ((*env)->ExceptionCheck(env)) {
     return 0;
    }
    jbyte result = (*env)->CallStaticByteMethod(env, cls, method,pos);
    if ((*env)->ExceptionCheck(env)) {
     return 0;
    }
    value=(uint8_t) result&0xFF;
    if(cls!=NULL)
    {
        (*env)->DeleteLocalRef(env,cls);
        if ((*env)->ExceptionCheck(env)) {
         return 0;
        }
    }
    return value;
}
void buffer_byte_write(JNIEnv * env, jobject this, jint pos, jint data)
{
    int value=data&0xFF;
    jclass cls = (*env)->FindClass(env,"com/App/Class");
    if ((*env)->ExceptionCheck(env)) {
        return;
    }
    jmethodID method = (*env)->GetStaticMethodID(env, cls, "writeByte", "(II)V");
    if ((*env)->ExceptionCheck(env)) {
     return;
    }
    (*env)->CallStaticVoidMethod(env, cls, method,value,pos);
    if ((*env)->ExceptionCheck(env)) {
     return;
    }
    if(cls!=NULL)
    {
        (*env)->DeleteLocalRef(env,cls);
        if ((*env)->ExceptionCheck(env)) {
         return;
        }
    }
    return;
}   

The code above works.

Now let's suppose that the data manipulation is get by a lot of inner functions which at the kernel is using the c functions buffer_read_byte and buffer_byte_write. How can I avoid at each call function level to explicitly pass as input (JNIEnv * env, jobject this)?

I have a lot of pre-existing functions which at the end needs to access the java buffer with buffer_read_byte and buffer_byte_write. How can I avoid in each pre-existing parent and child function to have to declared inputs (JNIEnv * env, jobject this), since JNIEnv is required only in the kernel functions buffer_read_byte and buffer_byte_write?

I checked for global JVM:

void Java_com_App_SimpleFunction(JNIEnv * env, jobject this, jint size)
{
    (*env)->GetJavaVM(env, &jvm);
    int address=0;
    for(address=0;address<(int)(size);address++)
    {
        value=buffer_read_byte(address)&0xFF;
        /*
        some data manipulation on ""value""
        */
        buffer_byte_write(address,value);
    }
    return;
}
uint8_t buffer_read_byte(jint pos)
{
    JNIEnv * env;
    jint rs=(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4);
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6; // choose your JNI version
    args.name = NULL; // you might want to give the java thread a name
    args.group = NULL; // you might want to assign the java thread to a ThreadGroup
    jint rs=(*jvm)->AttachCurrentThread(jvm, (void**)&env, &args);

    //...

    return value;
}
uint8_t buffer_byte_write(jint pos, jint data)
{
    JNIEnv * env;
    jint rs=(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4);
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6; // choose your JNI version
    args.name = NULL; // you might want to give the java thread a name
    args.group = NULL; // you might want to assign the java thread to a ThreadGroup
    jint rs=(*jvm)->AttachCurrentThread(jvm, (void**)&env, &args);

    //...

    return;
}   

But the call SimpleFunction(100) is not executing (I have no data modification on buffer) and makes app crash when try to execute GetEnv or, as well, AttachCurrentThread.

What is the best way for C code, that has no way to get its JNIenv, to call JAVA code?

xaa
  • 31
  • 1
  • 5
  • _What is the best way for C code, that has no way to get its JNIenv, to call JAVA code?_ Give it a way to get the env. If you cannot do that for some strange reason the you need to write a proxy function that can access it, copies in data the real function will need, calls the real function, then copies back data as necessary. – mah Dec 18 '15 at 14:38

1 Answers1

0

Maybe you need find out why it is crashing. Looks you are using correct method. Also you can check answers in questions below.

How to create static JNI Environment Pointer?

How to obtain JNI interface pointer (JNIEnv *) for asynchronous calls

Community
  • 1
  • 1
xwz7611
  • 138
  • 8