Gralloc1::Loader 与 gralloc 模块加载
Gralloc1::Loader
用于加载 HAL gralloc 模块。其类定义(位于 frameworks/native/include/ui/Gralloc1.h
)如下:
这个类只包含构造函数,析够函数和一个 Get 函数用于获得 Gralloc1::Device
。该类全部方法实现(位于frameworks/native/libs/ui/Gralloc1.cpp
)如下:
Gralloc1::Loader
在其构造函数中通过 hw_get_module()
函数完成 HAL gralloc 模块的加载,随后创建一个 Gralloc1::Device
。当 gralloc API 版本为 1 时,通过 frameworks/native/include/ui/Gralloc1.h
中定义的 gralloc1_open()
函数创建:
当 gralloc API 版本不为 1 时,则创建 Gralloc1On0Adapter
作为 Gralloc1::Device
,相关函数(位于frameworks/native/include/ui/Gralloc1On0Adapter.h
)如下:
Gralloc1::Loader
的构造函数为 hw_get_module()
传入模块 ID 和 hw_module_t
指针 module
加载 gralloc 模块,其中 module
用于接收加载的结果。gralloc 的模块 ID 定义(位于 hardware/libhardware/include/hardware/gralloc1.h
)如下:
hw_get_module()
函数用于加载 HAL gralloc 模块,其定义(位于 hardware/libhardware/hardware.c
)如下:
hw_get_module()
调用 hw_get_module_by_class()
实现其功能。hw_get_module_by_class()
通过两个步骤完成 gralloc 模块的加载:
- 找到 gralloc 模块文件的路径。
- 加载 gralloc 模块文件。
hw_get_module_by_class()
首先通过模块 ID 和模块实例名称得到模块名称,对于 gralloc 而言,模块 ID为 gralloc
,模块实例名称为空,然后获得模块子名称。模块子名称来自于系统属性。hw_get_module_by_class()
依次尝试从如下几个系统属性中获得模块子名称:
对于 Pixel 设备而言,系统属性 ro.hardware.gralloc
和 ro.arch
未定义,其它几个系统属性值如下:
无法由从系统属性获得的模块子名称找到所对应的模块文件时,则以 default
作为模块子名称继续查找。
有了模块名称和模块子名称,hw_get_module_by_class()
则依次在 /odm -> /vendor -> /system 等目录下查找相应的模块文件:
对于 Pixel 设备,可以在 /system/lib64/hw/
目录下找到如下的 gralloc 模块文件:
最终将采用 /vendor/lib64/hw/gralloc.msm8996.so
作为 gralloc 模块文件。关于这一点,可以从 surfacefinger 进程的内存映射镜像中看到:
hw_get_module_by_class()
通过 load()
函数来加载模块文件:
加载过程主要是加载动态链接库文件,找到其中名为 HAL_MODULE_INFO_SYM_AS_STR
,类型为 struct hw_module_t
的变量,并返回给调用者。
HAL 层要求 HAL 模块中都需要定义一个名为 HAL_MODULE_INFO_SYM_AS_STR 的 struct hw_module_t
变量。HAL_MODULE_INFO_SYM_AS_STR 定义(位于 hardware/libhardware/include/hardware/hardware.h
)如下:
前面看到的 gralloc 实现 gralloc.msm8996.so
位于( gralloc 接口实现) hardware/qcom/display/msm8996/libgralloc
,或位于 hardware/qcom/display/msm8996/libgralloc1
( gralloc1 接口实现)。
gralloc.default.so
实现位于 hardware/libhardware/modules/gralloc
,其 struct hw_module_t
定义(位于 hardware/libhardware/modules/gralloc/gralloc.cpp
)如下:
不同类型的 HAL 模块,不同类型 HAL 模块的具体实现通常会定义自己的 struct hw_module_t
结构,如 gralloc.default.so
的 struct private_module_t
,其定义(位于 hardware/libhardware/modules/gralloc/gralloc_priv.h
)如下:
struct private_module_t
的成员 base
类型为 gralloc_module_t
,该类型定义如下:
gralloc_module_t
类型的第一个成员 common
类型为 struct hw_module_t
。这实际是 C 语言对于继承的实现 —— 父结构体总是作为子结构体的第一个成员存在。对于 HAL gralloc 模块,其 struct hw_module_t
将总是 struct gralloc_module_t
结构的子结构,各个 gralloc 模块实现,通常又都会定义自己的私有 struct gralloc_module_t
结构。
按照接口约定,实现了 gralloc1 接口的 HAL gralloc 模块,其 module->methods->open()
函数应该通过参数 device
返回一个类型为 gralloc1_device_t
的结构,一个 struct hw_device_t
结构的子结构;而实现了 gralloc 接口的 HAL gralloc 模块,则应该通过相同的方法,返回 struct hw_device_t
结构的子结构 struct alloc_device_t
。
gralloc1_device_t
定义(位于 hardware/libhardware/include/hardware/gralloc1.h
)如下:
gralloc1_device_t
新定义了两个函数指针成员,它们也是 gralloc1 的实现模块必须要提供的函数。其中 getCapabilities
用于获得设备支持的 capabilities 的列表,getFunction
则用于获得实现不同功能的函数的指针。
struct alloc_device_t
接口定义如下:
struct alloc_device_t
新定义了用于分配和释放图形缓冲区的接口。
Gralloc1::Loader
的构造函数中,当 majorVersion
不为 1 时,将创建 Gralloc1On0Adapter
把 gralloc 接口下的 struct alloc_device_t
转为 gralloc1 接口下的 gralloc1_device_t
。
前面看到的 gralloc.default.so
,它实现了 gralloc 接口,而不是 gralloc1。
Gralloc1::Device
Gralloc1::Device
是对 gralloc1_device_t
的一个包装。Gralloc1::Device
定义(位于 frameworks/native/include/ui/Gralloc1.h
)如下:
Gralloc1::Device
定义了接口以提供图形内存的分配/释放、lock/unlock 操作,所有的这些操作都依赖于从 gralloc1_device_t
获得的函数指针实现。在Gralloc1::Device
构造期间,会加载相关的函数指针,以及设备的 capabilities:
Gralloc1::Device
中定义的 FunctionLoader
模板,即可以加载函数指针,同时它实现了 operator()
,也是一个函数对象:
FunctionLoader
模板藉由 gralloc1_device_t
的 getFunction()
接口获得函数指针。Gralloc1::Device
的函数函数类型定义像下面这样:
而所谓的函数 descriptor 则是用于标识函数的整数:
Gralloc1::Device
的所有功能实现,都依赖于从 gralloc1_device_t
的函数指针:
我们可以看一下 Gralloc1On0Adapter
,来简单了解 HAL gralloc 模块,gralloc1_device_t
可能的实现和功能。Gralloc1On0Adapter
继承自 gralloc1_device_t
:
Gralloc1On0Adapter
需要提供 gralloc1_device_t
所必需的 getCapabilities
和 getFunction
这两个回调:
这两个回调的实现在定义类的头文件里:
两个回调最终通过 doGetCapabilities()
和 doGetFunction()
两个成员函数完成其功能,这两个函数实现如下:
最终 Gralloc1On0Adapter
的这些功能函数有将依赖于 alloc_device_t
和 gralloc_module_t
提供的那些回调来完成其功能,如 alloc()
函数依赖于 alloc_device_t
:
lock/unlock 操作则都依赖于 gralloc_module_t
,以 lock 为例:
关于 HAL gralloc 模块更具体的实现,这里不再深追。
总结一下 Android 图形系统中,对于 gralloc 接口的情况,与图形缓冲区分配、映射有关的组件之间的结构,如下图所示:
如果是 gralloc1 接口的情况,则稍微有一点不同:
此外,在前面 BufferQueueCore
中创建 IGraphicBufferAlloc
时,我们看到这个对象总是会通过 surfacefinger 创建,然后通过 Binder IPC 传递给创建 BufferQueue 的进程一个句柄。后续在创建 BufferQueue 的进程中的生产者要分配 GraphicBuffer
,则这一分配过程实际也将发生在 surfaceflinger 进程中,创建的 GraphicBuffer
经过序列化之后,传回给创建 BufferQueue 的进程。在 GraphicBuffer
对象真正创建的时候,也会直接为其分配图形缓冲区。也就是说,在 Android 系统中,真正会分配图形缓冲区的进程只有 surfaceflinger,尽管可能会创建 BufferQueue 的进程有多个。
GraphicBufferAllocator
和 GraphicBufferMapper
在对象创建的时候,都会通过 Gralloc1::Loader
加载 HAL gralloc。只有需要分配图形缓冲区的进程才需要创建 GraphicBufferAllocator
,只有需要访问图形缓冲区的进程,才需要创建 GraphicBufferMapper
对象。从 Android 的日志分析,可以看到,只有 surfaceflinger 进程中,同时发生了为创建 GraphicBufferAllocator
和 GraphicBufferMapper
而加载 HAL gralloc。而为创建 GraphicBufferMapper
而加载 HAL gralloc 则发生在 zygote、bootanimation 等多个进程。可见能够访问图形缓冲区的进程包括 Android Java 应用等多个进程。
打赏
Done.
Android OpenGL 图形系统分析系列文章
在 Android 中使用 OpenGL
Android 图形驱动初始化
EGL Context 创建
Android 图形系统之图形缓冲区分配
Android 图形系统之gralloc