许多 Android 原始设备制造商 (OEM) 会出于各种原因(例如添加供应商堆和自定义缓存管理)修改 ION 内核驱动程序(如需详细了解这些修改,请参阅集成 ION 内存分配器)。为了让 OEM 能够在使用通用内核映像 (GKI) 时保留这些修改,Android 通用内核 v5.4 引入了一个框架,该框架能够模块化供应商专用 ION 堆,同时保留内置核心 ION 驱动程序。下图显示了该内核映像布局。
图 1. 模块化 ION 内核驱动程序
模块化 ION 堆具有以下优势。
- ION 核心驱动程序可作为 GKI 映像的一部分,让所有不与设备关联的性能优化和问题修复能够覆盖所有设备。
- 通用内核中的 ION 核心驱动程序可以处理堆注册,并对用户空间和内核客户端的接口进行管理。只有为了实现自定义堆操作时,才需要供应商堆模块。
- ION 核心驱动程序(作为 GKI 的一部分)可包含钩子,以便更轻松地跟踪内存用量,而在每个 OEM 各有自己的 ION 驱动程序版本的情况下,却不可能进行这种跟踪。
- 模块化供应商 ION 堆应该能使今后转换为
dmabuf
堆的任何转换都变得更加容易。
实现
ION 堆模块可以注册自己的 dmabuf
操作,以替换核心 ION 驱动程序注册的相应操作。如果堆实现缺少必要的替换,核心 ION 驱动程序不支持的 dmabuf
操作(如 get_flags()
)会返回 -EOPNOTSUPP
。
为了提升性能,dmabuf
驱动程序可以执行部分缓存维护(请参阅更改列表)。内核客户端可以使用 dma_buf_begin_cpu_access_partial
和 dma_buf_end_cpu_access_partial
函数执行部分缓存维护。
Android 通用内核包含系统和连续内存分配器 (CMA) 堆的模块化实现,可以用作堆模块化的参考。
对 ION UAPI 头文件的更改
ION 用户空间 API (UAPI) 头文件包含一个 ion_heap_id
枚举,用于定义可供供应商堆使用的堆 ID 范围。
/**
* ion_heap_id - list of heap IDs that Android can use
*
* @ION_HEAP_SYSTEM ID for the ION_HEAP_TYPE_SYSTEM
* @ION_HEAP_DMA_START Start of reserved ID range for heaps of type ION_HEAP_TYPE_DMA
* @ION_HEAP_DMA_END End of reserved ID range for heaps of type ION_HEAP_TYPE_DMA
* @ION_HEAP_CUSTOM_START Start of reserved ID range for heaps of custom type
* @ION_HEAP_CUSTOM_END End of reserved ID range for heaps of custom type
*/
enum ion_heap_id {
ION_HEAP_SYSTEM = (1 << ION_HEAP_TYPE_SYSTEM),
ION_HEAP_DMA_START = (ION_HEAP_SYSTEM << 1),
ION_HEAP_DMA_END = (ION_HEAP_DMA_START << 7),
ION_HEAP_CUSTOM_START = (ION_HEAP_DMA_END << 1),
ION_HEAP_CUSTOM_END = (ION_HEAP_CUSTOM_START << 22),
};
此外,新的 IOCTL
(ION_IOC_ABI_VERSION
) 还可以帮助用户空间客户端确定使用的是否为模块化堆。
替换通用系统堆
内置 ION 系统堆是 GKI 映像的一部分,用于确保需要访问通用/设备无关堆的任何功能都可以依赖于它的存在。因此,您无法替换 ION_HEAP_SYSTEM
的堆 ID。如需创建自定义系统堆,请使用自定义范围(ION_HEAP_CUSTOM_START
到 ION_HEAP_CUSTOM_END
)中的堆 ID 来执行分配。