0

我有一个 java 缓冲区,我需要一些 c 数据操作。为此,我调用了本机函数“SimpleFunction”,该函数调用 java 代码以检索特定索引处的缓冲区值 (buffer_read_byte) 并保存修改后的值 (buffer_byte_write)。

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)

我有很多预先存在的函数,最后需要使用 buffer_read_byte 和 buffer_byte_write 访问 java 缓冲区。由于仅在内核函数 buffer_read_byte 和 buffer_byte_write 中需要 JNIEnv ,如何避免在每个预先存在的父函数和子函数中必须声明输入(JNIEnv * env, jobject this) ?

我检查了全局 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;
}   

但是调用 SimpleFunction(100) 没有执行(我没有对缓冲区进行数据修改)并且在尝试执行GetEnvAttachCurrentThread时使应用程序崩溃。

对于无法获取其 JNIenv 的 C 代码调用 JAVA 代码的最佳方式是什么?

4

1 回答 1

0

也许您需要找出它崩溃的原因。看起来你正在使用正确的方法。您也可以在下面的问题中查看答案。

如何创建静态 JNI 环境指针?

异步调用如何获取JNI接口指针(JNIEnv *)

于 2015-12-18T19:22:51.453 回答