In Android 12, GKI 2.0 replaces the ION allocator with DMA-BUF heaps for the following reasons:
- Security: Because each DMA-BUF heap is a separate character device, access
to each heap can be controlled separately with sepolicy. This wasn't
possible with ION because allocation from any heap only required access to
- ABI stability: Unlike ION, the DMA-BUF heaps framework’s IOCTL interface is guaranteed to be ABI stable because it's maintained in the upstream Linux kernel.
- Standardization: The DMA-BUF heaps framework offers a well-defined UAPI. ION allowed custom flags and heap IDs that prevented developing a common testing framework because each device’s ION implementation could behave differently.
android12-5.10 branch of the Android Common Kernel disabled
CONFIG_ION on March 1, 2021.
The following is a brief comparison between ION and DMA-BUF heaps.
Similarities between the ION and DMA-BUF heaps framework
- The ION and DMA-BUF heaps frameworks are both heap-based DMA-BUF exporters.
- They both let each heap define its own allocator and DMA-BUF ops.
- Allocation performance is similar because both schemes need a single IOCTL for allocation.
Differences between the ION and DMA-BUF heaps framework
|ION heaps||DMA-BUF heaps|
|All ION allocations are done with
||Each DMA-BUF heap is a character device that's present at
|ION supports heap private flags.||DMA-BUF heaps don't support heap private flags. Each different kind of
allocation is instead done from a different heap. For example, the cached and
uncached system heap variants are separate heaps located at
|Heap ID/mask and flags need to be specified for allocation.||The heap name is used for allocation.|
The following sections list the components that deal with ION and describe how to switch them over to the DMA-BUF heaps framework.
Transitioning kernel drivers from ION to DMA-BUF heaps
Kernel drivers implementing ION heaps
Both ION and DMA-BUF heaps allow each heap to implement its own allocators and DMA-BUF ops. So you can switch from an ION heap implementation to a DMA-BUF heap implementation by using a different set of APIs to register the heap. This table shows the ION heap registration APIs and their equivalent DMA-BUF heap APIs.
|ION heaps||DMA-BUF heaps|
DMA-BUF heaps don't support heap private flags. So each variant of the heap
must be registered individually using the
API. To facilitate code sharing, it's recommended to register all variants of
the same heap within the same driver.
This dma-buf: system_heap example
shows the implementation of the cached and uncached variants of the system
Use this dma-buf: heaps: example template to create a DMA-BUF heap from scratch.
Kernel drivers directly allocating from ION heaps
The DMA-BUF heaps framework also offers an allocation interface for in-kernel clients. Instead of specifying the heap mask and flags to select the type of allocation, the interface offered by DMA-BUF heaps takes a heap name as input.
The following shows the in-kernel ION allocation API and its equivalent DMA-BUF
heap allocation APIs. Kernel drivers can use the
dma_heap_find() API to query
the existence of a heap. The API returns a pointer to an instance of
struct dma_heap, which can then be passed as an argument to the
|ION heaps||DMA-BUF heaps|
Kernel drivers that use DMA-BUFs
No changes are required for drivers that import only DMA-BUFs, because a buffer allocated from an ION heap behaves exactly the same as a buffer allocated from an equivalent DMA-BUF heap.
Transitioning the user-space clients of ION to DMA-BUF heaps
To make the transition easy for user-space clients of ION, an abstraction
libdmabufheap supports allocation in DMA-BUF heaps
and ION heaps. It first checks if a DMA-BUF heap of the specified name exists
and if not, falls back to an equivalent ION heap, if one exists.
Clients should initialize a
object during their initialization instead of opening
ion_open(). This is because file descriptors created by opening
/dev/dma_heap/<heap_name> are managed
internally by the
To switch from
libdmabufheap, modify the behavior of clients as
- Keep track of the heap name to use for allocation, instead of the head ID/mask and heap flag.
- Replace the
ion_alloc_fd()API, which takes a heap mask and flag argument, with the
BufferAllocator::Alloc()API, which takes a heap name instead.
This table illustrates these changes by showing how
do an uncached system heap allocation.
|Type of allocation||libion||libdmabufheap|
|Cached allocation from system heap||
|Uncached allocation from system heap||
uncached system heap variant
is awaiting approval upstream but is already part of the
To support upgrading devices, the
MapNameToIonHeap() API allows mapping a heap
name to ION heap parameters (heap name/mask and flags) to allow those interfaces
to also use name-based allocations. Here is a name-based allocation example.
Reference Gralloc implementation
The Hikey960 gralloc implementation uses
libdmabufheap, so you can use it as a
Required ueventd additions
For any new device-specific DMA-BUF heaps created, add a new entry to the
This Setup ueventd to support DMA-BUF heaps example
demonstrates how this done for the DMA-BUF system heap.
Required sepolicy additions
Add sepolicy permissions to enable a userspace client to access a new DMA-BUF heap. This add required permissions example shows the sepolicy permissions created for various clients to access the DMA-BUF system heap.
Accessing vendor heaps from framework code
To ensure Treble compliance, framework code can only allocate from pre-approved categories of vendor heaps.
Based on feedback received from partners, Google identified two categories of vendor heaps that must be accessed from framework code:
- Heaps that are based on system heap with device or SoC-specific performance optimizations.
- Heaps to allocate from protected memory.
Heaps based on system heap with device or SoC-specific performance optimizations
To support this use case, the heap implementation of the default DMA-BUF heap system can be overridden.
CONFIG_DMABUF_HEAPS_SYSTEMis turned off in
gki_defconfigto allow it to be a vendor module.
- VTS compliance tests ensure that the heap exists at
/dev/dma_heap/system. The tests also verify that the heap can be allocated from, and that the returned file descriptor (
fd) can be memory-mapped (mmapped) from user space.
The preceding points are also true for the uncached variant of the system heap, although its existence isn't mandatory for fully IO-coherent devices.
Heaps to allocate from protected memory
Secure heap implementations must be vendor-specific since the Android Common Kernel doesn't support a generic secure heap implementation.
- Register your vendor-specific implementations as
- These heap implementations are optional.
- If the heaps exist, VTS tests ensure that allocations can be made from them.
- Framework components are provided with access to these heaps so that they can enable heaps usage through the Codec2 HAL/non-binderized, same-process HALs. However, generic Android framework features can’t be dependent on them due to the variability in their implementation details. If a generic secure heap implementation gets added to the Android Common Kernel in the future, it must use a different ABI to avoid conflicts with upgrading devices.
Codec 2 allocator for DMA-BUF heaps
A codec2 allocator for the DMA-BUF heaps interface is available in AOSP.
The component store interface that allows heap parameters to be specified from the C2 HAL is available with the C2 DMA-BUF heap allocator.
Sample transition flow for an ION heap
To smooth the transition from ION to DMA-BUF heaps,
switching one heap at time. The following steps demonstrate a suggested workflow
for transitioning a nonlegacy ION heap named
my_heap that supports one
Step1: Create equivalents of the ION heap in the DMA-BUF framework. In this
example, because the ION heap
my_heap supports a flag
register two DMA-BUF heaps:
my_heapbehavior exactly matches the behavior of the ION heap with the flag
my_heap_specialbehavior exactly matches the behavior of the ION heap with the flag
Step 2: Create the ueventd changes for the new
my_heap_special DMA-BUF heaps. At this point, the heaps are visible as
the intended permissions.
Step 3: For clients that allocate from
my_heap, modify their makefiles
to link to
libdmabufheap. During client initialization, instantiate a
BufferAllocator object and use the
MapNameToIonHeap() API to map the
heap name/mask, flag> combination to equivalent DMA-BUF heap names.
allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )
Instead of using the
MapNameToIonHeap() API with the name and flag parameters,
you can create the mapping from
<ION heap mask, flag> to equivalent DMA-BUF heap names
by setting the ION heap name parameter to empty.
Step 4: Replace
ion_alloc_fd() invocations with
BufferAllocator::Alloc() using the appropriate heap name.
At this point, the client is functional but still allocating from the ION heap because it doesn't have the required sepolicy permissions to open the DMA-BUF heap.
Step 5: Create the sepolicy permissions required for the client to access the new DMA-BUF heaps. The client is now fully equipped to allocate from the new DMA-BUF heap.
Step 6: Verify that the allocations are happening from the new DMA-BUF heap by examining logcat.
Step 7: Disable the ION heap
my_heap in the kernel. If the client code
doesn't need to support upgrading devices (whose kernels might only support ION
heaps), you can also remove the