Android O Treble框架笔记(基于高通845平台)

tags: android


文章目录

  • Android O Treble框架笔记(基于高通845平台)
    • @[toc]
    • **0 前言**
    • **1 关于Treble架构**
    • **2 hardware中的IBinder与IBase**
      • **2.1 关于binder**
      • **2.2 关于base**
      • **2.3 对binder与base的理解**
    • **3 hardware中的toBinder与formBinder**
    • **4 HIDL的套路**

0 前言

1 关于Treble架构

这里关于treble的什么结构图呀之类的我就不贴了,反正讲treble的文章基本上都贴了一毛一样的图,这里就推荐几个我觉得讲的比较好的文章链接吧,看后面相关内容时默认已经掌握了以下链接中所述的内容。
AndroidO Treble架构分析
AndroidO Treble架构下的变化
AndroidO Treble架构下的接口文件编译
AndroidO Treble架构下Hal进程启动及HIDL服务注册过程
AndroidO Treble架构下Binder对象的转换过程
AndroidO Treble架构下hwservicemanager启动过程

上面6篇文章里面前面3篇比较简单,随便看看,关键的是AndroidO Treble架构下Hal进程启动及HIDL服务注册过程和AndroidO Treble架构下Binder对象的转换过程这两篇,如果对binder完全没什么概念的话可能比较难,但是只要自己结合代码实际跟以下就明白了。最后一篇了解以下没什么坏处。

2 hardware中的IBinder与IBase

2.1 关于binder

一般来说,Binder通信中由一个Bnxxx和一个Bpxxx组成,Bnxxx是指一个本地的Binder对象,或者理解为一个主机,Bpxxx是指一个远程Binder对象或者理解为从机。这里的远程我的理解是指的另外一个线程中的Binder对象,也就是需要通信的对端线程,对端线程有一个Bnxxx的对象,然后本地需要一个Bpxxx来与Bnxxx进行交互。换句话说就是如果我要与另外一个线程,那么对面的线程必须有一个主机(Bnxxx),然后我这里需要有一个从机(Bpxxx)才能进行通信。

在Hardware中,binder文件位于:system\libhwbinder\Binder.cpp

IBinder:hwbinder体系的所有类的父类,其中目前已知方法:

  • localBinder:如果此binder在通信中处于主机地位,则返回有效值,否则返回NULL,在binder类中该函数返回NULL,需要子类根据实际情况继承与实现;
  • remoteBinder:与localBInder完全相反,这两者一般有且仅有一个返回非NULL而另外一个返回NULL;

BHwBinder:继承自IBinder,在通信中处于主机地位的模块需要继承自该类,其中已知方法:

  • transact:发送需要发送的消息,一般需要重构该函数;
  • onTransact:处理消息,一般需要重构该函数,以实现特定消息相应;
  • localBinder:重载Binder中的该函数,使其返回this;

BpHwRefBase:hwbinder体系中与binder同级的基类,被BpInterface类继承,详见"system\libhwbinder\include\IInterface.h",其中已知方法:

  • mRemote成员:一般为BpHWxxx对象(该对象必须继承自IBinder接口),用来跟binder通信中的主机通信的接口,一般来说,最终都是通过IPCThreadState完成最终的数据传输操作;
  • remote方法:返回mRemote成员,可以通过该成员实现BpHWBinder相关操作;

在Hardware中与BHwBinder对等的类是BHwBinder类,该类位于:system\libhwbinder\BpHwBinder.cpp

BpHwBinder:继承自IBinder,在通信中处于从机地位的模块需要继承自该类,与BHwBinder地位相同,其中已知方法:

  • transact:最终通过IPCThreadState::self()->transact发送消息
  • remoteBinder:重载Binder中的该函数,返回this,同时没有重载localBinder,所以localBinder返回NULL;

2.2 关于base

IBase对象是Binder通信中的业务逻辑对象。
举个栗子:
binder通信中所谓的远程调用……既然要能调用函数,那么一定有一个对象,这个对象提供了一些方法。于是binder就这样实现了:
1、定义一个接口,继承自IBase
2、找一个类实现这个接口
3、在本地实例化这个类
4、本地程序调用这个类的接口
这样就完成了远程调用。
对于没有看过这块代码的人可能有些懵逼……感觉上面的做法就是一个普通的本地函数调用,跟远程调用没有半毛钱关系……其实本来就是这样,他确确实实就是个本地调用,这个世界上本来就不存在正真意义上的远程调用这种魔术……binder说白了就是一个基于消息的通信机制……关于google宣称的binder机制有多么多么的好,性能多么多么的强,其实没有那么夸张,其他手段和方法也可以实现比binder效率更高的通信!但我这里并不是要否定binder,我觉得binder更主要的贡献实在安全方面,binder的存在是权衡了安全和效率之后的产物,所以是非常有意义的,但是并不是神话。

这里有个比较关键的地方,就是找一个类实现这个接口,这个类是通过工具自动生成的,在AndroidO Treble架构下的接口文件编译里面已经说的很清楚了,至于自动生成的类里面方法的具体实现后面会分析,这里暂时跳过。

所以总结上面的过程就是,我本地本来就有一个对象,该对象实现了所有远程的接口,至于该对象是怎么实现的,我们不用去管,最后我们去调用这个对象的接口,可以得到正确的计算结果。

所以说,IBase其实就是业务逻辑,因为IBase的子孙对象就是正真实现被调用的方法的对象。

2.3 对binder与base的理解

上面说了,IBase对象是实现的业务逻辑,也就是本地调用的一个真实的对象,那么既然要能与远程的线程进行通信就必须有一个通信的模块,这个模块就是IBinder对象。IBinder对象中最关键的方法就是transact(),该函数会调用IPCThreadState::self()->transact()来完成最终的消息发送过程。

IBase对象通过remote()方法来获取与之绑定的IBinder对象,此IBinder对象在IBase对象创建时作为参数传入。这里以BpHwServiceManager为例:

相关的文件:BpHwServiceManager.h/serviceManagerAll.cpp
BpHwServiceManager继承自BpInterface<IServiceManager>BpInterface<IServiceManager>又继承自:

template<typename INTERFACE>
class BpInterface : public INTERFACE, public IInterface, public BpHwRefBase

所以,BpHwServiceManager继承自IServiceManagerBpInterfaceIInterface以及BpHwRefBase,其中BpHwRefBase是在IBinder.h所定义的,在前面提到过。
关于BpHwServiceManager中mRemote的来历:
BpHwServiceManager是在函数defaultServiceManager()中创建的:

sp<IServiceManager> defaultServiceManager() {{……while (details::gDefaultServiceManager == NULL) {details::gDefaultServiceManager =fromBinder<IServiceManager, BpHwServiceManager, BnHwServiceManager>(ProcessState::self()->getContextObject(NULL));……}}}return details::gDefaultServiceManager;
}

其中getContextObject()最终会返回一个BpHwBinder类型的对象:

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{return getStrongProxyForHandle(0);
}sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{……if (e != NULL) {……if (b == NULL || !e->refs->attemptIncWeak(this)) {b = new BpHwBinder(handle);
……result = b;} else {……}}return result;
}

接着进入fromBinder函数:

template <typename IType, typename ProxyType, typename StubType>
sp<IType> fromBinder(const sp<IBinder>& binderIface) {……if (binderIface->localBinder() == nullptr) {return new ProxyType(binderIface);}
……
}

这里实际上就是实例化了一个BpHwServiceManager对象:

/* serviceManagerAll.cpp */
BpHwServiceManager::BpHwServiceManager(const ::android::sp<::android::hardware::IBinder> &_hidl_impl): BpInterface<IServiceManager>(_hidl_impl),::android::hardware::details::HidlInstrumentor("android.hidl.manager@1.0", "IServiceManager") {}
/* IInterface.h */
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote): BpHwRefBase(remote)
{}

最终,mRemote成员被赋值为在getStrongProxyForHandle()中创建的BpHwBinder类型对象。

3 hardware中的toBinder与formBinder

toBinderformBinder在功能上基本上是相反的两个函数,而且经常会成对的使用,所以这里就一起来分析一下。这里的to和form的对象一般会是一个IBase对象,也就是说这两个函数的意思大多数情况下(就目前我所涉及到的地方)是指的把一个IBase对象封装进一个IBinder类型的对象和通过一个IBinder类型的对象得到一个IBase类型的对象。

这里先从简单的formBinder说起,该函数是从IBinder对象得到IBase对象的过程:

template <typename IType, typename ProxyType, typename StubType>
sp<IType> fromBinder(const sp<IBinder>& binderIface) {using ::android::hidl::base::V1_0::IBase;using ::android::hidl::base::V1_0::BnHwBase;if (binderIface.get() == nullptr) {return nullptr;}/* 通过localBinder来判断是Bp还是Bn */if (binderIface->localBinder() == nullptr) {/* 如果是Bp,则根据传入的类型创建一个对象,传入的ProxyType类型一般是Bpxxx,继承自IBase该IBase类在创建时把传入的参数binderIface(为IBinder类型)作为remote,使IBase与IBinder绑定 */return new ProxyType(binderIface);}/* 如果是Bn类型,则binderIface对象(BHwBinder类型)创建时已经有绑定的IBase对象了,这里直接获取 */sp<IBase> base = static_cast<BnHwBase*>(binderIface.get())->getImpl();/* 检查该IBase对象是否可以转换成IType类型的对象,说的明白一点,其实这里就是判断模板那里传进来的第一个参数和参数列表传进来的那个binder对象中绑定的IBase对象是不是有关系的,一般这种关系是继承关系,如果有关系,则继续后面的操作,如果没关系则返错,告诉调用者你传错参数了这里,必须保证模板传进来的第一个参数和第三个参数是有关系的,一般来说第三个参数必须继承自第一个参数,第一个参数继承自IBase */if (details::canCastInterface(base.get(), IType::descriptor)) {/* 这里就是一个类型转换,前面已经保证了可以转换 */StubType* stub = static_cast<StubType*>(binderIface.get());/* 返回一个IBase对象,该对象的类型为StubType,并继承自IType */return stub->getImpl();} else {return nullptr;}
}

接下来是toBindertoBinder就是从IBase对象得到IBinder对象的过程:

template <typename IType, typename ProxyType>
sp<IBinder> toBinder(sp<IType> iface) {IType *ifacePtr = iface.get();if (ifacePtr == nullptr) {return nullptr;}/* 通过IBase的isRemote()来判断该IBase对象是Bp还是Bn,Bp会重写该函数为true,bn则重写该函数为false,Ixxx接口里面重写该函数为false,IBase也为false */if (ifacePtr->isRemote()) {/* 如果是Bp的话,BpHwBinder在创建时会传入一个IBinder对象,这里将返回创建时传入的IBinder对象 */return ::android::hardware::IInterface::asBinder(static_cast<ProxyType *>(ifacePtr));} else {/* 获取该IBase对象的描述符,这里一般在Ixxx接口中,上面的例子里此处在ServiceManagerAll.cpp中,相关函数定义也在里面 */std::string myDescriptor = details::getDescriptor(ifacePtr);if (myDescriptor.empty()) {// interfaceDescriptor failsreturn nullptr;}/* 这里实际是获取了new BnHwServiceManager()的方法 */auto func = details::gBnConstructorMap.get(myDescriptor, nullptr);if (!func) {return nullptr;}/* 创建一个BnHwServiceManager类型对象,其继承关系:BnHwServiceManager-->BnHwBase-->BHwBinder-->IBinder所以可以转换成一个IBinder对象,并返回 */return sp<IBinder>(func(static_cast<void *>(ifacePtr)));}
}

在上面的例子中有两个很关键的对象:BpHwServiceManagerBnHwServiceManager。这两个对象都是通过*.hal文件自动生成的,这里盗一张图来说明:

里面的BpFoo.h和BnFoo.h就是和上面两个类相对应的,FooAll.cpp是iFoo、BpFoo和BnFoo的实现。

但是这里有一个有趣的地方,BpHwServiceManager是一个IBase类型的对象,BnHwServiceManager是一个IBinder类型的对象,这里很容易引起误解,因为这两个类的定位看上去很对称,而且名字也很像,但结果确实完全不同的东西……这两个类的类型的不同也可以从toBinder和formBinder两个函数里窥见一二。

关于这里,在后面的camera相关代码分析的时候还会进一步分析,但是关于Google为什么这么设计,暂时还没有更深刻的理解。虽然说Bp端属于远程调用,面对的是Ixxx接口,Bn端的Bn会通过binder发送,而binder只能传输IBinder类型的对象等等,我觉得这些都不足以回答上面的疑问,我觉得这些都只是表象,Google真正这样设计的目的应该还要更往下挖几层。

4 HIDL的套路

总结一下个人理解的treble框架下的Binder通信过程:
1、Bn端向Binder server把自己注册成一个server
2、Bp端通过Ixxx接口中的getserver()方法获取一个BpHwxxx对象,该对象继承自Ixxx。这里的所谓getserver其实最终还是自己在本地创建了一个BpHwxxx对象,只是通过binder机制找到binder server获取了一些Bn端的标志信息。
3、Bp调用Ixxx的某个接口,该接口其实是在BpHwxxx中实现的,所以实际上是调用的上面创建BpHwxxx本地对象的对应接口,然后该接口中通过remote()发送一条消息给Bn端
4、Bn端收到消息后,根据消息标志进行分类,然后调用BnHwxxx中的IBase对象的对应接口,这个IBase对象必须继承Ixxx接口,并且是在BnHwxxx创建时传给BnHwxxx的。
5、上面说的BnHwxxx中的IBase对象其实就是这个接口真实执行函数,该函数执行完后,将计算结果放在输入的保存输出结果的变量中,然后该输出结果变量会一层层返回,直到到达Bp端的调用处。

以上就是远程调用的流程,也是hw binder的通信过程,所以这里面其实根本就不是什么远程调用,纯粹的消息交互,客户端给服务端一条请求,服务端计算,然后将计算结果返回给客户端,仅此而已。

关于注册binder服务的理解:
什么要registerAsServer,为什么要getServer,目前的理解为,由于不同的进程互相之间最开始完全是不通的,必须有一边先把自己注册成一个server,然后提供一个Ixxxx的接口对象,这样另外的线程在需要与其通信时就可以通过Ixxxx::getserver拿到他的接口对象的标志信息,然后才可以进行通信。那么一个线程中其实可以有多个Ixxx接口对象,每个Ixxx接口对象通过一对Bnxxx和Bpxxx进行通信,但是所有其他的Ixxxx接口对象的获取还是要依赖最初注册为Server的那个Ixxx接口对象来完成,也就是说注册成Server的Ixxx接口对象要提供创建其余Ixxx接口对象的方法。

Android O Treble框架笔记(基于高通845平台)相关推荐

  1. Android O 的camera framework-hal层框架笔记(基于高通845平台)

    Android O 的camera framework/hal层框架笔记(基于高通845平台) tags: android camera 文章目录 Android O 的camera framewor ...

  2. 基于高通sdx12平台,简单介绍编译(bitbake)

    高通sdx12平台:bitbake 编译介绍 Audio machine.platform.dai等单独编译介绍 新添加bb文件 编译介绍 1.编译环境配置脚本 Audio machine.platf ...

  3. Android上HDMI介绍(基于高通平台)

    本文重点针对HDMI在android上的应用,而比较相关的就是overlay机制.overlay在这里只是简单的介绍,后续会有文章再专门详述. 我没记错的话,高通从7X30开始,平台就可以支持HDMI ...

  4. 基于高通X55平台的5G模组iperf灌包参数配置

    主机配置: iperf版本: iperf 2.0.0 测试环境: Windows10 根据高通文档说明,在iperf loopback灌包前需通过QPST工具将loopback_config.txt文 ...

  5. 050@ 高通845平台抓取3a log

    需要打开如下AF log: adb shell "echo logVerboseMask= 0x08000000>> /vendor/etc/camera/camxoverrid ...

  6. 高通SDX55平台:R8168 PHY驱动适配

    高通SDX55平台 R8168 PHY驱动适配 1. SDX55 CPE应用场景 高通5G平台SDX55支持5G独立组网(SA)和非独立组网(NSA)两种网络架构,同时兼容LTE和WCDMA制式,拥有 ...

  7. 【转载】高通msm8996平台的ASOC音频路径分析(基于androidN及linux3.1x)

    高通msm8996平台的ASOC音频路径分析(基于androidN及linux3.1x) tags : msm8996 sound linux android 原文:高通msm8996平台的ASOC音 ...

  8. 【高通SDM660平台 Android 10.0】(14) --- Camera ISP

    [高通SDM660平台 Android 10.0]--- Camera ISP 一.Camera ISP 与 DSP 区别 1.1 名词解释 1.2 功能解释 1.3 手机摄像头ISP是独立好还是内置 ...

  9. [转]QNX系统-基于高通骁龙SA8155平台,中科创达发布智能驾驶舱3.0解决方案

    如果你认为本系列文章对你有所帮助,请大家有钱的捧个钱场,点击此处赞助,赞助额0.1元起步,多少随意 声明:本文只用于个人学习交流,若不慎造成侵权,请及时联系我,立即予以改正 锋影 email:1741 ...

最新文章

  1. mongodb java 日志分析_记一次log4j与mongodb集成引发的问题分析
  2. 震撼!17 个改变世界的数学公式...
  3. 鸟哥Linux私房菜_基础篇(第二版)_第七章学习笔记
  4. 我写的一个给time_t赋值的小函数
  5. java高校教师工作量管理系统_基于ssh/bs/java/asp.net/php/web/安卓的高校教师工作量管理系统...
  6. 全国计算机等级考试题库二级C操作题100套(第38套)
  7. Kettle环境搭建及使用(数据迁移)
  8. 软件开发 —— 极限编程(XP:Extreme Programming)
  9. H2O中的随机森林算法介绍及其项目实战(python实现)
  10. 4G DTU设备数据上传阿里云微信小程序获取阿里云设备数据
  11. 显示器突然黑屏怎么办
  12. Android 仿qq 点赞功能
  13. ELK:ElasticSearch定期关闭和删除索引脚本
  14. 阿里云香港服务器和大陆服务器的优缺点分析
  15. iOS证书的种类和其作用
  16. 《那些年啊,那些事——一个程序员的奋斗史》——101
  17. 运筹帷幄——我国古代的高超算术
  18. C语言中文网的资源的使用——链接索引
  19. 04穿越功耗墙_怎么提升性能笔记
  20. 用u盘重装微软官方win10专业版--详细操作文档

热门文章

  1. 目标跟踪综述 (持续更新)
  2. 在读书郎平板上安装第三方应用
  3. 魔兽怀旧 核心数据人物基本数据分析,待续
  4. 乌云龙 php,【远方•夜读】安徽《乌云寻龙》作者•马洪星 主播•孙春苓
  5. [摄影基本学习]-02-器材了解(从零开始手把手教你学摄影)
  6. java smack jar_Smack:一个开源的XMPP用于即时通讯的客户端类库
  7. 公司发的月饼出虫了~~~~
  8. 德卡斯特里奥算法——找到Bezier曲线上的一个点
  9. SAP-QM 检验批状态汇总
  10. shardingsphere 支持达梦数据库