一直想好好整理一下最近的学习成果,也在思考着怎么写才能比较准确的表达出来,或者看看自己是否真的掌握了显示系统 ------ SurfaceFlinger 这块的知识。
这块体系庞大,难度也很高,很容易陷进去看的云里雾里。在平常的工作中,有时候感觉自己理解的也不够透彻,所以这次下决心好好整理一下这块的内容。这块结合读过的《深入理解Android 内核设计思想》以及平台上面很多大佬的博客,来展开描述。
1. OpenGL ES 与 EGL
下面的图中描述了 SurfaceFlinger 与 OpenGL ES 等模块的关系图
我们从下往上看:
- Linux 内核提供了统一的 framebuffer 显示驱动,设备节点为 /dev/graphics/fb* 或者 /dev/fb*, 其中 fb0 表示第一个 Monitor, 当前系统实现中只用到了一个显示屏。
- Android 的 HAL 层提供了 Gralloc 和 Composer , Gralloc 包括了 fb 和 gralloc 两个设备。
-
- fb : 负责打开内核中的 framebuffer、初始化配置,并提供了 post、setSwapInterval 等操作接口。
- gralloc : 管理帧缓冲区的分配和释放。(意味着上层只能通过它来访问帧缓冲区,保证了系统对 framebuffer 的有序使用和统一管理)
- Composer: 为厂商自定制"UI合成"提供了接口。直接使用者是 SF 中的 HWComposer (管理 Composer ,同时还负责 Vsync 信号的产生和控制)
- FramebufferNativeWindow :将OpenGL 函数库 "本地化",将其与具体平台中的窗口系统建立其关联。
- 为 OpenGL ES 配置本地窗口的是 EGL, 更多的是一个接口协议。可以去读取 egl.cfg 这个配置文件,然后根据用户的设定来动态加载 libagl (软件实现) 或者 libhgl(硬件实现)。
- DisplayDevices: 描述系统中支持的各种"显示设备"------ 具体有哪些 Display 是由 SF 在 readyToRun 中判断并赋值的。并且在初始化的时候会调用 eglGetDisplay、eglCreateWindowSurface 等接口,并利用 EGL 来完成对 OpenGL ES 环境的搭建。很多模块可以调用 OpenGL ES 提供的 API 的接口(glViewport、glClear、glMatrixMode、glLoadIdentity 等。
- OpenGL ES
-
- 配置类:EGL、DisplayHaedware 等
- 依赖类:FramebufferNativeWindow
- 使用类:使用者也可能是配置者,如 DisplayDevice 既扮演了构建 OpenGL ES 环境的角色,同时也是它的用户。
2. Android 的硬件接口 ------ HAL
HAL 是 android 子系统与 Linux Kernel 驱动之间通信的统一接口。
可以这样理解,HAL 层是连接硬件的抽象接口,它不可能针对某个硬件专门设计,它需要提取出众多设备中的共性,然后实现。同时,它要足够稳定,不能被频繁的改动,使用上面还得灵活。
一般情况下,HAL 接口由硬件厂商提供,手机厂商再拿来加载。
3. Android 终端显示设备的"化身"------ Gralloc 与 Framebuffer
Framebuffer 是内核系统提供的图形硬件的抽象描述,是一块包含屏幕显示信息的缓冲区。它提供的设备文件节点是 /dev/graphics/fb* , fb 按数字序号进行排列,如 fb0、fb1 等。其中第一个 fb0 是主显示屏幕,必须存在。
Android 中的各个子系统通常不会直接使用内核驱动,而是由 HAL 层来间接引用底层架构。
显示系统也同样如此,它借助于 HAL 层来操作帧缓冲区,而完成这一个任务的就是 Gralloc(主角登场),我们在前面也说了 Gralloc 属于 HAL 层。下面我们就来谈谈 Gralloc。
3.1. Gralloc 模块的加载
Gralloc 对应的模块是由 FramebufferNativeWindow 在构造函数中加载的。
hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
hw_get_module 是上层使用者加载 HAL 库的入口, 然后去在以下路径中查找与ID值匹配的库。
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
lib 库有以下几种形式:
gralloc.[ro.hardware].so
gralloc.[ro.product.board].so
gralloc.[ro.board.platform].so
gralloc.[ro.arch].so
当上面这些系统属性组成的文件不存在的时候,就使用默认的
最后,这个 default 库是 Android 原生态的实现,源码位置在 hardware/libhardware/modules/gralloc/中。
它主要由 gralloc.cpp、framebuffer.cpp 和 mapper.cpp 三个主要源文件编译生成。
3.2. Gralloc 提供的接口
在第一步 Gralloc 被 HAL 库成功加载后,我们来看一下它所提供的一些重要接口。
Gralloc 是 hw_module_t 的子类。
Gralloc 中,open 接口可以帮助上层使用者打开两种设备。
#define GRALLOC_HARDWARE_FB0 "fb0" // 主屏幕
#define GRALLOC_HARDWARE_GPU0 "gpu0" // 负责图形缓冲区的分配和释放
这两个设备分别由 FramebufferNativeWindow 中的 fbDev 和 grDev 成员变量来管理。
下图为 Gralloc 模块的简图