Android 进阶——Binder IPC之学习Binder IPC架构及原理概述(十二)

文章大纲

  • 引言
  • 一、Binder IPC 基础架构
    • 1、Binder IPC核心角色
    • 2、Binder IPC的数据流
  • 二、Binder IPC 协议通信流程
  • 三、Binder IPC 核心角色详解
    • 1、Server 进程及Server 组件
    • 2、Client进程及Client组件
    • 3、Service Manager 与实名 Binder
    • 4、Binder 驱动
  • 四、Binder 通信过程
  • 五、开发使用Binder
      • 1、注册服务
      • 2、获取服务
      • 3、使用服务
    • 4、Server进程根据Client进要求 调用 目标方法(即加法函数)
      • 4.1、 收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
      • 4.2、 将结算结果返回到Binder驱动
      • 4.3、Server进程 将目标方法的结果(即加法后的结果)返回给Client进程

引言

前面几篇文章,为我们学习Binder IPC通信机制提供了扎实的理论基础,接下来将正式进入Binder IPC通信架构及原理的解读。

在这里插入图片描述

一、Binder IPC 基础架构

Binder 是基于 C/S 架构的,由一系列的组件组成,包括 Client进程、Server进程、Service Manager进程、Binder 驱动。其中 Client进程、Server进程、Service Manager进程运行在用户空间,互相隔离,而Binder 驱动运行在内核空间。因此Client进程、Server进程、Service Manager 进程间的交互必须通过Binder驱动(系统调用 open、mmap 和 ioctl 函数来访问设备文件 /dev/binder,实现与 Binder 驱动的交互来间接的实现跨进程通信),而非直接交互的原因是,**因为Client进程、Server进程、Service Manager进程属于进程空间的用户空间,不可进行进程间交互,而Binder驱动属于进程空间的内核空间,可进行进程间(进程内)直接交互。**Binder IPC中的每一个Client、Server进程都各自独立维护着一个Binder线程池来处理IPC请求,因此Server、Client 进程都可以并发地发出IPC请求和响应IPC请求。

Server Manager进程与Binder驱动的交互也是通过Binder实现的。
在这里插入图片描述

1、Binder IPC核心角色

由上图可知Binder IPC 主要参与角色有五种:

角色说明参与对象
Client进程Binder服务的使用者Binder 代理对象
Server进程Binder服务的供应商Binder本地对象
Service Manager进程Binder服务的管理者,负责把Binder的名称到引用对象的转换,类似DNS的功能\
Binder驱动实现各种Binder的底层交互和管理,类似路由器。Binder实体对象、Binder引用对象(实体的引用)

Server 进程启动时主动向Binder驱动发起注册自己的Service组件IPC请求,然后Binder驱动响应IPC请求并转发该请求给Service Manager进程,再由Service Manager进程注册管理该Service 组件,于是Service Manager进程拥有了对应Server进程的信息(即完成了服务注册)。当Client 进程向Service Manager进程发起携带服务唯一标识的获取服务IPC请求时,再次由Binder驱动响应并转发给Service Manager进程Service Manager进程根据注册信息找到对应的服务对象,交由Binder驱动返回给Client

2、Binder IPC的数据流

在这里插入图片描述

二、Binder IPC 协议通信流程

Client进程和Server进程的一次IPC 流程可以从整体通信上分为五个步骤:

步骤说明
1Client 将通信数据封装为Parcel对象并传递到Binder驱动
2Client向Binder驱动发送BC_TRANSACTION_COMPLETE协议,Binder驱动根据协议内容找到目标Server进程后回复一个BR_TRANSACTION_COMPLETE告知Client其通信请求已被接受,Client接到BR_TRANSACTION_COMPLETE并处理后,会再次进入到Binder驱动程序中等待Server进程的响应结果
3Binder驱动在给Client回复一个BR_TRANSACTION_COMPLETE的同时,向目标Server进程发送一个BR_TRANSACTION返回协议,请求目标Server进程处理这个IPC请求
4Server进程接受BR_TRANSACTION并处理后,给驱动回复一个BC_REPLY协议,驱动根据协议内容找到目标Client进程后再次向Server进程发送一个BR_TRANSACTION_COMPLETE返回协议,告知Server已接到返回的相应结果,Server接到并处理了BR_TRANSACTION_COMPLETE协议后,一次IPC流程就结束了,接着会重新进入到驱动程序中等待下一次IPC请求
5Binder驱动在给Server进程发送BR_TRANSACTION_COMPLETE的同时,也会向目标Client进程发送一个BR_REPLY返回协议,代表Server进程已经处理完成IPC请求了并将结果返回给Client

从具体对象来看,一次Binder IPC (即Binder库 与 Binder 驱动的交互)需要至少五种核心对象参与:BpBinderBBinderBinder实体对象Binder代理对象Binder驱动程序。核心流程为BpBinder——>Binder引用对象——>Binder实体对象——>BBinder——>Binder 事务

在这里插入图片描述

步骤说明
1Client进程里的Binder代理对象在向Binder驱动中的Binder引用对象发起IPC请求,Binder驱动根据Client进程传入过来的Binder 代理对象的句柄值(BpBinder中的mHandle)找到目标Binder引用对象
2Binder驱动再根据Binder引用对象寻找对应的Binder实体对象并创建一个Binder事务,封装此次IPC请求。
3Binder驱动在根据Binder实体对象找到运行在Server进程的Binder本地对象,将Client进程发送的IPC请求携带的数据交给Binder本地对象处理。
4Binder本地对象在Server进程继续处理IPC请求,处理完成后将结果返回到Binder驱动Binder驱动把结果封装到步骤2创建的Binder事务中。
5Binder 驱动最后根据Binder事务的相关属性,找到发出IPC请求的Client进程,并通知Client进程把结果返回给Binder代理对象处理。

在浏览器输入一个域名地址http://www.xxx.com 按下回车后,因为不能直接通过域名找到目标服务器,接着访问 DNS 域名服务器(保存了域名和IP的映射)筛选出目标服务器,然后通过这个 ip 地址才能放到到 http://www.xxx.com 对应的服务器。

三、Binder IPC 核心角色详解

1、Server 进程及Server 组件

Server 进程运行于进程空间内的用户空间,作为Binder服务的供应商,Server组件启动时通过Binder驱动主动把自己注册到Server Manager进程之中(即主动建立binder服务名称和Binder引用对象的映射),方便Client随时通过Server Manager进程获取相应的Binder代理对象进而得到使用其服务提供的能力。

同一个Server进程可以同时运行多个Server组件(即提供Binder服务的代码模块),同一个Client进程也可以同时向多个Server 组件发起IPC 请求,每一个请求对应一个Client组件(或者成为Server代理),
在这里插入图片描述

2、Client进程及Client组件

Client进程是Binder服务的使用者,使用时通过Service Manager 进程通信获取Binder(本地对象的)代理对象,通过Binder代理对象经过Binder驱动去向Server进程发起IPC请求。

3、Service Manager 与实名 Binder

运行于用户空间的Service Manager守护进程是提供Binder服务的查询功能,根据注册时的Binder服务名称就能返回其对应的Binder引用对象,对于Binder服务通常是有一个唯一的字符串名称,主要想Servive Manager 注册了,应用就可以通过这个字符串名称来得到对应的Binder 引用对象,而Service Manager进程也是通过Binder IPC与其他进程进行通信的,至于实现细节后续再表,其作用就类似于DNS功能。

4、Binder 驱动

**Binder 驱动运行于内核空间,是整个Binder IPC的核心(由Android系统内核实现),Binder驱动实现open、mmap和ioctl系统调用,完成内核空间和用户空间缓存的映射以及对缓存和Server组件的管理。**包括不限于负责进程之间 Binder 通信的建立,Binder 在进程之间的传递,Binder对象生命周期管理(采用引用计数计数),数据包在进程之间的传递和交互等一系列底层支持,类似网络通信中路由器的功能。Server进程与Client进程的通信都需要依赖Binder驱动间接完成,Binder驱动抽象了一个虚拟设备文件dev/binder/并向用户空间暴露,使得应用程序进程可以通过它间接建立通信通道。

四、Binder 通信过程

在这里插入图片描述

BC_XXX代表用户空间的进程发送给Binder驱动的命令,而BR_XXX是Binder驱动返回给用户空间进程的命令。

至此,我们大致能总结出 Binder 通信过程:

  1. 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
  2. Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表。
  3. Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。

我们看到整个通信过程都需要 Binder 驱动的接入。下图能更加直观的展现整个通信过程(为了进一步抽象通信过程以及呈现上的方便,下图我们忽略了 Binder 实体及其引用的概念):

Binder驱动,通过虚拟出的物理设备(/dev/binder),连接Service进程、Client进程与Service Manager进程
在这里插入图片描述

五、开发使用Binder

Binder驱动、Service Manager进程属于Android基础架构是系统已经实现的,Client进程、Server 进程属于Android应用层需要开发者自己实现。跨进程通信时,开发者只需自定义Client、Server进程并显式使用上述3个步骤(注册服务,获取服务,使用服务),最终借助Android的基本架构功能就可完成进程间通信。

  • Binder机制在 Android中的实现主要依靠 Binder类,其实现了IBinder接口
  • 用一个应用Binder的实例来介绍怎么显式使用注册服务,获取服务,使用服务完成进程间通讯
    Client进程通过Server进程实现加法函数(两个整数相加) 。

主要步骤分解:

  • Client进程将两个整数传给Server进程
  • Server进程将相加之后的结果返回给Client进程

1、注册服务

Server进程通过Binder驱动向ServiceManager进程注册服务

    sp<ProcessState> proc(ProcessState::self());sp<CalcService> service = new CalcService();sp<IServiceManager> sm = defaultServiceManager(); sm->addService(“CalcService”, service);ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();

1.ProcessState::self()调用ProcessState的构造函数,创建一个实例,该操作打开binder驱动,并进行mmap函数,映射出binder驱动对应的映射内存缓冲区
2.创建CalcService实例,加法函数是CalcService的一个方法
3.获取一个ServiceManager对象BpServiceManager
4.调用BpServiceManager的addService方法,将服务(CalcService)注册到Service Manager
5.创建线程池
6.加入线程池,执行主线程和工作线程
注册服务后,Binder驱动持有 Server进程创建的Binder实体

2、获取服务

  • Client进程使用某个service前(此处是CalcService),需通过Binder驱动向ServiceManager进程获取相应的Service信息
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(“CalcService”);
    sp<ICalcService> calcService = interface_cast <ICalcService>(binder);
    
    1.获取一个ServiceManager对象BpServiceManager
    2.调用BpServiceManager的getService方法,根据服务名(“CalcService”)获取到ServiceManager管理的IBinder
    3.通过interface_cast调用asInterface()函数,返回IBinder的客户端,通过该客户端与服务端通讯

此时,Client进程与Server进程创建了连接

3、使用服务

Client进程根据获取到的Service信息(Binder代理对象),通过Binder驱动建立与该Service所在Server进程通信的链路,并开始使用服务

  • Client进程将参数(整数a和b)发送到Server进程

  • Server进程根据Client进程要求调用目标方法(即加法函数)

  • Server进程将目标方法的结果(即加法后的结果)返回给Client进程

  • Client进程将参数(整数a和b)发送到Server进程

status_t myAdd(int a, int b, String8& result)
{Parcel data, reply;data.writeInterfaceToken("CalcService");data.writeInt(a);data.writeInt(b);remote()->transact(CALC_ADD, data, &reply);//status_t ret = reply.readInt32();//String8 tempResult = reply.readString8();//result.setTo(tempResult);//return ret;	
}

1.目标参数与接口标识赋值
2.调用代理对象BpInterface的transact()将上述数据发送到Binder驱动

transact(CALC_ADD, data, reply, 0)
// 参数说明:
// 1. CALC_ADD:目标方法的标识符(Client进程和Server进程自身约定,可为任意)
// 2. data :上述的Parcel对象
// 3. reply:返回结果
// 0:可不管
// 注:在发送数据后,Client进程的该线程会暂时被挂起,若Server进程执行的耗时操作,请不要使用主线程,以防止ANR

3.Binder驱动根据代理对象找到对应的真身Binder对象所在的Server 进程(系统自动执行)
4.Binder驱动把数据发送到Server进程中,并通知Server 进程执行解包(系统自动执行)

4、Server进程根据Client进要求 调用 目标方法(即加法函数)

4.1、 收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法

   status_t BnCalcService::onTransact(int code, Parcel data, Parcel reply, int flags){// code即在transact()中约定的目标方法的标识符switch (code) { case CALC_ADD: { String8 tempResult;//获得目标方法的参数int arg0 = data.readInt();int arg1 = data.readInt();//调用服务端方法进行计算status_t ret = myAdd(arg0, arg1, tempResult);//将计算结果写入到reply返回reply->writeInt32(ret);reply->writeString8(tempResult);return NO_ERROR;			}}}

4.2、 将结算结果返回到Binder驱动

4.3、Server进程 将目标方法的结果(即加法后的结果)返回给Client进程

  1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
  2. 通过代理对象 接收结果(之前被挂起的线程被唤醒)
   status_t ret = reply.readInt32();String8 tempResult = reply.readString8();result.setTo(tempResult);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/137455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatis嵌套查询子集合只有一条数据

我们再用mybatis做嵌套查询时&#xff0c;有时会遇到子集合只有1条数据的情况&#xff0c;例如下这样&#xff1a; 数据库查询结果 xml <resultMap id"userMap" type"com.springboot.demo.test.entity.User"><id column"uid" property…

Leetcode150. 逆波兰表达式求值

Every day a Leetcode 题目来源&#xff1a;150. 逆波兰表达式求值 解法1&#xff1a;栈 用栈模拟逆波兰表示法表示的算术表达式的计算过程。 初始化一个栈 stk。 遍历字符串数组 tokens&#xff0c;根据当前字符串 token 决定操作&#xff1a; 若 token 是 1 个算符&am…

基于JavaWeb+SSM+Vue微信小程序校园兼职任务平台系统的设计和实现

基于JavaWebSSMVue微信小程序校园兼职任务平台系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 随着社会的发展和全球疫情的冲击&#xff0c;大学生的就业形势越来越严峻。越…

基于FPGA的模板匹配红外目标跟踪算法设计

为什么要写这篇文章 我写这篇文章的原因是一天在B站看到了一个大神发的视频是关于跟踪一个无人机的&#xff0c;看到作者跟网友的回复说是用的图像匹配算法&#xff0c;我就在网上搜索相关资料&#xff0c;最终找到一篇文献。文献中对该算法的评价很高&#xff0c;满足制导系统…

【第2章 Node.js基础】2.3 Node.js事件机制

2.3 Node.js事件机制 学习目标 &#xff08;1&#xff09;理解Node.js的事件机制&#xff1b; &#xff08;2&#xff09;掌握事件的监听与触发的用法。 文章目录 2.3 Node.js事件机制什么是事件机制为什么要有事件机制事件循环事件的监听与触发EventEmitter类常用API 什么是…

利用IP风险画像强化金融行业网络安全防御

在数字化时代&#xff0c;金融行业日益依赖互联网和技术创新&#xff0c;但这也使得金融机构成为网络攻击的主要目标。为了应对日益复杂的网络威胁&#xff0c;金融机构迫切需要采用先进的安全技术和工具。其中&#xff0c;IP风险画像技术成为提升网络安全的一项重要策略。 1.…

C语言C位出道心法(五):内存管理

C语言C位出道心法(一):基础语法 C语言C位出道心法(二):结构体|结构体指针|链表 C语言C位出道心法(三):共用体|枚举 C语言C位出道心法(四):文件操作 C语言C位出道心法(五):内存管理 一:C语言内存管理认知 二:C语言中内存堆|栈认知 三:C语言中引用内存丢失认知

ClickHouse介绍和使用

ClickHouse介绍和使用 1. 简介2. ClickHouse特点3. 数据类型3.1. 整型3.2. 浮点型3.3. Decimal型3.4. 布尔型3.5. 字符串3.6. 枚举类型3.7. 时间类型 4. 表引擎4.1. TinyLog4.2. Memory4.3. MergeTree4.3.1. partition by分区&#xff08;可选&#xff09;4.3.2. primary key 主…

项目管理之如何出道(下)

前言 是谁用烛火照亮整个中国&#xff1f;是一伙伙行走在高压线上的电力工人&#xff1b; 是谁用水枪保护千家万户&#xff1f;是一组组穿梭于大街小巷的消防队伍&#xff1b; 是谁用身体捍卫国防边境&#xff1f;是一队队跋涉在高山深林的可爱战士。 那么作为IT业界的我们&…

Python语法基础(变量 注释 数据类型 输入与输出 运算符 缩进)

目录 变量变量命名规则变量的类型变量的创建变量的作用域 注释的方法数据类型对象和引用的概念Number(数字)数据转换 输入与输出输入函数输出函数输出函数的end参数输出格式多行语句 运算符算术运算符赋值运算符三目运算符运算符的优先级 缩进缩进格式注意事项层级嵌套 变量 标…

(论文阅读24/100)Visual Tracking with Fully Convolutional Networks

文献阅读笔记&#xff08;sel - CNN&#xff09; 简介 题目 Visual Tracking with Fully Convolutional Networks 作者 Lijun Wang, Wanli Ouyang, Xiaogang Wang, and Huchuan Lu 原文链接 http://202.118.75.4/lu/Paper/ICCV2015/iccv15_lijun.pdf 【DeepLearning】…

Python--- lstrip()--删除字符串两边的空白字符、rstrip()--删除字符串左边的空白字符、strip()--删除字符串右边的空白字符

strip() 方法主要作用&#xff1a;删除字符串两边的空白字符&#xff08;如空格&#xff09; lstrip() 方法 left strip&#xff0c;作用&#xff1a;只删除字符串左边的空白字符 rstrip() 方法&#xff0c;作用&#xff1a;只删除字符串右边的空白字符 strip 英 /strɪp…

STM32H743XX/STM32H563XX芯片烧录一次后,再次上电无法烧录

近期在使用STM32H563ZIT6这款芯片在开发板上使用正常&#xff0c;烧录到自己打的板子就遇到了芯片烧录一次后&#xff0c;再次上电无法烧录的问题。 遇到问题需要从以下5点进行分析。 首先看下开发板的原理图 1.BOOT0需要拉高。 2.NRST脚在开发板上是悬空的。这里我建议大家…

基于AI智能分析网关的智慧视频监控系统一站式解决方案

1、功能概述 TSINGEE智能分析网关EasyCVR智慧视频监控系统基于云-边-端一体化协同架构&#xff0c;可兼容多协议、多类型的设备接入&#xff0c;实现视频数据采集、海量视频汇聚与处理、按需调阅、全网分发、 告警消息推送、数据级联共享、AI智能分析接入等视频能力服务&#…

合并两个有序链表OJ

合并两个有序链表OJ 文章目录 合并两个有序链表OJ一、题目及要求二、思路分析三、代码实现 一、题目及要求 二、思路分析 其次&#xff0c;题目里说了新链表是通过拼接原来的结点形成的&#xff0c;所以说我们不需要开辟新的空间。 三、代码实现 if (list1 NULL) {return li…

Zotero详细功能补充!熟练使用!【进阶版,持续更新】

Zotero安装请参见文章Zotero安装 1.改变条目文件夹 如果直接选择条目直接进行移动&#xff0c;能移动成功&#xff0c;但是原来文件夹和目标文件夹都会存在&#xff0c;实际是复制&#xff01; 如果只想保留在一个文件夹里面&#xff0c;可以选中条目&#xff0c;右击-从分…

ARMday03(寄存器读写、栈、程序状态寄存器、软中断和异常、混合编程)

单寄存器内存读写指令 将一个寄存器中的数值写入到内存&#xff0c;或者从内存中读取数据放在某一个指定寄存器中 指令码和功能 1.向内存中写&#xff1a; str{条件码} 目标寄存器,[目标地址]&#xff1a;将目标寄存器的4字节数值写入到目标地址为首地址的空间中 strh{条件码…

最新AI系统ChatGPT源码+AI绘画系统源码+支持GPT4.0+Midjourney绘画+搭建部署教程+附源码

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

CSRF(跨站请求伪造)攻击演示

目录 CSRF(跨站请求伪造)攻击演示CSRF 是什么CSRF 演示项目代码CSRF 演示过程服务启动演示 CSRF(跨站请求伪造)攻击演示 CSRF 是什么 CSRF&#xff08;Cross-Site Request Forgery&#xff09;跨站请求伪造&#xff0c;是一种网络安全攻击&#xff0c;其目标是利用被攻击者在…

软件安全测试怎么做?如何确保软件授权安全

在数字化不断演进的今天&#xff0c;软件安全测试变得至关重要。它验证了软件是否容易受到网络攻击&#xff0c;并检验恶意或意外输入对操作的影响。安全测试的目标是保障系统和信息的安全性和可靠性&#xff0c;确保它们不接受未授权的输入。 一、安全测试准备 开发者必须认识…