AndroidO Treble架构分析1

从AndroidO开始,google引入了Treble架构,目的是为了方便系统升级,将oem定制的东西和Framework分离。

0、HIDL Treble架构简介

AndroidO之前的版本:

在此之前的Android系统架构当中,Android Framework与Android HAL是打包成一个system.img的,而且Framework与HAL之间是紧耦合的,通过链接的方式使用相应的硬件相关so库。老版本的android 的系统框架当中framework与HAL之间的一般架构框架是:AndroidO Treble架构分析1_第1张图片

所以每次Android framework的升级需要对应的Android HAL升级

AndroidO以及以后的版本

在Android O以及以后的版本当中,Android 更新了新的框架设计在新的框架设计当中,引入了一套叫HIDL的语言来定义Freamework与HAL之间的接口,新的架构如下图:


跟以往的Android 版本相比较,Android O里使用HIDL来解耦Android Framework 与Vendor HAL Implemetation之间的关系,从而简化降低Android系统升级的影响与难度。

Android Framework会在system分区当中,而Vendor HAL Implemetation会在一个新定义的分区(Vendor.img)当中,这样刷新的system.img 才不会影响到Vendor HAL Implemetation,所以在Android O中的升级方式变成以下方式:

AndroidO Treble架构分析1_第2张图片

google的目的很理想,但现实很残酷,大部分oem厂商是没有google的研发实力的,无法跟上google的节奏,因此很多厂商还停留在android老版本,为了给oem厂商学习时间,同时保持Android向前兼容,google为HAL定义了3种类型:

1,BinderizedHALs,从名字上应该是指Binder化的HAL,也就是说HAL都被写成了binder service了,Android FW都是binder client。
2,PassthroughHALs,从google的官方介绍来说,这个是对原先HAL的包装,但是最终的binder service 跟binder client都是活在同一个进程当中。这个应该是对老版本HAL的兼容。

3,Same-ProcessHALs,由于某些性能的因素,这些HALs必须运行在Android Framework 所在的进程当中,比如surfaceflinger中的gralloc hal,如果进行进程分离,那么对系统性能影响较大。

AndroidO Treble架构分析1_第3张图片

1、HIDL 的概念

  HIDL 读作 hide-l,全称是 Hardware Interface Definition Language。它在 Android Project Treble 中被起草,在 Android 8.0 中被全面使用,其诞生目的是使 Android 可以在不重新编译 HAL 的情况下对 Framework 进行 OTA 升级。 
  HIDL 与 Android Vendor Test Suite (VTS) 测试有紧密的联系。关于 VTS 的介绍可以看我写的《Android Vendor Test Suite (VTS) 的概念、作用及测试方法》这篇文章。 
  使用 HIDL 描述的 HAL 描述文件替换旧的用头文件描述的 HAL 文件的过程称为 * HAL 的 binder 化(binderization)。所有运行 Android O 的设备都必须只支持 binder 化后的 HAL 模块。 
  已发布的 HIDL package包位于 Android 代码库的hardware/interfaces/vendor/目录下。使用 HDIL 描述的 HAL 接口存放在这些目录下的.hal文件中。比如我们可以在hardware/interfaces/audio/2.0/目录下找到部分 Audio HAL 描述文件,如下:

Android.bp
Android.mk
IDevice.hal
IDevicesFactory.hal
IPrimaryDevice.hal
IStream.hal
IStreamIn.hal
IStreamOutCallback.hal
IStreamOut.hal
types.hal
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2、HIDL 基础语法

  HIDL 的语法和 C 语言有点类似,支持嵌套声明,但不支持前向声明和预处理指令。以下是一些常用标记符和数据类型:

  • 标记符

    • /* */   多行注释
    • //    单行注释
    • [empty]  表明当前项的值为空
    • ?     放置在项前,表明该项为可选项
    •     表明该序列包含0个或多个如前述使用分隔符隔开的项
    • ,     逗号用于分隔序列中的元素
    • ;     分号用于标记每个元素的结束位置
    • @entry   当前HAL模块被使用时应当被最先调用的接口
    • @exit   当前HAL模块被调用时应当被最后调用的接口
    • @callflow(next={“name_a”, “name_b”, “name_c”})  当前接口被调用后可能被调用的接口列表。其中name_a接口被调用的概率最大,name_c接口被调用的概率最小。如果只存在1个可能被调用的接口,那么花括号{ }可以省略不写。如果给定的接口名无效,则会导致VTS编译失败。
    • @callflow(next={“*”})  当前接口被调用后可能会调用任意接口
  • 数据类型

    • struct  这个关键字定义一个结构体,格式与C++同
    • union  这个关键字定义一个联合体,格式与C++同
    • MQDescriptorSync & MQDescriptorUnsync  这2个关键字分别定义同步和非同步的FMQ(Fast Message Queue)描述符
    • memory  这个关键字用来声明HIDL中未被映射的共享内存
    • pointer  用这个关键字声明的pointer类型数据只能在HIDL内部使用
    • bitfield< T>模板  这个关键字用来定义一个与模板T相同的可进行位操作的数据。其中T是一个由用户定义的枚举数据类型
    • 有限数组  任何HIDL结构体中可被包含的数据类型都可以声明有限数组
    • 字符串  字符串在HIDL中以UTF8编码存储,所以在和由Java实现的接口进行交互时需要将编码格式转换为UTF16
    • vec< T>模板  这个关键字用来定义一个包含模板T的可变大小的buffer数据。其中T可以是除句柄外的任何HIDL内建或用户自定义数据类型
    • 用户自定义数据类型  用户可以自定义enum、struct、union类型的数据。定义enum数据的格式与C++11同,定义struct数据的格式与C同,定义union数据的格式与C同
  • 关键字

    • interface  用于声明HAL模块中的一个接口,是构成.hal文件的基本单元,可以从其它interface继承而来
    • package  用于声明当前.hal文件中各interface接口所属的包
    • import  用于导入其它包里声明的interface或数据类型,以便在当前.hal文件中使用
  • 示例

    • 结构体声明

      struct Point {
        int32_t x;
        int32_t y;
      };
      • 1
      • 2
      • 3
      • 4
      • 1
      • 2
      • 3
      • 4
    • 嵌套声明

      interface IFoo {
        uint32_t[3][4][5][6] multidimArray;
        vec<vec<vec<int8_t>>> multidimVector;
        vec<bool[4]> arrayVec;
        struct foo {
          struct bar {
            uint32_t val;
          };
          bar b;
        }
        struct baz {
          foo f;
          foo.bar fb; // HIDL uses dots to access nested type names
        }
        …
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    • bitfield< T> 数据声明

      enum Flag : uint8_t {  // 用户定义的枚举类型数据
        HAS_FOO = 1 << 0,
        HAS_BAR = 1 << 1,
        HAS_BAZ = 1 << 2typedef bitfield Flags;  // 声明一个可进行位操作的数据
      setFlags(Flags flags) generates (bool success);
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 有限数组声明

      struct foo {
        uint32_t[3] x; // array is contained in foo
      };
      • 1
      • 2
      • 3
      • 1
      • 2
      • 3
    • 用户自定义enum数据

      enum Color : uint32_t { RED = 0, GREEN, BLUE = 2 } // GREEN == 1
      • 1
      • 1
    • 一个完整的.hal文件

      package android.hardware.audio@2.0;  // 当前package包名
      import android.hardware.audio.common@2.0;  // 导入其它package包
      import IDevice;  // 导入其它.hal
      interface IDevicesFactory {  // 定义一个interface
        typedef android.hardware.audio@2.0::Result Result;
        enum Device : int32_t {  // 定义数据类型
          PRIMARY,
          A2DP,
          USB,
          R_SUBMIX,
          STUB
        };
        /**
         * Opens an audio device. To close the device, it is necessary to release
         * references to the returned device object.
         *
         * @param device device type.
         * @return retval operation completion status. Returns INVALID_ARGUMENTS
         *         if there is no corresponding hardware module found,
         *         NOT_INITIALIZED if an error occured while opening the hardware
         *         module.
         * @return result the interface for the created device.
         */
         openDevice(Device device) generates (Result retval, IDevice result);  // 定义一个方法
      };
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

3、HIDL 文件的组织结构

  每个 HIDL package包里都含有一个名为types.hal的文件,该文件中定义了这个包里所有 interface 共享的用户自定义数据类型,并且一般也会导入需要用到的其它包里的数据类型。 
  当前包中新的定义的 interface 可以继承自从其它包里导入的 interface,这样的继承关系可以使用extend关键字实现。比如下面示例中的 1.1 版本包中的 IQuux 接口就继承自 1.0 版本包中的 IQuux 接口:

// types.hal
package android.hardware.example@1.1
import android.hardware.example@1.0  // 导入1.0的包

// IQuux.hal
package android.hardware.example@1.1
interface IQuux extends @1.0::IQuux {  // 继承1.0包中的接口
  fromBarToFoo(foo.bar b) generates (foo f);  // 直接使用fromBarToFoo方法而不再在当前包中声明
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  由 Google 提供的包叫做core package,包名始终以android.hardware.开头,以子系统名加以区分。比如 NFC 包的名字就应该为android.hardware.nfc,摄像头包的名字就应该为android.hardware.camera。这些 core包存放于hardware/interfaces/目录下。由各芯片厂商和 ODM厂商提供的包叫做non-core package,包名形式一般以vendor.$(vendorName).hardware.开头,比如vendor.samsung.hardware.。这些 non-core包一般存放于vendor/$(vendorName)/interfaces/目录下。 
  包的版本使用主、次版本号进行描述,紧随包名之后。比如[email protected]表述这个 audio 包的版本是 2.0,主版本号是 2,次版本号是 0。 

  此外,每个 HIDL 包在被发布后就不能再对其内容进行变动了,如果要增加或修改这个包里的接口或数据类型,应该新建一个新版本的包,在这个新版本的包里进行变更。


转自文章

Android 8.0 HIDL》https://blog.csdn.net/a1264718192/article/details/78142062/

AndroidO Treble架构分析》https://blog.csdn.net/yangwen123/article/details/79835965

          



你可能感兴趣的:(Android开发之旅)