分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
在前面的一系列文章中,我们学习了Android应用程序与SurfaceFlinger服务的关系,以及SurfaceFlinger服务的启动过程、初始化硬件帧缓冲区的过程、线程模型。SurfaceFlinger服务所做的一切都是为了给Android应用程序提服务的,即为Android应用程序渲染它们的UI。在本文中,我们就详细分析SurfaceFlinger服务渲染Android应用程序UI的过程。
《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!
从前面Android系统Surface制的SurfaceFlinger服务的线程模型分析一文可以知道,SurfaceFlinger服务是通过它的UI渲染线程来将应用程序的UI渲染到硬件帧缓冲区中去的,因此,接下来我们就通过分析SurfaceFlinger服务的UI渲染线程的执行过程来分应用程序UI的渲染过程,这个过程如图1所示。
图1 SurfaceFlinger服务渲染应用程序UI的示意图
从图1就可以看出,SurfaceFlinger服务的UI渲染线程的执行过程如下所示:
1. 调用SurfaceFlinger类的成员函数handleConsoleEvents来处理控制台事件。
2. 调用SurfaceFlinger类的成员函数handleTransaction来处理系统显示屏以及应用程序窗口的属性变化,例如大小、旋转方向变化等。
3. 调用SurfaceFlinger类的成员函数handlePageFlip来让各个应用程序窗口设置它们当前所要渲染的图形缓冲区。
4. 如果SurfaceFlinger服务在编译的时候指定了USE_COMPOSITION_BYPASS宏,并且当前需要渲染的应用程序窗口只有一个,那么就会调用SurfaceFlinger类的成员函数handleBypassLayer来直接将这个应用程序窗口的图形缓冲区渲染到硬件帧缓冲区中去,否则的话,就要调用SurfaceFlinger类的成员函数handleRepaint来合成所有的应用程序窗口的图形缓冲区到一个主图形缓冲区中去。
5. 调用SurfaceFlinger类的成员函数postFramebuffer将前面得到的主图形缓冲区渲染到硬件帧缓冲区中去。
前面Android系统Surface制的SurfaceFlinger服务的线程模型分析一文中,我们已经分析过第1步的实现了,而通过前面Android应用程序与SurfaceFlinger服务的关系概述和学习计划这一系列文章的学习,我们也已经了解了应用程序窗口的图形缓冲区的创建过程,因此,接下来我们就在这些知识的基础上来详细分析第2步到第5的实现,即分别分析SurfaceFlinger类的成员函数handleTransaction、handlePageFlip、handleBypassLayer和postFramebuffer的实现。
1. handleTransaction
SurfaceFlinger类的成员函数handleTransaction是用来处理系统显示屏以及应用程序窗口的属性变化的,这个过程如图2所示。
图2 系统显示屏以及应用程序窗口的属性变化处理过程
这个过程可以分为6个步骤,接下来我们就详细分析每一个步骤。
Step 1. SurfaceFlinger.handleTransaction
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags){ Vector< sp<LayerBase> > ditchedLayers; /* * Perform and commit the transaction */ { // scope for the lock Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; handleTransactionLocked(transactionFlags, ditchedLayers); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; // here the transaction has been committed } /* * Clean-up all layers that went away * (do this without the lock held) */ const size_t count = ditchedLayers.size(); for (size_t i=0 ; i<count ; i++) { if (ditchedLayers[i] != 0) { //LOGD("ditching layer %p", ditchedLayers[i].get()); ditchedLayers[i]->ditch(); } }}
这个函数定义在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。
SurfaceFlinger类的成员函数handleTransaction是通过调用另外一个成员函数handleTransactionLocked来处理系统显示屏以及应用程序窗口的属性变化的,而SurfaceFlinger类的成员函数handleTransactionLocked在处理完成系统显示屏以及应用程序窗口的属性变化之后,会返回系统中那些已经销毁了的应用程序窗口。
从Android应用程序与SurfaceFlinger服务的关系概述和学习计划这一系列文章可以知道,在SurfaceFlinger服务这一侧,应用程序窗口一般是使用一个Layer对象来描述的,又由于Layer类是从LayerBase类继承下来的,因此,我们可以那些已经销毁了的应用程序窗口保存在一个类型为sp<LayerBase>的向量ditchedLayers中。
SurfaceFlinger类的成员函数handleTransaction最后就调用保存在向量ditchedLayers中的每一个LayerBase对象的成员函数dtich来执行被销毁的应用程序窗口的清理操作,接下来我们就继续分析SurfaceFlinger类的成员函数handleTransactionLocked,看看它是如何处理系统显示屏以及应用程序窗口的属性变化的。
Step 2. SurfaceFlinger.handleTransactionLocked
SurfaceFlinger类的成员函数handleTransactionLocked定义在文件rameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中,我们分三段来阅读:
void SurfaceFlinger::handleTransactionLocked( uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers){ const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); /* * Traversal of the children * (perform the transaction for each of them if needed) */ const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; if (layersNeedTransaction) { for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer = currentLayers[i]; uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; const uint32_t flags = layer->doTransaction(0); if (flags & Layer::eVisibleRegion) mVisibleRegionsDirty = true; } }
这段代码用来处理应用程序窗口的属性变化。
参数transactionFlags最开始是从SurfaceFlinger类的成员函数threadLoop传进来的。从前面Android系统Surface制的SurfaceFlinger服务的线程模型分析一文可以知道,SurfaceFlinger类的成员函数threadLoop在调用另外一个成员函数handleTransaction来处理系统显示屏以及应用程序窗口的属性变化之前,首先会调用成员函数getTransactionFlags来检查系统显示屏或者应用程序窗口的属性是否发生了变化。如果系统显示屏的属性发生了变化,那么传到这里的参数transactionFlags的eTransactionNeeded位就会等于1,而如果有应用程序窗口的属性发生了变化,那么传到这里的参数transactionFlags的eTraversalNeeded位就会等于1。为了方便描述,我们假设系统显示屏以及应用程序窗口的属性都发生了变化。
SurfaceFlinger类的成员变量mCurrentState指向了一个State对象,用来描述SufaceFlinger服务的当前状态,其中,这个State对象的成员变量layersSortedByZ是一个类型为LayerVector的向量,它里面保存了SufaceFlinger服务当前所需要渲染的应用程序窗口,而这些应用程序窗口都是使用一个LayerBase对象来描述的。
这段代码首先获得SufaceFlinger服务当前所需要渲染的应用程序窗口,接着再通过一个for循环来依次检查每一个应用程序窗口的属性是否发生了变化。如果某一个应用程序窗口的属性被修改过,那么调用用来描述这个应用程序窗口的一个LayerBase对象的成员函数getTransactionFlags得到的返回值trFlags就不会等于0,在这种情况下,这段代码就会调用这个LayerBase对象的成员函数doTransaction来处理对应的应用程序窗口的属性变化。
在LayerBase类中,有一个类型为int32_t的成员变量mTransactionFlags,每当SurfaceFlinger服务修改某一个应用程序窗口的属性时,都会将与其对应的LayerBase的成员变量mTransactionFlags的相应的位设置为1,这样LayerBase类的成员函数getTransactionFlags就可以通过这个成员变量来判断一个应用程序窗口的属性是否发生变化了。
如果一个应用程序窗口发生的属性变化是可见区域发生了改变,那么对应的LayerBase对象的成员函数doTransaction的返回值flags的Layer::eVisibleRegion位就会等于1。在这种情况下,这段代码就会将 SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true,表示后面要重新计算各个应用程序窗口的可见区域。
为了方便描述,我们假设发生了属性变化的应用程序窗口是一个普通类型的Surface,即用来描述它的实际是一个从LayerBase类继承下来的Layer对象。在这种情况下,前面实际上调用了Layer类的成员函数doTransaction来处理一个应用程序窗口的属性变化。在接下来的Step 3中,我们再详细分析Layer类的成员函数doTransaction的实现,现在我们接着往下阅读SurfaceFlinger类的成员函数handleTransactionLocked的代码:
/* * Perform our own transaction if needed */ if (transactionFlags & eTransactionNeeded) { if (mCurrentState.orientation != mDrawingState.orientation) { // the orientation has changed, recompute all visible regions // and invalidate everything. const int dpy = 0; const int orientation = mCurrentState.orientation; const uint32_t type = mCurrentState.orientationType; GraphicPlane& plane(graphicPlane(dpy)); plane.setOrientation(orientation); // update the shared control block const DisplayHardware& hw(plane.displayHardware()); volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; dcblk->orientation = orientation; dcblk->w = plane.getWidth(); dcblk->h = plane.getHeight(); mVisibleRegionsDirty = true; mDirtyRegion.set(hw.bounds()); } if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) { // freezing or unfreezing the display -> trigger animation if needed mFreezeDisplay = mCurrentState.freezeDisplay; if (mFreezeDisplay) mFreezeDisplayTime = 0; } if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { // layers have been added mVisibleRegionsDirty = true; } // some layers might have been removed, so // we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; const LayerVector& previousLayers(mDrawingState.layersSortedByZ); const size_t count = previousLayers.size(); for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer(previousLayers[i]); if (currentLayers.indexOf( layer ) < 0) { // this layer is not visible anymore ditchedLayers.add(layer); mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); } } } }
这段代码用来处理系统显示屏的属性变化。
在分析这段代码之前,我们首先了解SurfaceFlinger类的另外一个成员变量mDrawingState的含义。SurfaceFlinger类的成员变量mDrawingState与前面所介绍的成员变量mCurrentState类似,它的类型也为State,不过它是用来描述SufaceFlinger服务的上一次渲染状态的。通过这两个成员变量的比较,我们就可以知道系统显示屏的哪一个属性发生了变化。
前面提到,当系统显示屏的属性发生了变化,那么参数transactionFlags的eTransactionNeeded位就会等于1,在这种情况,这段代码就需要完成四件事情。
第一件事情是判断系统显示屏的旋转方向是否发生变化。State类的成员变量orientation用来描述显示屏的方向,因此,当SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量orientation的值不等于SurfaceFlinger类的成员变量mDrawingState所描述的一个State对象的成员变量orientation的值时,就说明系统显示屏的旋转方向发生了变化。在这种情况下,我们就需要将系统显示屏的旋转方向设置为SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量orientation的值,这是通过调用编号为0的一个GraphicPlane对象的成员函数setOrientation来实现的。
SurfaceFlinger服务的UI渲染线程在初始化的过程中,除了会初始化硬件帧缓冲区之外,还会创建一个类型为surface_flinger_cblk_t的对象,用来描述系统显示屏的信息,例如大小和旋转方向等,以便其它进程可以通过这个surface_flinger_cblk_t对象来获得系统显示屏的信息。这个surface_flinger_cblk_t对象就保存在SurfaceFlinger类的成员变量mServerCblk中。因此,当系统显示屏的旋转方向发生了变化时,我们还需要将变化后的旋转方向保存在SurfaceFlinger类的成员变量mServerCblk所描述的一个surface_flinger_cblk_t对象中。由于系统显示屏的旋转方向变化一般意味着宽度和高度也会发生变化,因此,我们还需要将旋转发生变化后得到的系统显示屏的宽度和高度值保存在SurfaceFlinger类的成员变量mServerCblk所描述的一个surface_flinger_cblk_t对象中。
系统显示屏的旋转方向同时也意味着我们需要重新计算各个应用程序窗口的可见区域以及重新绘制整个显示屏,因此,在这种情况下,我们还需要将SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true,以及将SurfaceFlinger类的成员变量mDirtyRegion的大小设置为整个显示屏的大小,即将系统UI的脏区域设置为整个显示屏的大小。
第二件事情是判断系统显示屏的冻结状态是否发生变化。State类的成员变量freezeDisplay用来描述显示屏的冻结状态,因此,当SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量freezeDisplay的值不等于SurfaceFlinger类的成员变量mDrawingState所描述的一个State对象的成员变量freezeDisplay的值时,就说明系统显示屏的冻结状态发生了变化。在这种情况下,我们就需要将SurfaceFlinger类的成员变量mFreezeDisplay的值设置为SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量freezeDisplay的值。如果显示屏的是由解冻状态变化为冻结状态的,那么还需要将显示屏的冻结时间设置为0,即将SurfaceFlinger类的成员变量mFreezeDisplayTime的值设置为0,以便可以将显示屏进入到冻结状态的最长时间设置为一个默认值,这一点可以参考前面Android系统Surface制的SurfaceFlinger服务的线程模型分析一文。
第三件事情是判断是否新增了应用程序窗口。State类的成员变量layersSortedByZ是一个类型LayerVector的向量,里面保存的是SurfaceFlinger服务在某一个状态下所拥有的应用程序窗口,因此,当SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量layersSortedByZ所指向的一个向量的大小值大于SurfaceFlinger类的成员变量mDrawingState所描述的一个State对象的成员变量layersSortedByZ所指向的一个向量的大小值时,就说明系统新增了应用程序窗口。在这种情况下,我们就需要将SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true,以表示我们需要重新计算各个应用程序窗口的可见区域。
第四件事情是判断是否移除了某些应用程序窗口。SurfaceFlinger类的成员变量mLayersRemoved用来描述是否有应用程序窗口被移除了。如果有有应用程序窗口被移除的话,那么这个成员变量的值就会等于true。在这种情况下,我们就需要是哪些应用程序窗口被移除了。计算的方法很简单,如果一个应用程序窗口存在于SurfaceFlinger类的成员变量mDrawingState所描述的一个State对象的成员变量layersSortedByZ所指向的一个向量中,但是不存在于SurfaceFlinger类的成员变量mCurrentState所描述的一个State对象的成员变量layersSortedByZ所指向的一个向量中,那么就说明这个应用程序窗口被移除了,因此,就需要将它保存输出参数ditchedLayers所描述的一个向量中,以便可以返回给上一步来处理。SurfaceFlinger类的成员变量mDirtyRegionRemovedLayer用来描述那些被移除了的应用程序窗口所占用的区域,因此,每当我们移除一个应用程序窗口的时候,都需要将它所占用的区域增加到SurfaceFlinger类的成员变量mDirtyRegionRemovedLayer所描述的一个区域去。
当处理完成那些被移除的应用程序窗口之后,我们就需要将SurfaceFlinger类的成员变量mLayersRemoved的值设置为false,并且将SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true,以表示我们需要重新计算现存的各个应用程序窗口的可见区域。
处理完成系统显示屏的属性变化之后,我们接着向下阅读SurfaceFlinger类的成员函数handleTransactionLocked的最后一行代码:
commitTransaction();}
这段代码只有一行,即调用SurfaceFlinger类的成员函数commitTransaction来告诉SurfaceFlinger服务,系统显示屏以及各个应用程序窗口的属性变化已经处理完毕,这时候SurfaceFlinger服务就可以切换状态了。在后面的Step 6中,我们再详细分析SurfaceFlinger类的成员函数commitTransaction的实现。
接下来,我们就继续分析Layer类的成员函数doTransaction的实现,以便可以了解应用程序窗口的属性变化的处理过程。
Step 3. Layer.doTransaction
uint32_t Layer::doTransaction(uint32_t flags){ const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); const bool sizeChanged = (front.requested_w != temp.requested_w) || (front.requested_h != temp.requested_h); if (sizeChanged) { ...... if (!isFixedSize()) { // we're being resized and there is a freeze display request, // acquire a freeze lock, so that the screen stays put // until we've redrawn at the new size; this is to avoid // glitches upon orientation changes. if (mFlinger->hasFreezeRequest()) { // if the surface is hidden, don't try to acquire the // freeze lock, since hidden surfaces may never redraw if (!(f