Binder机制原理、源码、AIDL,IBinder,Binder,IInterface,BinderDriver,需要的都在这里了

article/2025/9/2 9:17:03

导读:

本文分为三个阶段,

  • 第一阶段,原理概述,力争说人话的基础上,讲明白Binder机制在搞什么,为什么这样搞,以及具体是怎么搞的。
  • 第二阶段,代码层面描述,主要描述了,AIDL、IBinder、Binder、IInterface、Binder Driver是如何设计和实现第一阶段的构想。
  • 第三阶段,实例操作,不使用半自动的AIDL工具,纯手动利用Binder实现一把进程间通信。

相信这一套军体拳下来,应该能薛伟地掌握Binder的相关原理。

P.S. 本文code部分使用了伪代码,包含但不限于kotlin、java和汉字。。。不过应该都能看懂

Binder是Android系统用来实现高效IPC(进程间通信)所搭建的框架。在Android系统中的作用和他的名字一样,是像胶水一样,把系统各个服务进程粘合到了一起。

那么Android系统为什么要重新构建一个IPC框架呢?而不是直接使用Linux提供的IPC方案,类似管道,信号,socket等,首先是安全性的考量,这些Linux 原生IPC方案,都不能直接携带进程的信息,只能依赖上层的协议,比如socket是通过ip和端口来区分不同的进程,让伪造访问的难度降低,而Binder 的设计里是带有uid和pid来标识进程身份的,所以安全性会高很多;其次Binder机制的性能会非常的高,他只需要一次内存的拷贝即可, 而Android系统有很多个重要的服务进程,例如 AMS,PMS,SMgr,进程之间的交互非常的频繁,对IPC的性能有较高的要求, 最简单的例子,启动一个Activity也是需要IPC的,启动过程不再本文的描述范围内,有兴趣的话可以自行查阅资料。

首先为什么要IPC框架:

在这里插入图片描述
Android系统是基于linux的, 所以存在一个进程隔离的概念, 每个进程都由于虚拟地址的技术,认为自己独享整个系统, 所以并不能直接访问对方的内存地址,导致进程隔离。

那么物理概念的内存肯定只是大家共用的, 一定是可以访问的, 那么如果想完成这种操作就需要进入到内核空间来完成,此时沉入内核空间的进程被称为进入内核态, 而在用户空间则是用户态
在内核空间可以获得高级别权限,例如访问所有的内存地址。
那么显然我们打通User Space 中的两个进程,肯定需要一个内核模块来完成,所以我们需要一个Binder Driver,作为桥梁来互相访问各自进程的内存。
在这里插入图片描述

那么为什么Binder Driver这个外来物可以做为内核空间的驱动而存在呢,这是因为LKM机制,可以让一个可编译的模块作为内核模块进入到内核空间提供服务,所以Android 系统构建了一个Binder Driver 在内核态提供支持,讲了这么多,好像想做什么大概是明白了,但具体是怎么做的呢,还是不清楚,面对这种复杂的问题,就是拆分,把他拆分成一个一个问题逐一解决,Android团队设计的时候估计也是这么想的。
假设有一个服务进程S,一个客户端进程C(Binder机制是个C/S架构,你们应该已经发现了)首先一个问题就扑面而来,客户端C如何调用服务端S提供的服务呢,或者说我作为C如何能执行到S的函数,在说白了,需要个协议之类的东西,Binder Driver 对C提供了一个代理,一个IBinder对象,这个东西在C看来就是S,里面有相同的函数可以提供调用, 当C调用了代理IBinder提供的函数时候,Binder Driver就会让C的线程暂时挂起, 然后他去S那执行真正的函数,执行完毕,就把结果返回给C,唤醒C的线程。感觉好像C调用了S一样。
那么第二个问题就来了,我怎么找到C说的这个S,此时需要一个ServiceManager进程登场了, Server进程会通过Binder Driver向ServiceManager注册自己,好比加入通讯录的感觉, 此时能叫上来名字的话就可以找到本人的电话了。
在这里插入图片描述
所以大致想实现的设计是这样的:

首先定义一个接口 IDoSomeThing, 这个接口代表了S能干什么的能力,所以S需要实现这个接口 IDoSomeThingImpl , 并且给出这个实现的实例, 供别人调用。
但Binder Driver也要去S实现另一个接口,代表你要通过驱动来提供给其他进程使用,这个接口叫刚才提到的IBinder,所以这个IDoSomeThing还需要实现IBinder,至此Server进程的工作算是做完了。
那么C进程呢, C进程也得有这个IDoSomeThing的接口, 而且要和S的定义一模一样,虽然没有实现,但是起码知道对方S有什么能力, 当我想调用的时候, 我需要和BinderDriver要一个代理对象,代表S,对吧,这个代理对象的类型,也是IBinder, 这个IBinder 就被设计成代表一种可以使用BinderDriver的支持的能力, 至于是提供S的实现,还是提供给C的代理对象,那么就交给S的实现类和BinderDriver来处理。

至此,技术上的设计完成了,感觉上是可行的,那么我们来通过源码来看Android是怎么把这一套玩转跑通的。

从AIDL开始吧,aidl第一部就是使用aidl的语句定义一个接口,例如IDoSomeThing,里面有一个方法doSomeThing(), 你要把它定义为.aidl文件, 编译一下 gradle会帮你生成这个你定义的java版本 的接口:

interface  IDoSomeThing  : android.os.IInterface{doSomeThing() : Unit;// android.os.IInterface 定义的方法//@Override asBinder(): Binder
}

这个IInterface意思就是你是一个Binder官方认证的接口,你需要实现一个asBinder,来提供一个Binder对象。
但还没完,他还会在你的接口里生成一个内部抽象类Stub,而这个内部抽象类是无比的重要。

interface  IDoSomeThing  : IInterface{class Stub extends Binder : IDoSomeThing  {public fun asInterface ( ibinder:IBinder ): IDoSomeThing  {if(调用我的是自己进程内)//返回自己的实现return ibinder as IDoSomeThing  else 证明是其他的进程来调用返回代理对象return new Stub.Proxy(ibinder);}@Overridefun asBinder:IBinder =  this;fun onTransact(){调用我的doSomeThing函数读一下有没有参数传过来val result = this.doSomeThing()把result结果写回去。}}...
}

这个抽象类,有啥用,首先他也是一个IDoSomeThing ,所以在我们S进程里面,提供的实现类其实是这个Stub 的实现类。

class MyServiceProcess: Service{class MyBinder : Stub{doSomeThing(){//实现doSomeRealThing...}}@Overridefun onBind(intent: Intent):IBinder = new MyBinder();}

这里通过Service 的方法onBind,就把我们的实例提供给了BinderDriver.所有的跨进程通讯Server端都需要一个Service来提供给BinderDriver吗?大家可以扒一扒 ActivityManagerServer、IActivityManager、ActivityManagerNative、ActivityManagerProxy、ActivityManager这几个类的源码,看看AMS的IPC过程。
之前说过了, C和S必须都有接口,所以aidl生成的类,必须在两个进程都有才可以,两个APP的话就复制过去。
Server端先看到这里, 我们再看一下Client端,客户端绑定 远程服务的时候,是调用bindService方法(aidl的具体使用方式不再本文描述内,可以查看官方文档,写的特别好).

bindService(Intent(this, RemoteService.class){ service: IBinder->//onServiceConnected的回调内我的server进程服务代理对象 mService = Stub.asInterface(service);
}

欧,看到了asInterface, 这个方法,特别的简单,如果没有跨进程,就是直接返回sub, 如果跨了进程就返回代理对象,而Proxy这个类,又是stub的子类。

class Stub...{class Proxy:IDoSomeThing {private mRemote: IBinder;constuct(remote : IBinder){mRemote = remote;}@Overridefun asBinder = mRemote;fun doSomeThing(){写参数....val result  =  mRemote.transact(参数);....读结果}}
}

马上可以看到的是,她和stub不同,stub is 一个IBinder, 而Proxy只是持有了IBinder的引用,一个是策略模式,一个是代理模式。
可以看到C端通过bind到远程服务S端,会获得一个IBinder对象,我们用asInterface把这个IBinder传过去,换成S端的代理对象Proxy, Proxy是一个IDoSomeThing,所以当我们调用方法doSomeThing的时候, Proxy使用了Binder的一个方法transact,这就通知BinderDriver来处理一下, BInderDriver会调用server中的stub的实现类中的 onTransact()方法,我们在翻上去看一下, 完整的流程就无比清晰了:

C端进程的一个线程tc1,调用Proxy.doSomeThing, Proxy调用transact通知驱动, tc1挂起,
S端进程的一个线程ts1, 会被驱动回调onTransact,执行doSomeThing的真正实现 doRealSomeThing完成后返回给驱动,驱动在唤醒tc1线程,把结果返回,至此结束。

当然,一个S端可能对应着多个C端, S端是一个线程池维护的,给每个C端分别分配线程, 所以,onTransact可能会被多个线程回调,就会ts1,ts2,ts3等等,如果涉及到共享数据,做好多线程控制吧!

至此Binder机制 Java层的代码基本分析完毕,放一张剽窃来的画的贼屌的图吧,接口可能定义的不一样不过不妨碍感受一下。
在这里插入图片描述

终于到最后一步,实战阶段了,我们的目标是: 不使用aidl工具生成, 我们手写代码完成功能:
同学们自己去写吧。。反正我写了这个博客,基本上都是手撸了一遍, 还需要掌握一下Parcel这个类,毕竟跨进程涉及到把对象序列化和反序列化,相信你们也可以的。


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

相关文章

Android进阶——Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL

前言 Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从Linux相关的基础概念知识开始介绍,从基础概念知识中引出Binder机制,归纳Binder机制与Linux系统的跨进程机制的优缺点,接着分析Binder的通信模型和原理&#x…

[转]IBinder对象在进程间传递的形式

目录: 问题引出:由onServiceConnected()的IBinder类型说起IBinder传递时Driver Module的处理IBinder传递时framework的处理发送IBinder接收IBinder 问题引出:由onServiceConnected()的IBinder类型说起 当service被远程调用时,我们…

android i 网络接口,从IBinder接口学习Proxy-Stub设计模式

定义了抽象函数,如上图里的onTransact()函数,成为提供给众多子类别来实现的内部接口。我们以来表示之。 如下图所示: 图3、基类实现CI,并定义 ---- 由子类来实现内部接口。Binder基类的很重要目的是支持跨进程调用Service&#xf…

Android IPC 之获取服务(IBinder)

前言 IPC 系列文章: 建议按顺序阅读。 Android IPC 之Service 还可以这么理解 Android IPC 之Binder基础 Android IPC 之Binder应用 Android IPC 之AIDL应用(上) Android IPC 之AIDL应用(下) Android IPC 之Messenger 原理及应用 Android IPC 之服务端回调 Android…

android ibinder 机制,Android IBinder机制简单介绍

原理简介 我们都知道android 是通过IBinder来实现IPC(Inter Process Communication)进程间通信的。。。 借用一下: 1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中 2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者…

sql之嵌套查询中的带exists谓词的子查询

数据库系统概论之嵌套查询中的带exists谓词的子查询 一、exists谓词概述:exists谓词代表存在量词。带有exists谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。可以利用exists来判断属性与关系表之间的属于关系,关系…

sql in和exist

前言 最近写SQL的时候要求在排除A表中所存在的B表的某些同属性值的记录。 然后就想到了in和exist,但是其实一直都没有真正的去弄懂两者不同, 于是在网上查询了一些大佬的文章,然后去实践了一番,最后做一个总结 开始啰 1&#xff…

SQL之EXISTS的理解

将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可作为外查询的结果行,否则不能作为结果。 先上表 过程:外查询Persons表,提取出数据到E…

sql中exists的常用用法

exists中子查询结果集非空,则exists子查询返回true。如果exists子查询结果集为空,则exists子查询返回false。在平常的开发工作中,经常会用到exists,那么它应该如何使用呢? 1:查询兴趣爱好为跳舞的同学姓名及…

MySQL SQL语句EXISTS

MySQL中EXITS语句用于查明表中是否存在特定的行。普遍情况下EXITS与子查询一起使用,并返回与子查询返回的结果相等或匹配的行。如果行在表中存在,则返回true,否则返回false。在MySQL中使用EXISTS是低效的,因为EXISTS对查理表中的每…

SQL语句中EXISTS的用法

SQL萌新一个,在这里记录一下自学过程中遇到的问题。 exists:强调的是,是否有返回集,不需要知道具体返回的是什么 比如这两个表: 输入查询语句: select * from customer c where not exists( select * from…

sql中 exists的用法

现有:班级表(A_CLASS) 学生表( STUDENT) 注:学生表(STUDENT)的classId关联班级表(A_CLASS)的主键ID 代码: select * from STUDENT s WHERE exists (select 1 from A_ClASS c where s.CLASS_…

SQL语句中EXISTS的详细用法大全

SQL语句中EXISTS的详细用法大全 前言一、建表1.在MySQL数据库建表语句2.在ORACLE数据库建表语句 二、在SELECT语句中使用EXISTS1.在SQL中使用EXISTS2.在SQL中使用NOT EXISTS3.在SQL中使用多个NOT EXISTS4.在SQL中使用多个EXISTS5.在SQL中使用NOT EXISTS和EXISTS 三、在DELETE语…

DNS服务器解析问题

DNS服务器解析问题 前言 重点: 本文摘选链接:https://www.ancii.com/aazeaa674/ 正文 问题 域名状态异常会导致网站不能访问吗? 刚修改过域名解析,为什么不生效呢? 如何查看解析是否生效呢? 刚在注…

dns服务器怎么设置

dns服务器怎么设置 在修改DNS之前需要先知道你的大DNS服务器地址是什么,那么怎么来查询DNS服务器地址呢?直接按住键盘上的“winR”,调出运行框。在输入框中输入“cmd”,点击“确定”或者回车。在管理员界面中输入命令:…

手机显示DNS服务器异常,手机dns服务器异常怎么设置

手机dns服务器异常怎么设置 内容精选 换一换 华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。 本章节介绍如何通过控制台重启服务器。重启服务器时,可以批量更换云手机…

小米路由器显示DNS服务器设置错误,小米路由器dns地址怎么设置

小米路由器与日常所有的路由器一样,在默认情况下都是路由器的地址作为无线设备获取的 DNS 地址。如果你想手动修改小米路由器的DNS地址,也是可以的,下面是学习啦小编给大家整理的一些有关小米路由器dns地址设置方法,希望对大家有帮…

如何设置正确的dns服务器地址,dns服务器地址如何设置

dns服务器地址如何设置 (Windows 2000、Windows XP操作系统): 1、 开机后在桌面上选定图标"网上邻居", 点击鼠标右键, 在弹出的菜单上选择"属性"项,打开"网络和拔号连接"窗口, 如图 2、…

北京联通dns服务器位置,联通DNS服务器地址怎么设置

联通DNS服务器地址怎么设置 如电脑Win7系统,以下方法设置DNS:您右键点击电脑桌“网络”图标 ,“属性” >选择“控制面板” >在“网络和共享中心”中可看到当前的网络状况,点击左边的“更改适配器设置” >右键单击“本地连接”择“属性” >选择“internet协议版本4(TCP/…

路由器显示DNS服务器设置错误,路由器dns设置错误怎么处理

一般都给家里配上了无线路由器,但是在用了无线路由器后,很容易导致电脑断网,大家一般用软件检测后上面会显示是DNS地址出现了异常,那么应该怎么解决这个问题,不让电脑频繁断网呢?下面是学习啦小编给大家整理的一些有关…