GUI系统之SurfaceFlinger(14)handleTransaction

时间:2022-07-03 03:57:15
文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:
blog.csdn.net/uiop78uiop78/article/details/8954508


1.1.1 handleTransaction

有两个相似的函数,handleTransaction需要获取mStateLock锁,执行handleTransactionLocked,最后再将mHwWorkListDirty置为true。

后一个handleTransactionLocked才是真正处理业务的地方。从前面我们对transactionflags的解释来推断,它的具体工作应该会分为两部分,即traversal(对应eTraversalNeeded)和transaction(对应eTransactionNeeded)。

void SurfaceFlinger::handleTransactionLocked(uint32_ttransactionFlags)

{

    const LayerVector&currentLayers(mCurrentState.layersSortedByZ);

    const size_t count =currentLayers.size();

 

    /*第一部分,traversal所有layer*/

    const boollayersNeedTransaction = transactionFlags & eTraversalNeeded;

    if (layersNeedTransaction){//是否需要traversal

        for (size_t i=0 ; i<count ; i++) {//逐个layer来处理

            constsp<LayerBase>& layer = currentLayers[i];

            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);/*这个layer是否

                                                                    需要doTransaction*/

            if (!trFlags)continue;//如果不需要的话,直接进入下一个

 

            const uint32_tflags = layer->doTransaction(0);//由各layer做内部处理,下面会做详细分析

            if (flags &Layer::eVisibleRegion)//各layer计算可见区域是否变化

                mVisibleRegionsDirty = true;//可见区域发生变化

        }

    }

 

    /*第二部分,SurfaceFlinger执行transaction*/

    if (transactionFlags &eTransactionNeeded) {

        if (mCurrentState.orientation != mDrawingState.orientation) {

            /*角度产生变化,需要重新计算所有的可见区域,并且重绘*/

            const int dpy = 0;//第一个Display

            const intorientation = mCurrentState.orientation; //新的orientation

            GraphicPlane&plane(graphicPlane(dpy));

           plane.setOrientation(orientation);//将改变后的旋转角度设置到底层管理者

 

            // update theshared control block

            constDisplayHardware& hw(plane.displayHardware());

             /*下面的dcblk是一个供应用程序查询当前显示属性的“服务机构”,因而需要同步更新它*/

            volatiledisplay_cblk_t* dcblk = mServerCblk->displays + dpy;

           dcblk->orientation = orientation;

            dcblk->w =plane.getWidth();

            dcblk->h =plane.getHeight();

 

            mVisibleRegionsDirty= true; //旋转角度变化,当然可见区域也会变化

           mDirtyRegion.set(hw.bounds());//整个屏幕区域都是“脏”的

        }

 

        if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {// 有新的layer增加           

           mVisibleRegionsDirty = true;//可见区域需要重新计算

        }

 

        if (mLayersRemoved) {/*也可能有layers已经被移除,这样可见区域也会有变化。

                             比如原本被遮盖的部分或许就暴露出来了*/

            mLayersRemoved =false; //

           mVisibleRegionsDirty = true;

            constLayerVector& previousLayers(mDrawingState.layersSortedByZ);

            const size_t count= previousLayers.size();

            for (size_t i=0 ;i<count ; i++) {

                constsp<LayerBase>& layer(previousLayers[i]);

                if(currentLayers.indexOf( layer ) < 0) {/*在之前状态中存在,在现有状态中找不到,

                                                 说明它被removed了*/

                   mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);/*被移除layer的可见

                                                                           区域*/

                }

            }

        }

    }

    commitTransaction();//和Layer::doTransaction()的做法基本一样,多了几步操作

}

和我们预料的一样,整个函数分别处理eTraversalNeeded和eTransactionNeeded两种情况。注意layersNeedTransaction这个变量其实应该叫layersNeedTraversal更贴切一点,而后面eTransactionNeeded的情况下则没有另外声明bool变量来做判断。之所以叫做eTraversalNeeded,应该是因为这部分的源码是要遍历所有layer来实现的。不过遍历的过程中调用的各layer内部函数又叫做doTransaction()。后一个eTransactionNeeded有点类似于做整体处理,所以整个handleTransactionLocked的函数逻辑就是“分(遍历各layer)à总(SurfaceFlinger来做综合处理)”。名字有点混乱,大家稍微整理一下。

(1)  eTraversalNeeded

先来看eTraversalNeeded的处理。SurfaceFlinger中记录当前系统中layers状态的有两个全局变量,分别是:

State                  mDrawingState;

State                  mCurrentState;

前者是上一次“drawing”时的状态,而后者则是当前状态。这样我们只要通过对比这两个State,就知道系统中发生了什么变化,然后采取相应的措施。它们内部都包含了一个LayerVector类型的layersSortedByZ成员变量,从变量名可以看出是所有layers按照Z-order顺序排列的Vector。

所以我们可以从mCurrentState.layersSortedByZ来访问到所有layer,然后对有需要执行transaction的图层再调用内部的doTransaction()。显然,并不是每个layer在每次handleTransactionLocked中都需要调用doTransaction,判断的标准就是LayerBase::getTransactionFlags返回的标志中是否要求了eTransactionNeeded。大家要注意SurfaceFlinger和各Layer都有一个mTransactionFlags变量,不过含义不同。另外,Layer中也同样有mCurrentState和mDrawingState,虽然它们也分别表示上一次和当前的状态,但所属的State结构体是完全不同的。特对比如下:

GUI系统之SurfaceFlinger(14)handleTransaction

图 11‑36 两个State结构体对比

 

为了理解Layer究竟在doTransaction中做了些什么,我们先插入分析下它的实现:

uint32_t  Layer::doTransaction(uint32_tflags)

{…

    const Layer::State&front(drawingState());/*mDrawingState */

    const Layer::State&temp(currentState());/*mCurrentState */

 

    const bool sizeChanged =(temp.requested.w != front.requested.w) || (temp.requested.h !=front.requested.h);

    if (sizeChanged) {

        …

        mSurfaceTexture->setDefaultBufferSize(temp.requested.w, temp.requested.h);

    }

    …

    return LayerBase::doTransaction(flags);

}

首先判断图层的尺寸是否发生了改变(sizeChanged变量),即当前状态(temp)中的宽/高与上一次状态(front)一致与否。假如size发生了变化,我们调用mSurfaceTexture->setDefaultBufferSize()来使它生效。其中mSurfaceTexture是在Layer::onFirstRef()时生成的SurfaceTexture对象;SurfaceTexture内部又包含了一个BufferQueue成员变量(mBufferQueue),所以SurfaceTexture就是BufferQueue的管理封装类。这些知识我们在前几个小节已经详细分析过了,不清楚的可以回头看下。

BufferQueue::setDefaultBufferSize()改变的是内部的mDefaultWidth和mDefaultHeight两个默认的宽高值。当我们调用requestBuffers()请求Buffer时,如果没有指定width和height(值为0),BufferQueue就会使用这两个默认配置。

最后函数调用其父类LayerBase的doTransaction(),这才是整个实现的核心,我们来看下:

uint32_t LayerBase::doTransaction(uint32_t flags)

{

    const Layer::State&front(drawingState());//和前面函数是一样的

    const Layer::State&temp(currentState());

    …

    if (temp.sequence != front.sequence) {

        flags |= eVisibleRegion;

        this->contentDirty = true;

        const uint8_t type =temp.transform.getType();

        mNeedsFiltering =(!temp.transform.preserveRects() || (type >= Transform::SCALE));

    }

    commitTransaction();

    return flags;

}

这个函数也不长,主要难点就是理解sequence。这个变量是一个int值,当Layer的position、z-order、alpha、matrix、transparent region、flags、crop等一系列属性发生变化时(这些属性的设置函数都以setXXX开头,比如setCrop、setFlags),mCurrentState.sequence就会自增。因而当doTransaction时,它和mDrawing.sequence的值就不一样了。相比于每次属性变化时都马上做处理,这样的设计是合理的。因为它在平时只收集属性的变化,而到了特定的时刻(VSYNC信号产生时)才做统一处理。一方面这节约了系统资源;另一方面,部分属性的频繁变化会给整个画面带来不稳定感,采用这种方式就能规避这些问题。

仔细观察Layer和LayerBase的这两个doTransaction()实现,我们可以大致得出它们的目的,就是通过分析当前与上一次的状态变化,来制定下一步的操作——比如是否要重新计算可见区域(eVisibleRegion)、是否需要重绘(contentDirty)等等。

这些操作有的是要由SurfaceFlinger统一部署的,因而通过flags返回给调用者,比如eVisibleRegion;有些属于Layer的“家务”,因而只要内部做标记就可以了。

最后,commitTransaction()把mCurrentState赋给mDrawingState,这样它们两个的状态就一样了。在下一轮doTransaction()前,mCurrentState又会跟着属性的变更而改变,如此循环往复。

这样Layer::doTransaction()函数就结束了,带着flags值返回到前面的SurfaceFlinger::handleTransactionLocked()中。一旦某个layer明确表明可见区域发生了改变(eVisibleRegion),SurfaceFlinger中将其mVisibleRegionsDirty设为true,这个标志将影响后面的操作。

 

(2) eTransactionNeeded

完成当前系统中所有layer的遍历后,SurfaceFlinger就进入自己的“内务”处理了,即handleTransactionLocked()源码中的第二部分。我们在代码中列出了它需要完成的工作,也就是:

l  orientation

当显示屏旋转方向发生改变时,我们要把这一消息告知底层的管理者,即前几个小节讲过的GraphicPlane。变量dpy表示Display的编号,默认下都使用0。

接下来还需要同步更新的是mServerCblk中的信息,它是提供给各应用程序查询当前显示属性的,包括宽、高、格式、旋转角度、fps、密度等一系列数据。

显示屏旋转角度变化影响的范围是整个区域,所以在计算mDirtyRegion时,就直接设为整个屏幕(hw.bounds())

 

l  新增layer

与上一次相比,系统可能有新增的layer,我们只要对比两个State中的layer队列数目是否一致就可以得出结论了。假如图层有新增的话,可见区域需要重新计算,我们将mVisibleRegionsDirty置为true

 

l  移除layer

和上面的情况类似,有些layer也可能被移除了。针对这种情况,我们也需要重新计算可见区域。怎么知道哪些layer被移除了呢?有一个简单的办法就是比较两个State中的layersSortedByZ——假如一个layer在上一次的mDrawingState中还有,到了这次mCurrentState找不到了,那么就可以认定它被removed了。我们用mDirtyRegionRemovedLayer来记录这些被剔除图层的可见区域,因为一旦图层被移除,意味着被它遮盖的区域就有可能重新显露出来

 

在handleTransactionLocked()末尾,它也调用了commitTransaction()来结束整个业务处理。和LayerBase相同的地方是:

mDrawingState = mCurrentState;

这样两个状态就一样了。

另外,SurfaceFlinger还需要通知所有被移除的layer,相应的回调函数是onRemoved()。Layer在得到这一消息后,就知道它已经不会再被SurfaceFlinger处理了。最后,唤醒所有正在等待Transaction结束的线程:

mTransactionCV.broadcast();

SurfaceFlinger:: handleTransaction ()的流程图如下:

GUI系统之SurfaceFlinger(14)handleTransaction

图 11‑37 handleTransaction流程图