一篇文章搞定《理解Binder跨进程通信》

前言

Binder我称之为Android的老母亲
作为Android的重中之重,前面的《JVM完美图解》和《MMKV原理解析》都是铺垫啊兄弟们
一直不敢写这个Binder的文章,但是为了一篇文章系列比较完整,还是写一下,也当算是一次全面的复习。
本篇文章结构:

  • 什么是Binder(列举Android的常见的使用到Binder的)
  • 基础知识储备
  • Binder模型图解
  • 对比其他IPC机制的优点

什么是Binder

Binder是Android中的一种进程间通信(IPC)机制,用于实现不同进程之间的通信。
贯穿了我们整个Android体系:简单来说Binder是跨进程通信方式、它实现了IBinder接口,是连接各个Service、Manage和组件的桥梁。
比如:

  • AIDL
  • Activity的启动流程

其实呢这些只不过是我们的一些遇到的场景,真正使用到Binder是我们的Android框架的Service和Manager们

  • ActivityManagerService:它负责管理和调度应用程序的生命周期、进程管理、任务管理等。它使用了Binder机制进行进程间通信,与其他组件和系统服务进行交互。
  • PackageManagerService:是Android系统的一个组件,负责应用程序的安装、卸载、应用程序信息查询和管理。它使用了Binder机制与ActivityManagerService等组件进行通信和管理。通过Binder机制,PackageManagerService可以接受来自其他组件的请求,处理应用程序的安装和卸载,并提供应用程序的信息查询服务。
  • WindowManagerService:是Android系统的一个组件,负责窗口的添加、移除和管理、窗口的层级管理等。它也使用了Binder机制与其他组件进行通信,并与ActivityManagerService一起工作以管理应用程序的任务和窗口。通过Binder机制,WindowManagerService可以接收ActivityManagerService的指令,管理应用程序的窗口、任务切换等操作。
  • ActivityThread:是Android系统的核心组件之一,负责应用程序的启动、Activity的管理以及与ActivityManagerService的通信等。它也使用了Binder机制与ActivityManagerService进行通信,例如向ActivityManagerService发起启动Activity的请求、接收Activity生命周期的回调等。ActivityThread通过Binder机制与ActivityManagerService交互,协调应用程序的运行和Activity的管理。
  • ServiceManager:是Android系统的一个组件,用于进程间的服务发现和管理。它使用了Binder机制,为应用程序提供了许多系统服务的访问入口。应用程序可以通过ServiceManager获取系统服务的实例,并通过Binder机制与这些系统服务进行通信。
    这些包括ActivityManagerService、PackageManagerService、WindowManagerService、ActivityThread和ServiceManager都是Android系统的核心组件,它们通过Binder机制进行进程间通信,实现了不同组件之间的协作、应用程序的管理以及系统服务的访问和管理。Binder机制为Android系统提供了高效且安全的进程间通信能力。

基础知识储备

进程空间划分

一个进程空间分为 用户空间 & 内核空间,即把进程间用户隔离开来,再利用内核空间进行交互(这是一种常见内存隔离)

  • 用户空间:因为我们的APP都运行在我们的独立的APP进程中。所以你可以把APP想做成一个用户空间。两个用户空间数据不共享(也就是不可共享空间)
  • 内核空间:它是操作系统内核代码和数据的存放区域。内核空间的数据可共享。(也就是可共享空间)
  • 所有的进程都使用同一个内核空间
  • 传统的IPC通信过程如下
    在这里插入图片描述
  1. copy_from_user():将用户空间的数据拷贝到内核空间
  2. copy_to_user():将内核空间的数据拷贝到用户空间

可以看到:为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android中的APP的进程是相互独立、隔离的
如果想通信的话,需要借助内核空间进行IPC通信。

IPC通信

那Linux系统提供给我们的一些IPC通信有:

  • 共享内存(Shared Memory):共享内存是一种在多个进程之间共享存储区域的机制,进程可以通过读写共享内存来进行通信。
  • 套接字(Socket):套接字是一种在网络中进行进程间通信的机制,通过套接字可以在多台主机之间进行通信。
  • 管道(Pipe):管道是一种半双工的、基于内存的通道,可以用于父进程与子进程之间的通信。
  • 信号(Signal):信号是一种异步的通信机制,用于在进程之间传递通知和中断信息。
  • 信号量(Semaphore):信号量是一种用于进程之间同步和互斥的机制,可以用来保护共享资源的访问。
  • 消息队列(Message Queue):消息队列是一种在进程之间传递数据的机制,进程可以将消息发送到队列中,其他进程可以从队列中接收消息。

后面我们进行对比时会对此进行一些IPC的过程进行图解说明

Binder模型图解

上面说了很多的IPC的通信机制。
其实Binder不是正常的Linux的通信方式,他是Android操作系统中的进程间通信。
但是Android又是基于Linux内核开发,所以可以认为Binder也是Linux的一种IPC通信机制。

Binder通信过程

我们先来说说Binder是如何通信的吧。直接上图
在这里插入图片描述
可以看到相对于上面的传统IPC通信方式,少了一次CPU的copy过程。
发送数据工作流程:(在图中也有标识)

  • 1、Binder驱动创建一块接收缓存区
  • 2、实现地址映射关系:通过mmap创建内核空间和用户空间的映射(在MMKV中也有讲到)
  • 3、发送进程通过CPU拷贝(copy_from_user)发送数据到虚拟内存区
  • 4、内核空间中的空间映射
  • 5、因为mmap的映射关系,Binder的缓存区,相当于接受进程的用户空间,从而实现通信。

返回结果流程:(没有在图中标识,相信大家可以想到)

  • 1、因为mmap映射,所以接受进程返回结果到Binder缓冲区
  • 2、内核空间的空间映射
  • 3、通过CPU拷贝(copy_to_user)发送数据给发送进程

Binder的C/S模型

上面说的Binder的通信方式,他只是我们Binder模型中最重要的一环。接下来看看整个的Binder模型吧!!
Binder 跨进程通信机制模型基于Client - Server模式
说明:

  1. Client进程、Server进程 & Service Manager进程属于进程空间的用户空间,不可进行进程间交互
  2. Binder驱动 属于 进程空间的 内核空间,可进行进程间 & 进程内交互
    老样子先上图:(下一篇文章会用AIDL完整的实例这个图)
    在这里插入图片描述
  • Client进程:使用服务的进程。(Android的客户端)
  • Server进程:提供服务的进程。(Android服务进程)
  • ServiceManager进程:管理Service注册和查询(相当于一个表管理了Serve和Client对Binder的引用)
  • Binder驱动:上面的Binder通信。(mmap映射通信)
  • Binder模型的线程管理 采用Binder驱动的线程池,并由Binder驱动自身进行管理,一个进程的Binder线程默认最大16个,所以在ContentProvider他的CRUD方法只能同时有16个线程同时工作。

用文字的形式说明一下上面的过程:
1、注册服务(ServiceManager进程拥有了Server进程的信息)

  • Server进程向Binder驱动发起服务注册请求
  • Binder驱动将注册请求转发给ServiceManager
  • Service Manager进程添加Server进程信息

2、获取服务(此时不仅ServiceManager拥有了Client进程信息,也与Server建立起了联系)

  • Client向Binder驱动发起获取服务的请求,传递要获取的服务信息
  • Binder驱动将请求转发给ServiceManager
  • ServiceManager找到Client的服务请求对应的Server的服务信息
  • Binder驱动将找到的服务信息返回给Client进程

3、使用服务

  • 这时候建立起联系了就可以通过上面我们的Binder通信过程,开始使用我们的服务,进行发送进程->接受进程的通信过程。
  • 把图粘贴过来吧,方便看。就是下面的这个过程了。
    在这里插入图片描述

对比其他IPC机制的优点

性能上:

  • 传统的管道、消息队列、Socket都是需要copy两次的:copy_from_user 、 copy_to_user
  • Binder通过mmap机制让数据拷贝只copy一次,因为CPU的copy是消耗性能,这让Binder的性能更高一些
  • 共享内存的效率最高:他会在内核空间开辟一块两个进程的共享内存段,之后两个进程都可以操作这个进程段(那么有同学问了:那为什么不用共享内存,因为安全性不好往下看)

安全上:

  • 共享内存没有安全性的:需要在上层自己去控制安全性,因为两个进程操作的是同一块内核内存块。没有什么安全控制,随意的被别人入侵。(需要上层去控制访问权限、和同步机制)
  • 传统的IPC通信,身份都可造假比如:Socket的通信ip是客户端手动填入
  • Binder机制:每个进程都有UID/PID作为身份的标志。之后在通信时对身份进行验证后通信。安全性很高。

使用上:

  • Binder使用C/S结构,使用Binder像使用一个对象一样简单。

总结

Binder的内容需要看源码、实战来精通。
但是本文的入门是Android程序员必须要会的。

猜你喜欢

转载自blog.csdn.net/weixin_45112340/article/details/131841774