Binder驱动之Buffer Size

三个传输空间限制

Android中,由Zygote孵化的进程是经过ProcessState来建立Binder实体的。实体建立过程当中会映射一段内存空间用于数据传输,其大小设置为 ((1*1024*1024) - (4096*2))。异步

1.---> ProcessState.cpp 
    2.  
    3. #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
    4. . . . . . .
    5.ProcessState::ProcessState()
    6.    : mDriverFD(open_driver()) // 打开了Binder设备
    7.    , mVMStart(MAP_FAILED) // 内存映射的真实地址
    8.    , mManagesContexts(false)
    9.    , mBinderContextCheckFunc(NULL)
    10.    , mBinderContextUserData(NULL)
    11.    , mThreadPoolStarted(false)
    12.    , mThreadPoolSeq(1)
    13.{
    14.    if (mDriverFD >= 0) {
    15.        // 对Binder设备进行内存映射
    16.        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
    17.        if (mVMStart == MAP_FAILED) {
    18.            close(mDriverFD);
    19.            mDriverFD = -1;
    20.        }
    21.    }
    22.}

在Binder机制中,有一个很是特殊的Service,就是Service Manager。它作为Binder机制的守护进程,管理着其余的Services。它的Binder buffer大小也不一样,为(128*1024)。由于它只是用于管理services,提供addServcie,getService等功能,因此不会涉及大数据传输,由于没有分配较大的传输空间。async

1.---> service_manager.c
    2.  
    3.int main(int argc, char **argv)
    4.{
    5.    struct binder_state *bs;
    6.
    7.    bs = binder_open(128*1024);
    8.    ......
    9.}

Kernel中对Binder传输的大小也有个限制,大小为4M。这个限制使得全部的应用都没法申请大于4M的传输空间。大数据

1.---> binder.c
    2.  
    3.static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
    4.{
    5.    ......
    6.    if ((vma->vm_end - vma->vm_start) > SZ_4M)
    7.        vma->vm_end = vma->vm_start + SZ_4M;
    8.    ......
    9.    proc->buffer_size = vma->vm_end - vma->vm_start;
    10.    ......
    11.    proc->free_async_space = proc->buffer_size / 2;
    12.    ....
    13.}

目前,咱们获得的三个对Binder传输空间的限制。ui

  • (128*1024):对Service Manager的限制。
  • ((1*1024*1024) - (4096 *2)):对普通Android services的限制。
  • 4M:kernel能够接受的最大空间。

因此,实际应用能够申请的最大Binder Buffer是4M。但考虑实际传输的须要和节省内存,Android中申请的是(1M - 8K)。这个值是能够增长的,只要不大于4M就能够。spa

1M - 8K

Binder Buffer为何会是(1M - 8K),二不是整数值1M?这里看起来很奇怪,8K空间到底时用来作什么的?从GIT提交的记录能够看到下面的commits。code

Modify the binder to request 1M - 2 pages instead of 1M. The backing store in the kernel requires a guard page, so 1M allocations fragment memory very badly. Subtracting a couple of pages so that they fit in a power of two allows the kernel to make more efficient use of its virtual address space.

这段解释尚未充分理解,其大体的意思是:kernel的“backing store”须要一个保护页,这使得1M用来分配碎片内存时变得不好,因此这里减去两页来提升效率,由于减去一页就变成了奇数。至于保护页如何影响内存分配,须要后续分析内存管理时再进一步研究。进程

同步和异步

Binder通讯能够分为同步传输和异步传输,在设置传输空间大小时,将异步传输空间设置为同步传输的一半。
proc->free_async_space = proc->buffer_size / 2;
Binder经过红黑树进行buffer管理,将分配使用的buffer放入 allocated_buffers,将回收的buffer放入free_buffers。不管同步仍是异步,这里的操做都是相同的。内存

1.---> binder.c
    2. 
    3.struct binder_proc {
    4.    ......
    5.    struct list_head buffers;
    6.    struct rb_root free_buffers;
    7.    struct rb_root allocated_buffers;
    8.    size_t free_async_space;
    9.    ......
    10.}

而free_async_space只是用来统计异步传输时已经分配了多少空间。初始化时将其设置为所有buffer空间的一半,更多的是想对异步传输作一个限制,不但愿异步传输消耗掉全部的buffer。相比较而言,同步传输可能会承载更重要的数据,应该尽可能保证同步传输有可用buffer。而且异步传输是不须要等待返回的,连续的异步传输极可能将buffer耗光。ci

相关文章
相关标签/搜索