android - 使用 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
. Init
叫onCreate.
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;
}
解决方案
官方文档中的代码片段非常清楚:
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 创建共享内存。
推荐阅读
- php - 如何显示按日期排序的文件夹和子文件夹中的所有图像和视频(顶部较新)?
- javascript - ReactJS - 读取 json 数据
- ruby-on-rails - Rails gemacts_as_list:当列表项被销毁时如何处理列表项的重新排序?
- python - 熊猫根据 columnA.isin.list(columnB) 返回子集
- shell - 如何使用变量作为 xmlstarlet val 的输入?
- c - 在嵌入式设备上膨胀(解压缩)数据流
- javascript - 在 HTML 或 JavaScript 中是否有办法使用类似anything.com 的内容进行重定向,然后是用户的输入?
- reactjs - 来自 IPFS 的反应显示 pdf
- c# - 将文件保存到特定的本地化并将它们显示为 ListBox [WPF] 中的项目
- swift - Swift 只能从 firebase 中看到一个值(检索数据)