【问题标题】:How can I store values in Java parameters that are passed to JNI native C call如何将值存储在传递给 JNI 本机 C 调用的 Java 参数中
【发布时间】:2012-07-14 09:39:35
【问题描述】:

我正在编写一个执行加密、签名等安全模块的程序...我用 C 语言编写了执行上述功能的库。现在我使用 jni 从 java 调用这个 C 本机函数。

我面临的问题是我无法将结果(签名数据或加密数据)存储到 java 传递的参数中。我想将结果存储在我收到的参数中。请帮我。非常感谢。

以下是我在java中调用原生函数的API

sign("sign",byte[] file,int filelen,byte[] output,int outputlen)

在本机 C 调用中,我将在“文件”上执行签名,这是一个由输入文件内容组成的缓冲区,我想将其存储到输出中。我该怎么做,谁能帮帮我,我没有找到任何相关信息。

【问题讨论】:

  • Java 按值传递参数,因此您将无法为参数分配值。不过,您可以填充给定的字节数组。而且 Java 数组有一个 length 属性,因此将长度作为附加参数传递是没有用的。

标签: java java-native-interface


【解决方案1】:

通常,使用直接 ByteBuffer 调用本机库。

接口是MyClass.submit(ByteBuffer source, ByteBuffer dest)

static jmethodID ByteBuffer_position;
static jmethodID ByteBuffer_limit;

// Find method id's for ByteBuffer methods.
JNIEXPORT jint JNICALL Java_MyClass_initAPI
    (JNIEnv *env, jclass thisj) {
  jint error = 0;

  ByteBuffer_position = (*env)->GetMethodID(env, byteBufferClass, "position", "()I");
  if (ByteBuffer_position == NULL) error = -1;
  ByteBuffer_limit = (*env)->GetMethodID(env, byteBufferClass, "limit", "()I");
  if (ByteBuffer_limit == NULL) error = -1;

  return error;
}

// Get ByteBuffer pointers and sizes and encrypt
// Expects source buffer's position to indicate end of source
// Expects dest buffer's limit to indicate max output length
JNIEXPORT jint JNICALL Java_MyClass_submit (JNIEnv *env, jobject thisj,
    jobject sourceBuffer, jobject destBuffer ) {
    jint error = 0;

    unsigned char* sourcePtr = (*env)->GetDirectBufferAddress(env, source);
    unsigned char* destPtr = (*env)->GetDirectBufferAddress(env, dest);
    jlong sourceLen = (*env)->CallIntMethod(env, source, ByteBuffer_position);
    jlong destLen = (*env)->CallIntMethod(env, dest, ByteBuffer_limit);

    // Encrypt sourcePtr --> destPtr

    return error;
}

这应该足以让您了解这个想法。它是从工作代码中转述出来的,但在当前形式中未经测试。

【讨论】:

    【解决方案2】:

    以下代码允许您的本机代码直接访问两个原始字节数组输入的内容。

    JNIEXPORT void JNICALL Java_*mypackage*_sign(JNIEnv* env, jbytearray input, jint ilen, jbytearray output, jint olen) {
      char* pinput = (*env)->GetByteArrayElements(env, input, NULL);
      char* poutput = (*env)->GetByteArrayElements(env, output, NULL);
    
      sign(pinput, ilen, poutput, olen);
    
      (*env)->ReleaseByteArrayElements(env, input, pinput, 0);
      (*env)->ReleaseByteArrayElements(env, output, poutput, 0);
    }
    

    根据您的性能考虑(即,如果您想确保避免复制数组数据,或避免并发访问字节数组),here is an example 使用 GetPrimitiveArrayCritical。

    仅当您需要在本机代码和 Java 代码之间共享缓冲区的时间超过单个函数调用的持续时间时,才建议使用 NIO/直接缓冲区。

    【讨论】:

    • 感谢您的响应。我能够将输入内容访问到本机代码中,并且我对收到的输入执行了一些操作,它工作正常。现在我担心的是通过将值分配给我收到的参数(即在您的上下文中输出)将数据存储回我尝试过的输出参数,但它不起作用。我该怎么做,请帮帮我...
    • 以上示例确保写入“输出”参数缓冲区的任何内容都显示在输出原始数组中。如果要返回写入输出数组的字节数,只需将其用作返回值(而不是“void”)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多