Binder机制原理

article/2025/10/29 0:36:18

前言

本篇文章记录本人对Binder的学习,因为本人能力有限,若有错误,还请批评指正。
binder的使用文章推荐

1.Binder是什么?

  • 可以理解是为Android的血管。是一种进程间通信的机制。比如Activity,Service需要和AMS通信的时候,就需要Binder。
  • 除了进程间通信,也可以把Binder理解为一种虚拟物理设备驱动。虚拟表示没有实体,和键盘鼠标不一样。Binder是虚拟的。因为mmap映射时将虚拟内存映射到/dev/binder文件,在linux中这个代表一个驱动,所以说它是一种虚拟物理设备驱动。
  • 除此之外,在应用层,也可以把Binder理解为一个是一个能发起进程间通信的Java类,实现了IBinder接口。除此之外,AIDL中的Stub,Proxy也实现了IBinder,还有AMS等也实现了IBinder。另外在ServiceManager中查找服务时,所用到的Map集合的value也是IBinder类型的。

综上所述,Binder可以说是:
①进程间通信的机制
②虚拟物理设备驱动
③一个能发起进程间通信的Java类

2.为什么是Binder?

Linux也有一些很优秀的进程间通信机制,例如管道,消息队列,共享内存,socket等,但是为什么Android使用Binder而不是这些呢?
看Binder与共享内存,socket的对比

参考指标Binder共享内存socket
性能上需要拷贝1次需要拷贝0次需要拷贝2次
架构上C/S架构,很稳定,且易用难以控制,易用性差C/S架构(但是是一款通用的接口,传输效率低,开销大)
安全性上(最重要)①为每个APP分配UID②支持实名和匿名访问不分配UID,访问接入点是开放的,不安全不分配UID,访问接入点是开放的,不安全

解释下这幅图:

2.1 拷贝次数

(1)传统的IPC通信(两次拷贝)
基础知识:内存被操作系统划分成了两块:用户空间和内核空间,用户空间是用户程序代码运行的地方,内核空间是内核代码运行的地方,为了安全,它们是隔离的。即使用户的程序崩溃了,内核也不受影响。同时,内核空间映射到物理内存中是一块的,而用户空间,不同进程映射到的物理内存不一样。(所以内核空间的数据是共享的,从下面的图也可以看出来)
我们软件工程师所说的内存一般都是虚拟内存。
在这里插入图片描述
下面是我自己画的图,描述了传统IPC的过程
在这里插入图片描述
当需要进程间通信时,数据会先从进程1的用户空间,通过系统调用copy_from_user进入内核空间,然后再通过系统调用copy_to_user进入进程2的用户空间,从而完成通信。

可以看到,传统的IPC需要两次拷贝,每次拷贝都需要系统调用,上下文切换。
(2)Binder通信(一次拷贝)
在这里插入图片描述
可以看到,数据也会先从进程1的用户空间到系统的内核空间,完成一次拷贝,但是进入系统内核空间后,进程2的用户空间的数据接收区和内核空间的那部分区域,能够映射到同一块物理空间。这样就不用发生copy_to_user的系统调用了,从而不用第二次拷贝。
用到了mmap,即内存映射。即内存上的空间可以映射到磁盘上的对应区域(操作系统学过)
(3)共享内存(0次拷贝)
在这里插入图片描述
可以发现,它把copy_from_user省略掉了,直接就是进程1和进程2能够共享同一块物理内存,不需要拷贝。这样看似效率很高,但是实则易用性很差。因为程序员的水平是参差不齐的。这个技术本身没有问题,有问题的是使用这个技术的人。所以我觉得Binder的一次拷贝是故意的,目的是提高易用性。后面的mmap是谷歌工程师完成的,我们只需要让服务类继承Binder,那么它就具有了进程间通信的能力了。至于具体的细节,谷歌工程师已经帮我们封装好了。但是因为客户端太灵活了,情况很多,难以统一,所以谷歌工程师不能帮我们实现客户端这边的封装。

2.2 架构

这个其实就是C/S架构的好处,客户端有什么需求就丢给服务器,解耦,很稳定。而且很易用(Binder需要拷贝一次,而不是零次,为的就是易用性更高),程序员只需要关心业务本身代码,无需过度关注进程通信细节。
而共享内存的话,需要面临一系列复杂的问题,比如访问的安全性,同步等问题。

2.3 安全性

这个要分两方面来说
①首先Binder为每个app分配了一串UID,这串UID是app的唯一身份标识。而共享内存,socket等都是app自己生成类似的这种编码,直接交给上层,上层只管接收,没有能力去甄别对错。假如有恶意软件伪装,那么是无法跟踪这个软件的。
②其次是支持实名访问和匿名访问。实名访问的话,和共享内存,socket是一样的,这样安全性较低。匿名访问安全性高,我们自己写的AIDL一般就是匿名访问。匿名访问类似于滴滴打车,打过来的手机号是虚拟的,并不是实际的,也就是一个代理对象。

区分实名访问和匿名访问的标准是,有无在ServiceManager注册过。注册过的就是实名,反之就是匿名。
比较常见的实名如AMS,WMS等

3.mmap介绍

3.1 mmap是什么?

mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read、write 等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

3.2 mmap实现的c++

在这里插入图片描述
同时,使用mmap一般都要创建文件,因为linux一切皆文件。

4.AIDL是什么?

关于AIDL的参考文章

(1)定义

AIDL全程是Android Interface Difination Language,即接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。目的就是实现进程间通信。
其实它就是一个模板,真正起作用的不是AIDL文件,而是编译后,根据AIDL文件生成的那个Interface类。

(2)AIDL文件编译后的组成

以这样的AIDL文件为例
在这里插入图片描述

此AIDL文件在编译后,会生成这样一个interface
在这里插入图片描述
TestAidl接口里面有两部分
一个是静态抽象内部类Stub,一个是接口待实现的方法add
其中,Stub又实现了TestAidl接口。但是又因为Stub是抽象类,所以不必实现add方法,add方法的具体实现在具体的服务类里面。也就是Stub的子类

下面来看一下Stub的组成
在这里插入图片描述
看起来有点乱,但其实可以分成以下几部分

抽象类Stub 继承Binder  实现TestAidl{①静态的asInterface方法{返回代理类(分两种情况:同进程,直接返回继承该StubBinder;不同进程,返回静态代理类)}②重写的onTransact方法③静态代理类Proxy  实现TestAidl{实现add方法,主动调用transact方法}}

①一个是asInterface方法,如果是同一进程的,则直接返回继承该Stub的服务端对象,如果不是同一进程,则构造一个代理类,由这个代理类,来间接操作这个服务端对象。
②一个是onTransact方法,此方法在客户端调用transact方法时调用。下图是onTransact方法的代码
在这里插入图片描述
code是方法的代码,是一个int类型,因为客户端和服务端都实现同一个接口,那么他们都会实现同一批方法(在这里就是add方法),那么就可以为这一批方法进行统一编序号,方便方法的匹配调用。
③还有一个是静态代理类,它是对服务端的代理。里面的代码如下
在这里插入图片描述
会发现它和Stub的代码很像。没错,其实它代理的就是Stub的实现类,所以这是正常现象。我们再看add方法,里面有两个Parcel类型的变量,分别负责接收发送的参数,接收返回的数据。这里面就有transact方法的调用,这里调用就会调用到onTransact方法。transactonTransact方法的四个参数分别表示的含义为:
①用于区分执行哪个方法
②客户端传递的参数
③服务器返回回去的值
④标明是否有返回值,0表示有,1表示没有

(3)AIDL进行进程间通信的流程

①客户端调用bindService,在onServiceConnected的回调方法中,调用StubasInterface方法,得到mRemote值。(如果是同一进程,直接返回服务端对象。如果是不同进程,返回代理对象)。这里假设是不同进程
②客户端调用mRemoteadd方法,因为是不同进程,所以调用代理对象的add方法。
add方法里面会调用transact方法,然后客户端阻塞直到方法执行完成,拿到返回值。
④客户端调用transact方法,会调用服务端StubonTransact方法,里面会执行Stub子类即具体服务类的add方法。


http://chatgpt.dhexx.cn/article/rmVaPZDe.shtml

相关文章

Binder机制(非常好理解)

Binder是一种进程间通信机制,用来实现不同进程之间的通信。 Binder机制主要由四大块组成,分别是客户空间的client、server,serverManager,还有内核的Binder驱动。 下面我先看下图,利于理解Binder内部工作机制&#x…

Android进程间通信之一:Binder机制学习

Binder机制学习 Binder驱动Binder核心APILinux 使用两级保护机制:0 级供系统内核使用,3 级供用户程序使用。 Linux 下的传统 IPC 通信原理Linux 下的传统 IPC 通信原理Binder通信过程ServiceManager进程启动MMAP Binder驱动 binder驱动在以misc设备进行注…

Android跨进程通信:图文详解 Binder机制 原理

前言 如果你接触过 跨进程通信 (IPC),那么你对Binder一定不陌生虽然 网上有很多介绍 Binder的文章,可是存在一些问题:浅显的讨论Binder机制 或 一味讲解 Binder源码、逻辑不清楚,最终导致的是读者们还是无…

操作系统实验五--存储管理

文章目录 操作系统实验五--存储管理一、实验目的二、实验内容三、设计原理及相关算法四、结果分析五、源代码 操作系统实验五–存储管理 一、实验目的 1、了解虚拟存储技术的特点,掌握请求页式存储管理的主要页面置换算法原理。 2、掌握请求页式存储管理中页面置…

操作系统实验—存储管理

操作系统实验—存储管理 所有实验源码: gitee:https://gitee.com/infiniteStars/os-project github:https://github.com/helloworldzsq/OSproject 1.实验内容 设计一个虚拟存储区和内存工作区,并使用下述方法计算访问命中率。 ①…

操作系统实验——磁盘调度算法

文章目录 前言一、实验目的二、实验内容和要求三、实验程序四、运行结果运行结果截图 五、思考和分析程序实现(思路):分析几种算法: 附 前言 提示:本次实验在Linux(Ubuntu)中运行,程序中读取的文件需放在与c文件同一个文件夹中&a…

北航操作系统实验入门

有北航操作系统实验平台账号的部分读者反映不会操作。为了让读者尽快了解实验平台的操作,下面介绍lab0的实验步骤,希望读者能尽快掌握实验平台的使用方法。 1. 用学生账号登录 2. 点击【操作系统实验】进入实验界面 3. lab0实验环境介绍,仔细…

操作系统实验三进程间通信

文末也可直接获取实验文档 实验三 进程间通信 目录 1实验目的2 实验内容3实验详细操作步骤及程序清单:4相关问题及思考5总结6背景知识 1实验目的 1、了解linux系统中进程通信的基本原理。 2、分析进程竞争资源现象,学习解决进程互斥的方法。 2 实验内…

操作系统实验——进程控制

操作系统实验——进程控制 预习内容: 1.进程的概念 ⑴程序的并发执行 ⑵进程的定义 2.进程的描述 ⑴进程控制块 ⑵进程上下文 ⑶进程上下文切换 ⑷进程空间与大小 3. 进程状态及其转换 ⑴进程状态 ⑵进程状态转换 4.进程控制 ⑴进程创建与撤销 ⑵进程的阻塞与唤醒…

操作系统实验一

操作系统实验一 进程调度算法 一、实验目的 1.理解操作系统进程管理中进行进程调度的过程和调度算法的思想原理; 创建进程控制块PCB,并合理组织就绪队列。 2.理解进程的状态及变化,动态显示每个进程的当前状态及进程的调度情况。 掌握几…

操作系统实验一·创建进程

创建进程 1实验目的2实验内容:2.1Windows实现2.2Linux实现 3实验环境3.1Windows3.2Linux虚拟机 4程序设计和实现4.1Windows实现4.1.1函数解释4.1.2程序代码4.1.3运行结果 4.2Linux实现4.2.1函数解释4.2.2程序代码4.2.3运行结果 Use system calls to implement a “m…

操作系统实验

实验一 命令解释程序 实验内容 利用C语言编写一个微型命令解释程序minishell.c,该程序可接收并解释以下命令: (1) dir 列出当前目录 (2) cop file1 file2 拷贝文件 (3) era filename 删除文件 (4) disp string 显示字符串 (5) end 结束,退出…

操作系统实验报告

操作系统 一、实验一 通过 VMware 虚拟机软件安装 Linux二、实验目的三、实验内容(实验原理/运用的理论知识、算法/程序流程图、步骤和方法、关键源代码)四、实验结果与分析五、小结与心得体会 一、实验二 Windows 进程管理二、实验目的三、实验内容&…

操作系统实验——银行家算法

文章目录 一、实验目的二、实验内容和要求三、实验原理算法实现 四、实验程序代码如下: 五、验证数据和运行结果运行结果截图 六、思考与分析附 一、实验目的 掌握银行家算法思想,并能编程实现。 二、实验内容和要求 1、在Linux环境下编译运行程序&am…

操作系统实验(进程调度)

操作系统实验(进程调度) 一、实验目的二、实验内容三、实验准备3.1优先权算法3.2时间片轮转调度算法 四、实验 一、实验目的 1.1理解有关进程控制块、进程队列的概念。   1.2掌握进程优先权调度算法和时间片轮转调度算法的处理逻辑。 二、实验内容 2.1…

【MFC】CCriticalSection类在Release编译下调用Lock函数会报0xC0000008错误

【MFC】CCriticalSection类在Release编译下调用Lock函数会报错0xC0000008 问题描述方法一 CRITICAL_SECTION代替CCriticalSection方法二 使用WaitForSingleObject和ReleaseMutex()结语 问题描述 通过以下伪代码方式描述问题: 主对话框类内创建成员变量及结构体变量…

联合使用类CCriticalSection和类CSingleLock同步线程

(1)新建一个控制台工程SellTicketTest2,并在向导的“应用程序设置”中勾选“MFC”。 (2)打开SellTicketTest2.cpp,在开头中引入头文件。 #include "afxmt.h"(3)添加变量&…

单独使用CCriticalSection对象来同步线程

(1)新建一个控制台工程SellTicketTest,并在向导的“应用程序设置”中勾选“MFC”,因为CCriticalSection属于MFC类,如图所示。 (2)在SellTicketTest.cpp开头中引入头文件。 #include "afx…

linux查看java线程死锁_ccriticalsection 多线程 死锁_c++ 线程死锁_linux 线程 死锁

qq_407283393122018-12-10 一个很蠢的造成死锁的问题 wanglt3113172018-12-12 什么是死锁,死锁的原因,如何避免 apanying902019-01-09 c3p0连接死锁 Cain_1507662016-09-20 notify产生死锁的场景(备忘) liuchuanyangyan9132017-02-23 C3P0配置错误导致的…

MFC线程同步—— CCriticalSection类使用

多个线程访问临界区时,可以使用临界区对象。临界区对象是一个独占性共享资源,任一时刻只有一个线程可以拥有临界区。拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线…