首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android系统Surface制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的治理分析

2012-10-23 
Android系统Surface制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的管理分析在前文中,我们分析了Surfac

Android系统Surface制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的管理分析

        在前文中,我们分析了SurfaceFlinger服务的启动过程。SurfaceFlinger服务在启动的过程中,会对系统的硬件帧缓冲区进行初始化。由于系统的硬件帧缓冲区一般只有一个,并且不是谁都可以随便访问的,因此,它就需要由一个服务来统一管理。在Android系统中,这个服务便是SurfaceFlinger。在本文中,我们就详细分析SurfaceFlinger服务是如何管理系统的硬件帧缓冲区的。

        从前面Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划一文可以知道,SurfaceFlinger服务通过一个GraphicPlane对象来描述系统的显示屏,即系统的硬件帧缓冲区。GraphicPlane类内部聚合了一个DisplayHardware对象,通过这个DisplayHardware对象就可以访问系统的硬件帧缓冲区。DisplayHardware类内部又包含了一个FramebufferNativeWindow对象,这个FramebufferNativeWindow对象才是真正用来描述系统的硬件帧缓冲区的。FramebufferNativeWindow类的作用类似于在前面Android应用程序请求SurfaceFlinger服务创建Surface的过程分析一文中所介绍的Surface类,它是连接OpenGL库和Android的UI系统的一个桥梁,OpenGL库就是通过这个桥梁来将Android系统的UI渲染到硬件帧缓冲区中去的。GraphicPlane、DisplayHardware和FramebufferNativeWindow这三个类的关系如图1所示。

Android系统Surface制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的治理分析

图1 GraphicPlane、DisplayHardware和FramebufferNativeWindow的类关系图

       接下来,我们就分别介绍GraphicPlane、DisplayHardware和FramebufferNativeWindow这三个类的实现,以便可以理解SurfaceFlinger服务是如何通过它们来管理系统的硬件帧缓冲区的。

       从前面Android系统Surface制的SurfaceFlinger服务的启动过程分析一文可以知道,SurfaceFlinger服务在启动的过程中,会对系统的硬件帧缓冲区进行初始化,如下所示:


图2 DisplayHardwareBase类关系图

        DisplayHardwareBase类一方面用来控制SurfaceFlinger服务当前是否能够访问显示屏。当显示屏处于唤醒状态时,DisplayHardwareBase类的成员变量mScreenAcquired的值就会等于1,表示SurfaceFlinger服务就可以访问显示屏;而当显示屏处于睡眠状态时,DisplayHardwareBase类的成员变量mScreenAcquired的值就会等于0,表示SurfaceFlinger服务不可以访问显示屏。

        显示屏的唤醒/睡眠状态切换是由内核来通知DisplayHardwareBase类的,因此,DisplayHardwareBase类会通过一个线程来监控显示屏的唤醒/睡眠状态切换。这个线程是通过DisplayHardwareBase类的成员变量mDisplayEventThread来描述的。DisplayHardwareBase类的成员变量mDisplayEventThread所描述的线程的类型要么是DisplayEventThread,要么是ConsoleManagerThread,这两者均是从DisplayEventThreadBase类继续下来的,而后者又是从Thread类继承下来的。当硬件帧缓冲区的控制台被打开时,DisplayHardwareBase类的成员变量mDisplayEventThread所描述的线程的类型就是DisplayEventThread;当硬件帧缓冲区的控制台没有被打开时,DisplayHardwareBase类的成员变量mDisplayEventThread所描述的线程的类型就是ConsoleManagerThread。这里我们只考虑硬件帧缓冲区的控制台被打开的情况。

        用来监控显示屏唤醒/睡眠状态切换的线程是在DisplayHardwareBase对象的初始化过程中创建的,它运行起来之后,就会在一个无限循环中不断地监控显示屏唤醒/睡眠状态切换事件。为了方便描述,我们将这个线程称为控制台事件监控线程。DisplayEventThreadBase类的成员变量mFlinger指向了SurfaceFlinger服务,一旦控制台事件监控线程监控到显示屏发生唤醒/睡眠状态切换,那么就会通过它来通知SurfaceFlinger服务。

       控制台事件监控线程的运行过程大概上这样的。在每一次循环中,控制台事件监控线程首先监控显示屏是否要进入睡眠状态了。如果是的话,那么该线程就会通过DisplayEventThreadBase类的成员变量mFlinger来通知SurfaceFlinger服务,并且等待SurfaceFlinger服务处理完成这个通知。SurfaceFlinger服务一旦处理完成显示屏进入睡眠状态的事件,它就会调用DisplayHardwareBase类的成员函数releaseScreen来将其成员变量mScreenAcquired的值设置为0,表示它目前不可以访问显示屏。控制台事件监控线程接下来就会等待显示屏被唤醒过来。一旦显示屏被唤醒过来,那么该线程就会通过DisplayEventThreadBase类的成员变量mFlinger来通知SurfaceFlinger服务。SurfaceFlinger服务得到这个通知之后,就会调用DisplayHardwareBase类的成员函数acquireScreen来将其成员变量mScreenAcquired的值设置为1,表示它目前不可以访问显示屏。在下一篇文章分析SurfaceFlinger服务的线程模型时,我们再详细分析这个过程。

        DisplayHardwareBase类另一方面用来控制SurfaceFlinger服务当前是否能够在显示屏上渲染UI。当系统的其它组件请求SurfaceFlinger服务关闭显示屏时,SurfaceFlinger服务就会调用DisplayHardwareBase类的成员函数setCanDraw来将其成员变量mCanDraw的值设置为0;而当系统的其它组件请求SurfaceFlinger服务打开显示屏时,SurfaceFlinger服务就会调用DisplayHardwareBase类的成员函数setCanDraw来将其成员变量mCanDraw的值设置为1。只有当DisplayHardwareBase类的成员变量mScreenAcquired和mCanDraw的值均等于1时,SurfaceFlinger服务才可以在显示屏上渲染系统的UI。为了方便SurfaceFlinger服务判断它当前是否可以在显示屏上渲染系统的UI,DisplayHardwareBase类提供了另外一个成员函数canDraw。当DisplayHardwareBase类的成员函数canDraw的返回值等于true时,就表示SurfaceFlinger服务可以在显示屏上渲染系统的UI,否则就不可以。

       了解了DisplayHardwareBase类的作用之后,接下来我们就从它的构造函数开始分析它的初始化过程。

        DisplayHardwareBase类的构造函数的实现如下所示:

图3 FramebufferNativeWindow类关系

        前面提到,FramebufferNativeWindow类与在前面Android应用程序请求SurfaceFlinger服务创建Surface的过程分析一文中提到的Surface类的作用是类似的。FramebufferNativeWindow类一方面用来在OpenGL库和Android本地窗口系统之间建立连接,这样,我们就可以使用它的成员函数dequeueBuffer来为OpenGL库分配空闲图形缓冲区,以及使用它的成员函数queueBuffer来将OpenGL已经填充好UI数据的图形缓冲区渲染到硬件帧缓冲区中去。FramebufferNativeWindow类另一方面还继承了LightRefBase类,因此,从前面Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析一文可以知道,FramebufferNativeWindow类对象可以结合Android系统的轻量级指针sp来使用,以便可以自动维护生命周期。

        FramebufferNativeWindow类与Surface类又有不同的地方。从前面Android应用程序请求SurfaceFlinger服务创建Surface的过程分析一文可以知道,Surface类使用的图形缓冲区一般是在匿名共享内存中分配的,并且是由SurfaceFlinger服务来负责分配,然后再传递给应用程序进程使用的,而FramebufferNativeWindow类使用的图形缓冲区是直接在硬件帧缓冲区分配的,并且它可以直接将这些图形缓冲区渲染到硬件帧缓冲区中去。从前面Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析一文可以知道,要从硬件帧缓冲区中分配和渲染图形缓冲区,就必须要将HAL层中的Gralloc模块加载到当前的进程空间来,并且打开里面的gralloc设备和fb设备,其中,gralloc设备用来分配图形缓冲区,而fb设备用来渲染图形缓冲区。因此,FramebufferNativeWindow类包含了一个类型的alloc_device_t*的成员变量grDev和一个类型为framebuffer_device_t*的成员变量fbDev,它们分别指向HAL层中的Gralloc模块的gralloc设备和fb设备。

       FramebufferNativeWindow类在内部还包含了一个类型为sp<NativeBuffer>的数组buffers,用来描述OpenGL库可以使用的图形缓冲区,数组的大小等于NUM_FRAME_BUFFERS,即等于硬件帧缓冲区能够提供的图形缓冲区的个数。例如,在Android 2.3系统中,硬件帧缓冲区能够提供的图形缓冲区的个数等于2,这意味着Android系统可以使用双缓冲区技术来渲染系统的UI。由于OpenGL库所使用的图形缓冲区必须要实现android_native_buffer_t接口,因此,NativeBuffer类继承了android_native_buffer_t类。此外,NativeBuffer类还继承了LightRefBase类,因此,它的对象就和FramebufferNativeWindow类对象一样,可以结合Android系统的轻量级指针sp来使用,以便可以自动维护生命周期。

       了解了FramebufferNativeWindow类的作用之后,接下来我们就从它的构造函数开始分析它的实现,即分析它的类对象的创建过程。从前面DisplayHardware类的成员函数init的实现可以知道,FramebufferNativeWindow对象是在DisplayHardware对象初始化的过程中创建的,并且包含在DisplayHardware对象内部中,用来管理硬件帧缓冲区。

        FramebufferNativeWindow类的构造函数定义在文件frameworks/base/libs/ui/FramebufferNativeWindow.cpp中,它的实现比较长,我们分段来阅读:

int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,        android_native_buffer_t* buffer){    FramebufferNativeWindow* self = getSelf(window);    Mutex::Autolock _l(self->mutex);    framebuffer_device_t* fb = self->fbDev;    buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;    const int index = self->mCurrentBufferIndex;    GraphicLog& logger(GraphicLog::getInstance());    logger.log(GraphicLog::SF_FB_POST_BEFORE, index);    int res = fb->post(fb, handle);    logger.log(GraphicLog::SF_FB_POST_AFTER, index);    self->front = static_cast<NativeBuffer*>(buffer);    self->mNumFreeBuffers++;    self->mCondition.broadcast();    return res;}
        这个函数定义在文件frameworks/base/libs/ui/FramebufferNativeWindow.cpp中。

        参数window指向的实际上也是一个FramebufferNativeWindow对象,这个FramebufferNativeWindow对象是在DisplayHardware类的成员函数init中创建的,因此,函数在开始的地方同样是先将它转换一个FramebufferNativeWindow对象self。

        参数buffer指向的是一个实际类型为NativeBuffer的图形缓冲区,这个图形缓冲区是在FramebufferNativeWindow类的成员函数dequeueBuffer中分配的,如前所述。

        FramebufferNativeWindow类的成员函数queueBuffer目标就是要将参数buffer所描述的图形缓冲区渲染到硬件帧缓冲区中去,因此,我们就需要获得FramebufferNativeWindow对象self的成员变量fbDev所描述的一个fb设备。有了这个fb设备之后, 我们就可以调用它的成员函数post来将参数buffer所描述的图形缓冲区渲染到硬件帧缓冲区中去,这个过程可以参考Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析一文。

       参数buffer所描述的图形缓冲区被渲染到硬件帧缓冲区中去之后,它就变成一个空闲的图形缓冲区了,因此,我们就需要将它返回给FramebufferNativeWindow对象self内部的图形缓冲区数组buffers中去,并且将可用的空闲图形缓冲区的个数增加1,最后通过FramebufferNativeWindow对象self的成员变量mCondition所描述的一个条件变量将前面正在等待从FramebufferNativeWindow对象self内部分配空闲图形缓的线程唤醒。

       至此,FramebufferNativeWindow类的成员函数queueBuffer的实现就分析完成了,FramebufferNativeWindow类的实现也分析完成了。通过GraphicPlane、DisplayHardware和FramebufferNativeWindow这三个类的实现,我们就可以知道SurfaceFlinger服务是如何管理系统的显示屏,即系统的硬件帧缓冲区的了。

       从SurfaceFlinger服务创建一个DisplayHardwareBase对象来管理系统的显示屏的过程可以知道,这个DisplayHardwareBase对象会创建一个控制台事件监控线程来监控硬件帧缓冲区的睡眠/唤醒状态切换事件,而从前面Android系统Surface制的SurfaceFlinger服务的启动过程分析一文又可以知道,System进程在启动SurfaceFlinger服务过程中,又会创建一个Binder线程池,以及为SurfaceFlinger服务创建一个UI渲染线程,这样在SurfaceFlinger服务中,就存在三种不同类型的线程,在接下来的一篇文章中,我们就将分析详细SurfaceFlinger服务的线程模型,以便最后我们就可以更好地分析SurfaceFlinger服务的实现,敬请关注!

1楼careland_hqh31分钟前
期待这篇文章很久了,老罗给力啊

热点排行