Ion ABI Changes

Devices shipping kernel 4.14 and higher are affected by a major refactoring of the Ion kernel module, which many vendor graphics memory allocator (gralloc) hardware abstraction layer (HAL) implementations call to allocate shared memory buffers. This article provides guidance on migrating legacy vendor code over to the new version of Ion and discusses possible future application binary interface (ABI) breaks.

About Ion

Ion is part of the upstream kernel's work-in-progress staging tree. While in staging, Ion's userspace-to-kernel ABI may break between major kernel versions. While Ion ABI breaks don't directly affect either ordinary applications or already-launched devices, vendors migrating to new major kernel versions may encounter changes that affect vendor code calling into Ion. Additionally, future ABI breaks may occur as the Android systems team works with upstream to move Ion out of the staging tree.

Changes in android-4.14

Kernel 4.12 heavily refactored the Ion kernel code, cleaning up and removing parts of Ion that overlapped with other kernel frameworks. As a result, many legacy Ion ioctls are no longer relevant and have been removed.

Removal of Ion clients and handles

Before kernel 4.12, opening /dev/ion allocated an Ion client. The ION_IOC_ALLOC ioctl allocated a new buffer and returned it to userspace as an Ion handle (an opaque integer meaningful only to the Ion client that allocated it). To map buffers into userspace or share them with other processes, Ion handles were re-exported as dma-buf fds using the ION_IOC_SHARE ioctl.

In kernel 4.12, the ION_IOC_ALLOC ioctl directly outputs dma-buf fds. The intermediate Ion handle state has been removed, along with all ioctls that consume or produce Ion handles. Because dma-buf fds aren't tied to specific Ion clients, the ION_IOC_SHARE ioctl is no longer needed, and all Ion client infrastructure has been removed.

Addition of cache-coherency ioctls

Before kernel 4.12, Ion provided an ION_IOC_SYNC ioctl to synchronize the file descriptor with memory. This ioctl was poorly documented and inflexible. As a result, many vendors implemented custom ioctls to perform cache maintenance.

Kernel 4.12 replaced ION_IOC_SYNC with the DMA_BUF_IOCTL_SYNC ioctl defined in linux/dma-buf.h. Call DMA_BUF_IOCTL_SYNC at the start and end of every CPU access, with flags specifying whether these accesses are reads and/or writes. Although DMA_BUF_IOCTL_SYNC is more verbose than ION_IOC_SYNC, it gives userspace more control over the underlying cache maintenance operations.

DMA_BUF_IOCTL_SYNC is part of the kernel's stable ABI and is usable with all dma-buf fds, whether or not they were allocated by Ion.

Migrating vendor code to android-4.12+

For userspace clients, the Android systems team strongly encourages using libion rather than open-coding ioctl() calls. As of Android 9, libion automatically detects the Ion ABI at runtime and attempts to mask any differences between kernels. However, any libion functions that produced or consumed ion_user_handle_t handles no longer work after kernel 4.12. You can replace these functions with the following equivalent operations on dma-buf fds, which work on all versions of the kernel to date.

Legacy ion_user_handle_t call Equivalent dma-buf fd call
ion_alloc(ion_fd, …, &buf_handle) ion_alloc_fd(ion_fd, ..., &buf_fd)
ion_share(ion_fd, buf_handle, &buf_fd) N/A (this call isn't needed with dma-buf fds)
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) N/A (this call isn't needed with dma-buf fds)
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, ...);

For in-kernel clients, because Ion no longer exports any kernel-facing APIs, drivers that previously used the in-kernel Ion kernel API with ion_import_dma_buf_fd() must be converted to use the in-kernel dma-buf API with dma_buf_get().

Future Ion ABI breaks

Before Ion can be moved out of the staging tree, future kernel releases may need to break the Ion ABI again. The Android systems team doesn't expect these changes to affect devices launching with the next Android version, but such changes may affect devices launching with subsequent Android versions.

For example, the upstream community has proposed splitting the single /dev/ion node into multiple, per-heap nodes (e.g., /dev/ion/heap0) to enable devices to apply different SELinux policies to each heap. If this change is implemented in a future kernel release, it would break Ion ABI.