HIDL Hal 开发指南2 —— Android 8 HAL 变迁

Android 8 HAL 的变化

通过前面 传统 Hal 开发指南 的学习,我们知道,在 Android8 以前:

  • Hal 是对驱动操作的包装库,操作硬件的具体逻辑可以放到 Hal 中,驱动程序本身只提供基本的功能。这样可以规避 Linux 内核的开源协议,硬件厂商提供 Hal 的 so 库即可。
  • 形式上,Hal 是一个个的 so 库。
  • Google 通过 hw_device_t 和 hw_module_t 等结构体给 Hal 层的实现提供了整体的结构和框架。
  • Framework 中的程序通过 dlopen 函数来加载 so 库

Android8 之前的 Hal,本文称之为传统 Hal, 传统 Hal 的整体架构如下图所示:

到目前为止,一切都很美好,直到 Android 做大做强,Google 这边开发速度越来越快,新系统的发布越来越频繁。大量的老旧 Andorid 设备仍然跑着几年前的老系统。

为什么会这样呢?

在 Android8 以前,Framework 层由 Google 开发,一众下游厂商帮忙解 bug 加特性。HAL 层,芯片/方案厂商会根据自己主板的特性进行开发。每次 Google 那边 Framework 升级,Framework 与 Hal 之间的接口可能或多或少有变动,芯片/方案厂商就需要修改 Hal 层代码来适配 Framework 层的变化,适配好了,然后把源码下发到手机厂商,手机厂商拿到源码后又要接着来魔改 Framework 层。这就导致了,新系统升级需要最少三个阶段,费时费力,成本高,终端厂商升级意愿不强。

Google 的 boss 们肯定受不了,花了大价钱开发的软件,手机都升级不上去,我还怎么挣钱,这样不行,一群小弟拖老大的后腿。

为了挣更多的钱,在 Android8, Google 引入了一个叫 Treble 的架构,核心的修改主要有:

  • 添加了 Vendor 分区,Hal 都打包到 Vendor 分区去,Framework 打包到 System 分区。两个分区中的程序不能链接对方的 so 库。
  • HAL 不在是 so 库了,是一个个运行中的进程。
  • 扩展了 Binder,添加了 Framework 分区中进程与 Vendor 分区中进程通信的 HwBinder,Vendor 分区内不同进程同级通信的 VndBinder。
  • Framework 层通过 HwBinder RPC 调用访问 Vendor 中的 HAL 进程。

Android8 以后 Framework 与 HAL 之间的整体架构如下:

这个时候,只要我们保持 Framework 与 Vendor 之间的 Binder RPC 通信接口稳定,Framework 与 Vendor 就可以单独升级。Google 这边 Framework 开发好以后,终端手机厂商可以先用以前的 Vendor,直接用新的 Framework 来魔改,魔改好以后,直接推送 System 分区给老手机升级,芯片/方案厂商那边把 Vendor 升级好了以后,手机厂商拿到后,再把 Vendor 分区推送给老手机,或者 Vendor 就直接不升级了。这样,Google 开发的 Framework 就能更快的安装到用户手机上了。

理想很丰满,显示很骨感。

要实现上述场景的前提是,Vendor 分区中的 Natvie 程序/库只链接 Vendor 分区中的 so 库,Framework 分区中的 Native 程序/库只能链接 Framework 分区的库,不存在交叉链接的情况。另外还需要 Framework 和 Vendor 分区中的进程只通过 HwBinder RPC 通信,且通信的接口稳定。

实现上,这是不可能的,主要有两点原因:

  • 部分 Vendor 的实现需要使用到 Framework 中的 so 库,这样 Vendor 分区中的程序就需要链接到 Framework 中的 so 库。
  • 部分 HAL 在使用上有性能要求,使用 HwBinder RPC 访问性能不够看,这样 Framework 分区的程序就需要通过链接 Vendor 中的 Hal so 库来直接使用 HAL。

怎么解决呢?我们一个个看。

先看 Framework 分区中的 so 库怎么让 Vendor 分区链接到,而且不影响 System 分区的单独升级。

主要是两个手段:

  • 手段一:Framework 中重要的 so 库,由 Google 来维护,Google 来保证这些库的 API 稳定性。这些库统称为 LL-NDK,包含了 libEGL.so, libGLESv1_CM.so, libGLESv2.so, libGLESv3.so, libandroid_net.so, libc.so, libdl.so, liblog.so, libm.so, libnativewindow.so, libneuralnetworks.so, libsync.so, libvndksupport.so, libvulkan.so。这样,Framework 单独升级以后,由于这些库的 API 是稳定的,老的 Vendor 分区也是能正常工作的。

  • 手段二:如果一个 Framework 中的 so 库会被 Vendor 分区访问到,就把它复制一份到一个单独的路径中。这样, Framework 升级以后,Vendor 分区中用到的 Framework so 库是上一个版本的 Framework 中拷贝出来的,新的 Framework 中即使改变了这些 so 库的 API,也不影响 Vendor 的正常工作,这些拷贝两份的库称为 VNDK。另外需要知道的一点是,一个 so 库要成为 VDNK,需要满足一些要求:

    • 与 Framework 中的程序没有 IPC 通信
    • 不依赖于 ART 虚拟机
    • 不读取/写入文件格式不稳定的文件/分区
    • 没有需要法律审查的特殊软件许可
    • 其代码所有者不反对供应商使用该库

我们接着看另一个问题,Vendor 分区中的 Hal so 库怎么让 Framework 分区链接到,而且不影响 System 分区的单独升级。

解决方案也大体雷同,Framework 要加载的 HAL so 库,也是统一由 google 维护,Google 来保持其 API 的稳定性。这些 HAL so 库统称为 Same-Process HAL (SP-HAL)。SP-HAL 库有以下一些:

SP-HAL 也会链接 Framework 中的一些 so 库,这些 so 库必须是 VNDK 库或者 LL-NDK。一个 VNDK 库如果被 SP-HAL 链接了,我们就称之为 VNDK-SP 库。

官方的文档说,Google 的大佬们会加倍小心仔细检查 VNDK-SP 库,保证他们在 Framework 和 Vendor 中不出问题。

总结一下:

  • 问题:Framework 和 Vendor 中存在交叉链接,影响 Framework 的单独升级
  • 解法办法:
    • Google 下场保障 so 库 API 稳定性
    • 另外拷贝一份 so 库,Framework 和 Vendor 各用各的 so 库。

HwBinder 指南

前面我提到,在 Android 8,Google 扩展了 Binder。本节主要分析其中的 HwBinder。

我们先回顾一下 Binder 的整体架构:

  • Binder 是一个 linux 驱动程序,为应用层的跨进程函数调用(RPC)提供支持
  • Binder 驱动对应的设备文件是 /dev/binder
  • libbinder.so 库是对 Binder 驱动使用的包装库,方便应用程序的开发
  • 在 RPC 过程中,被调用的一方称为服务,通常需要提前注册到 ServiceManager
  • Binder 只能用于支持 Framework 中进程之间的 RPC 调用

HwBinder 与 Binder 的异同点如下:

  • HwBinder 和 Binder 的驱动程序是同一个
  • HwBinder 对应的设备文件是 /dev/hwbinder
  • HwBinder 有自己的 native 应用层库 libhwbinder.so
  • HwBinder 有自己的服务管家 HwServiceManager
  • HwBinder 用于支持 Framework 进程访问 vendor 中的服务

HwBinder 的整体架构如下:

实际的开发以及后续的源码分析,我更多接触的是应用层库 libhwbinder.so,这个库基本就是 libbinder.so 库的翻版:

源文件对比:

(图片来自 blog.csdn.net/yangwen123/...)

类对比:

(图片来自 blog.csdn.net/yangwen123/...)

通信架构对比:

(图片来自 blog.csdn.net/yangwen123/...)

这个库的实现了解一下就可以了,和 libbinder 大致类似,在 Android12 就不推荐使用了。

HIDL HAL 简介

AIDL 用于生成代码框架,帮助我们快速实现 Binder 的服务端与客户端。

大多数情况下,HAL 层以进程加 HwBinder 服务的形式存在,Framework 层通过 HwBinder 调用到 HAL 层的 Binder 服务。HIDL 作用与 AIDL 类似,用于生成代码框架,帮助我们快速实现 HwBinder 的服务端与客户端。

根据 Google 文档的介绍,HIDL HAL 可以分为以下几种:

  • Binderized HALs 绑定式:HAL 层以进程的形式存在,内部有一个 HwBinder 服务端对象,对外提供 HwBinder 远程调用服务。Framework 通过 HwBinder 远程调用到 HAL 中的函数,这些函数直接访问具体的驱动。
  • Passthrough HALs 直通式:这种模式存在,主要是为了复用传统 HAL 的实现。HAL 层以进程的形式存在,内部有一个 HwBinder 服务端对象,对外提供 HwBinder 远程调用服务。Framework 通过 HwBinder 远程调用到 HAL 中的函数,这些函数会去加载传统 HAL 实现来操作具体硬件。
  • Same-Process HALs 同进程式:有的 HAL 模块有性能需求,调用它们不能太慢了。这类 HAL 以 so 库的形式存在,Framework 层会直接链接这些 so 库,以保证调用的性能。

后续的章节,我们先写一个简单的 HIDL HAL 体验,接着在针对每一类 HAL,我们都会挑出一个源码中的实例来做详细分析。

参考资料

相关推荐
小雨cc5566ru5 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
bianshaopeng6 小时前
android 原生加载pdf
android·pdf
hhzz6 小时前
Linux Shell编程快速入门以及案例(Linux一键批量启动、停止、重启Jar包Shell脚本)
android·linux·jar
火红的小辣椒7 小时前
XSS基础
android·web安全
勿问东西9 小时前
【Android】设备操作
android
五味香9 小时前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
图王大胜11 小时前
Android Framework AMS(01)AMS启动及相关初始化1-4
android·framework·ams·systemserver
工程师老罗13 小时前
Android Button “No speakable text present” 问题解决
android
小雨cc5566ru14 小时前
hbuilderx+uniapp+Android健身房管理系统 微信小程序z488g
android·微信小程序·uni-app
小雨cc5566ru15 小时前
微信小程序hbuilderx+uniapp+Android 新农村综合风貌旅游展示平台
android·微信小程序·uni-app