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?