如何在JNI

时间:2017-06-28 13:59:12

标签: java c++ java-native-interface

JNIEXPORT jbyteArray JNICALL Java_ramRead_MainClass_readRam
        (JNIEnv *env, jobject, jobject len, jobject addr, jint pid)
{
        jclass c = (*env).GetObjectClass(len);
        jfieldID fid = (*env).GetFieldID(c, "len", "Ljava/math/BigInteger;");
        std::cout << "Object Field: " << (*env).GetObjectField(len, fid);

        struct iovec local[1];
        struct iovec remote[1];
        unsigned long long len1 = (*env).GetObjectField(len, fid) //This did not work out. the conversion to unsigned long long
        jbyte buf[len];
        jbyteArray buf1 = (*env).NewByteArray(len);

        local[0].iov_base = buf;
        local[0].iov_len = len;

        remote[0].iov_base = (void *) addr;
        remote[0].iov_len = len;

        nread = process_vm_readv(pid, local, 1, remote, 1, 0);

        (*env).SetByteArrayRegion(buf1, 0, len, buf);
        return buf1;
}

这是我的原生方法,正如您所看到的,它接收3个参数作为参数两个jobject和一个int。这两个工作是大整数, 最初它作为参数2复活int和一个long但是因为我需要传递大整数现在我有问题或者我应该说几个。

目标:

我需要从BigInteger获取jobject len值,然后我需要使用它来初始化jbyte buf[len]jbyteArray buf1 = (*env).NewByteArray(len)local[0].iov_len = len;的大小当然不能只用len初始化它们我需要从len获取大整数值,然后用它初始化大小。 然后我需要做同样的事情,使用jobject addr从中提取大整数值。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

您的方法存在的问题是您尝试访问BigInteger来电len的字段:

GetFieldID(c, "len", "Ljava/math/BigInteger;");

但是BigInteger没有这样的字段。

无法访问&#34;值&#34;直接BigInteger您可以从JNI做的最好的事情是将BigInteger转换为jlong(通过调用longValue上的Java方法BigInteger并使用它。

但是,如果您以任何方式将其转换为BigInteger,则使用jlong毫无意义。您将失去使用BigInteger所获得的任何精确度。所以不妨在Java中使用long(它仍然适合你提到的值0xffffffffff601000。)

此外,byte[]只能使用int编入索引,因此即使您使buf大于ByteBuffer,也无法通过Java访问。

我建议使用直接byte[]代替private static native void readRam(ByteBuffer buff, long address, int pid); ,因为您不必跨缓冲区复制数据。

你得到这样的东西:

JNIEXPORT void JNICALL Java_Main_readRam
    (JNIEnv *env, jclass, jobject byteBuffer, jlong addr jint pid) {

    struct iovec local[1];
    struct iovec remote[1];

    void* buf = env->GetDirectBufferAddress(byteBuffer);
    jlong len = env->GetDirectBufferCapacity(byteBuffer);

    local[0].iov_base = buf;
    local[0].iov_len = len;

    remote[0].iov_base = (void *) addr;
    remote[0].iov_len = len;

    process_vm_readv(pid, local, 1, remote, 1, 0);
}

然后在C ++中:

int bufferLength = ...;
long address = 0xffffffffff601000L;
int pid = ...;

ByteBuffer bb = ByteBuffer.allocateDirect(bufferLength);

readRam(bb, address, pid);

// use bb...

然后致电:

StringBuilder sb = new StringBuilder();
while(bb.hasRemaining()) {
    byte b = bb.get();
    if((b >= 32 && b < 127) || b == 10) {
        sb.append((char) b);
    }
}
String result = sb.toString();

关于你的评论,你可以这样做:

platformio platform install https://github.com/platformio/platform-espressif8266.git#feature/stage