当前位置: 移动技术网 > 移动技术>移动开发>Android > Intent传递数据大小的限制

Intent传递数据大小的限制

2020年07月23日  | 移动技术网移动技术  | 我要评论

Binder通信是无法传递大数据的,一次Binder通信最大可以传输是1MB-8KB(PS:8k是两个pagesize,一个pagesize是申请物理内存的最小单元)。如果传输数据超过这个大小,系统就会报错,因为Binder本身就是为了进程间频繁而灵活的通信所设计的,并不是为了拷贝大数据而使用的。

1MB-8KB的限制来源于哪里

#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.
        // 调用mmap接口向Binder驱动中申请内核空间的内存
        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();
        }
    }
}

如果一个进程使用ProcessState这个类来初始化Binder服务,这个进程的Binder内核内存上限就是BINDER_VM_SIZE,也就是1MB-8KB。

virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

对于普通的APP来说,我们都是Zygote进程孵化出来的,Zygote进程的初始化Binder服务的时候提前调用了ProcessState这个类,所以普通的APP进程上限就是1MB-8KB。

能否不用ProcessState来初始化Binder服务,来突破1M-8KB的限制?

当然可以了,Binder服务的初始化有两步,open打开Binder驱动,mmap在Binder驱动中申请内核空间内存,所以我们只要手写open,mmap就可以轻松突破这个限制。源码中已经给了类似的例子,ServiceManager进程(servicemanager进程的启动比zygote进程要早)为自己申请的Binder内核空间是128K,这个同ServiceManager的用途是分不开的,ServcieManager主要面向系统Service,只是简单的提供一些addServcie,getService的功能,不涉及多大的数据传输,因此不需要申请多大的内存。

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);//我们可以把这个数值改成2*1024*1024就可以突破这个限制了
    if (!bs) {
        fprintf(stderr, "failed to open binder driver\n");
        return -1;
    }

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    ...//省略部分代码
    
    bs->fd = open(driver, O_RDWR | O_CLOEXEC); //第一步:调用open打开Binder驱动
    
    ....//省略部分代码
    
    bs->mapsize = mapsize;//这里mapsize就是传递进来的128*1024
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); //第二步:调用mmap在Binder驱动中申请内核空间内存
    
    ....//省略部分代码

}

难道Binder驱动不怕我们传递一个超级大的数字进去吗?

其实是我们想多了,在Binder驱动中mmap的具体实现中还有一个4M的限制。

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了,会在驱动中被修改成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));

参考:
[007]一次Binder通信最大可以传输多大的数据?
探究intent传递大小限制
听说你Binder机制学的不错,来面试下这几个问题(一)

本文地址:https://blog.csdn.net/yzpbright/article/details/107442889

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网