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

前言

上一篇文章,在解析初始化GraphicBuffer中,遇到一个ion驱动,对图元进行管理。首先看看ion是怎么使用的:

1.打开驱动:

mIonFd = open(ION_DEVICE, O_RDONLY);

2.ioctl 发送ION_IOC_ALLOC命令

if(ioctl(mIonFd, ION_IOC_ALLOC, &ionAllocData)) {

err = -errno;

ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));

return err;

}

3.ioctl发送ION_IOC_MAP命令

ioctl(mIonFd, ION_IOC_MAP, &fd_data)

4.mmap 映射一段共享内存

base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE,

MAP_SHARED, fd_data.fd, 0);

5.ioctl ION_IOC_FREE 释放底层的句柄

ioctl(mIonFd, ION_IOC_FREE, &handle_data);

我们按照这个流程分析ion的源码。

本文基于Android的Linux内核版本3.1.8

正文

什么是ion?如果是音视频,Camera的工程师会对这个驱动比较熟悉。最早的GPU和其他驱动协作申请一块内存进行绘制是使用比较粗暴的共享内存。在Android系统中使用的是匿名内存。最早由三星实现了一个Display和Camera共享内存的问题,曾经在Linux社区掀起过一段时间。之后各路大牛不断的改进之下,就成为了dma_buf驱动。并在 Linux-3.3 主线版本合入主线。现在已经广泛的运用到各大多媒体开发中。

首先介绍dma_buf的2个角色,importer和exporter。importer是dma_buf驱动中的图元消费者,exporter是dma_buf驱动中的图元生产者。

这里借用大佬的图片:

dma_buf.png

ion是基于dma_buf设计完成的。经过阅读源码,其实不少思路和Android的匿名内存有点相似。阅读本文之前就算不知道dma_buf的设计思想也没关系,我不会仔细到每一行,我会注重其在gralloc服务中的申请流程,看看ion是如何管理共享内存,为什么要抛弃ashmem。

ion初始化

我们先来看看ion的file_operation:

static const struct file_operations ion_fops = {

.owner = THIS_MODULE,

.open = ion_open,

.release = ion_release,

.unlocked_ioctl = ion_ioctl,

.compat_ioctl = compat_ion_ioctl,

};

只有一个open和ioctl函数。但是没有mmap映射。因此mmap映射的时候一定其他对象在工作。

static struct platform_driver ion_driver = {

.probe = tegra_ion_probe,

.remove = tegra_ion_remove,

.driver = { .name = "ion-tegra" }

};

module_platform_driver(ion_driver);

module_platform_driver实际上就是我之前经常提到过的module_init的一个宏,多了一个register注册到对应名字的平台中的步骤。在这里面注册了一个probe方法指针,probe指向的tegra_ion_probe是加载内核模块注册的时候调用。

static struct ion_device *idev;

static int num_heaps;

static struct ion_heap **heaps;

static int tegra_ion_probe(struct platform_device *pdev)

{

struct ion_platform_data *pdata = pdev->dev.platform_data;

int err;

int i;

num_heaps = pdata->nr;

heaps = devm_kzalloc(&pdev->dev,

sizeof(struct ion_heap *) * pdata->nr,

GFP_KERNEL);

idev = ion_device_create(NULL);

if (IS_ERR_OR_NULL(idev))

return PTR_ERR(idev);

/* create the heaps as specified in the board file */

for (i = 0; i < num_heaps; i++) {

struct ion_platform_heap *heap_data = &pdata->heaps[i];

heaps[i] = ion_heap_create(heap_data);

if (IS_ERR_OR_NULL(heaps[i])) {

err = PTR_ERR(heaps[i]);

goto err;

}

ion_device_add_heap(idev, heaps[i]);

}

platform_set_drvdata(pdev, idev);

return 0;

err:

for (i = 0; i < num_heaps; i++) {

if (heaps[i])

ion_heap_destroy(heaps[i]);

}

return err;

}

先来看看对应的结构体:

struct ion_platform_data {

int nr;/*有多少ion_platform_heap*/

struct ion_platform_heap *heaps;/*ion_platform_heap 指针数组*/

};

再来看看对应ion内的堆结构体:

struct ion_platform_heap {

enum ion_heap_type type;/*heap 类型*/

unsigned int id;

const char *name;

ion_phys_addr_t base;/*heap 起始地址*/

size_t size;/*heap 大小*/

ion_phys_addr_t align;/*heap需要对齐*/

void *priv;

};

完成的事情如下几个步骤:

1.ion_device_create 初始化注册ion驱动

2.ion_heap_create和ion_device_add_heap 初始化ion_platform_data中申请内存的堆,并添加到ion驱动中管理

ion_device_create 初始化注册ion驱动

struct ion_device *ion_device_create(long (*custom_ioctl)

(struct ion_client *client,

unsigned int cmd,

unsigned long arg))

{

struct ion_device *idev;

int ret;

idev = kzalloc(sizeof(struct ion_device), GFP_KERNEL);

..

idev->dev.minor = MISC_DYNAMIC_MINOR;

idev->dev.name = "ion";

idev->dev.fops = &ion_fops;

idev->dev.parent = NULL;

ret = misc_register(&idev->dev);

...

idev->debug_root = debugfs_create_dir("ion", NULL);

if (!idev->debug_root) {

...

goto debugfs_done;

}

...

debugfs_done:

idev->custom_ioctl = custom_ioctl;

idev->buffers = RB_ROOT;

mutex_init(&idev->buffer_lock);

init_rwsem(&idev->lock);

plist_head_init(&idev->heaps);

idev->clients = RB_ROOT;

return idev;

}

我们不关注debug模式。其实整个就是我们分析了很多次的方法。把这个对象注册miscdevice中。等到insmod就会把整个整个内核模块从dev_t的map中关联出来。

我们来看看这个驱动结构体:

struct ion_device {

struct miscdevice dev;/*驱动设备符*/

struct rb_root buffers;/*ion_buffer ion内核缓冲区 红黑树*/

struct mutex buffer_lock;

struct rw_semaphore lock;

struct plist_head heaps;/*ion_buffer ion内核堆链表*/

long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,

unsigned long arg);

struct rb_root clients;/*每一个open进来的对象*/

struct dentry *debug_root;

struct dentry *heaps_debug_root;

struct dentry *clients_debug_root;

};

ion_heap_create 创建ion内存申请堆

struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)

{

struct ion_heap *heap = NULL;

switch (heap_data->type) {

case ION_HEAP_TYPE_SYSTEM_CONTIG:

heap = ion_system_contig_heap_create(heap_data);

break;

case ION_HEAP_TYPE_SYSTEM:

heap = ion_system_heap_create(heap_data);

break;

case ION_HEAP_TYPE_CARVEOUT:

heap = ion_carveout_heap_create(heap_data);

break;

case ION_HEAP_TYPE_CHUNK:

heap = ion_chunk_heap_create(heap_data);

break;

case ION_HEAP_TYPE_DMA:

heap = ion_cma_heap_create(heap_data);

break;

default:

return ERR_PTR(-EINVAL);

}

...

heap->name = heap_data->name;

heap->id = heap_data->id;

return heap;

}

这里有四个不同堆会申请出来,我们主要来看看默认的ION_HEAP_TYPE_SYSTEM对应的heap流程。

ion_system_heap_create

static const unsigned int orders[] = {8, 4, 0};

static struct ion_heap_ops system_heap_ops = {

.allocate = ion_system_heap_allocate,

.free = ion_system_heap_free,

.map_dma = ion_system_heap_map_dma,

.unmap_dma = ion_system_heap_unmap_dma,

.map_kernel = ion_heap_map_kernel,

.unmap_kernel = ion_heap_unmap_kernel,

.map_user = ion_heap_map_user,

.shrink = ion_system_heap_shrink,

};

struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)

{

struct ion_system_heap *heap;

int i;

heap = kzalloc(sizeof(struct ion_system_heap) +

sizeof(struct ion_page_pool *) * num_orders,

GFP_KERNEL);

if (!heap)

return ERR_PTR(-ENOMEM);

heap->heap.ops = &system_heap_ops;

heap->heap.type = ION_HEAP_TYPE_SYSTEM;

heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;

for (i = 0; i < num_orders; i++) {

struct ion_page_pool *pool;

gfp_t gfp_flags = low_order_gfp_flags;

if (orders[i] > 4)

gfp_flags = high_order_gfp_flags;

pool = ion_page_pool_create(gfp_flags, orders[i]);

if (!pool)

goto destroy_pools;

heap->pools[i] = pool;

}

heap->heap.debug_show = ion_system_heap_debug_show;

return &heap->heap;

....

}

struct ion_system_heap {

struct ion_heap heap;

struct ion_page_pool *pools[0];

};

其实真正象征ion的内存堆是下面这个结构体

struct ion_heap {

struct plist_node node;

struct ion_device *dev;

enum ion_heap_type type;/*类型*/

struct ion_heap_ops *ops;/*堆操作*/

unsigned long flags;/*此时是ION_HEAP_FLAG_DEFER_FREE*/

unsigned int id;

const char *name;

struct shrinker shrinker;/*回收资源方法*/

struct list_head free_list;/*空闲资源*/

size_t free_list_size;

spinlock_t free_lock;

wait_queue_head_t waitqueue;

struct task_struct *task;

int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);

};

不管原来的那个heap,会新建3个ion_system_heap,分别order为8,4,0,大于4为大内存。意思就是这个heap中持有一个ion_page_pool 页资源池子,里面只有对应order的2的次幂,内存块。其实就和伙伴系统有点相似。

还会设置flag为ION_HEAP_FLAG_DEFER_FREE,这个标志位后面会用到。

ion_page_pool_create 创建页资源池

struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)

{

struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),

GFP_KERNEL);

if (!pool)

return NULL;

pool->high_count = 0;

pool->low_count = 0;

INIT_LIST_HEAD(&pool->low_items);

INIT_LIST_HEAD(&pool->high_items);

pool->gfp_mask = gfp_mask | __GFP_COMP;

pool->order = order;

mutex_init(&pool->mutex);

plist_node_init(&pool->list, order);

return pool;

}

struct ion_page_pool {

int high_count;

int low_count;

struct list_head high_items;

struct list_head low_items;

struct mutex mutex;

gfp_t gfp_mask;

unsigned int order;

struct plist_node list;

};

在pool中分为2个链表一个是high_items,另一个是low_items。他们之间的区分在此时就是以2为底4的次幂为分界线。

ion_device_add_heap

void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)

{

struct dentry *debug_file;

....

if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)

ion_heap_init_deferred_free(heap);

if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink)

ion_heap_init_shrinker(heap);

heap->dev = dev;

down_write(&dev->lock);

plist_node_init(&heap->node, -heap->id);

plist_add(&heap->node, &dev->heaps);

...

#ifdef DEBUG_HEAP_SHRINKER

...

#endif

up_write(&dev->lock);

}

因为打开了标志位ION_HEAP_FLAG_DEFER_FREE和heap存在shrink方法。因此会初始化两个回收函数。

1.ion_heap_init_deferred_free

2.ion_heap_init_shrinker

3.ion_heap 添加到ion_device的heap红黑树中。

ion_heap_init_deferred_free 启动销毁heap中free资源的线程

static int ion_heap_deferred_free(void *data)

{

struct ion_heap *heap = data;

while (true) {

struct ion_buffer *buffer;

wait_event_freezable(heap->waitqueue,

ion_heap_freelist_size(heap) > 0);

spin_lock(&heap->free_lock);

if (list_empty(&heap->free_list)) {

spin_unlock(&heap->free_lock);

continue;

}

buffer = list_first_entry(&am

你可能感兴趣的:(Android驱动代码dump)