V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kerb15
V2EX  ›  Android

为什么 Binder 驱动需要在内核空间开辟两个缓存区?

  •  
  •   kerb15 · 2021-04-08 22:03:31 +08:00 · 8804 次点击
    这是一个创建于 1330 天前的主题,其中的信息可能已经有所发展或是发生改变。

    学习 Binder 通信原理的时候,看到下面这段话


    Binder 通信的步骤如下所示:

    1.Binder 驱动在内核空间创建一个 [数据接收缓存区] 。 2.在内核空间开辟一块 [内核缓存区] ,建立内核缓存区和数据接收缓存区之间的映射关系,以及数据接收缓存区和接收进程用户空间地址的映射关系。 3.发送方进程通过 copy_from_user()函数将数据拷贝 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。

    整个过程只使用了 1 次拷贝,不会因为不知道数据的大小而浪费空间或者时间,效率更高。

    摘自刘望舒的《 Android 进阶指北》


    想问下为什么需要开辟两个缓存区,这两个缓存区互相映射的目的是什么,直接使用一个缓存区不行吗?

    有没有研究过的大佬解答一二,谢谢~

    4 条回复    2021-04-12 21:40:40 +08:00
    rochek
        1
    rochek  
       2021-04-09 11:15:06 +08:00
    既然学习,建议看代码
    tylinux
        2
    tylinux  
       2021-04-09 13:29:34 +08:00
    传统 IPC 就是一个内核缓冲区,但是这样会有两次内存拷贝,发送 -> 内核 -> 接收。Binder 里的『数据接收缓存区』其实是 mmap 到 『内核缓存区』的,同时,也会 mmap 到接收进程的用户空间下,所以一次 copy 就可以把数据同步到接收进程了。(非专业 Android 开发,可能有误)
    kerb15
        3
    kerb15  
    OP
       2021-04-09 14:13:40 +08:00 via Android
    @tylinux 你的意思是不是说『内核缓存区』是属于内核空间的,而『数据缓存区』是 binder 驱动的,binder 驱动没办法让『内核缓存区』跟接受进程的用户空间直接做映射,所以必须在自己内部加多一块『接收数据缓存区』,做映射的中转
    erwa
        4
    erwa  
       2021-04-12 21:40:40 +08:00
    说下我的理解提供参考:

    1. Binder 通信过程的数据由『协议数据』+『 RPC Data (用户的数据)』组成,但其中『协议数据』包含着『 RPC Data 』的数据大小、首地址等其它用于通信逻辑的信息
    2. 驱动程序通过 copy_from_user() 将『协议数据』拷贝到内核,一通逻辑后,在『目标进程』映射的虚拟地址空间中分配『 RPC Data 』大小的内存
    3. 再通过 copy_from_user() 将『 RPC Data 』直接拷贝到这块内存,也就是一次拷贝的来源
    4. 通知目标进程的 Binder 线程处理任务,它会通过 copy_to_user() 将『协议数据』拷贝到它的用户空间

    也就是:用户数据拷贝一次,协议数据要拷贝两次

    所以对于书中『开辟的两个缓存区』我也持有疑问。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2803 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 15:34 · PVG 23:34 · LAX 07:34 · JFK 10:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.