Android显示系统概述

67 阅读5分钟

一、系统架构(静态):Android 图形系统的整体结构与主要模块

可以先在脑子里想象这样一个自上而下的分层示意:

+---------------------------------------------------+
| 应用层 App: View, Canvas, SurfaceView, GLSurfaceView |
+---------------------------------------------------+
| 框架层 Framework: ViewRootImpl, Choreographer, WMS |
+---------------------------------------------------+
| 原生图形库: Skia, HWUI, OpenGL ES / Vulkan, EGL     |
+---------------------------------------------------+
| 系统服务: SurfaceFlinger (合成器)                   |
+---------------------------------------------------+
| HAL: Hardware Composer (HWC), Gralloc HAL           |
+---------------------------------------------------+
| 内核与驱动: GPU 驱动, 显示驱动, 内存/ION/DRM 等       |
+---------------------------------------------------+
| 硬件: GPU, 显示控制器, 屏幕 Panel                   |
+---------------------------------------------------+

1. 应用 & UI 层

  • View / ViewGroup

    • Android UI 的基础元素,负责测量、布局、绘制。

    • onMeasure() / onLayout() / onDraw() 这三大流程你应该很熟

  • Canvas

    • 给 View 的 2D 绘图接口:drawRect(), drawText(), drawBitmap() 等。

    • 在软件渲染时由 CPU + Skia 执行;硬件加速时,Skia 会生成 GPU 命令(OpenGL ES/Vulkan)。

  • Surface / SurfaceView / TextureView / GLSurfaceView

    • Surface:一块可供绘制和显示的“窗口缓冲区”,拥有自己的 BufferQueue。

    • SurfaceView / GLSurfaceView / TextureView 等是对 Surface 的不同封装,适合视频、游戏等场景。

2. 框架 & 系统服务层

  • ViewRootImpl

    • 连接 View 树和 WindowManager 的桥梁。

    • 管理 View 的 measure/layout/draw 整个 UI 渲染流程。

  • Choreographer

    • VSync 驱动的调度器:每到一个显示刷新周期(如 16.7ms),回调:

      • 输入处理

      • 动画计算

      • View 的绘制(doFrame()

  • WindowManagerService (WMS)

    • 管理所有窗口(Activity、Dialog、系统栏等)的位置、Z序、可见性;

    • 为每个窗口创建/管理对应的 Surface

    • 告诉 SurfaceFlinger 有哪些 Layer 要参与合成。

3. 原生图形库

  • Skia

    • Google 的 2D 图形引擎,Android UI 绘制的核心。

    • 支持软件渲染(CPU)和硬件渲染(通过 OpenGL ES/Vulkan 调 GPU)。

    • 上层 Canvas 调用最终会由 Skia 翻译为绘图/渲染命令。

  • Android HWUI

    • Android UI 渲染子系统,基于 Skia + GPU。

    • 把 View 的 draw() 转换为 DisplayList(渲染指令列表),由 RenderThread 提交 GPU 执行。

  • OpenGL ES / Vulkan

    • 面向 GPU 的图形 API。

    • OpenGL ES 长期是 Android 图形渲染主力;Vulkan 更新、更底层、更高性能,近年用于高性能渲染和新管线。

  • EGL

    • 负责将 OpenGL ES 与底层 “本地窗口系统/Surface” 绑定。

    • 管理 上下文(Context)和 绘制目标 Surface。

4. 显示合成核心:SurfaceFlinger

  • SurfaceFlinger

    • 运行在独立进程中的 系统级合成器。

    • 功能:

      • 作为各个 Surface 的 消费者,从它们的 BufferQueue 中取出最新缓冲区;

      • 根据 WMS 提供的层级、位移、透明度等信息,决定如何把这些 Surface 合成到一张“最终屏幕图像”里;

      • 与 Hardware Composer (HWC) 协作,尽量用硬件能力完成合成,减少 GPU 消耗。

5. HAL:Hardware Composer & Gralloc

  • Gralloc HAL(Graphic Allocator)

    • 负责图形缓冲区的 分配/释放。

    • 为 app、SurfaceFlinger 等提供共享的 graphic buffer,通常使用 ION/DRM 等内核机制。

  • Hardware Composer HAL(HWC)

    • 提供硬件合成接口。

    • SurfaceFlinger 把每个 Layer 的信息(位置、缩放、旋转、透明度等)交给 HWC:

      • HWC 能直接用显示控制器的 Overlay 等硬件单元把多个 Layer 合成(硬件合成);

      • 对无法硬合成的 Layer(如复杂的混合效果),回退给 GPU 合成。

6. 内核与硬件

  • GPU 驱动

    • 接收来自 OpenGL ES/Vulkan 的命令,驱动 GPU 执行渲染。
  • 显示驱动 / DRM / KMS

    • 管理显示控制器(Display Controller),把最终帧缓冲送到屏幕。
  • 硬件

    • GPU:专门处理图形渲染。

    • Display Controller + Panel(屏幕):控制扫描显示每一帧图像。

二、渲染流程(动态):从 View 渲染到屏幕的完整数据流

用一个简化的流水线示意(宏观):

App(UI线程)   →   RenderThread/GPU    →   BufferQueue   →  SurfaceFlinger/HWC   →  Display
(绘制指令)         (渲染到 Surface)        (帧缓冲队列)         (合成最终图像)        (显示)

阶段 1:UI 渲染(App 侧)

  1. VSync 到来 & Choreographer 调度

    1. 显示每 16.7ms(60Hz 屏)发出一个 VSync 信号;

    2. Choreographer 在 UI 线程收到 VSync,依次回调:

      • 输入处理(input)

      • 动画更新(animation)

      • View 树绘制(traversal:measure/layout/draw)

  2. View 树绘制

  • ViewRootImpl#doTraversal()

    • performMeasure()onMeasure():测量尺寸;

    • performLayout()onLayout():摆放子 View;

    • performDraw()View#draw()onDraw():生成绘制指令。

  • 硬件加速开启时(默认),UI 并不是直接一笔一笔画到屏幕:

    • View 的绘制被记录为 DisplayList(RenderNode);

    • 这些 DisplayList 会在 RenderThread 上提交给 GPU 执行。

3. RenderThread & GPU 渲染到 Surface

  • RenderThread 是一个后台线程,专门负责 OpenGL ES/Vulkan 渲染:

    • 根据 DisplayList 调用 Skia/GPU API;

    • GPU 将结果渲染到一个 Surface 的 buffer 上(由 Gralloc 分配)。

阶段 2:Buffer 提交(Producer → BufferQueue)

  1. Producer:应用或 RenderThread

    1. 绘制完成后调用 eglSwapBuffers()unlockCanvasAndPost()

      • 把填充好的 buffer enqueue 到 BufferQueue;

      • 同时从 BufferQueue dequeue 下一块空闲 buffer,用于下一帧。

  2. BufferQueue

    1. 典型实现:一个队列 + N 个 GraphicBuffer。

    2. 生产者:App/RenderThread(或其他图像源,如 Camera、视频解码器);

    3. 消费者:SurfaceFlinger 或其他使用该 Surface 的下游组件。

阶段 3:合成(SurfaceFlinger + HWC/GPU)

  1. SurfaceFlinger 消费 BufferQueue

    1. 在下一次系统 VSync 到来时,SurfaceFlinger 线程也被唤醒:

      • 遍历所有可见 Layer(各窗口、状态栏、导航栏、壁纸等);

      • 从各自的 BufferQueue 中 取出最新的 buffer。

  2. 决定合成策略:HWC vs GPU

    1. SurfaceFlinger 把要显示的 Layer 列表交给 HWC 的 prepare()

      • HWC 根据硬件能力,标记哪些 Layer 自己能合成;

      • 对于不能处理的 Layer(如复杂混合、超出数量等),标记为 Client 由 GPU 合成。

    2. 然后:

      • HWC 能合成的部分:由显示控制器/Overlay 直接合成;

      • 客户端(Client)部分:SurfaceFlinger 用 GPU 渲染这些 Layer 到一个中间 buffer,再交给 HWC。

  3. 提交给显示控制器

    1. 最终得到一张“完整屏幕”的帧(或多平面的帧配置),交给显示驱动:

      • 在下一次刷新扫描时,显示控制器从该帧缓冲读数据;

      • 面板按行扫描把图像画出来。

阶段 4:显示器扫描

  • 屏幕以固定刷新率(如 60Hz/90Hz/120Hz)从上到下逐行刷新:

    • 一次刷新周期内读取固定的帧缓冲内容;

    • 下一次刷新前,SurfaceFlinger/HWC 可以准备下一帧。