ION ABI 变更

搭载内核 4.14 及更高版本的设备受到一项对 ION 内核模块的重大重构的影响,许多供应商图形内存分配器 (gralloc) 硬件抽象层 (HAL) 实现会通过调用该模块来分配共享内存缓冲区。本文提供了有关如何将旧版供应商代码迁移到新版 ION 的指导,并讨论了未来可能出现的应用二进制接口 (ABI) 中断问题。

ION 简介

ION 是上游内核正在开发中的状态树的一部分。在生产前调试阶段,ION 的用户空间到内核 ABI 可能会在主要内核版本之间产生中断。尽管 ION ABI 中断不会直接影响普通应用或已发布的设备,但如果供应商迁移到新的主要内核版本,可能会遇到影响对 ION 的供应商代码调用的变更。此外,随着 Android 系统团队与上游合作将 ION 迁出状态树,未来也可能会出现 ABI 中断问题。

android-4.14 中的变化

内核 4.12 大幅度重构了 ION 内核代码,清理并移除了 ION 中与其他内核框架重叠的部分。因此,许多旧版 ION ioctl 不再有存在的意义,也已经被移除了。

移除了 ION 客户端和句柄

在内核 4.12 之前,打开 /dev/ion 会分配一个 ION 客户端。ION_IOC_ALLOC ioctl 分配了一个新的缓冲区,并将其作为 ION 句柄(仅对分配它的 ION 客户端有意义的不透明整数)返回至用户空间。如需将缓冲区映射到用户空间或与其他进程共享缓冲区,可使用 ION_IOC_SHARE ioctl 将 ION 句柄重新导出为 dma-buf fd。

在内核 4.12 中,ION_IOC_ALLOC ioctl 可直接输出 dma-buf fd。中间 ION 句柄状态以及所有使用或生成 ION 句柄的 ioctl 均已移除。由于 dma-buf fd 并未与特定的 ION 客户端相关联,因此不再需要 ION_IOC_SHARE ioctl,并且所有 ION 客户端基础架构均已移除。

添加了缓存一致性 ioctl

在内核 4.12 之前,ION 提供了一个 ION_IOC_SYNC ioctl 来使文件描述符与内存实现同步。此 ioctl 的相关记录不完整,并且不够灵活。因此,许多供应商实现了自定义 ioctls 来执行缓存维护。

内核 4.12 将 ION_IOC_SYNC 替换为 linux/dma-buf.h 中定义的 DMA_BUF_IOCTL_SYNC ioctl。在每次 CPU 访问开始和结束时调用 DMA_BUF_IOCTL_SYNC,并通过标志来指明这些访问为读取和/或写入。尽管与 ION_IOC_SYNC 相比,DMA_BUF_IOCTL_SYNC 更为冗长,但它可以使用户空间更好地控制底层缓存维护操作。

DMA_BUF_IOCTL_SYNC 是内核的稳定 ABI 的一部分,适用于所有 dma-buf fd,无论它们是否由 ION 分配。

将供应商代码迁移至 android-4.12+

对于用户空间客户端,Android 系统团队强烈建议使用 libion,而不是对 ioctl() 调用进行开放编码。从 Android 9 开始,libion 会在运行时自动检测 ION ABI,并尝试掩盖内核之间的任何差异。但是,在内核 4.12 之后,生成或使用 ion_user_handle_t 句柄的任何 libion 函数都无法再继续使用。您可以使用 dma-buf fd 上的以下等效操作(适用于到目前为止的所有内核版本)替换这些函数。

旧版 ion_user_handle_t 调用 等效 dma-buf fd 调用
ion_alloc(ion_fd, …, &buf_handle) ion_alloc_fd(ion_fd, ..., &buf_fd)
ion_share(ion_fd, buf_handle, &buf_fd) 不适用(dma-buf fd 不需要此调用)
ion_map(ion_fd, buf_handle, ...) mmap(buf_fd, ...)
ion_free(ion_fd, buf_handle) close(buf_fd)
ion_import(ion_fd, buf_fd, &buf_handle) 不适用(dma-buf fd 不需要此调用)
ion_sync_fd(ion_fd, buf_fd)
If (ion_is_legacy(ion_fd))
    ion_sync_fd(ion_fd, buf_fd);
else
    ioctl(buf_fd, DMA_BUF_IOCTL_SYNC, ...);

对于内核中客户端,由于 ION 不再导出任何面向内核的 API,因此,以前将内核中 ION 内核 API 与 ion_import_dma_buf_fd() 结合使用的驱动程序必须转换为将内核中 dma-buf APIdma_buf_get() 结合使用。

未来的 ION ABI 中断问题

在将 ION 移出状态树之前,未来的内核版本可能需要再次中断 ION ABI。Android 系统团队并不希望这些变更影响到搭载下一个 Android 版本的设备,但此类变更可能会影响到搭载后续 Android 版本的设备。

例如,上游社区已提议将单个 /dev/ion 节点拆分为多个按堆划分的节点(例如 /dev/ion/heap0),从而使设备能够针对各个堆应用不同的 SELinux 政策。如果在未来的内核版本中实现此变更,可能会中断 ION ABI。