盒子
盒子
文章目录
  1. Linux IPC
    1. 管道
    2. 信号量
    3. 信号
    4. 共享内存
    5. 消息队列
    6. socket
  2. Binder
  3. 推荐

Binder纯理论分析

接下来的一段时间,我们会来深入认识一下Android中的Binder机制。

今天的主要是来对Binder做一个较全面的介绍,为之后的深入分析做一个预热准备。

Linux IPC

首先Binder是Android中的一种独有的跨进程通信方式,简称IPC。它是专门为Android平台设计的。

那为什么要设计出Binder这个烦人的东西呢?我们都知道Android是基于Linux系统进行演变过来的,所以理应也能直接使用Linux的IPC通信方式。

所以在理解Binder的设计初衷之前,我们先来了解一下Linux系统中现有的IPC通信方式。

Linux现有的IPC通信方式有6种:

  1. 管道
  2. 信号量
  3. 信号
  4. 共享内存
  5. 消息队列
  6. socket

管道

英文为pipe,在Linux中它的本质是一个文件系统,通过一个进程以写的方式打开文件,另一个进程以读的方式进行打开文件,通过这样读写的方式,实现了进程间的通信。

只不过该文件是位于Linux内存中,所以操作管道就是以文件的方式操作Linux内存缓存区。

同时管道还有大小限制,默认为4k,一旦写入端超过大小限制,管道将会阻塞。

信号量

主要作用于进程间的资源互斥访问,通过PV两种操作等待与发送信号。

P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

所以信号量主要是用来解决多个进程对同一资源的竞争问题,类似于多线程的同步锁。

信号

Linux中定义的一种软中断,有64种,分为可靠信号与不可靠信号,多用于消息传递与通知,不适合传递信息。

共享内存

共享内存顾名思义,允许不同的进程访问同一块内存地址空间,它也需要进行两次数据拷贝操作,分别是将数据拷贝到共享内存中,又从共享内存中间将数据拷贝出来。

但需要注意的是,共享内存是不提供同步机制。

意思就是说,在其中一个进程进行写操作时,并不能放在另一进程进行读操作。

为了解决这个问题,共享内存一般都与前面说的信号量一起使用。

消息队列

消息队列通过一个进程向另一个进程发生消息块的方式进行通信,它与管道非常类似,都需要发送与接收,数据拷贝两次。

不同点是

  1. 消息队列可以防止同步与阻塞问题。
  2. 消息队列的接收方可以进行选择性接收。
  3. 发送的消息块有最大限制

socket

Linux中的socket是基于C/S架构的,传输效率低,多用于跨网络与跨设备的通信。

在Android底层使用socket来进行init与zygote等进程间的通信。

最后简单的来看一张图来了解在Linux中不同进程中的通信过程。

所以通过上面的分析,Linux现有的几种IPC通信方式都不是很适合Android间的进程通信。

例如管道、共享内存与消息队列都需要拷贝两次数据,同时有的还会存在阻塞与同步问题;另外的信号、信号量与socket由于使用场景的原因,都不适合用于Android中快速的进程间的数据通信。

Binder

那么Binder通信方式是怎么样的呢?

Binder本身是基于C/S架构的,层次分明,架构稳定,同时Binder内部只需使用一次数据拷贝操作,就能达到进程间数据的通信;另外Binder还支持鉴别用户进程的Uid,为Android提供身份的验证。

我们先来通过一张图来简单看下基于Binder的进程通信过程

Binder数据通信流程是,将数据从client端拷贝到内核空间,在内核空间中会提前通过mmap方式建立与server端的内存地址映射,通过内存地址映射server端可以直接访问内核空间中的数据,从而避免将数据拷贝到server端,提高进程间的通信速度。

在整个通信的过程中主要做的事情是:

  1. 通过/dev/binder打开binder驱动
  2. 通过mmap建立内存地址映射
  3. 通过ioctl与binder驱动交互,进行数据传输
  4. client使用BpBinder的transact方法进行事务请求
  5. server使用BBinder的onTransact方法来接收相应的事务

由于Android中主要使用Binder来进行service的注册与获取,所以为了更好的管理service的注册,使用了ServiceManager来进行统一管理service的注册。

在service的注册过程中ServiceManager就相当于server端,内部开启loop循环,不断接收消息将注册的service保存到注册表svclist中。

最终关于Binder的整个大致流程如下图所示

其中client与server位于应用层,ServiceManager位于用户空间,binder驱动位于内核空间。

对于开发者来说,用户空间与内核空间是透明的,我们只需关注应用层client与server的实现,就可以方便的使用Binder的通信机制。

以上是对Binder的一个理论分析,接下来的一段时间,我将结合源码来分析service的注册过程,从而探索Binder的整个工作流程,感兴趣的读者可以关注一下。

推荐

android_startup: 提供一种在应用启动时能够更加简单、高效的方式来初始化组件,优化启动速度。不仅支持Jetpack App Startup的全部功能,还提供额外的同步与异步等待、线程控制与多进程支持等功能。

AwesomeGithub: 基于Github的客户端,纯练习项目,支持组件化开发,支持账户密码与认证登陆。使用Kotlin语言进行开发,项目架构是基于JetPack&DataBinding的MVVM;项目中使用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。

flutter_github: 基于Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。

android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。

daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。

支持一下
赞赏是一门艺术