У меня есть Java-буфер, для которого мне нужна некоторая c-манипуляция данными. Для этого я вызываю собственную функцию «SimpleFunction», которая вызывает java-код для извлечения значения буфера по определенному индексу (buffer_read_byte) и для сохранения измененного значения (buffer_byte_write).Код C должен вызывать буфер Java-кода, но не имеет возможности получить его JNIEnv
Java сторона:
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 сторона:
#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;
}
Код выше работ.
Теперь давайте предположим, что манипуляции с данными получают множество внутренних функций, которые в ядре используют c функции buffer_read_byte и buffer_byte_write. Как я могу избежать на каждом уровне функции вызова, чтобы явно передать вход (JNIEnv * env, jobject this)?
У меня есть много ранее существовавших функций, которые в конце должны получить доступ к java-буферу с помощью buffer_read_byte и buffer_byte_write. Как я могу избежать в каждой ранее существовавшей родительской и дочерней функции иметь объявленные входы (JNIEnv * env, jobject this), так как JNIEnv требуется только в функциях ядра buffer_read_byte и buffer_byte_write?
Я проверил для глобальной виртуальной машины Java:
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;
}
Но SimpleFunction вызова (100) не выполняется (у меня нет изменения данных о буфере) и делает приложение сбой при попытке выполнить GetEnv или, как ну, AttachCurrentThread.
Каков наилучший способ для кода C, который не имеет возможности получить его JNIenv, для вызова кода JAVA?
_What это лучший способ для кода C, что не имеет возможности получить его JNIEnv, чтобы позвонить JAVA-код? _ Дайте ему способ получить окр. Если вы не можете сделать это по какой-то странной причине, вам нужно написать прокси-функцию, которая может получить к ней доступ, скопировать данные, необходимые реальной функции, вызвать реальную функцию, а затем скопировать данные по мере необходимости. – mah