我希望有一个共享内存块(ashmem
区域),它可以从本机代码映射和访问。我还希望这个块可以被多个应用程序使用。我还希望它能够在SDK级别7(Android 2.1)上运行
有两条路线。我可以用原生代码创建一个ashmem区域;但问题是 - 如何将整数文件描述符传递给另一个进程?您可以通过FileDescriptor
封送Parcel
个对象,但无法在原始FD周围构建一个对象。还有ParcelFileDescriptor
支持构造并检索整数FD,但相关方法仅在SDK级别12或更高版本中受支持。
或者,我可以创建一个MemoryFile
。有一个fugly way可以在Parcels中传递它。但是,如何从中检索文件描述符,以便本机代码具有mmap()
的某些内容?
答案 0 :(得分:3)
在从1.5到4.1的所有Android版本上,FileDescriptor
都有一个名为int
的{{1}}数据成员。它在早期版本的Android上是私有的,在最近的版本上是私有的。通过一些有意识的访问控制颠覆,您可以通过反射或通过JNI访问它。每个都可以绕过访问控制 - 在反射的情况下,默认情况下通过descriptor
(如果是JNI)。
考虑到这一点,您可以围绕原生FD构建Field.setAccessible()
就好了。构造一个空白的,然后设置FileDescriptor
。这就是构建这些代码时Android代码的一些部分。
这个肮脏的黑客最终是否会破裂,谁知道呢。幸运的是,在我的情况下,它不是一个核心功能 - 有一些优雅的降级。
如果平台允许,可以有条件地使用受支持的descriptor
方法,使用字段访问黑客作为后备。这样,它将是相对未来的证明。
答案 1 :(得分:3)
对于此jniCreateFileDescriptor()https://android.googlesource.com/platform/libnativehelper/+/jb-dev/include/nativehelper/JNIHelp.h,helper库libnativehelper.so中有一个方法。它基本上与前面的答案中说明的相同,但您可能会发现这种方法更清晰。
答案 2 :(得分:0)
这是在处理类似问题时对我有用的方法:
不是使用shmfd = open(SHM_PATH,O_RDWR)来创建和获取文件描述符,而是将其替换为
int fd = ashmem_create_region("SharedRegionName", size);
并使用文件描述符获取基址:
int base_address = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
//写数据 您可以使用返回描述符的本机函数将base_address从本机代码传递给您的java代码。
然后我使用aidl接口创建一个服务,并使用此接口从另一个进程绑定此服务。从服务我使用ParcelFileDescriptor对象返回到另一个进程。您可以通过以下方式创建ParcelFileDescriptor:
ParcelFileDescriptor desc = ParcelFileDescriptor.fromFd(fd);