摘要:本节主要来讲解Android10.0 HwBinder的通信原理概要
阅读本文大约需要花费18分钟。
文章首发微信公众号:IngresGe
专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!
[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析
[Android取经之路] 系列文章:
《系统启动篇》
《日志系统篇》
《Binder通信原理》:
在前面我们写了一个《Binder通信原理》的系列文章,这次准备来写一写HwBinder的系列文章。
HAL binder是Android O(8.0)专门用于HAL(Hardware Abstract Layer)层(native)进程与其clients之间的通信机制(clients可以是native进程,也可以是Java Framework进程)。HAL binder替代了早先使用的socket通信,其kernel层实际是基于原有的binder驱动,但为了配合Client与Server之间的数据传输,需要使用特定的中间层HIDL来进行接口与数据的转换。那么,相对之前的HAL通信方式(socket),基于HIDL的HAL通信有什么优势?从系统架构的角度,HIDL为客户端与服务端提供了清晰的接口;从效率的角度,binder IPC实际在传输数据上只有一次拷贝,而socket实际传输需要两次数据拷贝。
在Android 8.0 之前,Binder机制比较简单,只有一个驱动设备"/dev/binder",一个守护进行"/system/bin/servicemanager",一个binder库"/system/lib64/libbinder.so".
在Android 8.0开始,Android引入了Treble的机制,为了方便Android系统的快速移植、升级,提升系统稳定性,Binder机制被拓展成了
"/dev/binder", "/dev/hwbinder","/dev/vndbinder"。
我们原先使用的"/dev/binder",成为框架进程的专有节点,这意味着供应商进程无法再访问此节点。供应商进程可以访问 /dev/hwbinder,但必须将其 AIDL 接口转为使用 HIDL。
对于想要继续在供应商进程之间使用 AIDL 接口的供应商,需要使用 /dev/vndbinder(而非 /dev/binder)。
Android8.0及之后的Binder域如下图所示:
Binder和HwBinder的一些差异
Binder -> HwBinder
BpProxy -> BpHwBinder
BBinder -> BHwBinder
JavaBBinder -> JHwBinder
BinderProxy.java -> HwRemoteBinder.java
Binder.java -> HwBinder.java
HwBinder架构如下图所示:
在Android 8.0之前,Android Framework与Android HAL是打包成一个system.img的,而且Framework与HAL之间是紧耦合的,HAL是一个个的.so库,库和framework位于同一个进程。
Android8.0之前 的系统框架当中framework与HAL之间的一般架构框架是:
在上图的这种架构中,每次Android的Framework进行升级时,对应的HAL层都需要跟着升级,费时费力,这也Android最新版本推广较慢的原因。
在Android 8.0及之后,Android觉得这也不行,每次出了新版本,但是用的人很少,得让大家快速使用新版本。于是Android引入了一个Treble的架构,把vendor的一些功能和库与system进行分离,OEM厂商设计的内容都放到vendor中去,Android原生的放到system中,这样Android只要升级System就能快速完成版本的升级,在这个场景下,Android Framework放在了System空间,厂商的HAL库放在了Vendor空间,两者之间使用hwbinder进行通信,通信的接口语言为HIDL。
Android8.0及之后 的系统框架当中framework与HAL之间的一般架构框架是:
下图展示了Android 有Treble和没有Treble的升级方式:
在Android 8.0之前,这是我们最熟悉也一直使用的Binder。Java层继承Binder,Native C/C++层继承Bbbinder,然后通过servicemanager进程注册实名Binder,然后通过已经创建好的Binder接口传递匿名Binder对象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。
在Android 8.0后,这个Binder机制继续保留,/dev/binder 设备节点成为框架进程的专有节点,这意味着供应商进程无法再访问此节点。
如果你是系统厂商,在system分区有进程,/dev/biner机制还是可以继续使用,但是你的进程在vendor分区,那只能使用/dev/hwbinder 或者/dev/vndbinder.
Binder机制需要两个进程都同属于System分区
hwbinder和 binder不同,hwbinder是一套全新的流程,有单独的驱动设备"/dev/hwbinder",独立的守护进程"hwservicemanager",独立的SDK-"libhwbinder"
HwBinder机制可以跨System和Vendor分区使用
Android 8.0中引入了Treble机制,Treble 项目通过将底层供应商实现从 Android 内核框架中剥离出来,使Android更新变得更简单。这种模块化的设计允许分别独立更新平台和供应商提供的组件。让更新变得更轻松、更快速,然而,Treble 加强模块化设计还有一个目的:提高安全性。
Treble引入后,新增了一个vendor.img, 即原先的system分区,被拆分为了system分区和vendor分区,soc及供应商的功能实现都需要放到vendor分区,这样将system和vendor相关的镜像分开,便于能方便地更新和升级system,并且不依赖vendor等底层。
在Android 8.0之前,HAL是一个个的.so库,通过dlopen来进行打开,库和framework位于同一个进程, 在此之前的Android 系统架构当中,Android Framework 与Android HAL是打包成一个system.img的,而且Framework 与HAL之间是紧耦合的,通过链接的方式使用相应的硬件相关so库。
Android 8.0之前的通信机制如下图所示:
所以每次Android framework的升级需要对应的Android HAL升级,这需要供应商花费很多的人力去升级相应的 Vendor HAL Implemetation,这也就是导致Android版本升级很缓慢,很多用户几年之后,Android都不能得到及时更新。
在Android8.0及以后的版本中,Android设计了一套新的机制来隔离HAL层,引入了一个HIDL的语言来定义Framework和HAL之间的接口
在Android 8.0以及以后的版本当中,Android 更新了新的框架设计在新的框架设计当中,引入了一套叫HIDL的语言来定义Freamework与HAL之间的接口,Android Framework会在system分区当中,而VendorHAL Implemetation会在一个新定义的分区(Vendor.img)当中,这样刷新的system.img 才不会影响到Vendor HAL Implemetation。
在Android 8.0及之后,HAL库和framework不在同一个进程,他们之间使用hwbinder进行进程间通信。
Android 8.0引入Treble后,各层的通信机制如下:
HwBinder 通信采用 C/S 架构,从组件视角来说,包含 Client、 Server、 HwServiceManager 以及 HwBinder 驱动,其中 HwServiceManager 用于管理系统中的各种服务。
HwBinder 在 framework 层进行了封装,通过 JNI 技术调用 Native(C/C++)层的 HwBinder 架构。
HwBinder 在 Native 层以 ioctl 的方式与 Binder 驱动通讯。
HwBinder通信原理图如下:
HwBinder通信流程如下:
首先服务端需要向HwServiceManager进行服务注册,HwServiceManager有一个全局的service列表mServiceMap,用来缓存所有服务的对象和name。
客户端与服务端通信,需要拿到服务端的对象,由于进程隔离,客户端拿到的其实是服务端的代理,也可以理解为引用。客户端通过HwServiceManager从mServiceMap中查找服务,HwServiceManager返回服务的代理。
拿到服务对象后,我们需要向服务发送请求,实现我们需要的功能。通过 BpHwBinder 将我们的请求参数发送给 内核,通过共享内存的方式使用内核方法 copy_from_user() 将我们的参数先拷贝到内核空间,这时我们的客户端进入等待状态。然后 Binder 驱动向服务端的 todo 队列里面插入一条事务,执行完之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间(这里只是执行了拷贝命令,并没有拷贝数据,binder只进行一次拷贝),唤醒等待的客户端并把结果响应回来,这样就完成了一次通讯。
在这里其实会存在一个问题,Client和Server之间通信是称为进程间通信,使用了HwBinder机制,那么Server和HwServiceManager之间通信也叫进程间通信,Client和Server之间还会用到HwServiceManager,也就是说HwBinder进程间通信通过HwBinder进程间通信来完成,这就好比是 孵出鸡前提却是要找只鸡来孵蛋,这是怎么实现的呢?
HwBinder的实现比较巧妙:预先创造一只鸡来孵蛋:HwServiceManager和其它进程同样采用HwBinder通信,HwServiceManager是Server端,有自己的HwBinder对象(实体),其它进程都是Client,需要通过这个HwBinder的引用来实现HwBinder的注册,查询和获取。
HwServiceManager提供的HwBinder比较特殊,它没有名字也不需要注册,当一个进程使用BINDER_SET_CONTEXT_MGR_EXT命令将自己注册成HwServiceManager时HwBinder驱动会自动为它创建HwBinder实体(这就是那只预先造好的鸡)。
其次这个HwBinder的引用在所有Client中都固定为0(handle=0)而无须通过其它手段获得。也就是说,一个Server若要向HwServiceManager注册自己HwBinder就需要通过0这个引用号和HwServiceManager的Binder通信。
类比网络通信,0号引用就好比域名服务器的地址,你必须预先手工或动态配置好。要注意这里说的Client是相对HwServiceManager而言的,一个应用程序可能是个提供服务的Server,但对HwServiceManager来说它仍然是个Client。
/system/tools/hidl/ |
根据HAL接口 .hal来产生相应的Proxy(client端接口)以及stub(server端接口) |
/system/libhidl |
HIDL状态与HAL服务管理接口 |
/hardware/interfaces/ |
各个模块HAL层接口,每个模块都包含了一个Android.bp的脚步来生成对应的代理(Proxy)与存根对象(stub),如radio接口IRadio.hal,sensors接口ISensors.hal |
android_os_HwBinder.java\cpp (JNI) |
Java层HAL binder的JNI代码,负责将Java层的请求传递给相应的server进程 |
/dev/hwbinder |
/kernel/msm-4.9/drivers/android/binder.c |
/kernel/msm-4.9/drivers/android/binder_alloc.c |
hwservicemanager |
/system/hwservicemanager/hwservicemanager.rc |
/system/hwservicemanager/ServiceManager.cpp |
/system/hwservicemanager/HidlService.cpp |
/system/hwservicemanager/HidlService.h |
libhwbinder |
/system/libhwbinder/Binder.cpp |
/system/libhwbinder/BpHwBinder.cpp |
/system/libhwbinder/IInterface.cpp |
/system/libhwbinder/IPCThreadState.cpp |
/system/libhwbinder/ProcessState.cpp |
/system/libhwbinder/Parcel.cpp |
/system/libhwbinder/include/hwbinder/Binder.h |
/system/libhwbinder/include/hwbinder/BpHwBinder.h |
/system/libhwbinder/include/hwbinder/IBinder.h |
/system/libhwbinder/include/hwbinder/IInterface.h |
/system/libhwbinder/include/hwbinder/IPCThreadState.h |
/system/libhwbinder/include/hwbinder/ProcessState.h |
/system/libhwbinder/include/hwbinder/Parcel.h |
Android引入Treble机制后,扩展了一个vendor分区,为了能够快速的进行升级,做了隔离HAL层的机制,为了System/System、System/Vendor、Vendor/Vendor 之间进行不同的进程间通信,把原有的Binder机制拆分成了Binder、HwBinder、VndBinder。
Binder和VndBinder 共用一套libbinder、servicemanager的代码,使用AIDL接口,两者不能共存。
HwBinder采用了单独的libhwbinder、hwservicemanager的代码,单独管理,使用HIDL接口。
三者之间互不干扰,在方便系统升级的同时,又提升了系统的安全和稳定性。
参考:
《Android Treble Architecture: Part 3 - Changes for Treble[Binder & ServiceManager]》
我的微信公众号:IngresGe