有两个相似的函数,handleTransaction需要获取mStateLock锁,执行handleTransactionLocked,最后再将mHwWorkListDirty置为true。
后一个handleTransactionLocked才是真正处理业务的地方。从前面我们对transactionflags的解释来推断,它的具体工作应该会分为两部分,即traversal(对应eTraversalNeeded)和transaction(对应eTransactionNeeded)。
void SurfaceFlinger::handleTransactionLocked(uint32_ttransactionFlags)
{
const LayerVector¤tLayers(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结构体是完全不同的。特对比如下:
图 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 ()的流程图如下:
图 11‑37 handleTransaction流程图