Android14显示系统框架概述

文章目录

资料快车

1)看完不懂我吃:Android 渲染(显示)原理 - 传统架构

https://juejin.cn/post/7484470326080929827#heading-8

2)Android Graphics 图像显示系统 - 全面解读 - 旧架构

https://www.cnblogs.com/roger-yu/p/15641545.html

3)Android图形图像显示-Display-Surfaceflinger-Fence-DRM-SKIA/OpenGL/Vulkan

https://www.cnblogs.com/bluestorm/p/17662946.html

4)DRM架构

Android画面显示流程一 : https://blog.csdn.net/qq_42282862/article/details/131595316

Android画面显示流程二:https://blog.csdn.net/qq_42282862/article/details/131596401

Android画面显示流程三:https://blog.csdn.net/qq_42282862/article/details/131600816

surfaceflinger : https://blog.csdn.net/qq_42282862/article/details/131606904

preface

Android显示系统从上到下涉及的模块极其多,可以说是系统里最复杂的模块,任一个模块都可以使用一个篇章来描述,任重而道远

1、Android的UI绘图

1、Android的UI底层是用CPU绘图还是GPU绘图

复制代码
都支持,高端平台(TV/手机/平板/车载等)基本都使用GPU硬件加速,重点学习硬件加速

2、应用层如何绘制UI,什么时候需要绘制UI?

复制代码
绘图时机:
- `ViewRootImpl.performTraversals()` - 主绘制入口
- 响应 VSync 信号
- 窗口切换、窗口大小、属性有改变;
- 视图失效(invalidate)

3、Activity与绘图?

在应用层的角度,Activity是一个活动界面,在这个界面我们可以放置各种元素,这些元素就需要绘图,注意界面本身也是绘图的结果,总体而言,一个完整绘图上叠放各种小绘图;

1)站在应用的角度,UI界面的设计分为两步

绘图 - 静态效果,再添加 特效 - 动态效果,在Android中,UI绘图使用View,特效使用View动画

好比PPT,我们先画好每一页精美的内容(静态效果),再给每一页添加出场效果、退场效果(动态效果)

动态效果实现:代码实现让一个View先平移,后旋转,最后淡出

复制代码
1.使用属性动画来实现
/android/frameworks/base/core/java/android/view/animation/AnimationSet.java
2.
ObjectAnimator moveIn = ObjectAnimator.ofFloat(myView, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(myView, "alpha", 1f, 0f);

AnimatorSet animSet = new AnimatorSet();
// 按顺序执行
animSet.playSequentially(moveIn, rotate, fadeOut);
// 或者同时执行
// animSet.playTogether(moveIn, rotate, fadeOut);
// 或者更复杂的组合
// animSet.play(rotate).with(fadeOut).after(moveIn);

animSet.setDuration(1000);
animSet.start();

2)UI绘图依赖的硬件资源?

1、简单绘图底层可以使用软件CPU实现、也可以使用硬件实现(2D图形模块、GPU),虽然他们都拥有这样的能力,但效率和效果不同,不同的平台,根据自身资源情况来选择实现方式;

2、渲染、特效这些较为复杂,工作量大的任务,一般都使用GPU来承担;

2、Android显示系统框架

在Android的快速发展下,新技术不断涌现,架构也在不断进化,新旧架构我们都应该了解,以便能在项目中区分出来,不至于迷乱在繁杂的架构

1)Android经典图形架构图(低版本架构)

以上来自Android4.0源码版本的架构

1)libagl - android graphic library - Android自有软件实现的图形引擎库

2)libhgl - hardware graphic library - 硬件实现的图形引擎库,厂商提供

3)应用程序可以直接调用EGL和OpenGL-ES的接口,不一定要经过SurfaceFlinger,也是理所当然的,毕竟SF只是集中管理的功能;

4)简单概述就是围绕三个主线进行

1、APP向SF申请buffer用以存放自己的显示内容;

2、APP使用Skia/GL等图形库画图、GPU渲染,最后结果存放在buffer,最后提交给SF进一步处理;

3、SF组织合成送显;

2)框架图-面向对象视角

notes

1、VSync是project butter工程中加入的一种同步机制,可以是硬件产生,也可以使用软件来模拟-VsyncThread;

2、surface的含义,"表面",好比一张空白纸(内存),应用可以在这张纸上素描、着色、渲染,产出一帧完整的图片;

3)基于DRM框架图

1、Linux类操作系统

其中图形库部分与Android系统比较相近 (skia + mesa3D + DRM)

2)基于DRM架构的Android的显示系统

1、在 Android 12 中,GKI 2.0 将 ION 分配器替换为了 DMA-BUF 堆(从名字可以看出,DMA是趋势,主要使用DMA内存加速);

2、Android开源图形库实现同样也是 :skia + mesa3D + DRM

4)小结

Android显示系统 可以划分为 窗口系统和 图形库体系

3、Android窗口系统概述

1、最简单的窗口系统?

一个APP+FB显示,这只能做一些简单的显示,比如单片机。

2、Android上的窗口系统实现

不同平台,不同系统,窗口系统的实现多种多样,应当专注于当前的项目平台,不要迷失方向;

Android Framework 实现的SurfaceFlinger、WMS、View、Activity等等都属于窗口系统内容,是Android平台的特有实现,涉及内容生成-产生窗口、多个内容如何呈现 - 窗口组织管理,以便呈现出各种各样的窗口效果

3、WMS、View体系与SurfaceFlinger的关系

这里的框图重点体现WMS、View和SF这几个主体,不会糅杂太多细节和分支,框架应该如此!

1)WMS是管理者;

2)View是生成者;

3)SF是消费者,也是硬件资源管理者;

WMS、View都属于上层使用者,在Android显示子系统 原理探索中 可以简单了解框架(逻辑的堆砌过于庞大)

4、Android图形库体系

图形库(OpenGL-ES/Vulkan)是一个极其复杂的模块,算是另一个领域的知识(音视频领域),学习显示框架时,不求深入,我们把握框架即可!

1)Android图形库EGL/OpenGL-ES-wrapper/OpenGL-ES

1)Android系统图形栈 OpenGL-ES和EGL介绍: https://blog.csdn.net/u010029439/article/details/90413006

2)OpenGL ES库和EGL库的加载过程: https://blog.csdn.net/ninver2007/article/details/97152412

3)Android系统EGL源码分析:https://segmentfault.com/a/1190000045166147

2)EGL介绍

1、基本认识
复制代码
EGL : khronos(机构) Native Platform graphics interface
1、主要负责图形环境管理、surface/buffer绑定、渲染同步等,介于本地窗口系统和Rendering API之间的一层接口;
2、由于openGL ES是开源软件,如何保证上层应用调用的是稳定API?通过设计中间层EGL并由google统一管理实现。
3、调用链路:应用程序 -> EGL -> Rendering API(openGL ES)-> GPU
1)OpenGL ES接口成千上百,应用都需要通过EGL来访问?不是,只有管理相关API才需要,其它API可以直接调用

4、EGL适用于X11、Wayland、Android等系统

5、谁来实现?
在Android源码中Android framework有自己的实现,有很多开源软件都实现了-比如Mesa3D;
2、源码介绍
复制代码
1、Framework java层
/android/frameworks/base/opengl/java

核心实现 - 封装GL,让应用程序更方便使用
/android/frameworks/base/opengl/java/android/opengl/GLSurfaceView.java

2、JNI
frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp:EGL本地代码的JNI调用接口
frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
frameworks/base/core/jni/android_opengl_GLESXXX.cpp:OpenGL功能函数的JNI调用接口

3、native cpp层
/android/frameworks/native/opengl/libs/EGL

libEGL (共享库)
├── libEGL_getProcAddress (静态库)
│   └── getProcAddress.cpp
├── libEGL_blobCache (静态库)
│   ├── BlobCache.cpp
│   └── FileBlobCache.cpp
└── 核心源文件
    ├── egl_tls.cpp          # 线程本地存储
    ├── egl_cache.cpp        # 着色器缓存
    ├── egl_display.cpp      # 显示管理
    ├── egl_object.cpp       # 对象生命周期
    ├── egl_layers.cpp       # 层支持
    ├── egl.cpp              # EGL 入口点
    ├── eglApi.cpp           # EGL API 实现
    ├── egl_platform_entries.cpp  # 平台入口
    ├── Loader.cpp           # 驱动加载
    └── egl_angle_platform.cpp     # ANGLE 平台支持

4、EGL加载openGL ES库
源码:/android/frameworks/native/opengl/libs/EGL/Loader.cpp
官方说明:https://source.android.google.cn/docs/core/graphics/implement-opengl-es?hl=zh-cn
1)4.4版本之前EGL (libegl.so) 根据egl.cfg来加载软件实现还是硬件实现的图形库;
2)4.4版本之后使用属性确定加载哪个库
路径:/vendor/lib/egl 、/vendor/lib64/egl
属性名:ro.hardware.egl、ro.board.platform
libEGL_${ro.hardware.egl}.so
libGLESv1_CM_${ro.hardware.egl}.so
libGLESv2_${ro.hardware.egl}.so

libEGL_${ro.board.platform}.so
libGLESv1_CM_${ro.board.platform}.so
libGLESv2_${ro.board.platform}.so

/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
SurfaceFlinger::init()
/android/frameworks/native/opengl/libs/EGL/eglApi.cpp
--eglGetDisplay(EGLNativeDisplayType display)
/android/frameworks/native/opengl/libs/EGL/egl.cpp
---egl_init_drivers()
----egl_init_drivers_locked()
/android/frameworks/native/opengl/libs/EGL/Loader.cpp
------loader.open()
------load_driver() //加载对应的GL-ES库


4、使用EGL的绘图的一般步骤:
获取 EGL Display 对象:eglGetDisplay()
初始化与 EGLDisplay 之间的连接:eglInitialize()
获取 EGLConfig 对象:eglChooseConfig()
创建 EGLContext 实例:eglCreateContext()
创建 EGLSurface 实例:eglCreateWindowSurface()
连接 EGLContext 和 EGLSurface:eglMakeCurrent()
使用 OpenGL ES API 绘制图形:gl_*()
切换 front buffer 和 back buffer 送显:eglSwapBuffer()
断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()
删除 EGLSurface 对象
删除 EGLContext 对象
终止与 EGLDisplay 之间的连接

3)OpenGL ES Wrapper库

复制代码
1、OpenGL ES Wrapper库:OpenGL ES Wrapper 库是一个对 OpenGL ES API 进行封装的一个包裹库,它向上为应用程序提供了标准的 OpenGL ES API,向下可以和不同厂商实现的 OpenGL ES 库进行绑定,将 OpenGL ES API 和对应的实现函数一一绑定在一起。

2、
OpenGL ES 1.x API 的 Wrapper 库
/android/frameworks/native/opengl/libs/GLES_CM >> libGLESv1_CM.so
OpenGL ES 2.0 的 Wrapper 库
/android/frameworks/native/opengl/libs/GLES2  >> libGLESv2.so

4)OpenGL-ES协议及其实现介绍

1、背景

1)由于openGL需要较高的内存配置、耗电高等特点不适合移动设备,openGL-ES则解决这些问题,广泛应用在汽车电子、手机等;

2)不仅适合3D图形的实现,也广泛应用于2D的视频和图像处理,拥有强大的渲染和特效处理功能;

3)底层需要依赖GPU渲染,当然也可以CPU渲染;

2、实现介绍
复制代码
1、OpenGl-ES是一套规范协议,定义一套供上层进行调用的API(相当于interface),抽象GPU的功能,使得开发者不必关系底层GPU类型和具体实现;
2、实现OpenGL-ES协议的库我们有时也叫openGL-ES,注意区分!比如Mesa3D

3、OpenGL ES库:OpenGL ES 库就是上面 OpenGL ES 中定义的 API 的具体实现。
1)基于GPU的闭源实现
由于每个显卡制造厂商的 GPU 硬件结构不同,从而导致各个厂商的OpenGL ES 库也各不相同,所以 Android 系统中的 OpenGL ES 库通常是由硬件厂商提供的,通常存放在 Android 系统中的 /system/lib64/egl 下面或者 /vendor/lib64/egl 目录下。

硬件库-厂家提供
 /vendor/lib/egl/libEGL.so
 /vendor/lib/egl/libGLESv1_CM.so
 /vendor/lib/egl/libGLESv2.

2)基于GPU的开源实现-Mesa3D,有时也会用协议名称表示openGL-ES

3)基于CPU的纯软件实现(AOSP)
OpenGL ES软件实现(Android 7.1路径,注意高版本Android已被移除)
/frameworks/native/opengl/libagl/
库名:libGLES_android.so

4、编译工具
/android/frameworks/native/opengl/tools/glgen/

5、编译
1)**LL-NDK**:Low-Level NDK,供系统库使用的稳定接口。
2)编译优化
#if defined(__arm__)
    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    
    #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
        asm volatile(
            "mrc p15, 0, r12, c13, c0, 3 \n"  // 获取 TLS
            "ldr r12, [r12, %[tls]] \n"
            "cmp r12, #0 \n"
            "ldrne pc, [r12, %[api]] \n"      // 跳转到实际函数
            : : [tls] "J"(TLS_SLOT_OPENGL_API*4),
                [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))
            : "r0", "r1", "r2", "r3", "r12"
        );
#endif

5)Skia与OpenGL-ES/Vulkan 简述

1、Skia: 提供统一的绘制 API,可以直接使用 CPU 栅格化(软件绘制);也可以通过 OpenGL ES/Vulkan 与 GPU 交互进行加速渲染(硬件加速)。

2、OpenGL-ES/Vulkan: 图形/计算 API,用来让程序与 GPU 交互、把场景画成屏幕上的像素。

因此,Skia 位于应用与 GPU API 之间:应用调用 Skia 的 API;Skia 在 CPU 或 GPU 上进行栅格化;GPU 路径下 Skia 再通过 OpenGL ES/Vulkan 与 GPU 交互。应用也可以绕过 Skia 直接用 OpenGL/Vulkan,但 Android UI 体系默认用 Skia。后文会结合代码详细介绍。

3、OpenGL-ES/Vulkan对比

1)Android 7以上都支持OpenGL-ES/Vulkan,如何选用?

2)Vulkan Android官方介绍:

https://android-docs.cn/games/develop/vulkan/overview

3)Vulkan 与 OpenGL ES 核心对比

4)如果用编程语言来类比,OpenGL-ES相当于Java语言,Vulkan相当于C语言,Vulkan 更贴近驱动编程;

6)Android如何使用OpenGL-ES

1.OpenGL-ES就是一个图形库,可以画各种图、渲染各种特效(转场、翻页效果)等等;

2.Android应用程序使用OpenGL-ES,间接调用EGL接口 或 直接调用OpenGL-ES接口都可以,但一般都会搭配EGL;

3、为了方便上层使用,Google肯定也会有自己的封装 简化应用程序使用GL库

4)OpenGL-ES也会通过JNI暴露给java程序直接使用

5)由于图形库是显示的重要底层组件,但凡需要增强显示效果的场合都需要直接或间接使用它,比如以下场景

1、SurfaceFlinger使用GL库,哪些场景?当HWC处理不了的复杂合成,SF会调用GL分担部分合成工作

2、游戏应用程序使用GL库

3、开机动画使用GL库

4、Skia使用GL库

因此你会看到源码许多地方都有EGL/GL的身影,让人感到极其混乱,本质上都是为了各方使用OpenGL-ES

复制代码
1.native层使用opengl
/android/frameworks/native/opengl

2.framework-java层使用opengl
/android/frameworks/base/opengl

3.skia库使用opengl
/android/external/skia/src/gpu/gl/egl

4.mesa3d实现的EGL
/android/external/mesa3d/src/egl

6)小结

1、Native可以是SurfaceFlinger、CPP程序等;

7)简化OpenGL ES开发-GLSurfaceView

1、Android系统已经在SDK为开发人员封装了一整套OpenGL-ES的使用和管理机制,

2、java层代码可以通过以下两种方式来搭建OpenGL-ES环境;

1)直接使用SDK提供的EGL,GLES类

复制代码
/android/frameworks/base/opengl/java/android/opengl/EGL15.java
/android/frameworks/base/opengl/java/android/opengl/GLES32.java

2)使用GLSurfaceView

复制代码
1、产生的背景:使用EGL,GLES编程也比较复杂,因此Android继续封装出一个更易用的类GLSurfaceView,应用程序可以直接使用,当前很多Android游戏都是直接或间接通过GLSurfaceView完成;

2、GLSurfaceView主要特性
1)管理EGLDisplay - 表示一个显示屏;
2)管理Surface
3)GLSurfaceView会创建新的线程,已使得整个渲染过程不会阻塞UI主线程
4)用户可以通过SetRenderer()自定义渲染方式

1、类图

2、Surface申请流程

3、源码分析

复制代码
1.init初始化
/android/frameworks/base/opengl/java/android/opengl/GLSurfaceView.java
private void init() {
    /android/frameworks/base/core/java/android/view/SurfaceHolder.java
    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
}

2. 设置Renderer实现用户自定义渲染方式
private void setRenderer(Renderer renderer) {
    new SimpleEGLConfigChooser();
    new DefaultContextFactory();
    new DefaultWindowSurfaceFactory();
    mRenderer = renderer;
    mGLThread = new GLThread(mThisWeakRef);
    mGLThread.start();
}

3.GLThread的运行
static class GLThread extends Thread {
    run() --不断等待和处理渲染事件
    --guardedRun();
    ----mEglHelper = new EglHelper()
    ----readyToDraw()
    ------mEglHelper.start(); //创建GL-ES使用环境
    --------mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
    --------mEgl.eglInitialize(mEglDisplay, version)
    --------view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
    --------view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
    ----gl = (GL10) mEglHelper.createGL();
    ----GLSurfaceView view = mGLSurfaceViewWeakRef.get();
    ----view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
    ----view.mRenderer.onDrawFrame(gl); //开始渲染
    ----mEglHelper.swap();  //把渲染结果显示到屏幕
}

5、UI的构造过程剖析

认识构造UI的各个对象和流程十分重要,源码实现的过程 就是将这些实体(对象)、策略(函数方法) 转化为代码表示;了解框架和这些构造过程看代码将会事半功倍;

1)一个APP构造UI画面过程

1、使用图形库画基础图形,多个图形构造一幅画面;

2、构造完成后数据送到显示控制器,最终在显示器中显示出来;

2)多个APP共同构造出界面

1、一般一个界面由多个APP共同构造而成;

2、相对单个APP构造界面,这将复杂很多,涉及合成,层级优先级等;

3、layerstack

3)转化为代码表示

1、Surface是APP中负责管理 界面构造的管理单元(操作方法的集合);

2、GraphicBuffer是图形数据的载体,使用BufferQueue队列数据结构组织;

4)UI界面构造流水线图

1、一个页面包含多种元素,每个元素都单独使用GL生成,最后放在一个layer里面;

2、一个APP可以画出多个页面(即layer),每个页面都可以保存起来,需要的时候再调用;

3、如果一个页面需要更新,则标记为dirty,SF会进行合成更新到layer里面;

6、音视频库-FFMPEG

复制代码
1、简介
FFmpeg : fast forward moving picture Experts Group //快速处理音视频的工具集
FFmpeg 是一个开源、免费、跨平台的音视频处理解决方案
源码:
/android/vendor/amlogic/common/external/ffmpeg/

2、核心组成:
ffmpeg: 命令行工具本身,用于对音视频文件进行转换、抓取、编辑等操作。
ffplay: 一个简单、跨平台的媒体播放器,基于 FFmpeg 库和 SDL 库开发,常用于快速测试和调试。
ffprobe: 一个多媒体流分析工具,用于查看媒体文件的格式、码流、编码信息等元数据。
一系列编解码库(libavcodec): 这是 FFmpeg 最核心的部分,是一个包含了众多音视频编解码器的库。它支持几乎所有你能想到的音视频格式(如 H.264, H.265, VP9, AV1, AAC, MP3 等)。

格式处理库(libavformat): 一个包含多种多媒体容器格式的解封装器和封装器的库,用于处理各种文件格式(如 MP4, MKV, FLV, MOV 等)。

3、主要功能:
格式转换(转码): 将一个视频文件(如 MKV)转换为另一种格式(如 MP4),或者改变其编码(如将 H.264 转为 H.265 以减小文件体积)。
编解码: 对音频和视频流进行编码(压缩)和解码(播放)。
视频抓取和录制: 从视频设备或屏幕上抓取内容。
流媒体处理: 支持推流、拉流以及流媒体的转换。
基本编辑: 如裁剪、拼接、调整音量、添加水印、调整速度等。
信息提取与分析: 使用 ffprobe 获取媒体的详细信息。


4、是否依赖硬件?可选

7、PQ及其他视频处理模块

1、这些是什么,处于什么层级?

1)在传输给显示屏真正显示之前,对图像数据的校准,以获得满足需求的显示效果;

2)可以使用GPU+软件算法实现?当然可以,使用硬件模块处理是为了高效,分担CPU/GPU的负担!

3)可以集成在CPU或独立的硬件模块(主板端或屏端都可以);

2、如何工作?

配置好寄存器,硬件自动工作?

复制代码
Android平台下 drm,kms中有设置色温的属性吗?

/android/frameworks/base/services/core/java/com/android/server/display/color/ColorDisplayService.java
ColorDisplayService.java中的colormatirx,这个可以调色温,

何小龙 - drm 有对 PQ 的支持,主要通过 property 来设置,大部分 code 都在 drm_color_mgmt.c 中。
PQ 一般不经过 gpu 驱动,主要通过窗口系统来直接设置,目前没有标准的做法,都是各 vendor 厂商自己添加的,gamma_lut 对色温能起到一定的效果,大部分硬件还是通过 color matrix 来实现色温效果的。

8、图形处理的专业化-音视频领域

1)图形、图像处理专业知识复杂庞大,属于音视频专业领域,有专门的工种

1、渲染引擎工程师(skia、nanovg、agg);

2、Android图示工程师(Android图形系统性能,帧率优化);

3、OS视窗高级工程师(skia、软硬件合层、x11/wayland);

2)涉及的模块?

中间件 - Opengl、ffmpeg、skia等等

硬件音视频处理模块 - GPU、视频编解码、音频编解码等等