通俗易懂的Android多进程间通信 binder机制

一丶Android多进程通信的应用场景?

  • 保活
  • webview
  • 加载图片
  • push推送
  • 与系统服务通信
二丶为什么要用binder
  • Android系统内核是linux内核
  • Linux内核进程通信有:管道、内存共享、Socket、File;
  • 对比:

通俗易懂的Android多进程间通信 binder机制

文章插图
 
Binder的一次拷贝发生在用户空间拷贝到内核空间;
用户空间: App进程运行的内存空间;
内核空间: 系统驱动、和硬件相关的代码运行的内存空间 , 也就是进程ID为0的进程运行的空间;
程序局部性原则: 只加载少量代码;应用没有运行的代码放在磁盘中 , 运行时高速缓冲区进行加载要运行的代码;默认一次加载一个页(4K) , 若不够4K就用0补齐;
MMU:内存管理单元;
给CPU提供虚拟地址;
当对变量操作赋值时:
  • CPU拿着虚拟地址和值给到MMU
  • MMU用虚拟地址匹配到物理地址 , MMU去物理内存中进行赋值;
物理地址: 物理内存的实际地址,并不是磁盘;
虚拟地址: MMU根据物理内存的实际地址翻译出的虚拟地址;提供给CPU使用;
通俗易懂的Android多进程间通信 binder机制

文章插图
 

通俗易懂的Android多进程间通信 binder机制

文章插图
 
页命中:CPU读取变量时 , MMU在物理内存的页表中找到了这个地址;
页未命中:CPU读取变量时 , MMU在物理内存的页表中没有找到了这个地址 , 此时会触发MMU去磁盘读取变量并存到物理内存中;
普通的二次拷贝:
应用A拷贝到服务端:coay_from_user
从服务端拷贝到应用B:coay_to_user
mmap():
  • 在物理内存中开辟一段固定大小的内存空间
  • 将磁盘文件与物理内存进行映射(理解为绑定)
  • MMU将物理内存地址转换为虚拟地址给到CPU(虚拟地址映射物理内存)
共享内存进程通信:
  • 进程A调用mmap()函数会在内核空间中虚拟地址和一块同样大小的物理内存 , 将两者进行映射
  • 得到一个虚拟地址
  • 进程B调用mmap()函数 , 传参和步骤1一样的话 , 就会得到一个和步骤2相同的虚拟地址
  • 进程A和进程B都可以用同一虚拟地址对同一块映射内存进行操作
  • 进程A和进程B就实现了通信
  • 没有发生拷贝 , 共享一块内存 , 不安全
【通俗易懂的Android多进程间通信 binder机制】Binder通信原理:
角色:Server端A、Client端B、Binder驱动、内核空间、物理内存
  • Binder驱动在物理内存中开辟一块固定大小(1M-8K)的物理内存w , 与内核空间的虚拟地址x进行映射得到
  • A的用户空间的虚拟地址ax和物理内存w进行映射
  • 此时内核空间虚拟地址x和物理内存w已经进行了映射 , 物理内存w和Server端A的用户空间虚拟地址ax进行了映射:也就是 内核空间的虚拟地址x = 物理内存w = Server端A的用户空间虚拟地址ax
  • B发送请求:将数据按照binder协议进行打包给到Binder驱动 , Binder驱动调用coay_from_user()将数据拷贝到内核空间的虚拟地址x
  • 因步骤3中的三块区域进行了映射
  • Server端A就得到了Client端B发送的数据
  • 通过内存映射关系 , 只发生了一次拷贝

通俗易懂的Android多进程间通信 binder机制

文章插图
 
Activity跳转时 , 最多携带1M-8k(1兆减去8K)的数据量;
真实数据大小为:1M内存-两页的请求头数据=1M-8K;
应用A直接将数据拷贝到应用B的物理内存空间中 , 数据量不能超过1M-8K;拷贝次数少了一次 , 少了从服务端拷贝到用户;
IPC通信机制:
  • 服务注册
  • 服务发现
  • 服务调用
以下为简单的主进程和子进程通信:
1、服务注册: 缓存中心中有三张表(暂时理解为三个HashMap , Binder用的是native的红黑树):


推荐阅读