首页 > 解决方案 > 使用 Android NDK SharedMemory.h 进行多进程

问题描述

我一直在 Android Studio(使用 NDK)中尝试多处理(使用共享内存)。我安装了 NDK、LLDB、CMake。我也使用 API 级别 26,最小 SDK 也是 26(OREO,8.0)。

我创建了 native_lib.cpp,并制作了一些用于测试 FD 的文件。

我做了简单的小班测试。

班级有int FileDescriptor, char* buffer.

我检查了变量,似乎成功了。ASharedMemory_Create() returns fd,我可以从中获取内存大小ASharedMemory_getSize(int fd)

但是我怎样才能从另一个进程访问共享内存呢?我需要为 IPC 使用 java 吗?如果可以的话,我只想使用本机。目前java仅用于UI。

https://developer.android.com/ndk/reference/group/memory

我在这里检查。如果有什么值得我参考的,请告诉我。谢谢你。

已编辑------------------------------------------------- --

我想在父母和孩子之间建立共享记忆。也想自由访问共享内存。孩子对孩子,孩子对父母,父母对孩子。

在父母中制作文件描述符和缓冲区工作顺利,但是当我尝试在孩子中制作缓冲区或 fd 时,我无法访问它。

我对 . 使用了相同的名称和大小ASharedMemory_create,但在我看来,其他进程制作了不同的文件描述符。不知道怎么回事。

下面是我native_lib.cpp的测试。与按钮匹配的功能,除了Init. InitonCreate.

int fd[4];
char* buffer[4];

int myFd;
int* cBuf;

const char* names[4] = {"Test", "Inter", "Process", "Mech"};
const int size = 512;

extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_SyncBuffer(
        JNIEnv *env,
        jobject /* this */) {
    int cVal;
    memcpy(&cVal, cBuf, sizeof(int));

    for(int i = 0 ; i < cVal; ++i)
    {
        if(fd[i] != NULL) {
            buffer[i] = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
        }
    }
}

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

    pid_t pid = fork();
    int cVal;

    if(pid < 0) {
        return;
    } else if(pid == 0) {
        memcpy(&cVal, cBuf, sizeof(int));

        fd[cVal] = ASharedMemory_create(names[cVal], size);
        buffer[cVal] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[cVal], 0);

        memset(buffer[cVal], 0, size);
        memcpy(buffer[cVal], names[cVal], strlen(names[cVal]));

        cVal++;
        memcpy(cBuf, &cVal, sizeof(int));

        sleep(1);
        exit(1);
    }
}

extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_Init(
        JNIEnv *env,
        jobject /* this */) {
    myFd = ASharedMemory_create("Num", sizeof(int));
    cBuf = (int*) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, myFd, 0);

    for(int i = 0 ; i < 4; ++i) fd[i] = ASharedMemory_create(names[i], size);

    buffer[0] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd[0], 0);
    memcpy(buffer[0], names[0], strlen(names[0]));

    memset(cBuf, 0, sizeof(int));
}

extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetFd(
        JNIEnv *env,
        jobject /* this */, jint idx) {
    return fd[idx];
}

extern "C" JNIEXPORT jbyteArray JNICALL
Java_org_techtwon_multipro_MainActivity_GetBuffer(
        JNIEnv *env,
        jobject /* this */, jint idx) {

    jbyteArray tmp = (*env).NewByteArray(strlen(buffer[idx]));

    env->SetByteArrayRegion(tmp, 0, strlen(buffer[idx]), (jbyte*) buffer[idx]);

    return tmp;
}

extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetcVal(
        JNIEnv *env,
        jobject /* this */, jint idx) {

    int cVal;
    memcpy(&cVal, cBuf, sizeof(int));

    return cVal;
}

标签: androidc++android-ndkipcshared-memory

解决方案


官方文档中的代码片段非常清楚:

int fd = ASharedMemory_create("memory", 128);

// By default it has PROT_READ | PROT_WRITE | PROT_EXEC.
char *buffer = (char *) mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

strcpy(buffer, "This is an example."); // trivially initialize content

// limit access to read only
ASharedMemory_setProt(fd, PROT_READ);

// share fd with another process here and the other process can only map with PROT_READ.

名字没有任何意义,只对调试有帮助。大小应该匹配。

这是您应该用于 API 29 及更高版本的 API,旧方法(如下)不再适用

如果您还需要涵盖 API 26 以下的设备,则需要一个将 IOCTL 直接转换为文件描述符的回退。/dev/ashmem从 Android 早期就可以使用:

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/ashmem.h>

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

ioctl(fd, ASHMEM_SET_NAME, "memory");
ioctl(fd, ASHMEM_SET_SIZE, 128);

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

甚至还有一个包装这个共享内存以便在 Java 中使用的好例子:ANDROID – 使用 ASHMEM 创建共享内存


推荐阅读