当前位置: 首页 > news >正文

Binder总结篇1-Binder原理

Binder总结篇1-Binder原理

需要学会Binder的基本使用和原理,需要的知识点有:

  1. Linux进程和空间的概念

  2. 虚拟地址概念

  3. 常用IPC,他们的基本流程和Binder的区别

  4. C/S架构基本思路,也就是Binder驱动,ServerManager,Client和Server这四个概念。

  5. AIDL以及支持的数据类型,包括Parcelable等,以及编写

  6. Service(Android的四大组件之一),Binder等几个具体的java类使用。

以下是自己的一些Binder学习总结,如有侵权请联系删除。

Linux的进程和空间的概念

在Linux系统中,进程是分配给应用程序运行的最小描述,即一个应用程序最少有一个进程,而一个进程之间又最少有一个线程,进程给应用程序分配内存空间。

空间:在Linux中,为了保持系统的稳定性,分为内核空间和用户空间,内核空间的权限最高,用户空间的权限最低。比如读写文件,网络请求就是在内核空间中进行的。

在Linux中,存在着进程隔离,也就是进程A无法直接访问进程B的数据,他们之间各自具有独立的内存。假如他们需要进行通信,就必须通过IPC来实现,主要是通过两个方法:copy_from_usercopy_to_user

虚拟地址

在给应用程序分配内存的时候,对于应用程序来说,他是一片连续的内存空间,但是实际上,这些内存空间映射到具体的物理内存中是碎片化的不连续的,这个在应用程序看来是连续的空间就是通过虚拟地址实现的。通过虚拟地址,让应用程序看似拥有连续的内存空间,从而映射到具体的物理内存中。

比如,在32位系统中,可以寻址的空间长度是2的32次方,也就是4GB。

传统IPC

包括:

  1. 共享内存

  2. 消息管道

  3. Socket

  4. 信号量

这些是常用的IPC方法,一般而言,他们会经历两次的数据copy,共享内存除外。

第一次是发送方将数据通过copy_from_user拷贝到内核空间中,这是第一次。然后,接收方在自己的内存空间中,分配缓存区,通过copy_to_user方法把内核空间的数据复制到自己进行读取。

如下图:

对于Android系统而言,上面的几种方式都不太适合,首先对于两次的数据拷贝,存在的问题是:

  1. copy次数多耗费时间

  2. 接收方不知道需要分配多大的内存接受数据,或者是需要提前通知接受方分配而耗费时间。

对于共享内存,虽然它无需copy但是较为难以控制,安全性方面较差。

那么Binder在这方面具有什么优势呢?

  1. Binder是只需要一次数据copy,仅低于共享内存。

  2. 他基于C/S架构,职责分离又相互独立,稳定性更好。

  3. 在安全性方面,传统的IPC接收方无法获取对方可靠的进程PId,从而无法鉴别对方身份。但是在Android中,他会为每一个安装好的App分配一个自己的UID,从而做到可以鉴别身份。

所以Binder是Android系统进行IPC采用的手段。那么Binder为什么只是可以一次数据拷贝就行了呢?

这个就是利用虚拟内存了。Binder借助内存映射,在内核空间和接收方的用户空间的数据缓存区做了一层内存映射。也就是说,在发送方将数据拷贝到内存空间的时候,内核空间的这部分地址同时也会被映射到接收方的内存缓存中,这样子,就少了一次从内和空间拷贝到用户空间。

如下图:

Binder 的通信原理

在Binder中,有四个概念,Binder驱动,ServerManager,Client以及Server,这四个部分组成了BinderC/S架构。

他跟一次网络请求很相似:Client通过域名发起请求,通过DNS域名解析器解析具体的ip地址,然后再通过路由转发到具体的Server,再然后Server将请求结果通过路由转发回Client。

在Binder的IPC中,有如下几个部分:

  1. Binder驱动

Binder驱动是一种虚拟的字符设备,注册在/dev/bindr中,其中定义了一套Binder通信协议,负责建立进程间Binder通信,提供了数据包在进程之间传递的底层支持。

他的角色类似路由,他是提供进程间通信的底层支持。负责将Client端的请求转发到Server,并将Server的数据返回给Client。

2 ServerManager

他的作用类似DNS服务器,负责将Client请求的Server的Binder描述转化为具体的Server地址,以便Binder驱动将Client的请求转达到Server。当Server需要提供服务的时候,他必须先向ServerManager注册,这样子,ServerManager中,就存有一份类似key-value的数据,保存了一份Server的Binder字符名称和Binder引用的映射以便Client可以找到。

  1. Client

Client的作用是发起请求,通过Binder向ServerManager发起请求获取Server的具体地址,然后交由Binder驱动转发。

  1. Server

Server假如需要对外提供服务,他就需要先将自己注册到ServerManager中,以便被解析出来。Server在响应请求之后,就将数据通过Binder驱动再次将数据传递会Client。

这就是一次完整的IPC调用。

还有一个问题就是ServerManager的产生,因为Client/Server都是需要通过Binder与ServerManager进行通信的,那么这个ServerManager是如何产生的呢?

  1. 在Android系统启动之后,会创建一个名词为servermanager的进程,可以查看ZygoteInit文件,在里面的main方法中,调用ZygoteforkSystemServer产生。它通过一个约定的命令BINDERSERVER_MGR向Binder驱动注册,申请成为ServerManager。Binder驱动会自动为ServerManager创建一个Binder实体

  2. 这个Binder实体的引用在所有的Client中都是0,也就是说各个Client通过0这个引用就可以与ServerManager进行通信。

Binder的代理机制

上面是我们的IPC过程,在这个过程中,Client需要获取到Server端的Binder引用,那么这个引用是真正的Server引用吗,他是如何实现的呢,A进程并无法直接获取B进程的对象。这个就是需要通过Binder的代理机制实现。

我们在Client端,向ServerManager获取具体的Server端的Binder引用的时候,会首先进过Binder驱动,Binder驱动它并不会把真正的Server的Bind人引用返回给Client端,而是返回一个代理的java对象,该对象具有跟Server端的Binder引用相同的方法签名,这个对象为ProxyObject,他具有跟Server的Binder实例一样的方法,只是这些方法并没有Server端的能力,这个ProxyObject的能力是可以通过Binder驱动,正在实现对Server的Binder进行调用,从而完成数据传递。

比如,当Binder驱动接受到Client进程的请求,就去ServerManager中查询,在ServerManager中查询到具体的Server具体之后,就创建一个Server端的Binder对象的ProxyObject,并且将该ProxyObject返回给Client 。然后Client就通过ProxyObject调用其中的方法,ProxyObject的方法再去调用Binder驱动,这个Binder驱动就去Server进程中,调用具体的Server进程的具体的Binder对象的方法,然后再通过Binder驱动返回数据给Client。

如下图

AIDL

上面我们大概梳理了Binder调用的整体流程,知道Binder的大概原理。在Android中,是通过AIDL这一描述性接口语言实现的。

什么是AIDL:Android 接口定义语言 (AIDL)

关于如何使用AIDL将在下一篇文章在做详细使用。

参考文章

关于Binder,作为应用开发者你需要知道的全部(同时也是本文的文章图片来源)

为什么Android要采用Binder作为IPC机制

Binder系列-开篇

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

写给 Android 应用工程师的 Binder 原理剖析

相关文章:

  • malloc()函数(Linux程序员手册)及函数的正确使用【转】
  • ListBean 排序
  • HYPER-V的安装和双机调试的配置(一)
  • java核心技术读书笔记
  • Android 9.0新特性
  • JS中逻辑运算符中 == 的问题
  • Apache2.2.x版本不支持PFS,无法通过ATS的问题
  • 惰性计算辨析
  • 洛谷P4016 负载平衡问题(费用流)
  • JavaWeb-JSPELJSTL
  • list、dict、str虽然是Iterable,却不是Iterator
  • jQuery(一)
  • C# 中类和结构的区别
  • vue-cli 3.0 初体验
  • 谷歌 Fuchsia 上手体验,将取代Android/win10
  • ES6指北【2】—— 箭头函数
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • avalon2.2的VM生成过程
  • canvas 高仿 Apple Watch 表盘
  • CSS实用技巧
  • Elasticsearch 参考指南(升级前重新索引)
  • Flex布局到底解决了什么问题
  • Git 使用集
  • golang 发送GET和POST示例
  • If…else
  • Linux后台研发超实用命令总结
  • redis学习笔记(三):列表、集合、有序集合
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • 从0实现一个tiny react(三)生命周期
  • 服务器从安装到部署全过程(二)
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 世界上最简单的无等待算法(getAndIncrement)
  • 一起参Ember.js讨论、问答社区。
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​VRRP 虚拟路由冗余协议(华为)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)scrum常见工具列表
  • .bat批处理出现中文乱码的情况
  • .NET 使用配置文件
  • .NET单元测试
  • .NET企业级应用架构设计系列之结尾篇
  • @JsonSerialize注解的使用
  • @Valid和@NotNull字段校验使用
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [2021ICPC济南 L] Strange Series (Bell 数 多项式exp)
  • [8481302]博弈论 斯坦福game theory stanford week 1
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)