在 Android 8.0 时,Treble Project 重新设计了 Android 操作系统框架,以便让制造商能够以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。在这种新架构中,HAL 接口定义语言(HIDL,发音为“hide-l”)指定了 HAL 和其用户之间的接口,让用户能够替换 Android 框架,而无需重新编译 HAL。看官方文档,一直看的云里雾里的,不甚理解,这里写一些自己的理解,也许有错误的地方,慢慢纠正。

HAL 类型

概念的明确,为和谷歌文档概念一致。直通式和绑定式指的是语义上从架构上进行的划分,而直通模式和绑定模式是从实现上的划分。

  • Same-Process HAL,分为两种
    • 一种是使用 HIDL 语言封装的,无 service ,只有 *-impl.so 库和具体实现模块,客户端通过 getService() 获取到的是同一个进程中的实例,在 manifest.xml 中指定的传输模式也是 passthrough,但是具体的厂商实现模块也是可以不要的,把实现全放到 *-impl.so 中(例如谷歌的 mapper 和 renderscript)。但厂商为了省事,-impl.so 只是做了封装。对应谷歌 HAL Roadmap 中的②
    • 一种是未使用 HIDL 封装的,只有具体实现模块,系统只能通过 dlopen dlsym 调用,这种方式只能由谷歌使用,厂商不允许使用这种方式。例如对 OpenGL 库的加载
  • 直通式,都有,但 service 起来时注册的是 passthrough 传输模式,调用的是 defaultPassthroughServiceImplementation(),可用于 ②sp-hal 模式和 ③绑定模式
  • 绑定式:
    • 若服务注册时调用的是 registerAsService(),则没有 *-impl.so 和具体的实现模块,实现都放在 service 中。因为这种注册方式,并没有 HIDL_FETCH_IXxx 方法(被注释掉了),所以也就用不到具体的实现模块了。对应谷歌 HAL roadmap 中的④
    • 若服务注册时调用的是 defaultPassthroughServiceImplementation(),就是上面的直通式用于绑定模式,对应谷歌 HAL roadmap 中的③

HAL Roadmap

其中直通式中说的这些库都有,针对的是是大多数的 HAL,有些由于实现的不同,是不需要具体的厂商实现模块的。如 health 和 bluetooth,虽然服务注册的是直通式,但是在 HIDL_FETCH_IHealth 返回的是自己的实例,android.hardware.health@1.0-impl.so 实现了所有接口,就不需要具体的厂商实现模块了。

而又有的一些是厂商自己设计的接口和实现,因此又不一样,但大多数还是上边的规律。

搭载 8.0 出厂的设备,只能采用绑定式(③④模式),需遵守谷歌的规定,因此在 manifest.xml 中除了谷歌规定的几个直通式 HAL,其它的传输模式只能指定为 hwbinder,完全 binder 化。升级到 8.0 的设备,能同时使用绑定式和直通式(②③④模式),也就是除了规定外的 HAL,在 manifest.xml 中的传输模式两者都可以使用。而以前通过 libhardware get_hw_module() 的方式(对应谷歌 hal roamap 中的①)已被废弃,dlopen dlsym 方式只能由谷歌自己使用。

manifest.xml

  1. getStub 为 true 时,不论 manifest 中写的什么传输模式,都采用 PassthroughServiceManager 获取接口对象
  2. getStub 为 false 时,则根据 manifest 中所写的传输模式来选择接口对象获取方式
    • 为 hwbinder 时,采用 defaultServiceManager,从 hwservicemanager 中查询
    • 为 passthrough 时,则采用 PassthroughServiceManage 来获取

而针对升级到 8.0 的设备,存在一种情况:getStub 为 false,manifest.xml 中又把传输模式指定为了 passthrough,那么此时也可以不需要 service daemon(不采用③绑定模式),而直接使用 ②sp-hal 模式。

所以一个 HAL 服务具体走哪个模式,需要同时看注册时使用的方法;和 getService 时 传入的参数 getStub 的值;和 manifest 中指定的传输模式。但是目前所有的 getStub 都被定义为了 false。

具体实现

因此根据 manifest 中指定的传输模式可以分为两种:

  1. 当指定为 passthrough 模式时,在 ②③ 模式下~~(此时其实只有②模式了,是针对升级到 8.0 的设备)~~,客户端 getService() 时,调用的是 libhidl 库中的 getPassthroughServiceManager(),返回一个 PassthroughServiceManager 实例,这个 PassthroughServiceManager 类是 system/libhidl/transport/ServiceManagement.cpp 的一个内部类,实现都在其中。直通式注册服务时,也会调用到 getService(),并将服务通过 registerReference(fqName, name) 注册到 hwservicemanager 中,但并不会调用到其它方法。而 sp-hal 因为没有 service 的 daemon,因此并不会事先就被注册到 hwservicemanager 中去,只有在客户端申请服务时,才会一并注册到 hwservicemanager,若并没有客户端申请该服务,那么 hwservicemanager 中就不会存在该服务。sp-hal 最后获取到的是同一进程中的实例,不是一个代理对象
  2. 当指定为 hwbinder 模式时,在 ③④模式下,getService() 时,调用的是 libhidl 库中的 defaultServiceManager(),通过 binder 返回的是 HwServiceManager 实例,最终远程调用 hwservicemanager daemon 中的方法,获取到代理对象

参考