Framework笔记 | binder详解

简介: Framework笔记 | binder详解
谈谈你对binder的理解

思路:

  • binder是干嘛的(注意拓展)
  • binder存在的意义是什么?

为什么不用别的替代方案呢?(主要分三点展开)

  • binder的架构原理是怎样的?

(可以把架构图画出来,对着图讲)

binder是干嘛的

通信

  • binder分成两端

一个是Client端,一个是Server端,两者
可以在同一进程,也可以在不同进程

  • Client端可以向Server端发起远程调用

可以传数据,把数据当做函数的参数来传;

  • 远程调用进程的边界是比较模糊的,

你不用关心对方是在哪一个进程;



远程调用机制常规套路

  • 首先,Client端要调用Server端的某个函数(如这里的call()函数);

做法是首先把参数序列化到一个buffer,
然后通过Linux的各种跨进程通信方式传到Server端的buffer,

  • 接着反序列化buffer,还原出各个参数;
  • 然后调用Server端对应的函数如这里的call函数;
  • 最后把函数返回结果按原路返回到Client端;



机制需要注意的问题

  • **性能要好;

跨进程传递buffer的时候速度要快,
尽量减少拷贝的次数;**

  • **要方便:

Linux提供的跨进程通信工具好比只是一根电话线,
电话转发的算法,
电话发送端声音转电信号,
接收端电信号转声音,
这些都需要做好上层工作;
也就是说,
我们需要在Linux提供的跨进程底层传输机制上,
再搭建一套完整的框架才行,
不然应用层开发很艰难;**

  • **安全:

就像打电话一样,
首先肯定不是电话过来我就要接,还要看看号码是谁;
其次最好是要有个骚扰拦截机制;**

所以一套好用的 远程调用机制还是很复杂的,
需要兼顾性能、方便、安全等因素,
而Binder机制,就是这么一个好机制!




物理内存 即移动设备上的RAM,
当启动一个Android程序时,会启动一个Dalvik VM(或ART)进程
系统会给它分配固定的内存空间(16M,32M不定),这块内存空间会映射到RAM上某个区域。
然后这个Android程序就会运行在这块空间上。
**

为什么需要IPC?!!

**每一个APP对应一个VM进程
进程之间的内存相互独立,无法直接交流,
只能以Linux Kernel 为媒介,
进行IPC!!!**

binder存在的意义是什么

  • **binder是跑在驱动层(如上图中的Drivers)的,

同时它不是基于Linux的跨进程通信机制;
它在内核态是没有用到任何Linux提供的跨进程底层传输机制
它是单独被创作出来的一套机制;**

  • 性能

Linux的跨进程通信机制中管道和Socket,
在跨进程通信的时候是需要内核来做中转的,
这个就意味着两次数据拷贝(从应用层拷到内核,从内核拷到应用层)
binder是有点区别,
对于Binder来说,
数据从发送方的缓存区拷贝到内核的缓存区,
而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,
所以只要拷一次;

  • 方便应用

逻辑简单直接,不会出问题;
共享内存虽然性能很好,但是用起来很复杂;

  • 安全

普通的跨进程通信方式其实是不太安全的,
像Socket,ip地址、端口什么的都是开放的,
别人知道它的ip地址就能来连接它了;
或者说管道也是,
知道管道的名称,就能往里面写东西;
这样子其实是不太安全的,很容易被人为利用;
**主要是因为,
我们拿不到调用方可靠的声明信息,
这个声明信息总不能让调用方自己去填吧,明显不可靠;
可靠的方式是,
这个身份标记只能由IPC机制本身在内核开通添加
关于这一点Binder是做到了**

以上三点足够说明Binder存在的意义



Binder的通信架构

  • **四端参与,

Client、Server、ServiceManager、binder驱动;**

  • **上图展示的是系统服务binder通信

只有系统服务才能注册到ServiceManager
应用服务binder是不能注册到ServiceManager,通过不了验证的;**

  • Client是应用进程;

Server是系统服务,可能跑在SystemService进程,也可能是在单独的进程;
ServiceManager是单独的系统进程;
**这里不论哪个进程,它们在启动的时候,
第一件事,都是要先启动binder机制,这个是binder通信的前提;**



进程如何启动binder机制?

  • 打开binder驱动

这样binder驱动就会为进程创立一套档案;

  • 创立后返回档案的描述符(句柄)

用这个描述符去进行内存映射,分配缓冲区(接下来的binder通信需用到缓冲区);

  • 最后,启动binder线程;

启动binder线程,
一方面是要把这个线程注册到Binder驱动,
另一方面这个线程要进入Loop循环,不断地跟binder驱动进行交互;


binder通信

ServiceManager
  • 下面这个是ServiceManager的入口函数main:
  • 首先调用binder_open()打开binder驱动,映射内存,然后启动binder线程
  • 接着调用binder_become_context_manager()

“binder成为了上下文的管理者”,
作用是:
告诉binder驱动——“我就是ServiceManager,我就是中转站
(像整理诸多电话发送端,分配给诸多电话接收端的一个中转站),
,大家不论是注册还是查询都可以来找我”;

  • 最后调用binder_loop(),进入binder的Loop循环;
binder的loop循环


函数中,

  • 首先把当前线程注册成binder线程

BC_ENTER_LOOPER这个指令
写到binder驱动(binder_write())
就表示把当前线程注册成binder线程
这里所说的当前线程
ServiceManager的主线程;

  • 接着是一个for循环,里边,

首先是读,
BINDER_WRITE_READ,看起来好像是又写又读,
但其实我们看bwr_read_size是大于0的,
write_size没有赋值,所以这里是
binder驱动发过来的数据、请求读进来;(ioctl())

  • 接着解析读进来的数据 / 请求

然后调用回调函数func去处理这个请求;

相关阅读:图一图二

ServiceManager总的流程就如上了;

接着往下,回顾架构图:

  • ServiceManager启动Binder机制之后,

它就进入了一个loop循环,(详细的如刚刚描述)
等待Client和Server的请求;

  • Server是系统服务,Client一般是应用程序;

**系统服务启动之后,才是应用启动;
所以图中这里,Server端是先和ServiceManager交互的;**

  • **Server启动的时候,

要先把自己的binder对象
注册到ServiceManager;
接下来看一下相关的代码;**



以系统服务SurfaceFlinger,观察系统服务是怎么在ServiceManager注册的

  • 首先看一下SurfaceFlinger的入口main函数:

    • 首先头两行就是启动binder机制,即打开binder驱动,映射内存,然后启动binder线程
    • 接着第三第四行是,binder实体对象的初始化,

对于系统服务SurfaceFlinger,
它的业务类对象就是SurfaceFlinger,
这个业务类对象SurfaceFlinger同时也是一个binder实体对象;

- 初始化完了之后,

就是要向ServiceManager注册了,
注册的话首先通过defaultServiceManager()
拿到ServiceManager的BpBinder;
然后,
发起Service调用,
把flinger这个binder对象
传到ServiceManager;sm->addServier();

    - **(>- 相关阅读 [Binder学习笔记(二)——defaultServiceManager()返回了什么?](https://www.cnblogs.com/palance/p/5468341.html))**
- 最后进入一个loop循环;`flinger->run();`
系统服务是在ServiceManager注册的整个流程就是如上这样;



看一下defaultServiceManager()的实现

  • 重点了解一下怎么获取ServiceManager对象
  • 首先第一行,

有一个gDefaultServiceManager
它只初始化一次,然后直接返回;

  • 接着是一个while循环,

聚焦标红的地方,
ProcessState::self()->getContextObject()
是真正获取ServiceManager对象的;

  • getContextObject()的作用:

getStrongProxyForHandle(0)
查询0号handle值对应的binder引用,即ServiceManager

 - 有点像要查某家公司的电话号码,

需要打114查号台查询,
这里的ServiceManager就类似于114,
正如所有人都知道114是干嘛的,
**所有的启用binder机制的进程
都知道0号handle对应的就是ServiceManager;**

- 那我们要查系统服务的时候,

只要找0号的handle咨询即可;

- 若没有查到0号handle?

可能这个ServiceManager还没有来得及给自己注册binder驱动;
就像114客服人员还没来得及上班一样;
那怎么办?
等一会儿再重新试试咯——if(....==NULL)sleep(1);



接着看一下addService()的实现

小结,addService()的作用:

  1. 保存诸多数据到Parcel中,尤其注意Service系统服务的binder对象也写到Parcel实例data中;
  2. 调用transact(),进行后续的逻辑;

  • **两个Parcel成员

data是发到驱动的参数,
reply是驱动返回的结果,**
把各种参数都放进data里面,
包括Service系统服务的binder对象也写到Parcel实例data中;(data.writeStrongBinder(service);

  • 写好之后(各种data.writexxx()之后),

remote()拿到ServiceManagerBinderProxy对象,
然后调用其方法transact()
把请求发出去,请求参数包括
请求码ADD_SERVICE_TRANSACTION
data、&reply等等;

transact()干的事情
transact()把请求转给了IPCThreadState
调用IPCThreadStatetransact()注意这里的mHandle,
我们可以看到底层在跟驱动交互的时候,
它是不分BPBinder,还是BinderProxy这些的,
它只认这个Handle值

所以我们看上层封装的这么一层层对象,
其实传递到最后,
核心就是传递到,这么一个Handle值操作上来;
之后,
code其实就是函数调用码,
data就是带的参数,
reply就是binder驱动返回的结果,
flags就是一些标志;



接着看IPCThreadStatetransact()函数

  • 函数中,

首先调用writeTransactionData()就是
要把要写到binder驱动中的数据准备好;
**我们知道binder驱动是不认识这个Parcel的数据结构的,
我们得先把它转化成一个binder驱动 认识数据结构
binderTransactionData这个数据结构
再发给binder驱动
writeTransactionData()的作用
就是完成这个数据结构的转化过程,
或者说这个数据准备过程;**

**总之,
这个方法会将传递来的参数组装成一个binder_transaction_data结构体对象
然后将cmd(BC_TRANSACTION)和这个结构体对象tr
都写入IPCThreadState的属性mOut中**。

  • 接着往下看,

这个waitForResponse()就是跟binder驱动交互,和通信协议的,
这个方法主要调用了talkWithDriver方法,
与Binder驱动进行数据交互,
并一直等待Binder驱动响应,接收服务端返回结果

函数中,
首先判断一下传进来transact()flags
如果是TH_ONE_WAY
就不用等回复了,两个相关参数都传NULL
waitForResponse(NULL,NULL)
如果不是TH_ONE_WAY
就需要有一个reply来接收回复,
调用时有传进来reply,则用调用传进来的reply
没有传进来的,则临时创建一个Parcel来充当reply



接着看请求在Server端是怎么处理的

  • 以上就是ServiceManagerServer端主要代码;
  • binder的Server端处理请求都是在onTransact()里边;
  • swich(code)找到ADD_SERVICE_TRANSACTION这个case

然后从Pacel里面,
系统服务binder读出来(data.readStrongBinder();),
读出来的是
**根据binder引用对应的handle值
封装的一个BinderProxy对象;**

  • 接着调用本地的addService函数,

把刚刚取出来的系统服务binder存好;

- 上面讨论过了,

addService()的作用是
保存诸多数据到Parcel中,
包括Service系统服务binder对象也写到Parcel实例data中;

data.readStrongBinder();读出来的是
系统服务的一个BinderProxy对象
而Binder和BinderProxy是IBinder的子类,
这里向上转型成IBinder对象(sp<IBinder> b );
然后调用本地的addService函数,存好数据;

  • 存好数据之后,

reply中写一个返回值;

在Server端注册就差不多是这样了;
至于Client端从ServcieManager获取系统服务的原理跟这个差不多;



Binder通信的分层架构图

通过这个架构图我们回顾一下刚刚讨论的知识点:
这个图我们可以分成几个维度来看,

  • 首先有三个角色,

Client、Server、Binder驱动

  • 从分层的角度,又可以分成

应用层Framework层(Java层 + Native层)驱动层

  • 从Binder对象的角度看,

可以分成两端,
代理端(Proxy、BinderProxy、BpBinder)
实体端(Stub、Binder、BBinder)

  • Client端开始看,

当我们拿到一个Binder对象的Proxy的时候,
我们要发起IPC调用了;
这个调用其实就是把请求往下
丢给了BinderProxy;
请求继续往下走,又会丢到
Native层Proxy--BpBinder对象;
然后这个BpBinder对象,又会把请求
转交给IPCThreadState
通过IPCThreadStatetransact函数
发送请求到Binder驱动;

  • 接着驱动再转发,发到Server进程;

然后在Server进程的Binder线程里边,
就会处理、执行到onTransact()函数,
再一层层往上,传到应用层;

  • 所以我们看这个分层,

其实跟网络里边传输的分层(计网四层、五层、七层协议等)有点像;






Binder和BinderProxy是IBinder的子类;
相关文章
|
Linux Android开发
Android源码剖析之Framework层基础版(窗口、linux、token、Binder)
  本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 关于Framework,就是应用层底下的控制层,离应用层最近,总想找个机会,写写WindowMangerService和ActivityManagerService(注意非控件,而是指一类服务)以及其他一些东西,对底层做一个更为全面的认识。
1131 0
|
6月前
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
222 0
|
4月前
|
缓存 安全 Java
Android深入Binder拦截问题分析
【7月更文挑战第1天】Android Binder 拦截可实现虚拟化、测试、SDK检测、逆向分析及ROM扩展。通过Java层aidl代理,利用IBinder接口规范来拦截通信。拦截步骤包括:替换Binder服务缓存对象,如ActivityManagerService;代理ServiceManager以控制服务获取。此操作需系统权限,可能涉及安全风险和版本差异,非必要时应谨慎。
|
Java API Android开发
Android中Binder在项目中的具体使用详解
Android中Binder在项目中的具体使用详解
195 0
|
Java Android开发 C++
Android中的Binder概述
Android应用的开发离不开四大组件(Activity,Service,BroadcastReceiver,ContentProvider),而这四大组件所涉及的通信底层都是依赖于Binder IPC机制的。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅如此,整个Android系统架构中,大量采用了Binder机制作为IPC方案,当然也存在部分其它的IPC方式,比如Zygote通信便是采用Socket。 概念:Binder是Android中的一种IPC方式,提供远程过程调用(RFC)功能。
|
Java 开发工具 Android开发
Android中的Binder学习笔记
Android中的Binder学习笔记
Android中的Binder学习笔记
|
缓存 安全 Java
❤️Android Binder原理图解❤️
之前了解到进程与多进程,涉及多进程不可避免的遇到了进程间通信,说到进程间通信,Binder 成了一道绕不过的坎。接下来咱们逐一了解。
681 0
❤️Android Binder原理图解❤️
|
Android开发
Android后台杀死系列之四:Binder讣告原理
Android后台杀死系列之四:Binder讣告原理
425 0
Android后台杀死系列之四:Binder讣告原理
|
消息中间件 存储 缓存
Android进程间通信之一:Binder机制学习
Android进程间通信之一:Binder机制学习
226 0
Android进程间通信之一:Binder机制学习
|
Java Android开发 C++