简体   繁体   English

NDK中的共享内存区域

[英]Shared memory region in NDK

I want to have a shared memory block (an ashmem region) that's mapped and accessed from native code. 我想要一个共享内存块(一个ashmem区域),该内存块是从本机代码映射和访问的。 I also want this block to be used by several applications. 我也希望该块可以被多个应用程序使用。 I also want it to work on SDK level 7 (Android 2.1) 我也希望它能在SDK级别7(Android 2.1)上运行

There are two routes. 有两条路线。 I can create an ashmem region in native code; 我可以用本机代码创建一个ashmem区域。 but then the question is - how do I pass an integer file descriptor to another process? 但是然后的问题是-如何将整数文件描述符传递给另一个进程? You can marshal FileDescriptor objects via a Parcel , but there's no way to construct one around a raw FD. 您可以通过Parcel FileDescriptor对象,但是无法围绕原始FD构造对象。 There's also ParcelFileDescriptor which supports constructing around and retrieving integer FD's, but the relevant methods are only supported in SDK level 12 or even higher. 还有ParcelFileDescriptor ,它支持围绕和检索整数FD的构造,但是相关方法仅在SDK级别12或更高版本中受支持。

Alternatively, I can create a MemoryFile . 另外,我可以创建一个MemoryFile There's a fugly way to pass it around in Parcels. 有一种在包裹中传递它的丑陋方法 But how do I retrieve a file descriptor from it so that native code has something to mmap() ? 但是,如何从文件描述符中检索文件描述符,以便本机代码具有mmap()

On all versions of Android since 1.5 to 4.1, FileDescriptor has an int data member called descriptor . 在从1.5到4.1的所有版本的Android上, FileDescriptor都有一个称为descriptorint数据成员。 It's package-private on earlier versions of Android, private on recent ones. 它在较早版本的Android上是私有包,在最近的Android上是私有包。 With a bit of deliberate access control subversion, you can access it - either via reflection, or via JNI. 通过一些故意的访问控制颠覆,您可以通过反射或JNI进行访问。 Each can bypass access control - in case of reflection, via Field.setAccessible() , in case of JNI - by default. 默认情况下,每个用户都可以绕过访问控制(如果发生反射,则通过Field.setAccessible() ;如果是JNI,则可以Field.setAccessible()

With that in mind, you can construct a FileDescriptor around a native FD just fine. 考虑到这一点,您可以很好地围绕本机FD构造FileDescriptor Construct a blank one, then set descriptor . 构造一个空白的,然后设置descriptor That's what bits and pieces of Android code do when constructing those. 这就是构造这些代码时会执行的零碎工作。

Whether this dirty hack will break eventually, who knows. 谁知道,这个肮脏的hack最终是否会破裂。 Fortunately, it's not a core piece of functionality in my case - there's some graceful degradation. 幸运的是,在我看来,这并不是核心功能,而是有些优雅的降级。

One may conditionally employ supported ParcelFileDescriptor methods, if the platform allows, using the field access hack as a fallback. 如果平台允许,则可以有条件地使用受支持的ParcelFileDescriptor方法,使用字段访问技巧作为后备方法。 This way, it'll be relatively future proof. 这样,它将是相对未来的证明。

There is a method in helper library libnativehelper.so for this jniCreateFileDescriptor() https://android.googlesource.com/platform/libnativehelper/+/jb-dev/include/nativehelper/JNIHelp.h . 辅助程序库libnativehelper.so中有一个用于此jniCreateFileDescriptor() https://android.googlesource.com/platform/libnativehelper/+/jb-dev/include/nativehelper/JNIHelp.h的方法 It basically does the same thing as stated in previous answer but you might find this approach a bit cleaner. 它基本上执行与先前答案中所述相同的操作,但是您可能会发现此方法更简洁。

This is how it worked for me while working with a similar problem: 这是我在处理类似问题时的工作方式:

Instead of using shmfd = open(SHM_PATH, O_RDWR) for creating and getting file descriptor I replaced it with 与其使用shmfd = open(SHM_PATH,O_RDWR)创建和获取文件描述符,我将其替换为

int fd = ashmem_create_region("SharedRegionName", size); 

and used the file descriptor to get base address: 并使用文件描述符获取基地址:

int base_address = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

// write data You can pass the base_address to your java code from the native code using a native function that returns the descriptor. //写入数据您可以使用返回描述符的本机函数将base_address从本机代码传递到Java代码。

Then I create a Service with aidl interface and used this interface to bind this service from another process. 然后,我创建一个带有aidl接口的服务,并使用该接口从另一个进程绑定该服务。 From the Service I have used a ParcelFileDescriptor object to return to another process. 从服务中,我已使用ParcelFileDescriptor对象返回到另一个进程。 You can create ParcelFileDescriptor by: 您可以通过以下方式创建ParcelFileDescriptor:

ParcelFileDescriptor desc = ParcelFileDescriptor.fromFd(fd);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM