The Android ION memory allocator
ION heaps
ION设计的目标
为了避免内存碎片化,或者为一些有着特殊内存需求的硬件,比如GPUs、display controller以及camera等,在系统启动的时候,会为他们预留一些memory pools,这些memory pools就由ION来管理。通过ION就可以在硬件以及user space之间实现zero-copy的内存share。
ION的实现
ION通过ION heaps来展示presents它对应的memory pools。不同的Android硬件可能会要求不同的ION heaps实现,默认的ION驱动会提供如下三种不同的ION heaps实现:
- ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc_user()
- ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kzalloc
. ION_HEAP_TYPE_CARVEOUT: carveout memory is physically contiguous and set aside at boot.
开发者可以自己实现更多的ION heaps。比如NVIDIA就提交了一种ION_HEAP_TYPE_IOMMU的heap,这种heap带有IOMMU功能。
不管哪一种ION heaps实现,他们都必须实现如下接口:
struct ion_heap_ops {
int (*allocate) (struct ion_heap *heap,
struct ion_buffer *buffer, unsigned long len,
unsigned long align, unsigned long flags);
void (*free) (struct ion_buffer *buffer);
int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len);
struct scatterlist *(*map_dma) (struct ion_heap *heap,
struct ion_buffer *buffer);
void (*unmap_dma) (struct ion_heap *heap,
struct ion_buffer *buffer);
void * (*map_kernel) (struct ion_heap *heap,
struct ion_buffer *buffer);
void (*unmap_kernel) (struct ion_heap *heap,
struct ion_buffer *buffer);
int (*map_user) (struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma);
};
简单来说,接口的各个函数功能如下:
allocate()
和free()
分别用来从heap中分配或者释放一个ion_buffer
对象- 对于物理连续的内存,
phys()
用来得到ion_buffer
对象的物理内存地址及其大小。如果heap没有提供物理连续的内存,那么它也可以不用提供这个接口。其中,ion_phys_addr_t
将来会被定义在/include/linux/types.h中的phys_addr_t
替代。 map_dma()
和unmap_dma()
分别来用使ion_buffer
对象为DMA(Direct Memory Access,直接内存存取。顾名思义,不占用cpu资源,从一个硬件存储区域把一部分连续的数据复制到另一个硬件存储区域)做好准备或者取消做好准备map_kernel()
和unmap_kernel()
分别用来把physical memory映射(map)到内核虚拟地址空间(kernel virtual address space)或者取消映射map_user()
用来把physical memory映射(map)到用户内存空间(user space)。为什么没有对应的unmap_user()
呢?因为,这个映射用一个file descriptor来表示,当这个file descriptor关闭的时候,这个映射关系就自动取消了。
在user space使用ION
使用场景
典型的,在用户空间使用的设备访问库(user space device access libraries)一般使用ION来分配大块连续的media buffers。比如,still camera library分配一个capture buffer来供camera device使用。当这个buffer填满video data的时候,这个library就能把这块buffer传递给kernel,然后让JPEG硬编码模块来处理。
具体使用细节
在user space 的C/C++程序能够能够分配ION内存之前,它必须获得访问/dev/ion
的权限。通过调用open("/dev/ion", O_RDONLY)
就可获得一个以handle形式返回的file descriptor,这个file descriptor用来代表一个ION client。注意,虽然传给open
一个O_RDONLY
参数,但是你仍然可对这块memory进行写操作。在一个user process中最多有一个client。当有了一个client之后,就可以开始分配ION内存。为了分配内存,client必须填满下面的ion_allocation_data
结构,handle
除外,因为它是output参数。其他三个参数分别指明内存的大小、对齐方式以及flags。flags是一个bit mask,用来说明可以从哪些heaps中分配想要的内存。其决定顺序由系统启动时,通过ion_device_add_heap()
添加的heap顺来决定。比如,ION_HEAP_TYPE_CARVEOUT是在ION_HEAP_TYPE_CONTIG之前被add的,那么如果flags = ION_HEAP_TYPE_CONTIG | ION_HEAP_TYPE_CARVEOUT
,那么就是先尝试分配ION_HEAP_TYPE_CARVEOUT类型的heap,如果不行,再尝试分配ION_HEAP_TYPE_CONTIG类型的heap。()
struct ion_allocation_data {
size_t len;
size_t align;
unsigned int flags;
struct ion_handle *handle;
}
user space通过ioctl()
系统接口来与ION交互。在client填充ion_allocatoin_data
结构之后,就可以通过调用int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)
来allocate a buffer。这个调用介绍之后,分配的buffer会通过ion_allocatoin_data
的handle
来返回,但是CPU不可以访问这个buffer。这个handle