gpt4 book ai didi

android - API Level 26 以下的 NDK 和 SDK 之间共享内存

转载 作者:行者123 更新时间:2023-11-30 16:06:06 41 4
gpt4 key购买 nike

用 C++ 编写的库会产生连续的数据流,并且必须将其移植到不同的平台上。现在将lib集成到android应用程序中,我正在尝试在NDK和SDK之间创建共享内存。

下面是工作 fragment ,

native 代码:

#include <jni.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/ashmem.h>
#include <android/log.h>
#include <string>

char *buffer;
constexpr size_t BufferSize=100;
extern "C" JNIEXPORT jobject JNICALL
Java_test_com_myapplication_MainActivity_getSharedBufferJNI(
JNIEnv* env,
jobject /* this */) {

int fd = open("/dev/ashmem", O_RDWR);

ioctl(fd, ASHMEM_SET_NAME, "shared_memory");
ioctl(fd, ASHMEM_SET_SIZE, BufferSize);

buffer = (char*) mmap(NULL, BufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

return (env->NewDirectByteBuffer(buffer, BufferSize));
}

extern "C" JNIEXPORT void JNICALL
Java_test_com_myapplication_MainActivity_TestBufferCopy(
JNIEnv* env,
jobject /* this */) {

for(size_t i=0;i<BufferSize;i = i+2) {
__android_log_print(ANDROID_LOG_INFO, "native_log", "Count %d value:%d", i,buffer[i]);
}

//pass `buffer` to dynamically loaded library to update share memory
//

}

SDK代码:

//MainActivity.java
public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.

static {
System.loadLibrary("native-lib");
}

final int BufferSize = 100;
@RequiresApi(api = Build.VERSION_CODES.Q)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ByteBuffer byteBuffer = getSharedBufferJNI();

//update the command to shared memory here
//byteBuffer updated with commands
//Call JNI to inform update and get the response
TestBufferCopy();
}


/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native ByteBuffer getSharedBufferJNI();
public native int TestBufferCopy();
}

问题:

  1. Accessing primitive arrays仅当垃圾收集器支持固定时,从 Java 到 native 才是引用。反过来也是如此吗?
  2. Android 平台是否保证始终引用从 NDK 共享到 SDK,而没有多余的副本?
  3. 这是共享内存的正确方式吗?

最佳答案

您只需要/dev/ashmem即可在进程之间共享内存。 NDK 和 SDK(Java/Kotlin)工作在同一个 Linux 进程中,并且可以完全访问相同的内存空间。

定义可在 C++ 和 Java 中使用的内存的常用方法是创建 Direct ByteBuffer。您不需要 JNI,Java API 有 ByteBuffer.allocateDirect(int capacity) 。如果您的逻辑流更自然地在 C++ 端分配缓冲区,则 JNI 具有 NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)您在问题中使用的函数。

在 C++ 端使用 Direct ByteBuffer 非常容易,但在 JVM 端则不太高效。原因是该缓冲区不受数组支持,并且您拥有的唯一 API 涉及 ByteBuffer.get()具有类型变体(获取字节数组、字符、整数……)。您可以控制当前position在缓冲区中,但以这种方式工作需要一定的纪律:每个 get() 操作都会更新当前位置。此外,对该缓冲区的随机访问相当慢,因为它涉及调用定位和获取 API。因此,在某些重要数据结构的情况下,用 C++ 编写自定义访问代码并通过 JNI 调用“智能”getter 可能会更容易。

重要的是不要忘记设置 ByteBuffer.order(ByteOrder.nativeOrder()) 。新创建的字节缓冲区的顺序是违反直觉的 BIG_ENDIAN。这适用于从 Java 和 C++ 创建的缓冲区。

如果您可以在 C++ 需要访问此类共享内存时隔离实例,并且并不真正需要始终固定它,则值得考虑使用字节数组。在 Java 中,您可以更有效地进行随机访问。在NDK端,您将调用GetByteArrayElements()GetPrimitiveArrayCritical() 。后者效率更高,但它的使用对您可以调用的 Java 函数施加了限制,直到数组被释放为止。在 Android 上,这两种方法都不涉及内存分配和复制(但没有官方保证)。即使 C++ 端使用与 Java 相同的内存,您的 JNI 代码也必须调用适当的 Release…() 函数,并且最好尽早执行此操作。通过 RAII 处理此获取/释放是一个很好的做法。

关于android - API Level 26 以下的 NDK 和 SDK 之间共享内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60055133/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com