如何在 JNI 中访问 jobject 的值

How to access values of a jobject in JNI

本文关键字:访问 jobject 的值 JNI      更新时间:2023-10-16
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。两个 jobject 是大整数, 最初它作为参数恢复了两个int和一个long,但由于我现在需要传递大整数,我遇到了一个问题,或者我应该说其中的几个。

目标:

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

任何帮助将不胜感激。

您的方法的问题在于您正在尝试访问BigInteger调用len字段:

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

BigInteger没有这样的领域。

无法直接访问BigInteger的"值"。从 JNI 中,你能做的最好的事情就是将BigInteger转换为jlong(通过在BigInteger上调用 Java 方法longValue)并使用它。

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

此外,byte[]只能用int索引,所以即使你buf比这更大,也无法从Java访问它。

我会使用直接ByteBuffer而不是byte[]重新命令,因为您不必跨缓冲区复制数据。

你会得到这样的东西:

private static native void readRam(ByteBuffer buff, long address, int pid);

然后在C++:

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);
}

然后打电话:

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();