「Anonymous Shared Memory 匿名共享内存」是 Android 特有的内存共享机制,它可以将指定的物理内存分别映射到各个进程自己的虚拟地址空间中,从而便捷的实现进程间内存共享,Ashmem 的实现依赖 Ashmem 设备节点。
怎么理解设备节点呢?
Linux 抽象了对硬件的处理,所有的硬件设备都可以当作普通文件一样来看待,设备节点文件是设备驱动的逻辑文件,其中对设备的描述包括文件操作函数集合,应用程序可以通过这些函数来访问硬件设备。
除了磁盘等真正的硬件设备,还可以通过内存抽象,使用设备节点文件的方式来描述一个"设备"并使用它,Ashmem、Binder 驱动都是属于这种内存抽象的"设备"。
介绍 Ashmem 设备节点前,先了解下ueventd进程。ueventd 就是 Android 中负责创建和管理设备节点的进程,创建设备节点文件有两种方式:
静态节点文件:以预先定义的设备信息为基础,当 ueventd 进程启动后,统一创建设备节点文件
动态节点文件:即在系统运行中,当有设备插入 USB 端口时,ueventd 进程就会接收到这一事件,为插入的设备动态创建设备节点文件
Ashmem 设备节点就属于静态节点文件,创建过程如下:
Android 系统启动,解析 init.rc,启动 ueventd 进程
ueventd 进程会去解析 ueventd.rc,读取 ashmem 设备节点信息到系统中
其中 ueventd.rc 文件格式如下:
可以看到包括 binder、ashmem 在内的一系列设备节点信息都会在这里读取到系统中。
随后 ashmem 会调用 ashmem.c 文件的 ashmem_init 进行初始化:
通过 kmem_cache_create() 函数创建了两个 cache,后面申请内存时需要用到,kmem_cache_create() 并没有真正的分配内存,后续还要调用 kmem_cache_alloc() 。
由于 ashmem 属于misc 杂项设备,所以调用 misc_register(&ashmem_misc) 进行设备注册。ashmem_misc 就是 Ashmem 的设备描述,定义如下:
.fops 就是上面提到的"文件操作函数集合",即 Ashmem 设备的操作函数集,如下
其中 ashmem_open、ashmem_mmap 及 ashmem_ioctl 函数比较重要,依次来看:
「1.ashmem_open」
ashmem_open 主要做了两个工作,
调用 kmem_cache_zalloc 方法从 ashmem_area_cachep 分配了一块内存,这个方法和 cache 上面都提到过;
将 ashmem_area 记录在 file 中 。
「2.ashmem_mmap」
首先拿到在 ashmem_open 函数中创建的 ashmem_area,然后判断如果 asma->file 为空,说明这是第一个访问该共享内存的进程,调用 shmem_file_setup() 函数在 tmpfs 中创建一个临时文件,用于进程间的内存共享;如果 asma->file 不为空,直接调用 shmem_set_file 进行内存映射。
「3.ashmem_ioctl」
ashmem_ioctl 即根据 ioctl 命令做相应的操作,设置或获取 size、名称等。
最后
Android 上层提供了一些内存共享工具类,就是基于 Ashmem 来实现的,比如 MemoryFile、 SharedMemory。问题来了,你知道它们的实现原理吗?从上层 Java 类到 Linux 内核 Ashmem 驱动具体是如何调用的呢?
领取专属 10元无门槛券
私享最新 技术干货