SurfaceFlinger 概念 & 执行流程

656 阅读7分钟

概念

SurfaceFlinger 是一个系统服务,如:AudioFlinger、AudioPolicyService 等等,系统的服务。 SurfaceFlinger 服务负责管理系统的帧缓冲区设备,并且负责渲染系统的 UI,即各个应用程序的 UISurfaceFlinger 服务运行在 System 进程中,用来统一管理系统的帧缓冲区设备。由于 SurfaceFlinger 服务运行在 System 进程中,因此,Android 应用程序为了能够将自己的 UI 绘制在系统的帧缓冲区上,它们就必须通过 BinderSurfaceFlinger 服务进行通信,如图所示:

image.png

Android 应用程序与 SurfaceFlinger 服务的关系

每一个 Android 应用程序与 SurfaceFlinger 服务都有一个连接,这个连接都是通过一个类型为 ClientBinder 对象来描述的。这些 Client 对象是 Android 应用程序连接到 SurfaceFlinger 服务的时候由 SurfaceFlinger 服务创建的,而当 Android 应用程序成功连接到 SurfaceFlinger 服务之后,就可以获得一个对应的 Client 对象的 Binder 代理接口了。有了这些 Binder 代理接口之后,Android 应用程序就可以通知 SurfaceFlinger 服务来绘制自己的 UI 了。

Android 应用程序在通知 SurfaceFlinger 服务来绘制自己的 UI 的时候,需要将 UI 元数据传递给 SurfaceFlinger 服务,例如,要绘制 UI 的区域、位置等信息。一个 Android 应用程序可能会有很多个窗口,而每一个窗口都有自己的 UI 元数据,因此,Android 应用程序需要传递给 SurfaceFlinger 服务的 UI 元数据是相当大的。在这种情况下,通过 Binder 进程间通信机制来在 Android 应用程序与 SurfaceFlinger 服务之间传递 UI 元数据是不合适的,这时候 Android 系统的 匿名共享内存机制(Anonymous Shared Memory) 就派上用场了。(这里暂时不做过多介绍,等待后续更新)

SurfaceFlinger 类的定义

image.png

SurfaceFlinger 类

重点成员变量
  • mCurrentState:用来描述系统 下一次要渲染的UI 的状态。
  • mDrawingState:用来描述 当前正要渲染的 UI 的状态。
  • mVisibleLayerSortedByZ:是一个类型为 spVector,它是用来保存 SurfaceFlinger 服务下一次要渲染的、处于可见状态的 Surface 的,它们是来自 SurfaceFlinger 类的成员变量mDrawingState 所描述的一个 State 对象的成员变量 layersSortedByZ 的。
  • mGraphicPlanes:是一个类型为 GraphicPlane 的数组,它是用来描述系统所有的显示设备的。从这个数组的大小等于 1 可以知道,当前 Android 系统只支持一个显示设备。
重点函数

SurfaceFlinger 类中有这些比较重要的函数 threadLoopwaitForEventsignalEventhandleConsoleEventshandleTransactionhandlePageFliphandleRepaintpostFramebuffer。我们看下这些函数的执行流程并且分析每个函数的作用

执行流程

那么 SurfaceFlinger 的执行流程是怎样的?

image.png

SurfaceFlinger 服务虽然是在 System 进程中启动的,但是它在启动的时候创建一个线程来专门负责渲染UI。为了方便描述,我们将这个线程称为 UI渲染线程UI渲染线程 的执行函数就为 SurfaceFlinger 类的成员函数 threadLoop,同时它有一个消息队列。当 UI渲染线程 不需要渲染UI时,它就会在SurfaceFlinger 类的成员函数 waitForEvent 中睡眠等待,直到 SurfaceFlinger 服务需要执行新的 UI 渲染操作为止。

SurfaceFlinger服务什么时候会需要执行新的UI渲染操作呢?

当系统显示屏属性发生变化,或者应用程序窗口发生变化时,它就需要重新渲染系统的 UI。这时候SurfaceFlinger 服务就会从 SurfaceFlinger 类的成员函数 waitEvent 中唤醒,并且依次执行SurfaceFlinger 类的成员函数 handleConsoleEventshandleTransactionhandlePageFliphandleRepaintpostFramebuffer 来具体执行渲染 UI 的操作。

  • 函数 handleConsoleEvents 用来处理控制台事件;
  • 函数 handleTransaction 用来处理系统显示屏属性变化以及应用程序窗口属性变化;
  • 函数 handlePageFlip用来获得应用程序窗口下一次要渲染的图形缓冲区,即设置应用程序窗口的活动图形缓冲区;
  • 函数 handleRepaint 用来重绘应用程序窗口;
  • 函数postFramebuffer 用来将系统UI渲染到硬件帧缓冲区中去。

我们知道,应用程序是运行在与 SurfaceFlinger 服务不同的进程中的,每当应用程序需要更新自己的 UI 时,它们就会通过 Binder 进程间通信机制来通知 SurfaceFlinger 服务。SurfaceFlinger 服务接到这个通知之后,就会调用 SurfaceFlinger 类的成员函数signalEvent 来唤醒UI渲染线程,以便它可以执行渲染UI的操作。注意,SurfaceFlinger 服务是通过 Binder 线程来获得应用程序的请求的,因此,这时候SurfaceFlinger 服务的UI渲染线程实际上是被 Binder 线程唤醒的。SurfaceFlinger 类的成员函数 signalEvent 实际上是通过向UI渲染线程的消息队列发送一个类型为 INVALIDATE 的消息来唤醒 UI 渲染线程的。

前面提到, SurfaceFlinger服务在在执行UI渲染操作时,需要调用SurfaceFlinger类的成员函数handleConsoleEvents来处理控制台事件。这怎么理解呢?

SurfaceFlinger 服务在启动的时候,还会创建另外一个线程来监控由内核发出的帧缓冲区硬件事件。为了方便描述,我们将这个线程称为控制台事件监控线程。每当帧缓冲区要进入睡眠状态时,内核就会发出一个睡眠事件,这时候 SurfaceFlinger 服务就会执行一个释放屏幕的操作;而当帧缓冲区从睡眠状态唤醒时,内核就会发出一个唤醒事件,这时候 SurfaceFlinger 服务就会执行一个获取屏幕的操作。

State 类

  • layersSortedByZ:是一个类型为 LayerVector 的向量,里面保存的系统所包含的 Surface,每一个Surface 使用一个 LayerBase 对象来描述,并且它们按照 Z轴 顺序来排列。

  • orientationorientationType:类型均为 uint8_t,它们用来描述屏幕的方向。

  • freezeDisplay:类型是 uint8_t,用来描述屏幕是否处于被冻结状态。

GraphicPlane 类

重要成员
  • mHw:指向一个DisplayHardware对象,用来描述一个硬件显示设备;

  • mOrientationmWidthmHeight:均为 int,分别用来描述一个硬件显示设备的旋转方向、宽度和高度。

重要函数
  • setDisplayHardware:设置一个 GraphicPlane 对象内部所包含的一个硬件显示设备。
  • displayHardware:获取一个 GraphicPlane 对象内部所包含的一个硬件显示设备。

DisplayHardware 类

重要成员
  • mNativeWindow:它是一个类型为 FramebufferNativeWindow 的强指针。
重要函数
  • flip:用来渲染系统 UI 的,即将后端的图形缓冲区翻转为前端的图形缓冲区,并且渲染在硬件帧缓冲区去。

FramebufferNativeWindow 类

是用来描述一个 Android 系统本地窗口,而这个窗口代表的是系统的硬件帧缓冲区。它是 OpenGL 库和AndroidUI 系统之间的一个桥梁。

重要成员
  • fbDevgrDevfbDevgrDev 分别指向一个 framebuffer_device_t 设备和一个 alloc_device_t 设备。framebuffer_device_t 设备和一个 alloc_device_t 设备是由 HAL模块 Gralloc 来提供的,它们分别用来分配图形缓冲区和渲染图形缓冲区

  • buffers:类型为 NativeBuffer 的数组,这个数组用来描述一个图形缓冲区堆栈,堆栈的大小为 NUM_FRAME_BUFFERS,这些图形缓冲区是直接在硬件帧缓冲区中分配的,有别于 Surface 类所使用的图形缓冲区,因为后者所使用的图形缓冲区是在匿名共享内存分配的。

重要函数
  • dequeueBuffer 来获得一个用来填充 UI 数据的图形缓冲区,而通过它的成员函数

  • queueBuffer 来将一个已经填充好 UI 数据的图形缓冲区渲染到系统的帧缓冲区中去。

参考文章