写给ashmem /为什么android免费ashmem?

Eun*_*Eun 6 android shared-memory android-ndk ashmem

我想在两个(ndk-)进程之间共享数据.为此,我使用ashmem使用此来源.
一个过程是连续read(read_mem),一个过程是写一次(write_mem).

问题是读取过程没有获得编写器的值.

通过观察阅读器的地图,我发现android会立即删除共享内存文件ashmem_create_region.


read_mem.c

// read_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"

#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
    int shID = ashmem_create_region(SHM_NAME, 2);
    if (shID < 0)
    {
        perror("ashmem_create_region failed\n");
        return 1;
    }
    // right here /dev/ashmem/test_mem is deleted
    printf("ashmem_create_region: %d\n", shID);
    char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
    if (sh_buffer == (char*)-1)
    {
        perror("mmap failed");
        return 1;
    }
    printf("PID=%d", getpid());
    do
    {
        printf("VALUE = 0x%x\n", sh_buffer[0]);
    }
    while (getchar());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

write_mem.c

// write_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"

#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
    int shID = ashmem_create_region(SHM_NAME, 2);
    if (shID < 0)
    {
        perror("ashmem_create_region failed\n");
        return 1;
    }
    printf("ashmem_create_region: %d\n", shID);
    char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
    if (sh_buffer == (char*)-1)
    {
        perror("mmap failed");
        return 1;
    }
    printf("PID=%d\n", getpid());
    int ch = getchar();
    sh_buffer[0] = ch;
    printf("Written 0x%x\n", ch);
    munmap(sh_buffer, 2);
    close(shID);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:
阅读

130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0
Run Code Online (Sandbox Code Playgroud)

写作

shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41
Run Code Online (Sandbox Code Playgroud)

再次阅读VALUE = 0x0(按回车)

看着读者的地图:

shell@mako:/ $ cat /proc/29655/maps | grep test_mem
b6ef5000-b6ef6000 rw-s 00000000 00:04 116213     /dev/ashmem/test_mem (deleted)
Run Code Online (Sandbox Code Playgroud)

正如你所看到的那样test_mem被删除了WHILE read_mem还活着.


其他信息

两个文件都使用android ndk-build命令编译为可执行文件
设备:LG Nexus 4(AOSP Lollypop)
我检查/dev/ashmem它存在.
ashmem取自这里

Dig*_*git 24

Ashmem不像Linux上的常规共享内存那样工作,并且有充分的理由.

首先,让我们尝试解释"(已删除)"部分,这是关于如何在内核中实现ashmem的实现细节.它的真正含义是在/ dev/ashmem /目录中创建了一个文件 条目,然后删除了,但相应的i-node仍然存在,因为它至少有一个打开的文件描述符.

您实际上可以创建几个具有相同名称的ashmem区域,它们都将显示为"/ dev/ashmem/<name>(已删除)",但它们中的每一个都对应于不同的i节点,因此不同 记忆 区域.如果您查看/ dev/ashmem /,您会看到该目录仍为空.

这就是为什么ashmem区域的名称实际上只用于调试.没有办法按名称"打开"现有区域.

当关闭最后一个文件描述符时,会自动回收ashmem i节点和相应的内存.这很有用,因为这意味着如果您的进程因崩溃而死亡,内核将自动回收内存.常规SysV共享内存不是这种情况(崩溃过程只会泄漏内存!在像Android这样的嵌入式系统上是不可接受的).

您的测试程序会创建两个具有相同名称的不同的ashmem区域,这就是为什么它们不能按您认为的那样工作.你需要的是:

1)在其中一个过程中创建一个ashmem区域.

2)将新文件描述符传递给从第一个进程到第二个进程的区域.

一种方法是分叉第一个进程来创建第二个进程(这将自动复制文件描述符),但这在Android下通常不是一个好主意.

更好的选择是使用sendmsg()和recvmsg()通过两个进程之间的Unix域套接字发送文件描述符.这通常很棘手,但作为一个例子,看看下面的源文件中的SendFd()和ReceiveFd()函数是为NDK编写的:

https://android.googlesource.com/platform/ndk/+/android-5.0.0_r7/sources/android/crazy_linker/tests/test_util.h

瞧,希望这会有所帮助

  • 文件描述符编号是特定于进程的.默认情况下,命令行可执行文件将打开3个文件描述符(0 = stdin/1 = stdout/2 = stderr),因此第一个open()调用可能返回3. (3认同)
  • 赞成,因为它很好地描述了内部结构,尽管这里有一个错误。没有 `/dev/ashmem/` 文件夹,有一个 `/dev/ashmem` 设备文件,并且 `/proc/&lt;pid&gt;/ 中有 `/dev/ashmem/&lt;name&gt; (deleted)` 条目地图`只是名称。 (2认同)