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

相關文章
相關標籤/搜索