基于 Linux Kernel v5.4.123 | 源码路径:
drivers/staging/android/ion/
ION 是 Android 引入 Linux 内核的统一内存分配框架,解决多硬件设备(GPU、Camera、Display、Video)之间零拷贝共享物理内存的问题。本文使用 4+1 架构视图模型对 ION 进行全面的架构分析。
逻辑视图关注系统的关键抽象、模块职责和它们之间的关系。
ION 的设计分为三层,每层有清晰的职责边界:
┌─────────────────────────────────────────────────┐ │ 用户态接口层 (User Interface) │ │ /dev/ion 字符设备 + ioctl (ALLOC / QUERY) │ │ 输入: len, heap_id_mask, flags │ │ 输出: dma-buf fd │ └──────────────────────┬──────────────────────────┘ │ ┌──────────────────────▼──────────────────────────┐ │ 核心框架层 (Core Framework) │ │ ion_device — 全局单例,管理所有 heap │ │ ion_buffer — buffer 元数据 + sg_table │ │ dma_buf_ops — 与 Linux dma-buf 框架对接 │ │ deferred free — 延迟释放 + shrinker 回收 │ └──────────────────────┬──────────────────────────┘ │ ion_heap_ops (虚函数表) ┌──────────────────────▼──────────────────────────┐ │ 堆实现层 (Heap Implementations) │ │ System Heap — 散布页面 + page pool │ │ System Contig — 物理连续 buddy 分配 │ │ CMA Heap — CMA 预留区连续分配 │ │ (厂商自定义 Heap — EXPORT_SYMBOL 扩展) │ └─────────────────────────────────────────────────┘
┌──────────────────┐ │ ion_device │ 全局单例 │──────────────────│ │ dev: miscdevice │ /dev/ion │ lock: rw_sem │ │ heaps: plist │──┐ 优先级链表 │ heap_cnt: int │ │ └──────────────────┘ │ │ 1:N ┌────────────────────┘ ▼ ┌──────────────────┐ │ ion_heap │ 堆抽象 │──────────────────│ │ type: enum │ SYSTEM / DMA / ... │ ops: heap_ops* ─┼──────┐ │ id: uint │ │ │ flags: ulong │ │ │ shrinker │ │ │ free_list │ ▼ │ task: kthread │ ┌──────────────────┐ └──────────────────┘ │ ion_heap_ops │ 虚函数表 │ │──────────────────│ │ 1:N 分配 │ allocate() │ ▼ │ free() │ ┌──────────────────┐ │ map_kernel() │ │ ion_buffer │ │ unmap_kernel() │ │──────────────────│ │ map_user() │ │ heap: ion_heap* │ │ shrink() │ │ size: size_t │ └──────────────────┘ │ flags: ulong │ │ sg_table* ──────┼───── 核心:物理页面描述 │ attachments list │──┐ │ kmap_cnt: int │ │ │ vaddr: void* │ │ └──────────────────┘ │ │ 1:N ┌───────────────┘ ▼ ┌──────────────────────────┐ │ ion_dma_buf_attachment │ 每设备一份 │──────────────────────────│ │ dev: device* │ 哪个设备 │ table: sg_table* │ dup 的 sg_table 副本 └──────────────────────────┘
ION 使用 C 语言函数指针实现策略模式,核心框架通过 heap->ops->allocate() 调用具体堆实现,完全不关心底层分配细节:
ion_heap_ops (接口) ┌────────────────┐ │ allocate() │ │ free() │ │ map_kernel() │ │ map_user() │ │ shrink() │ └───────┬────────┘ ┌─────────────┼─────────────┐ ▼ ▼ ▼ system_heap_ops kmalloc_ops ion_cma_ops ┌────────────┐ ┌──────────┐ ┌──────────┐ │多阶贪心分配│ │buddy整块 │ │CMA 区域 │ │+ page pool │ │分配 │ │分配 │ └────────────┘ └──────────┘ └──────────┘
新增一种堆类型只需:
ion_heap_ops 结构体并实现回调ion_device_add_heap()(EXPORT_SYMBOL 导出)框架代码零修改,完全开放-封闭。
ION 与 Linux dma-buf 框架的关系是**导出者(exporter)**角色:
ION (exporter) 设备驱动 (importer) ───────────── ────────────────── ion_alloc() → ion_buffer_create() → dma_buf_export(dma_buf_ops) → dma_buf_fd() → fd ──────────────→ fd 通过 IPC 传递 │ dma_buf_get(fd) dma_buf_attach() → ion_dma_buf_attach() dma_buf_map_attachment() → ion_map_dma_buf() │ 设备通过 DMA 地址访问内存(零拷贝)
ION 提供 dma_buf_ops 告诉 dma-buf 框架如何操作 ION 分配的内存(attach、map、sync、release),设备驱动只依赖 dma-buf 标准 API,不直接依赖 ION。
进程视图关注运行时并发、线程、同步机制和时序行为。
| 上下文 | 身份 | 做什么 |
|---|---|---|
| 用户进程 | ioctl(ION_IOC_ALLOC) 调用方 | 分配/释放 buffer |
| deferred free kthread | 每个 DEFER_FREE heap 一个 | 后台回收 freelist 中的 buffer |
| kswapd | 内核内存回收守护线程 | 内存压力时通过 shrinker 回收 ION 缓存 |
| 设备驱动上下文 | GPU/Camera/Display 驱动 | attach、map、sync dma-buf |
用户进程 A 用户进程 B │ │ │ ioctl(ALLOC) │ ioctl(ALLOC) ▼ ▼ down_read(&dev->lock) ◄── rw_semaphore ──► down_read(&dev->lock) │ (读锁,可并发) │ │ 遍历 heaps │ 遍历 heaps │ heap->ops->allocate() │ heap->ops->allocate() │ └── page pool: mutex_lock │ └── page pool: mutex_lock │ (每个 pool 独立锁) │ (可能阻塞在同一 pool) │ │ │ spin_lock(&heap->stat_lock) │ spin_lock(&heap->stat_lock) │ 更新统计信息 │ 更新统计信息 │ │ up_read(&dev->lock) up_read(&dev->lock)
关键同步设计:
dev->lock(rw_semaphore):分配/查询用读锁(可并发),添加 heap 用写锁(互斥)heap->stat_lock(spinlock):保护统计计数器,临界区极短pool->mutex:每个 page pool 独立锁,不同 order 的分配不互斥buffer->lock(mutex):保护 attachments 链表和 kmap_cnt用户进程 (释放路径) deferred free kthread ───────────────── ───────────────────── close(fd) → dma_buf refcount = 0 → ion_dma_buf_release() → _ion_buffer_destroy() │ │ DEFER_FREE? │ Yes: │ spin_lock(&free_lock) │ list_add(buffer, freelist) │ free_list_size += size │ spin_unlock(&free_lock) │ wake_up(&waitqueue) ──────► wait_event_freezable() 被唤醒 │ │ │ (用户进程立即返回) │ │ spin_lock(&free_lock) │ 取出 buffer │ spin_unlock(&free_lock) │ │ │ ion_buffer_destroy() │ ├── zero 清零 buffer │ ├── 页面放回 page pool │ └── kfree(buffer)
deferred free kthread 以 SCHED_IDLE 优先级运行 — 只在系统空闲时调度,不与用户进程争 CPU。
系统内存不足 │ ▼ kswapd 唤醒 │ ▼ shrink_slab() 遍历所有注册的 shrinker │ ├── ion_heap_shrink_count() │ return freelist_pages + pool_pages // "我有 2048 页可回收" │ └── ion_heap_shrink_scan(nr_to_scan=512) │ ├── 1. ion_heap_freelist_shrink() // 先回收 freelist │ 设置 ION_PRIV_FLAG_SHRINKER_FREE │ ion_buffer_destroy() │ └── free_buffer_page() │ └── __free_pages() // 直接还系统,跳过 pool │ freed = 300 页 │ └── 2. heap->ops->shrink() // 不够,再回收 page pool ion_page_pool_shrink() └── __free_pages() // pool 中取出页面还系统 freed += 212 页
CPU cache 物理内存 设备 DMA ───────── ──────── ──────── [旧数据] 读到旧数据 begin_cpu_access(DMA_FROM_DEVICE): dma_sync_sg_for_cpu() invalidate cache ──────────────────→ [设备写入的新数据] CPU cache 失效 可见了 CPU 读写 buffer ◄──────────────────── [从物理内存加载] end_cpu_access(DMA_TO_DEVICE): dma_sync_sg_for_device() flush cache ───────────────────────→ [CPU 写入的新数据] 设备读到新数据 写回物理内存
开发视图关注代码组织、文件结构、模块依赖和构建配置。
drivers/staging/android/ ├── uapi/ │ └── ion.h # 用户态 API(ioctl 定义、堆类型枚举) │ 127 行 | 对外契约,ABI 稳定 └── ion/ ├── Kconfig # 内核配置选项 ├── Makefile # 构建规则(4 行) ├── ion.h # 内部头文件(数据结构 + 函数声明) │ 303 行 | 框架与堆实现之间的接口 ├── ion.c # 核心框架 │ 668 行 | 设备注册、ioctl、dma-buf ops、buffer 生命周期 ├── ion_heap.c # 堆通用辅助 │ 315 行 | map/unmap、deferred free、shrinker、zero ├── ion_page_pool.c # 页面缓存池 │ 155 行 | pool 分配/释放/shrink ├── ion_system_heap.c # System Heap + System Contig Heap │ 377 行 | 多阶贪心分配、page pool 集成 └── ion_cma_heap.c # CMA Heap 138 行 | CMA 区域连续分配 ───────── 总计约 1960 行(含头文件)
┌──────────────┐ │ uapi/ion.h │ 用户态 ABI └──────┬───────┘ │ include ┌──────▼───────┐ │ ion.h │ 内部接口 └──┬───┬───┬───┘ │ │ │ include ┌────────────┘ │ └────────────┐ ▼ ▼ ▼ ┌────────┐ ┌────────────┐ ┌──────────────┐ │ ion.c │ │ ion_heap.c │ │ ion_page_ │ │ │ │ │ │ pool.c │ └────────┘ └────────────┘ └──────────────┘ │ ▲ ▲ │ include │ 调用 │ 调用 │ ┌──────┴────────────────┘ │ │ │ ┌────┴─────────────┐ ┌───────────────┐ │ │ ion_system_heap.c│ │ ion_cma_heap.c│ │ └──────────────────┘ └───────────────┘ │ │ │ └──────────────┴─────────────────────┘ 都通过 ion_device_add_heap() 注册
makefile# Makefile
obj-$(CONFIG_ION) += ion_system_heap.o ion_page_pool.o ion_heap.o ion.o
obj-$(CONFIG_ION_CMA_HEAP) += ion_cma_heap.o
kconfig# Kconfig menuconfig ION bool "Ion Memory Manager" depends on HAS_DMA && MMU select GENERIC_ALLOCATOR select DMA_SHARED_BUFFER config ION_CMA_HEAP bool "Ion CMA heap support" depends on ION && DMA_CMA
关键依赖:
HAS_DMA — 需要 DMA 支持MMU — 需要 MMU(虚拟内存映射)DMA_SHARED_BUFFER — 自动启用 dma-buf 框架DMA_CMA — CMA Heap 需要 CMA 支持内核启动 → do_initcalls() │ ├── level 4: subsys_initcall │ └── ion_device_create() // 创建 /dev/ion,初始化全局 ion_device │ └── level 6: device_initcall ├── ion_system_heap_create() // 注册 System Heap (id=0) ├── ion_system_contig_heap_create() // 注册 Contig Heap (id=1) └── ion_add_cma_heaps() // 遍历 CMA 区域,注册 CMA Heap (id=2+)
subsys_initcall(level 4)先于 device_initcall(level 6),保证 internal_dev 在堆注册时已就绪。
物理视图关注硬件拓扑、内存布局和设备映射。
物理内存布局 (典型 ARM SoC 4GB) ┌──────────────────────────────────────┐ 0x0000_0000 │ 内核保留区 │ ├──────────────────────────────────────┤ │ │ │ ZONE_NORMAL (lowmem) │ │ ┌─────────────────────┐ │ │ │ buddy allocator │ │ │ │ ┌─────────────────┐ │ │ │ │ │ ION System Heap │ │ │ ← 从 buddy 分配 │ │ │ (散布页面) │ │ │ page pool 缓存在此 │ │ └─────────────────┘ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ ION Contig Heap │ │ │ ← 从 buddy 分配(连续) │ │ └─────────────────┘ │ │ │ └─────────────────────┘ │ ├──────────────────────────────────────┤ │ ZONE_HIGHMEM │ │ (ION System Heap 也可用) │ ├──────────────────────────────────────┤ │ │ │ CMA 预留区 │ │ ┌─────────────────────┐ │ │ │ ION CMA Heap │ │ ← 从 CMA 区域分配(连续) │ │ (设备树中预留) │ │ │ └─────────────────────┘ │ │ │ ├──────────────────────────────────────┤ │ MMIO / 设备寄存器 │ └──────────────────────────────────────┘ 0xFFFF_FFFF
┌─────────────────┐ │ 物理内存页面 │ │ page0, page1, │ │ page2, ... │ └────────┬────────┘ │ sg_table (原始) │ ┌─────────────────┼─────────────────┐ │ dup │ dup │ dup ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ sg_table │ │ sg_table │ │ sg_table │ │ (GPU 副本) │ │ (Display │ │ (Camera │ │ │ │ 副本) │ │ 副本) │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ dma_map_sg dma_map_sg dma_map_sg │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ GPU IOMMU │ │ Display │ │ Camera │ │ 页表 │ │ (直通/IOMMU)│ │ IOMMU 页表 │ │ │ │ │ │ │ │ DMA addr: │ │ DMA addr: │ │ DMA addr: │ │ 0x0010_0000 │ │ 0x8000_0000 │ │ 0xFF00_0000 │ └─────────────┘ └─────────────┘ └─────────────┘
同一块物理内存,每个设备通过各自的 IOMMU 映射得到不同的 DMA 地址。这就是为什么每个 attachment 需要 dup 独立的 sg_table。
用户进程虚拟地址空间 内核虚拟地址空间 ┌────────────────────┐ ┌────────────────────┐ │ │ │ │ │ mmap(dma-buf fd) │ │ vmap (kmap) │ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ │ 0x7f001000 │──┼── remap_ ─┼─▶│ 0xffff8800 │ │ │ │ 用户虚拟地址 │ │ pfn_ │ │ 内核虚拟地址 │ │ │ └──────────────┘ │ range │ └──────────────┘ │ │ │ │ │ │ └────────────────────┘ └─────────┼──────────┘ │ ┌───────▼────────┐ │ 物理页面 │ │ 0x8000_1000 │ │ 0x8000_5000 │ │ 0x9000_0000 │ ← 可能不连续 └────────────────┘
场景视图通过端到端的用例将其他四个视图串联起来。
这是 Android 上最典型的 ION 使用场景:
时间 ──────────────────────────────────────────────────────────► 用户进程 (SurfaceFlinger / CameraService) │ │ 1. open("/dev/ion") │ 2. ioctl(ION_IOC_ALLOC, {len=1920*1080*4, mask=system_heap, CACHED}) │ └── ion_alloc() │ └── ion_buffer_create() │ └── ion_system_heap_allocate() │ ├── pool_alloc(order=8) × 7 = 7MB │ └── pool_alloc(order=4) × 13 = 832KB ≈ 7.9MB │ └── dma_buf_export() → dma_buf_fd() → fd=7 │ │ 3. 将 fd=7 传给 Camera HAL(通过 Binder IPC) │ Camera HAL │ 4. dma_buf_get(fd=7) │ dma_buf_attach(camera_dev) → ion_dma_buf_attach() │ └── dup_sg_table() → camera 拥有独立 sg_table │ dma_buf_map_attachment(WRITE) → ion_map_dma_buf() │ └── dma_map_sg(camera_dev) → 获得 camera 的 DMA 地址 │ │ 5. Camera 硬件通过 DMA 将图像写入 buffer │ │ 6. dma_buf_unmap_attachment() │ 将 fd 传给 GPU 进程 │ GPU 驱动 │ 7. dma_buf_attach(gpu_dev) → 再 dup 一份 sg_table │ dma_buf_map_attachment(READ) → dma_map_sg(gpu_dev) │ └── GPU IOMMU 映射 → GPU 看到的 DMA 地址 │ │ 8. GPU 读取 buffer 做图像处理,结果写回同一 buffer │ │ 9. dma_buf_unmap_attachment() │ 将 fd 传给 Display │ Display 驱动 (HWC) │ 10. dma_buf_attach(display_dev) │ dma_buf_map_attachment(READ) → Display DMA 地址 │ │ 11. Display 控制器通过 DMA 读取 buffer,输出到屏幕 │ │ 12. dma_buf_unmap / detach(各设备依次) │ 用户进程 │ 13. close(fd=7) │ → dma_buf refcount=0 │ → ion_dma_buf_release() │ → _ion_buffer_destroy() │ └── DEFER_FREE: 加入 freelist,后台线程稍后回收
系统状态:可用内存低,kswapd 已激活 用户进程 │ ioctl(ION_IOC_ALLOC, 2MB) │ └── ion_alloc() └── ion_buffer_create() └── heap->ops->allocate() │ ├── alloc_largest_available(order=8) │ └── pool 空 → alloc_pages(GFP_HIGHUSER | __GFP_NORETRY) │ └── 失败(内存不足,不等待回收) │ ├── alloc_largest_available(order=4) │ └── pool 空 → alloc_pages(GFP_HIGHUSER) │ └── 触发内核直接回收(direct reclaim) │ └── 成功,得到 64KB │ ├── ... 继续分配 order=0 页面填满剩余 │ └── 首次 allocate 整体失败(某个 order=0 也失败了) │ ├── 检测到 DEFER_FREE ├── ion_heap_freelist_drain(heap, 0) // 清空 freelist │ └── 释放了 3 个延迟回收的 buffer → 归还 5MB 给系统 │ └── 重试 allocate → 成功 与此同时,kswapd 线程: kswapd │ shrink_slab() │ → ion_heap_shrink_count() → 报告 1024 页可回收 │ → ion_heap_shrink_scan(512) │ ├── freelist_shrink(已空) → freed=0 │ └── pool_shrink() │ ├── pool[order=8]: 3 个 1MB 页 → __free_pages → freed=768 │ └── 够了,停止 │ └── 系统可用内存恢复到安全水位
GPU 渲染完成,CPU 需要读取结果: 用户进程 │ │ // GPU 已经通过 DMA 写入了数据 │ │ ioctl(dmabuf_fd, DMA_BUF_IOCTL_SYNC, DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ) │ └── ion_dma_buf_begin_cpu_access(DMA_FROM_DEVICE) │ ├── kmap_get() → vmap buffer 到内核 │ └── dma_sync_sg_for_cpu() │ └── invalidate CPU cache // 确保 CPU 读到设备写入的最新数据 │ │ ptr = mmap(dmabuf_fd) │ memcpy(dst, ptr, size) // CPU 安全地读取 GPU 输出 │ │ ioctl(dmabuf_fd, DMA_BUF_IOCTL_SYNC, DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ) │ └── ion_dma_buf_end_cpu_access(DMA_FROM_DEVICE) │ ├── kmap_put() → kmap_cnt-- │ └── dma_sync_sg_for_device() │ └── (FROM_DEVICE 方向通常无需 flush)
以下用户态 C 程序演示 ION 的完整使用流程:查询 heap → 分配 buffer → mmap → 读写 → 释放。
保存为 ion_example.c:
c/*
* ION 用户态使用示例
* 演示:查询 heap、分配 buffer、mmap 读写、释放
*
* 编译:gcc -o ion_example ion_example.c
* 运行:./ion_example (需要 root 权限,且系统有 /dev/ion)
*
* 注意:此程序需要在带 ION 的 Android/Linux 内核上运行。
* 如果在普通 Linux PC 上,/dev/ion 不存在,程序会提示并退出。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/ion.h> /* 需要内核头文件 */
/* 如果系统头文件中没有 ion.h,手动定义 */
#ifndef ION_IOC_ALLOC
#define ION_IOC_MAGIC 'I'
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query)
struct ion_allocation_data {
__u64 len;
__u32 heap_id_mask;
__u32 flags;
__u32 fd;
__u32 unused;
};
#define MAX_HEAP_NAME 32
struct ion_heap_data {
char name[MAX_HEAP_NAME];
__u32 type;
__u32 heap_id;
__u32 reserved0;
__u32 reserved1;
__u32 reserved2;
};
struct ion_heap_query {
__u32 cnt;
__u32 reserved0;
__u64 heaps;
__u32 reserved1;
__u32 reserved2;
};
#define ION_FLAG_CACHED 1
#endif
static const char *heap_type_name(int type)
{
switch (type) {
case 0: return "SYSTEM";
case 1: return "SYSTEM_CONTIG";
case 2: return "CARVEOUT";
case 3: return "CHUNK";
case 4: return "DMA (CMA)";
default: return "CUSTOM";
}
}
int main(int argc, char *argv[])
{
int ion_fd, buf_fd, ret;
size_t buf_size = 4096; /* 分配 4KB */
void *mapped;
/* 1. 打开 /dev/ion */
ion_fd = open("/dev/ion", O_RDONLY);
if (ion_fd < 0) {
perror("open /dev/ion failed (需要 ION 内核支持)");
return 1;
}
printf("[1] /dev/ion opened, fd=%d\n", ion_fd);
/* 2. 查询可用 heap */
struct ion_heap_query query;
memset(&query, 0, sizeof(query));
query.cnt = 0;
query.heaps = 0;
ret = ioctl(ion_fd, ION_IOC_HEAP_QUERY, &query);
if (ret < 0) {
perror("ION_IOC_HEAP_QUERY (get count) failed");
close(ion_fd);
return 1;
}
printf("[2] System has %u heaps\n", query.cnt);
struct ion_heap_data *heaps = calloc(query.cnt, sizeof(*heaps));
query.heaps = (__u64)(unsigned long)heaps;
ret = ioctl(ion_fd, ION_IOC_HEAP_QUERY, &query);
if (ret < 0) {
perror("ION_IOC_HEAP_QUERY (get data) failed");
free(heaps);
close(ion_fd);
return 1;
}
unsigned int system_heap_mask = 0;
for (unsigned int i = 0; i < query.cnt; i++) {
printf(" heap[%u]: name=%-24s type=%-14s id=%u\n",
i, heaps[i].name, heap_type_name(heaps[i].type),
heaps[i].heap_id);
if (heaps[i].type == 0) /* ION_HEAP_TYPE_SYSTEM */
system_heap_mask = 1 << heaps[i].heap_id;
}
if (!system_heap_mask) {
printf("No system heap found, using mask=1\n");
system_heap_mask = 1;
}
free(heaps);
/* 3. 分配 buffer */
struct ion_allocation_data alloc;
memset(&alloc, 0, sizeof(alloc));
alloc.len = buf_size;
alloc.heap_id_mask = system_heap_mask;
alloc.flags = ION_FLAG_CACHED;
ret = ioctl(ion_fd, ION_IOC_ALLOC, &alloc);
if (ret < 0) {
perror("ION_IOC_ALLOC failed");
close(ion_fd);
return 1;
}
buf_fd = alloc.fd;
printf("[3] Buffer allocated: %zu bytes, dma-buf fd=%d\n",
buf_size, buf_fd);
/* 4. mmap 到用户空间 */
mapped = mmap(NULL, buf_size, PROT_READ | PROT_WRITE,
MAP_SHARED, buf_fd, 0);
if (mapped == MAP_FAILED) {
perror("mmap failed");
close(buf_fd);
close(ion_fd);
return 1;
}
printf("[4] Buffer mmap'd at %p\n", mapped);
/* 5. 写入数据 */
const char *test_msg = "Hello from ION!";
memcpy(mapped, test_msg, strlen(test_msg) + 1);
printf("[5] Wrote: \"%s\"\n", (char *)mapped);
/* 6. 读回验证 */
char readbuf[64];
memcpy(readbuf, mapped, strlen(test_msg) + 1);
printf("[6] Read back: \"%s\"\n", readbuf);
printf(" Data integrity: %s\n",
strcmp(test_msg, readbuf) == 0 ? "PASS" : "FAIL");
/* 7. 清理 */
munmap(mapped, buf_size);
close(buf_fd); /* 释放 dma-buf → 触发 ION buffer 释放 */
close(ion_fd);
printf("[7] Cleanup done. Buffer released via deferred free.\n");
return 0;
}
编译和运行:
bash# 交叉编译(ARM Android 设备)
$ aarch64-linux-gnu-gcc -o ion_example ion_example.c -static
$ adb push ion_example /data/local/tmp/
$ adb shell chmod +x /data/local/tmp/ion_example
$ adb shell /data/local/tmp/ion_example
# 或者在有 ION 的 Linux 开发板上直接编译
$ gcc -o ion_example ion_example.c
$ sudo ./ion_example
预期输出:
[1] /dev/ion opened, fd=3 [2] System has 3 heaps heap[0]: name=ion_system_heap type=SYSTEM id=0 heap[1]: name=ion_system_contig_heap type=SYSTEM_CONTIG id=1 heap[2]: name=linux,cma type=DMA (CMA) id=2 [3] Buffer allocated: 4096 bytes, dma-buf fd=4 [4] Buffer mmap'd at 0x7f8a001000 [5] Wrote: "Hello from ION!" [6] Read back: "Hello from ION!" Data integrity: PASS [7] Cleanup done. Buffer released via deferred free.
注意: 如果在没有 ION 的普通 Linux PC 上运行,第一步
open("/dev/ion")就会失败并报错No such file or directory。ION 仅在 Android 内核或手动启用了CONFIG_ION=y的内核中可用。
/dev/ion 设备提供用户态 ioctl 接口,分配结果以 dma-buf fd 形式返回,实现多设备零拷贝共享ion_device_add_heap 通过 EXPORT_SYMBOL 导出,SoC 厂商可在树外代码中注册自定义 heap,框架零修改dma-buf heaps(5.6+)取代,5.18 中完全移除drivers/staging/android/ion/drivers/dma-buf/dma-buf.c,include/linux/dma-buf.hdrivers/dma-buf/heaps/(Linux 5.6+)