文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/
GUI系统之SurfaceFlinger章节目录:
blog.csdn.net/uiop78uiop78/article/details/8954508
1.1.1 VSync信号的处理
经过上一小节的分析,现在我们已经明白了系统是如何通过硬件设备或者软件模拟来产生VSync信号的,也明白了它的流转过程。VSync最终会被EventThread::threadLoop()分发给各监听者,在当前版本中是MessageQueue。
MessageQueue通过与EventThread建立一个Connection来监听事件,简图如下:
图 11‑35 Connection代表了EventThread和对事件感兴趣的对象的连接
对VSYNC等事件感兴趣的对象,比如MessageQueue,首先要通过EventThread::createEventConnection()来建立一个连接,实际上就是生成了一个EventThread::Connection对象。这个对象将对双方产生如下影响:
l 当Connection::onFirstRef()时,它会主动调用EventThread::registerDisplayEventConnection()来把自己加入到mDisplayEventConnections中,这是保证事件发生后EventThread能找到“连接”的关键一步
l 当MessageQueue得到Connection后,它会马上调用getDataChannel来获得一个BitTube。从逻辑关系上看,Connection只是双方业务上连接,而BitTube则是数据传输通道,各种Event信息就是通过这里传输的
void MessageQueue::setEventThread(const sp<EventThread>&eventThread)
{
mEventThread =eventThread;
mEvents = eventThread->createEventConnection(); //建立一个Connection
mEventTube = mEvents->getDataChannel();//马上获取BitTube
mLooper->addFd(mEventTube->getFd(), 0,ALOOPER_EVENT_INPUT, MessageQueue::cb_eventReceiver, this);
}
从扮演的角色上来看,EventThread是Server,不断地往Tube中写入数据;而MessageQueue是Client,负责读取数据。可能有人会很好奇,MessageQueue如何得知有Event到来,然后去读取它呢?答案就是它们之间的数据读写模式采用的是Socket(AF_UNIX域)。
上面这个函数的末尾,通过Looper添加了一个fd,这实际上就是Socket pair中的一端。然后Looper将这个fd与其callback函数(即MessageQueue::cb_eventReceiver)加入全局的mRequests进行管理。
KeyedVector<int, Request> mRequests;
这个Vector会集中所有需要监测的fd,这样当Looper进行pollInner时,只要有事件需要处理,它就可以通过回调函数通知“接收者”。这里面的实现细节主要包括BitTube.cpp和Looper.cpp,有兴趣的读者可以自行研究下。
当Event发生后,MessageQueue::cb_eventReceiver开始执行,进而调用eventReceiver。如果event的类型是DisplayEventReceiver::DISPLAY_EVENT_VSYNC,这是我们想要监听的事件,所以再调用mHandler->signalRefresh():
void MessageQueue::Handler::signalRefresh() {
if((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh)== 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
根据前几个小节我们分析的SurfaceThread工作模式,这个Message会进入它的消息处理队列,然后在SurfaceFlinger::onMessageReceived()中得到处理:
void SurfaceFlinger::onMessageReceived(int32_t what)
{…
switch (what) {
caseMessageQueue::REFRESH: {
const uint32_tmask = eTransactionNeeded | eTraversalNeeded;
uint32_ttransactionFlags = peekTransactionFlags(mask);
if(CC_UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
handlePageFlip();
handleRefresh();
constDisplayHardware& hw(graphicPlane(0).displayHardware());
…
if(CC_LIKELY(hw.canDraw())) {
handleRepaint();
hw.compositionComplete();
postFramebuffer();
} else {
hw.compositionComplete();
}
} break;
}
}
经过几个版本的变迁,现在SurfaceFlinger只处理REFRESH一个消息,不过源码中遗留下了很多没用的代码J,大家注意辨别。我们将重点的部分通过高显帮大家划出来,即下面几个函数:
l handleTransaction
即处理事务,什么样的事务呢?在SurfaceFlinger::setTransactionState()中我们可以看到,假如当前的orientation和新的不符合时,会将eTransactionNeeded置位;当应用程序请求createSurface、removeSurface,或者addLayer、removeLayer时也会把它置位。另一个flag被置位的情况则包括:layer的size、alpha、matrix、transparentregion、visibility变化等等。
总结起来,就是当与系统显示相关的状态(比如新增/减少了Surface,显示屏的变化等等)改变,或者某个Layer自身状态(比如它的大小尺寸、可见性、透明度等等)改变时,就需要执行Transaction。
l handlePageFlip
由前面的分析我们知道,每个Layer对应着最多32个BufferSlot,这样系统在进行一次刷新时,必须先决定使用哪个buffer,并利用这一缓冲区更新纹理。另外,我们还需要计算所有图层的可见区域和“脏区域”,以便最终的合成显示。
l handleRefresh
版本更新遗留下的函数,当前实现中没有起到作用,相信在后续升级中会进一步完善。
l handleWorkList
创建HWComposer中的mList,这个列表将用于后续的layer合成。这个函数比较简单,我们不单独介绍。
l handleRepaint
计算出最终的脏区域,并执行实际的合成工作(composeSurfaces),我们将做详细源码分析。
l postFramebuffer
将上一步中生成的缓冲区数据post到framebuffer中,这样才能真正在物理屏幕上显示出来。分为两条路径,即HWComposer::commit和直接调用eglSwapBuffers()
这些函数基本涵盖了SurfaceFlinger的所有功能,接下来的几个小节我们将详细分析它们,各个击破。