Binder 内存分配

来源:互联网 发布:sql中别名 编辑:程序博客网 时间:2024/06/10 02:21

android6.0已经把binder_buffer有关的操作和binder.c分开了,实现在binder_alloc.c文件里面
一、binder_alloc_mmap_handler函数进行map,先看这个结构体:

struct binder_alloc {    struct mutex mutex;    struct vm_area_struct *vma;    struct mm_struct *vma_vm_mm;    void *buffer; // map 的地址就是这里了    ptrdiff_t user_buffer_offset; //内核空间和用户空间的差    struct list_head buffers; //所有的buffers列表    struct rb_root free_buffers; //只进行了预定,没有分配,按大小排序    struct rb_root allocated_buffers; //已经分配了,按地址排序    size_t free_async_space; //用于异步请求的空间    struct binder_lru_page *pages;//所有的pages    size_t buffer_size; //总共的大小    uint32_t buffer_free;    int pid;};

参数alloc和proc相关,也就是每个进程一个,vma用户调用传入参数
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma);
这个函数流程比较简单,关键流程如下:
1、

area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);    alloc->buffer = area->addr;    alloc->user_buffer_offset =vma->vm_start - (uintptr_t)alloc->buffer;

预定空间,初始化alloc的buffer和user_buffer_offset变量.
2、

alloc->pages = kzalloc(sizeof(alloc->pages[0]) *                   ((vma->vm_end - vma->vm_start) / PAGE_SIZE),                   GFP_KERNEL);

分配pages的空间
3、

buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);   buffer->data = alloc->buffer;   list_add(&buffer->entry, &alloc->buffers);   buffer->free = 1;   binder_insert_free_buffer(alloc, buffer);   alloc->free_async_space = alloc->buffer_size / 2;

往free_buffer里放置一个buffer,设置free_async_space为总空间的一半
二、binder_alloc_new_buf 分配一个binder_buffer,调用了binder_alloc_new_buf_locked
关键流程如下:
1、计算需要分配的空间大小
2、

struct rb_node *n = alloc->free_buffers.rb_node;    while (n) {        buffer = rb_entry(n, struct binder_buffer, rb_node);        BUG_ON(!buffer->free);        buffer_size = binder_alloc_buffer_size(alloc, buffer);        if (size < buffer_size) {            best_fit = n;            n = n->rb_left;        } else if (size > buffer_size)            n = n->rb_right;        else {            best_fit = n;            break;        }    }    if (n == NULL) {        buffer = rb_entry(best_fit, struct binder_buffer, rb_node);        buffer_size = binder_alloc_buffer_size(alloc, buffer);    }

在free_buffers查找适当的内存,看一下

static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,                       struct binder_buffer *buffer){    if (list_is_last(&buffer->entry, &alloc->buffers))        return (u8 *)alloc->buffer +            alloc->buffer_size - (u8 *)buffer->data;    return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data;}

如果只有一个成员alloc的结束地址减去buffer的开始地址,比如binder_alloc_mmap_handler调用后
此时buffer只有一个成员buffer->data和alloc->buffer相同,返回总的大小。
否则free_buffer的下一个开始减去自己的开始,从这里看,binder_buffer的数据应该是连续的分配
在alloc申请的空间buffer里的。
2、

ret = binder_update_page_range(alloc, 1,        (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr);

前面是对齐等操作,然后binder_update_page_range分配页面了。
3、

rb_erase(best_fit, &alloc->free_buffers);    buffer->free = 0;    buffer->free_in_progress = 0;    binder_insert_allocated_buffer_locked(alloc, buffer);    binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,             "%d: binder_alloc_buf size %zd got %pK\n",              alloc->pid, size, buffer);    buffer->data_size = data_size;    buffer->offsets_size = offsets_size;    buffer->async_transaction = is_async;    buffer->extra_buffers_size = extra_buffers_size;

从free_buffers中移除,添加到allocated_buffer,内存分配完成。
三、释放

binder_buffer void binder_alloc_free_buf(struct binder_alloc *alloc,                struct binder_buffer *buffer)

1、

ret = binder_update_page_range(alloc, 1,        (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr);    

释放页面
2、

rb_erase(&buffer->rb_node, &alloc->allocated_buffers);    buffer->free = 1;

从已分配红黑树中移除
3、

if (!list_is_last(&buffer->entry, &alloc->buffers)) {        struct binder_buffer *next = binder_buffer_next(buffer);        if (next->free) {            rb_erase(&next->rb_node, &alloc->free_buffers);            binder_delete_free_buffer(alloc, next);        }    }    if (alloc->buffers.next != &buffer->entry) {        struct binder_buffer *prev = binder_buffer_prev(buffer);        if (prev->free) {            binder_delete_free_buffer(alloc, buffer);            rb_erase(&prev->rb_node, &alloc->free_buffers);            buffer = prev;        }    }    binder_insert_free_buffer(alloc, buffer);

这部分先看看能不能和相邻的free_buffer里的binder_buffer合并,能合并则合并,然后把最终的binder_buffer插入进free_buffer里面。
总结:两个红黑树存储已分配和未分配的buffer,临近的free_buffer会被合并,free_buffer红黑树
便于查找大小合适的块进行分配,allocated_buffer存储地址便于查找和释放,其它的先不分析。
水平有限,如有错误,敬请指正。

原创粉丝点击