Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程

init启动SurfaceFlinger

SurfaceFlinger目前的启动方式是做为init进程中的一个Service来启动。在init中添加如下配置代码:

[cpp]

系统将启动/system/bin/目录下的surfaceflinger bin文件来运行SurfaceFlinger。

关于init.rc的语法问题,我们将有专门的文章展开讨论(TODO)。

SurfaceFlinger启动过程

我们继续来看下对应的bin文件中的代码,位置在android\frameworks\native\services\surfaceflinger下。

[cpp]

从上面代码中我们看到SF的创建过程主要有四个步骤,我们来逐一分析一下。

1. 创建SF对象

[cpp]

其实这个创建过程很简单,无非就是初始化了一些值。从配置中读取了一些值。需要注意的一点是,SurfaceFlinger实现了三个接口:

[cpp]

BnSurfaceComposer意思是指这个Surface混合的native端,这显然也符合我们对SF功能的认识—-用于Layer的混合处理。另外,我们会在后面消息的处理一节中单独讲解HWComposer::EventHandler接口的作用。

2.初始化

其实相比SurfaceFlinger的创建,初始化做了更多的工作。这一过程比较复杂,我们分为几部分来分析:

2.1 EGL初始化

[cpp]

首先SF初始化时,会进行一些EGL的初始化工作。我们知道EGL是用来管理绘图表面(Drawing surfaces),并且提供了如下的机制1) 与本地窗口系统进行通信(本地窗口在X-Window下是XDisplay ID,在MS Windows下是Window DC,而在Android平台上EGL是NativeDisplayType)2) 查找绘图表面可用的类型和配置信息3) 创建绘图表面4) 同步OpenGL ES 2.0和其他的渲染API(Open VG、本地窗口系统的绘图命令等)5) 管理渲染资源,比如材质

eglGetDisplay调用egl_display_t::get_display(dpy)获取(连接)显示设备的句柄。egl_display_t结构用来存储get_display函数获取的物理显示设备。这里的EGL_DEFAULT_DISPLAY类型是NativeDisplayType,是一个关联系统物理屏幕的通用数据类型。

每个 EGLDisplay 在使用前都需要通过eglInitialize函数来初始化。初始化 EGLDisplay 的同时,你可以得到系统中 EGL 的实现版本号。

这个整个过程是由平台实现的,我们看不到具体实现代码(libagl里面有一套谷歌的实现,但是非常简单)。

2.2 创建HWComposer

[cpp]

接下来是创建了一个HWComposer,也就是一个负责硬件合成的模块。但是我们也看到上面的注释明确写着,下面可能并没有一个真正的硬件支持。我们来研究下这个HWComposer的创建过程:

[cpp]

2.3 EGL配置

HWC模块创建完成之后,我们继续回到SurfaceFlinger的初始化过程,后面将继续是一些EGL相关的配置:

[cpp]

2.4 display设置

EGL和OpenGL ES的配置设置完毕之后,我们将对display进行设置。

[cpp]

上面这段代码其实涉及到了三个重要的概念,BufferQueue、FrameBufferSurface以及DisplayDevice。BufferQueue做为Graphic的核心组件,我们在讲解Graphic总体结构时已经有说明,后面会另开专题说明。我们先来看下FrameBufferSurface的实现:

[cpp]

我们使用了BufferQueue来创建了一个FramebufferSurface,显然这个FramebufferSurface是一个消费者。在创建过程我们使用了屏幕的编号和HWC,我们可以猜测这个FBS是和一个屏幕绑定的,而且最终应该也是要通过HWC进行渲染。我们可以理解为这是SF在这个屏幕上使用的帧缓冲区,那么也就是一旦使用SF合成,最后数据应该是合成在了这里面(待验证),然后这里面的数据通过HWC显示在了屏幕上。猜测一下,这个是不是就是抓dump时抓到的那个HWC_FRAMEBUFFER_TARGET?

FBS的创建并没有特别之处,需要留意的是这里设置了MaxBufferCount和MaxAcquiredBufferCount,我们在Graphic总体架构一文中已经提到了设置这两个属性的作用。

DisplayDevice其实是抽象了显示设备,封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。来看下他的创建过程:

[cpp]

这段创建同样相当之长,我们目前只关注这里面创建了一个EGLSurface。我们在前面的文章中曾经提到过这个类,这个实际上就是一个供GLES使用的窗口缓冲区,为GLES提供了一个绘制的地方。在这个EGLSurface里面是一个Surface,本质上下面还是一个BufferQueue。渲染这个EGLSurface将导致一个buffer出队渲染入队的过程,lock和unlock过程是通过eglSwapBuffers函数来提供的。

2.5 makeCurrent

看完了上面几个重要概念的讲解,我们继续回到SF的init过程中来。下面是对主屏幕对应的display进行makeCurrent操作:

[cpp]

注意到这里调用的实际上是DisplayDevice类提供的函数,这也某种程度上说明了我们前面提到的DisplayDevice的作用是:封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。看下这个makeCurrent函数:

[cpp]

这里获取了当前使用的EGLSurface,一旦发现这个Surface发生了改变,就要重新调用eglMakeCurrent函数来设置,这是因为一个线程同时只能有一个EGLSurface作为current。而关于eglMakeCurrent函数的更详尽的说明,我们将在EGL和GLES的章节中给予说明。

2.6 EventThread的创建

再次回到SF的init过程中来:

[cpp]

这段讲了EventThread的创建和使用。EventThread主要用于VSYNC消息的处理,我们同样会单开一个章节来讲解VSYNC的逻辑。EventControlThread是用来向真实的VSync硬件发命令的,我们这里暂时不展开。而一旦硬件不能正常发送VSYNC命令时,我们则通过软件方式模拟,我们可以看到这里把模拟的间隔时间设置为16.6ms左右。

2.7 初始化显示设备

终于到了init函数的最后几句话,首先是初始化显示设备。

[cpp]

我们来看初始化显示设备的逻辑:

[cpp]

其中setTransactionState函数在很多地方都会有调用,作用主要是处理上层的各个命令,并根据flag设置event通知Threadloop进行处理,TODO而onScreenAcquired同样是一个重要的函数,不仅在这里,在屏幕会唤醒时同样会调用。

[cpp]

这里有几个点比较重要,首先是通知HWC,调用了HWC的acquire函数:

[cpp]

接下来,调用了EventThread的onScreenAcquired函数。

[cpp]

临行之前,面对太多的疑问和不解:为何是一个人?

Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程

相关文章:

你感兴趣的文章:

标签云: