写信给 ashmem/为什么 android 会释放 ashmem? [英] Writing to ashmem / why does android free ashmem?

查看:13
本文介绍了写信给 ashmem/为什么 android 会释放 ashmem?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在两个 (ndk-) 进程之间共享数据.为此,我通过 source 使用 ashmem.
一个进程连续读取(read_mem),一个进程写入一次(write_mem).

I want to share data between two (ndk-)processes. For this I use ashmem using this source.
One process is continuously reading (read_mem) and one process is writing one time (write_mem).

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

The problem is that the read process is not getting the values of the writer.

通过查看阅读器的地图我发现android在ashmem_create_region之后立即删除了共享内存文件.

By watching the maps of the reader I found that android deletes the shared memory file right after ashmem_create_region.

// 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
");
        return 1;
    }
    // right here /dev/ashmem/test_mem is deleted
    printf("ashmem_create_region: %d
", 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
", sh_buffer[0]);
    }
    while (getchar());
    return 0;
}

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
");
        return 1;
    }
    printf("ashmem_create_region: %d
", 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());
    int ch = getchar();
    sh_buffer[0] = ch;
    printf("Written 0x%x
", ch);
    munmap(sh_buffer, 2);
    close(shID);
    return 0;
}

<小时>

这是输出:
阅读


This is the output:
Reading

130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0

写作

shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41

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

看读者的地图:

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

如您所见,test_mem 已删除WHILE read_mem 仍然存在.

as you can see test_mem is deleted WHILE read_mem is still alive.

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

Both files are compiled as executable using the android ndk-buildcommand
Device: LG Nexus 4 (AOSP Lollypop)
I checked /dev/ashmem it exists.
ashmem taken from here

推荐答案

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

Ashmem doesn't work like regular shared memory on Linux, and there is a good reason for it.

首先,我们来解释一下(deleted)"部分,这是内核中如何实现ashmem的一个实现细节.真正的意思是在/dev/ashmem/目录下创建了一个fileentry,然后removed,但是对应的i-node 仍然存在,因为它至少有一个打开的文件描述符.

First, let's try to explain the "(deleted)" part, this is an implementation detail of how ashmem is implemented in the kernel. What it really means is that a file entry was created in the /dev/ashmem/ directory, then later removed, but that the corresponding i-node still exists because there is at least one open file-descriptor for it.

您实际上可以创建多个具有相同名称的 ashmem 区域,它们都将显示为/dev/ashmem/(已删除)",但每个区域都对应一个不同的 i-node,因此是一个不同的 记忆 区域.如果您在/dev/ashmem/下查看,您会看到该目录仍然是空的.

You could actually create several ashmem regions with the same name, and they would all appear as "/dev/ashmem/<name> (deleted)", but each one of them would correspond to a different i-node, and thus a different memory region. And if you look under /dev/ashmem/ you would see that the directory is still empty.

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

That's why the name of an ashmem region is really only used for debugging. There is no way to 'open' an existing region by name.

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

An ashmem i-node, and corresponding memory, is automatically reclaimed when the last file descriptor to it is closed. This is useful because it means that if your process dies due to a crash, the memory will be reclaimed by the kernel automatically. This is not the case with regular SysV shared memory (a crashing process just leaks the memory! Something unacceptable on an embedded system like Android).

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

Your test programs create two distinct ashmem regions with the same name, that's why they dont work as you think they should. What you need instead is:

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

1) Create a single ashmem region in one of the process.

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

2) Pass a new file descriptor to the region from the first process to the second one.

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

One way to do that is to fork the first process to create the second (this will automatically duplicate the file descriptors), but this is generally not a good idea under Android.

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

A better alternative is to use sendmsg() and recvmsg() to send the file descriptor through a Unix-domain socket between the two processes. This is generally tricky, but as an example, have a look at the SendFd() and ReceiveFd() functions in the following source file was written for the NDK:

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

瞧,希望这会有所帮助

这篇关于写信给 ashmem/为什么 android 会释放 ashmem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆