前言
在第六章中征椒,我通過匿名共享內(nèi)存的方式解決Binder通信是無法傳遞大數(shù)據(jù)的問題娇哆,一次Binder通信最大可以傳輸是1MB-8KB(PS:8k是兩個pagesize,一個pagesize是申請物理內(nèi)存的最小單元)
但是這個答案對不對呢勃救,我只能說不準(zhǔn)確碍讨,接下來我們來仔細(xì)研究一下
1MB-8KB的限制來源于哪里
frameworks/native/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)//這里的限制是1MB-4KB*2
ProcessState::ProcessState(const char *driver)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
// 調(diào)用mmap接口向Binder驅(qū)動中申請內(nèi)核空間的內(nèi)存
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
}
如果一個進(jìn)程使用ProcessState這個類來初始化Binder服務(wù)溉躲,這個進(jìn)程的Binder內(nèi)核內(nèi)存上限就是BINDER_VM_SIZE净捅,也就是1MB-8KB荆永。
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
對于普通的APP來說,我們都是Zygote進(jìn)程孵化出來的,Zygote進(jìn)程的初始化Binder服務(wù)的時候提前調(diào)用了ProcessState這個類粗恢,所以普通的APP進(jìn)程上限就是1MB-8KB。
問一下自己,能否不用ProcessState來初始化Binder服務(wù),來突破1M-8KB的限制鱼鸠?
答案是當(dāng)然可以了,Binder服務(wù)的初始化有兩步麻蹋,open打開Binder驅(qū)動刹勃,mmap在Binder驅(qū)動中申請內(nèi)核空間內(nèi)存,所以我們只要手寫open乏梁,mmap就可以輕松突破這個限制揖曾。源碼中已經(jīng)給了類似的例子模暗。
frameworks/native/cmds/servicemanager/bctest.c
int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;
bs = binder_open("/dev/binder", 128*1024);//我們可以把這個數(shù)值改成2*1024*1024就可以突破這個限制了
if (!bs) {
fprintf(stderr, "failed to open binder driver\n");
return -1;
}
frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
...//省略部分代碼
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
....//省略部分代碼
bs->mapsize = mapsize;//這里mapsize=128*1024
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
....//省略部分代碼
}
難道Binder驅(qū)動不怕我們傳遞一個超級大的數(shù)字進(jìn)去嗎隶糕?
其實是我們想多了株旷,在Binder驅(qū)動中mmap的具體實現(xiàn)中還有一個4M的限制
/drivers/staging/android/binder.c
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
if (proc->tsk != current)
return -EINVAL;
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;//如果申請的size大于4MB了齿尽,會在驅(qū)動中被修改成4MB
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
目前的結(jié)論
1.通過手寫open,mmap初始化Binder服務(wù)的限制是4MB
2.通過ProcessState初始化Binder服務(wù)的限制是1MB-8KB
再問一下自己,4M或1MB-8KB這個答案是不是正確?
我發(fā)現(xiàn)一處代碼
/drivers/staging/android/binder.c
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
//省內(nèi)部分代碼
proc->free_async_space = proc->buffer_size / 2;//這個代碼引起我注意,async代碼異步的意思
barrier();
proc->files = get_files_struct(current);
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
size_t data_size,
size_t offsets_size, int is_async)
{
//省略部分代碼
if (is_async &&
proc->free_async_space < size + sizeof(struct binder_buffer)) {
//對于oneway的Binder調(diào)用诵原,可申請內(nèi)核空間辑畦,最大上限是buffer_size的一半,也就是mmap時候傳遞的值的一半暂筝。
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd failed, no async space left\n",
proc->pid, size);
return NULL;
}
為什么要做這樣子的限制鸵赖,我的猜想是Binder調(diào)用中同步調(diào)用優(yōu)先級大于oneway(異步)的調(diào)用肾砂,為了充分滿足同步調(diào)用的內(nèi)存需要,所以將oneway調(diào)用的內(nèi)存限制到申請內(nèi)存上限的一半。
問題:一次Binder通信最大可以傳輸多大的數(shù)據(jù)嚷狞?
再問一下自己,自己寫的APP能否突破1M-8KB的限制
答案是理論上可以传货,但是不建議這樣子操作,因為Binder驅(qū)動中并沒有對open祖乳,mmap有調(diào)用次數(shù)的限制作媚,App可以通過JNI調(diào)用open女揭,mmap來突破這個限制境蔼,但是會對當(dāng)前正在進(jìn)行Binder調(diào)用的APP造成不可想象問題,當(dāng)然可以先close Binder驅(qū)動疮鲫。但是一旦這個APP沒有Binder通信了,這個APP就不能正常使用了,APP和其他應(yīng)用刹淌,AMS喊崖,WMS的交互可都是依賴于Binder通信,所以還是那句話,無Binder無Android。