2015-12-18 9 views
0

У меня есть 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?

+0

_What это лучший способ для кода C, что не имеет возможности получить его JNIEnv, чтобы позвонить JAVA-код? _ Дайте ему способ получить окр. Если вы не можете сделать это по какой-то странной причине, вам нужно написать прокси-функцию, которая может получить к ней доступ, скопировать данные, необходимые реальной функции, вызвать реальную функцию, а затем скопировать данные по мере необходимости. – mah

ответ