编写ashmem/为什么Android免费提供ashmem? [英] Writing to ashmem / why does android free ashmem?

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

问题描述

我想在两个(ndk-)进程之间共享数据.为此,我通过使用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.

AND

通过观察读者的地图,我发现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\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;
}

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;
}


这是输出:
阅读


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已被删除期间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它是否存在.
摘录自此处

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.

首先,让我们尝试解释(已删除)"部分,这是有关如何在内核中实现ashmem的实现细节.真正的含义是在/dev/ashmem/目录中创建了一个文件 条目,然后稍后将其删除,但是相应的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/< name>(已删除)",但是每个区域都对应于一个不同的i节点,因此,不同 内存 区域.而且,如果您在/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索引节点和相应的内存.这很有用,因为这意味着如果您的进程由于崩溃而死,内核将自动回收内存.常规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)在其中一个过程中创建一个烟灰缸区域.

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

Voila,希望对您有所帮助

Voila, hope this helps

这篇关于编写ashmem/为什么Android免费提供ashmem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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