对于想从事Android多媒体底层开发的工程师,我们需要了解DMA buf。不管是vedio,camera还是display,GPU的buf都来自于ION,而ION是基于DMA buf实现的。

一 DMA BUF的历史

想要深层次的认识DMA buf,我们需要了解DMA buf的历史。dma-buf 最初的原型为 shrbuf,由 Marek Szyprowski (Samsung)于2011年8月2日首次提出,他实现了 “Buffer Sharing” 的概念验证(Proof-of-Concept),并在三星平台的 V4L2 驱动中实现了 camera 与 display 的 buffer 共享问题。

Buffer sharing proof-of-concept [LWN.net]https://lwn.net/Articles/455098/DMA buffer sharing in 3.3 [LWN.net]https://lwn.net/Articles/474819/Marek Szyprowski发布的缓冲区共享补丁集,让多个内核子系统在用户空间的控制下共享内存成为可能。这种功能想要安全的导出到应用程序,必须解决几个关键的挑战:

(1) 应用程序不允许在任意内核地址上创建缓冲区。

(2) 用户空间无法访问内核空间,因此内核必须为应用程序提供一些方法引用特定缓冲区。

(3) 共享缓冲区必须在所有用户都释放它之前是不会消失的。

后来 Sumit Semwal (Linaro) 基于 Marek Szyprowski 的 patch 重构了一套新的框架,也就是我们今天看到的 dma-buf 核心代码,它经历了社区开发人员给出的重重考验,并最终于 2012 年 2 月 merge 到了 Linux-3.3 主线版本中,这也是 dma-buf 的第一个正式版本。此后 dma-buf 被广泛应用于内核多媒体驱动开发中,尤其在 V4L2、DRM 子系统中得到了充分应用。
DMA buffer sharing in 3.3 [LWN.net]https://lwn.net/Articles/474819/~airlied/linux - Official DRM kernel treehttps://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-prime-dmabuf&id=dc4e05acd66a13a1a30de07f21a0420f2949caa8~airlied/linux - Official DRM kernel treehttps://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-prime-dmabuf&id=22e1c055c1c1c300761d784faab26e6db2f068b9回到2011年8月,LWN研究了Marek Szyprowski发布的DMA缓冲区共享补丁集。从那时起,该补丁被Sumit Semwal采纳,他根据许多开发人员的评论对其进行了大量修改。不过,核心思想还是一样的:这种机制允许在驱动程序之间共享DMA缓冲区,否则这些驱动程序可能不知道彼此。最初的目标使用是在视频流的生产者和消费者之间共享缓冲区;例如,一个相机设备可以获取帧流到一系列与图形适配器共享的缓冲区中,这样就可以捕获和显示数据,而无需在内核中进行复制。

二 ION BUF的介绍

ION是Android的统一内存管理接口,它被广泛应用于几乎所有基于ARM的Android设备。它最初是在Android 4.0中由谷歌引入的,最初的设计目的是取代以前的碎片化内存使用接口。ION尝试实现几个重要的的目标,而这些目标以前从未同时实现过的。与管理系统中的常规内存不同,ION被设计用于共享和管理具有特殊约束的内存,例如物理上连续的内存。它的主要目标是支持GPU和摄像头等硬件设备设置的特殊要求。例如,一些设备需要物理上连续的内存来运行,而一些设备需要特定的缓存一致性协议来让DMA正确运行。为了满足这些需求,在给定的Android手机上,ION使用一组为底层硬件设备预配置的内存堆进行定制。

如前所述,ION旨在实现两个主要目标。首先,它旨在支持具有不同内存需求的硬件设备。在ION之前,不同的SoC供应商通过专有和相互不兼容的接口来实现这一点,如用于高通的PMEM,用于英伟达的NVMAP,以及用于TI的CMEM。系统和应用程序开发人员必须为所有这些接口定制他们的代码,以确保代码可以跨所有不同的平台工作。由于ION的引入,这个问题得到了极大的缓解,它定义了一个与SoC制造商无关的通用接口。驱动程序形式的底层实现可以由SoC和智能手机供应商,以确保他们返回用户空间要求的正确类型的内存。

与大多数暴露给用户空间接口一样,统一ION接口是在/dev/ion文件上进行操作,例如可以通过open()和ioctl()系统调用来操作该文件。具体支持的操作集包括" alloc "和" free "。用户空间代码需要指定一个应该从中分配内存的堆id。所示图1,每个ION堆都有指定的名称、id,更重要的是关联的堆类型是为特定的Android设备预定义的。

表1展示了一组由aosp定义的堆类型,以及我们在所研究的Android设备中遇到的定制堆类型的一个选定子集。 尽管不完整,但它说明了使用不同类型和属性堆的ION的复杂性。有些堆类型可能具有类似的属性:CMA和安全的CMA。然而,它们实际上有不同的用途。CMA可通过第三方应用程序和系统服务访问。然而,SECURE CMA通常用于trusted world,因此从用户空间无法访问。

通常,堆分为两类: 1) 未保留的。最具代表性的是SYSTEM堆,它使用低级伙伴分配器(根据我们的分析)作为其内存提供程序,这与通过malloc()分配的内存相同。2) 保留。这包括CARVEOUT和CMA堆涉及在启动时留出内存,以便在运行时消除内存碎片。

ION的第二个目标是允许在用户空间、内核空间和硬件设备之间有效地共享内存。 这是通过直接共享内存页来实现的,以避免复制。具体来说,按照前面解释的ION接口,一旦从堆中成功分配内存,将向用户空间返回一个文件描述符,随后可以使用该描述符调用mmap()将分配的页面映射到用户空间。这个特性在许多场景中都很方便。例如,在图形处理同时需要软件和硬件渲染的情况下,OpenGL等库可以轻松地操作用户空间中的内存,GPU也可以在零复制的情况下填充同一块物理内存。

三 ION BUF的使用

可以参考这篇文章:The Android ION memory allocator [LWN.net]https://lwn.net/Articles/480055/(1)从用户空间使用ION

<1> 获取权限

用户空间C/ c++程序必须被授予访问/dev/ ION设备的权限,然后才能从ION分配内存。调用

open("/dev/ion", O_RDONLY)

返回一个文件描述符作为一个表示ion客户端的句柄。是的,可以通过打开O_RDONLY来分配可写内存。每个用户进程只能有一个客户端。为了分配一个缓冲区,客户端需要在这个数据结构中填写除handle字段外的所有字段:

struct ion_allocation_data {size_t len;size_t align;unsigned int flags;struct ion_handle *handle;}

handle字段是输出参数,而前三个字段指定对齐方式、长度和标志作为输入参数。flags字段是一个位掩码,表示要从其中分配一个或多个ION堆,回退顺序根据启动引导期间通过调用ion_device_add_heap() 首次添加的ION堆进行排序。在默认实现中,ION_HEAP_TYPE_CARVEOUT被添加在ION_HEAP_TYPE_CONTIG之前。ION_HEAP_TYPE_CONTIG | ION_HEAP_TYPE_CARVEOUT标志表示从ION_HEAP_TYPE_CARVEOUT进行分配,并回退到ION_HEAP_TYPE_CONTIG。

<2> 开辟空间

用户空间客户机使用ioctl()系统调用接口与ION交互。为了分配一个缓冲区,客户端进行如下调用:

int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)

这个调用返回一个由ion_handle表示的缓冲区,它不是cpu访问的缓冲区指针。句柄只能用于获取用于缓冲区共享的文件描述符,如下所示:

int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data);

这里client_fd是对应于/dev/ion的文件描述符,而fd_data是一个包含输入句柄字段和输出fd字段的数据结构,定义如下:

   struct ion_fd_data {struct ion_handle *handle;int fd;}

fd字段是可以用于共享的文件描述符。在Android设备上,BINDER IPC机制可以用来将fd发送给另一个进程进行共享。为了获得共享缓冲区,第二个用户进程必须首先通过open("/dev/ion", O_RDONLY) 系统调用获得一个客户端句柄。ION通过进程的PID跟踪它的用户空间客户机(具体来说,是进程中的“组长”线程的PID)。在同一个进程中重复调用open("/dev/ion", O_RDONLY)将返回另一个文件描述符,该描述符与内核中相同的客户机结构相对应。

<3> 释放内存空间

为了释放缓冲区,第二个客户端需要通过调用munmap()来撤销mmap()的影响,第一个客户端需要关闭它通过ION_IOC_SHARE获得的文件描述符,并调用ION_IOC_FREE,如下所示:

int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data);

这里ion_handle_data持有的句柄如下所示:

   struct ion_handle_data {struct ion_handle *handle;}

ION_IOC_FREE命令使句柄的引用计数器减1。当这个引用计数器达到0时,将销毁ion_handle对象,并更新受影响的ION记录数据结构。

(2)在内核中共享ION缓冲区

在内核中,ION支持多个客户机,每个客户机对应一个使用ION功能的驱动程序。内核驱动调用以下函数来获取一个ION客户端句柄:

 struct ion_client *ion_client_create(struct ion_device *dev, unsigned int heap_mask, const char *debug_name)

第一个参数dev是与/dev/ion关联的全局ION设备;为什么需要一个全局设备,为什么它必须作为参数传递,还不完全清楚。第二个参数heap_mask以与ion_allocation_data相同的方式选择一个或多个ION堆。前一节已经介绍了flags字段。对于涉及多媒体中间件的智能手机用例,用户进程通常从ION分配缓冲区,使用ION_IOC_SHARE命令获取文件描述符,然后将文件描述符传递给内核驱动程序。内核驱动调用ion_import_fd()将文件描述符转换为一个ion_handle对象,如下所示:

struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user);

ion_handle对象是驱动程序对共享缓冲区的客户端本地引用。ion_import_fd()调用查找缓冲区的物理地址,看看客户端之前是否已经获得了同一个缓冲区的句柄,如果已经获得,这个调用只是增加现有句柄的引用计数器。

一些硬件块只能在物理相邻的缓冲区上操作,因此受影响的驱动需要通过以下调用将ion_handle转换为物理缓冲区:

 int ion_phys(struct ion_client *client, struct ion_handle *handle,ion_phys_addr_t *addr, size_t *len)

不用说,如果缓冲区在物理上不是连续的,那么这个调用将失败。当处理来自客户机的调用时,ION总是验证输入文件描述符、客户机和handle参数。例如,在导入文件描述符时,ION确保文件描述符确实是由ION_IOC_SHARE命令创建的。当调用ion_phys()时,ION将验证缓冲区句柄是否属于允许客户端访问的句柄列表,如果该句柄不在列表中,则返回错误。这种验证机制减少了不必要的访问和意外资源的可能性。

ION通过debugfs提供调试可见性。它在/sys/kernel/debug/ion目录下组织调试信息,在与堆和通过符号名称或pid标识的客户端相关联的存储文件中记录信息。

感兴趣的同学还可以参考下面这篇文献,介绍了关于ion buf的安全漏洞方面的问题:

https://www.cs.ucr.edu/~zhiyunq/pub/ccs16_ion.pdfhttps://www.cs.ucr.edu/~zhiyunq/pub/ccs16_ion.pdf

ANDROID ION_BUFFER相关推荐

  1. android之ION内存管理器(1)-- 简介

    by JHJ(jianghuijun211@gmail.com) 为什么需要ION 回顾2011年末[2],LWN审查了android kernel patch[3],以期望将这些patch合并到ke ...

  2. Android ION 内存管理

    ION的设计初衷 Android为了更好的针对移动设备内存的管理,设计出了ION内存管理机制,主要是为了解决以下几个问题: 预留大块连续内存,比如camera,display,GPU等模块 避免内存随 ...

  3. android之ion内存储器管理器,Android ION

    场景:android之ION内存储器管理器(1)- 简介 android之ION内存管理器(1)-- 简介 by JHJ(jianghuijun211@gmail.com) 为什么需要ION 回顾20 ...

  4. linux ion 分配地址,Android ION内存分配

    ION设计的目标 为了避免内存碎片化,或者为一些有着特殊内存需求的硬件,比如GPUs.display controller以及camera等,在系统启动的时候,会为他们预留一些memory pools ...

  5. android 内存管理 ion,Android学习之ION memory manager

    ION是google在Android4.0 ICS为了解决内存碎片管理而引入的通用内存管理器,它会更加融合kernel.目前QCOM MSM, NVDIA Tegra, TI OMAP, MRVL P ...

  6. ion android 内核,Android Ion用户空间和内核空间

    为什么需要ION 回顾2011年末[2],LWN审查了android kernel patch[3],以期望将这些patch合并到kernel主线中.但是PMEM(android实现的 一个内存分配器 ...

  7. android内存地址分配,Android ION内存分配

    ION设计的目标 为了避免内存碎片化,或者者为少量有着特殊内存需求的硬件,比方GPUs.display controller以及camera等,在系统启动的时候,会为他们预留少量memory pool ...

  8. Android驱动代码dump,Android 重学系列 ion驱动源码浅析

    前言 上一篇文章,在解析初始化GraphicBuffer中,遇到一个ion驱动,对图元进行管理.首先看看ion是怎么使用的: 1.打开驱动: mIonFd = open(ION_DEVICE, O_R ...

  9. The Android ION memory allocator

    什么是ION ? 我的理解就是google在android4.0引入的一种内存管理器,来替代之前各个芯片厂家自己的方案..以下是网上找到的: it has become clear that PMEM ...

最新文章

  1. AI时代龙争虎战 什么是传统安企“护城河”?
  2. InnoDB Master Thread I/O Rate详解
  3. Gradle在IDEA中创建web项目
  4. 文本挖掘技术在CIC的应用--转载
  5. 【论文相关】历年CVPR、ICCV、ECCV论文合集下载
  6. java微服务,微在哪_Java:ChronicleMap第3部分,快速微服务
  7. 1到100的偶数之和是多少_什么白酒适合收藏,收藏多久出手,茅台五粮液老酒价格是多少?...
  8. Chrome 开发者工具网络性能使用
  9. 你真应该再多了解些Handler机制
  10. isodata算法确定k均值聚类的k值
  11. GraphQL 总结 + 在Django应用(Graphene)
  12. Java版漏斗计时器_新学期新气象 教你在《我的世界》做出特别铃声
  13. 最新智云全能API接口查询PHP源码V1.1
  14. [思语]_心上人,我想对你说
  15. 欧几里得定理(nyoj775)
  16. vector和list的使用
  17. linux磁盘变为raw,LINUX下如何挂载RAW格式的硬盘
  18. 企业微信SCRM的设计理念是什么?和CRM有什么不同?
  19. 关于error: The following untracked working tree files would be overwritten by checkout的解决方案
  20. 多层Android锁机样本分析

热门文章

  1. dreamcast游戏_Dreamcast Collection游戏百度网盘下载-DC游戏合集下载PC硬盘版-西西游戏下载...
  2. EUI学习之Group
  3. 安卓大作业(AndroidStudio开发)日记记事本app
  4. 南京师范大学计算机技术调剂,2016年南京师范大学接收双“985工程”高校优秀调剂生...
  5. H5+ app自动更新思路
  6. android仿iphone苹果桌面源码拖拉排
  7. 力控 Force Control
  8. 安富莱v6开发板网口通讯_【安富莱】各种开发板和模块的资料下载汇总贴(2020-04-06)...
  9. java 行为参数化_Java中的行为参数化
  10. Detecting noop updates