模块化 GKI 的 ION 堆

许多 Android 原始设备制造商 (OEM) 会出于各种原因(例如添加供应商堆和自定义缓存管理)修改 ION 内核驱动程序(如需详细了解这些修改,请参阅集成 ION 内存分配器)。为了让 OEM 能够在使用通用内核映像 (GKI) 时保留这些修改,Android 通用内核 v5.4 引入了一个框架,该框架能够模块化供应商专用 ION 堆,同时保留内置核心 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_partialdma_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_STARTION_HEAP_CUSTOM_END)中的堆 ID 来执行分配。