AOSP Framework & Internals
3 min read

DMA-BUF

Explore the modern Linux kernel standard that has completely replaced ION for hardware buffer sharing in Android.

While the ION Memory Allocator was incredibly successful at solving Android's hardware memory sharing problems, it had a major political flaw: it was a custom Google invention.

The mainline Linux kernel community (who maintain the core OS used by servers and desktops) did not like ION and refused to merge it into the official Linux kernel tree. This forced Google to maintain ION as an "out-of-tree" patch for nearly a decade.

To align with the upstream Linux community and achieve the Generic Kernel Image (GKI), Google officially deprecated ION and transitioned Android to the open-source standard: DMA-BUF.

What is DMA-BUF?

DMA-BUF (Direct Memory Access Buffer) is the official Linux kernel framework for sharing memory buffers between multiple hardware drivers and the user space.

Conceptually, DMA-BUF does exactly what ION did. It allows the GPU, the Camera, and the Display driver to all read and write to the exact same physical block of RAM using a shared File Descriptor (FD).

Exporters and Importers

The DMA-BUF framework relies on a strict Exporter/Importer model.

  1. The Exporter: A specific hardware driver (like the GPU driver) allocates a block of memory and "exports" it as a DMA-BUF File Descriptor.
  2. The Importer: The user space application takes that FD and passes it to another hardware driver (like the Display driver). The Display driver "imports" the buffer, verifying that it has the correct permissions and hardware constraints to read it.

DMA-BUF Heaps (The ION Replacement)

To fully replace ION's ability to allocate memory from specific zones (like contiguous memory or secure carveouts), the Linux community introduced DMA-BUF Heaps.

Starting with Android 12 and kernel version 5.10, the /dev/ion device was completely removed. Instead, the device exposes multiple character devices mapping to the different hardware pools:

  • /dev/dma_heap/system
  • /dev/dma_heap/system-secure
  • /dev/dma_heap/linux,cma
// Allocating memory using the modern DMA-BUF Heaps interface
int heap_fd = open("/dev/dma_heap/system", O_RDONLY);

struct dma_heap_allocation_data alloc_data = {
    .len = 10 * 1024 * 1024, // 10MB
    .fd_flags = O_RDWR | O_CLOEXEC,
};

// Returns a DMA-BUF File Descriptor natively
ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data);

Sync Fences

Sharing a buffer between two hardware chips creates a massive race condition. If the GPU is drawing a frame into a DMA-BUF, and the Display driver tries to read it before the GPU is finished, the screen will "tear" and show a corrupted image.

DMA-BUF natively supports Sync Fences. A fence is a kernel-level synchronization primitive attached to the buffer.

  • When the GPU starts drawing, it attaches an "in-progress" fence to the buffer.
  • The Display driver receives the buffer but sees the fence. The kernel forces the Display hardware to pause.
  • When the GPU finishes drawing its last pixel, it "signals" the fence. The kernel instantly wakes up the Display hardware, which then safely reads the completed image to the screen.

You can actually view active sync fences on your device using ADB:

adb shell dumpsys SurfaceFlinger --sync