Android SurfaceFlinger对VSync信号的处理过程分析

本文详细解析了Android系统中SurfaceFlinger服务如何通过VSync事件触发屏幕更新,包括消息循环机制、事件连接建立、VSync事件读取与处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android SurfaceFlinger服务的消息循环过程源码分析中分析了SurfaceFlinger的消息循环过程,SurfaceFlinger通过维护一个消息队列来实现消息的异步处理。Android应用程序消息循环源码分析介绍了消息循环定义的Looper对象不仅可以处理Java层和C++层的消息,同时也可以监控用户添加的文件句柄。Android SurfaceFlinger服务的消息循环过程源码分析也介绍了SurfaceFlinger与EventThread线程间的VSync事件连接Connection的创建及注册到EventThread线程过程,同时将Connection中的Socket读端添加到SurfaceFlinger消息循环中监听。在Android VSync事件分发过程源码分析中介绍了EventThread线程负责分发VSync事件给已注册的Connection连接,下图就是SurfaceFlinger与EventThread之间的关系图:

上图显示了EventThread线程是通过Socket方式与SurfaceFlinger的消息循环通信的,EventThread线程是Server,往Socket的发送端写入VSync事件信息,SurfaceFlinger是Client,从Socket的接收端读取到VSync事件信息,从而响应VSync中断信号。在将Socket的接收端添加到SurfaceFlinger的消息循环Looper对象中时,注册了Socket接收端数据读取时的回调函数:

void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
    mEventThread = eventThread;
    mEvents = eventThread->createEventConnection();
    mEventTube = mEvents->getDataChannel();
    mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,MessageQueue::cb_eventReceiver, this);
}

createEventConnection()用于创建一个事件连接Connection,通过调用Connection的getDataChannel()函数返回一个BitTube对象,这是对Socket通信方式的封装类,描述了VSync事件信息的数据通道。调用BitTube对象的getFd()函数既可得到创建的Socket的发送端句柄,然后调用Looper类提供的addFd()函数将Socket发送端句柄添加到SurfaceFlinger的消息循环Looper对象中监听,同时注册回调函数MessageQueue::cb_eventReceiver。通过Looper添加了一个fd,这实际上就是Socket pair中的一端。然后Looper将这个fd与其callback函数(即MessageQueue::cb_eventReceiver)加入全局的mRequests进行管理。这个Vector会集中所有需要监测的fd,这样当Looper进行pollInner时,只要Socket接收端有数据可以读取时,SurfaceFlinger消息循环自动调用该函数来处理VSync事件,addFd()函数的最后一个参数this指向当前SurfaceFlinger的消息队列MessageQueue对象。

int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
    return queue->eventReceiver(fd, events);
}

参数data即是上面addFd()函数的最后一个参数this指向的SurfaceFlinger的消息队列MessageQueue对象,这里进一步调用MessageQueue的eventReceiver()函数

int MessageQueue::eventReceiver(int fd, int events) {
    ssize_t n;
    DisplayEventReceiver::Event buffer[8];
    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
        for (int i=0 ; i<n ; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
				//如果事件类型为DISPLAY_EVENT_VSYNC时,通过指定消息队列对象的mHandler发送刷新消息
                mHandler->signalRefresh();
                break;
            }
        }
    }
    return 1;
}

函数通过调用DisplayEventReceiver::getEvents()函数从Socket接收端读取VSync事件信息,Android VSync事件分发过程源码分析中介绍了,EventThread线程可以通过Socket发送端写入多个Event事件信息,在Socket接收端同样可以连续读取多个事件信息,当getEvents()函数从Socket接收端读取到多个事件信息时,接着就遍历这些事件,并且只对事件类型为DisplayEventReceiver::DISPLAY_EVENT_VSYNC的事件即VSync事件做处理,事件处理过程就是通过Handler向SurfaceFlinger的消息队列发送一个消息:

void MessageQueue::Handler::signalRefresh() {
    if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
        mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
    }
}

这里只是简单地向SurfaceFlinger的消息队列发送一个MessageQueue::REFRESH消息,关于消息的发送过程,请参考Android应用程序消息循环源码分析。SurfaceFlinger消息循环线程对该消息的处理过程如下:

void MessageQueue::Handler::handleMessage(const Message& message) {
    switch (message.what) {
        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
        case REFRESH:
            android_atomic_and(~eventMaskRefresh, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
    }
}

从上面可以看出,函数调用SurfaceFlinger的onMessageReceived函数来处理MessageQueue::REFRESH消息

void SurfaceFlinger::onMessageReceived(int32_t what)
{
    ATRACE_CALL();
    switch (what) {
        case MessageQueue::REFRESH: {
            const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
            uint32_t transactionFlags = peekTransactionFlags(mask);
            if (CC_UNLIKELY(transactionFlags)) {
                handleTransaction(transactionFlags);
            }
            handlePageFlip();
            handleRefresh();
            const DisplayHardware& hw(graphicPlane(0).displayHardware());
            if (CC_UNLIKELY(mHwWorkListDirty)) {
                handleWorkList();
            }
            if (CC_LIKELY(hw.canDraw())) {
                handleRepaint();
                hw.compositionComplete();
                postFramebuffer();
           #if defined(LAYER_DUMP_BMP)
                frame_count++;
           #endif
            } else {
                hw.compositionComplete();
            }
        } break;
    }
}

1. handleTransaction

函数handleTransaction处理系统显示屏以及应用程序窗口的属性变化。
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
    ATRACE_CALL();
    // here we keep a copy of the drawing state (that is the state that's
    // going to be overwritten by handleTransactionLocked()) outside of
    // mStateLock so that the side-effects of the State assignment
    // don't happen with mStateLock held (which can cause deadlocks).
    State drawingState(mDrawingState);

    Mutex::Autolock _l(mStateLock);
    const nsecs_t now = systemTime();
    mDebugInTransaction = now;
	//系统显示屏的属性发生了变化,eTransactionNeeded位就会等于1
	//应用程序窗口的属性发生了变化,eTraversalNeeded位就会等于1
    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
	//检查系统显示屏或者应用程序窗口的属性是否发生了变化
    transactionFlags = getTransactionFlags(mask);
    handleTransactionLocked(transactionFlags);

    mLastTransactionTime = systemTime() - now;
    mDebugInTransaction = 0;
    invalidateHwcGeometry();
    // here the transaction has been committed
}
函数handleTransaction是通过调用另外一个成员函数handleTransactionLocked来处理系统显示屏以及应用程序窗口的属性变化。
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
	//mCurrentState指向当前状态State对象,State对象的成员变量layersSortedByZ保存了SufaceFlinger服///务当前所需要渲染的应用程序窗口
    const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
    const size_t count = currentLayers.size();
	//应用程序窗口的属性发生了变化
    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;
        }
    }
	//系统显示屏的属性发生了变化
    if (transactionFlags & eTransactionNeeded) {
		//mDrawingState用来描述SufaceFlinger服务的上一次渲染状态
		//mCurrentState用来描述SufaceFlinger服务当前渲染状态
		//判断系统显示屏的旋转方向是否发生变化
        if (mCurrentState.orientation != mDrawingState.orientation) {
			//重新设置系统显示屏的旋转方向
            const int dpy = 0;
            const int orientation = mCurrentState.orientation;
            // Currently unused: const uint32_t flags = mCurrentState.orientationFlags;
            GraphicPlane& plane(graphicPlane(dpy));
            plane.setOrientation(orientation);
			//同步更新的是mServerCblk中的信息,它是提供给各应用程序查询当前显示属性的,
			//包括宽、高、格式、旋转角度、fps、密度等一系列数据。
            // 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 (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
            //需要重新计算各个应用程序窗口的可见区域
            mVisibleRegionsDirty = true;
        }
        //判断是否移除了某些应用程序窗口
        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]);
				//在mCurrentState找不到了,就认为被移除了
                if (currentLayers.indexOf( layer ) < 0) {
					//需要将它所占用的区域增加到mDirtyRegionRemovedLayer所描述的一个区域去
                    mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
                }
            }
        }
    }
	//系统显示屏以及各个应用程序窗口的属性变化已经处理完毕,把mCurrentState赋给mmDrawingState
    commitTransaction();
}
应用程序窗口属性变化处理过程
frameworks\native\services\surfaceflinger\Layer.cpp
uint32_t Layer::doTransaction(uint32_t flags)
{
    ATRACE_CALL();
	//每一个应用程序窗口在内部也分别使用两个类型为State的成员变量来描述前后状态
	//mDrawingState描述上一次的渲染状态
    const Layer::State& front(drawingState());
	//mCurrentState描述当前渲染状态
    const Layer::State& temp(currentState());
	//判断窗口大小是否改变
    const bool sizeChanged = (temp.requested.w != front.requested.w) ||
                             (temp.requested.h != front.requested.h);
	//应用程序窗口的大小发生了变化
    if (sizeChanged) {
        // the size changed, we need to ask our client to request a new buffer
        // record the new size, form this point on, when the client request
        // a buffer, it'll get the new size.
        mSurfaceTexture->setDefaultBufferSize(temp.requested.w, temp.requested.h);
    }
	//判断是否为固定大小模式
    if (!isFixedSize()) {
        const bool resizePending = (temp.requested.w != temp.active.w) ||
                                   (temp.requested.h != temp.active.h);
        if (resizePending) {
            flags |= eDontUpdateGeometryState;
        }
    }
    return LayerBase::doTransaction(flags);
}

frameworks\native\services\surfaceflinger\LayerBase.cpp
uint32_t LayerBase::doTransaction(uint32_t flags)
{
    const Layer::State& front(drawingState());
    const Layer::State& temp(currentState());
    // always set active to requested, unless we're asked not to
    // this is used by Layer, which special cases resizes.
    if (flags & eDontUpdateGeometryState)  {
    } else {
        Layer::State& editTemp(currentState());
        editTemp.active = temp.requested;
    }
	//窗口激活状态发生变化,需要重新计算可见区域
    if (front.active != temp.active) {
        // invalidate and recompute the visible regions if needed
        flags |= Layer::eVisibleRegion;
    }
	//sequence用来描述一个应用程序窗口的其它属性是否发生过变化,当Layer的position、z­order、alpha
	//matrix、transparent region、flags、crop等一系列属性发生变化,sequence的值就会比原来增加1。
	//通过sequence收集属性的变化,而到了VSYNC信号产生时才做统一处理
    if (temp.sequence != front.sequence) {
        // invalidate and recompute the visible regions if needed
        flags |= eVisibleRegion;
        this->contentDirty = true;
        // we may use linear filtering, if the matrix scales us
        const uint8_t type = temp.transform.getType();
        mNeedsFiltering = (!temp.transform.preserveRects() ||(type >= Transform::SCALE));
    }
    //应用程序窗口属性变化已经处理完毕,交换前后状态
    commitTransaction();
    return flags;
}
首先获得SufaceFlinger服务当前所需要渲染的应用程序窗口,接着通过一个循环来依次检查每一个应用程序窗口的属性是否发生了变化。在SurfaceFlinger这边,应用程序窗口使用一个Layer对象来描述,在LayerBase类中,有一个类型为int32_t的成员变量mTransactionFlags,每当SurfaceFlinger服务修改某一个应用程序窗口的属性时,都会将与其对应的LayerBase的成员变量mTransactionFlags的相应的位设置为1,这样LayerBase类的成员函数getTransactionFlags就可以通过这个成员变量来判断一个应用程序窗口的属性是否发生变化了。如果某一个应用程序窗口的属性被修改,调用这个LayerBase对象的成员函数doTransaction来处理对应的应用程序窗口的属性变化。如果一个应用程序窗口发生的属性变化是可见区域发生了改变,那么函数doTransaction的返回值flags的Layer:eVisibleRegion位就会等于1。在这种情况下,将 SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true,表示后面要重新计算各个应用程序窗口的可见区域。当参数transactionFlags的eTransactionNeeded位等于1,表示系统显示屏的属性发生了变化。此时首先判断系统显示屏的旋转方向是否发生变化,判断方法就是比较mCurrentState对象的成员变量orientation与mDrawingState对象的成员变量orientation的值。如果不相同,就说明系统显示屏的旋转方向发生了变化。此时,就需要将系统显示屏的旋转方向设置为mCurrentState对象的成员变量orientation的值。 SurfaceFlinger服务在启动时,创建了类型为surface_flinger_cblk_t的对象mServerCblk,用来保存系统显示屏的信息,并共享显示屏信息给其他进程访问。因此,当系统显示屏的旋转方向发生了变化时,需要修改mServerCblk中保存的显示屏信息。系统显示屏的方向发生变化意味着需要重新计算各个应用程序窗口的可见区域以及重新绘制整个显示屏,因此,将变量mVisibleRegionsDirty的值设置为true,同时将系统UI的脏区域mDirtyRegion的大小设置为整个显示屏的大小。当mCurrentState的成员变量layersSortedByZ所指向的向量大小大于mDrawingState的成员变量layersSortedByZ所指向的向量大小时,就说明系统新增了应用程序窗口。mLayersRemoved用来描述是否有应用程序窗口被移除了。如果有应用程序窗口被移除的话,就需要查找出被移除的应用程序窗口。如果一个应用程序窗口存在于mDrawingState的成员变量layersSortedByZ所指向的向量中,但是不存在于mCurrentState的成员变量layersSortedByZ所指向的向量中,就说明这个应用程序窗口被移除了,因此需要将被移除的应用程序窗口所占用区域增加到mDirtyRegionRemovedLayer描述的区域中。无论是新增应用程序窗口还是移除应用程序窗口,都需要重新计算各个应用程序窗口的可见区域,因此将变量mVisibleRegionsDirty的值设置为true。
<think>嗯,用户想深入了解SurfaceFlinger的图层合成机制和VSync信号处理的细节。这个问题涉及Android图形系统的核心机制,需要从硬件交互、软件调度和性能优化多角度解释。 用户提供的引用材料很有价值:引用1提到VSync信号触发合成流程的关键作用,引用2强调VSync专用socket的底层支持,引用3则补充了DisplayDevice与合成的关系。这些正好构成回答的主线——应该按"信号触发→图层准备→合成执行→显示输出"的逻辑链展开。 考虑到用户的技术背景,需要特别注意: 1)解释专业术语时保持精准度,比如"INVALIDATE消息"要明确是SurfaceFlinger内部通信机制 2)突出硬件合成(HWC)与软件合成的切换逻辑,这是性能优化的关键 3)用分层结构说明合成流程,避免信息过载 特别要强调VSync的双重作用:既是合成开始的触发器,又是帧率稳定的控制器。这点在引用1和2中都有隐含线索,需要显性化表达。 对于技术难点部分,比如"异步合成模式",准备用硬件能力差异的例子说明。用户可能关心实际开发中的卡顿问题,所以最后补充的优化建议要包含具体场景(如视频播放时旋转屏幕)。 生成的问题设计成阶梯式:从机制原理(问题1)→异常处理(问题2)→扩展应用(问题3)。这样用户可以根据兴趣选择深入方向。</think>以下是对 Android SurfaceFlinger 图层合成流程与 VSync 信号处理机制的详细解析,结合核心引用内容整理: --- ### **一、图层合成核心流程** 1. **图层管理与更新** - SurfaceFlinger 接收来自不同应用的图层数据(称为 **Surface**),每个图层对应一个应用的 UI 视图。 - 维护按 **Z-Order(深度顺序)** 排序的图层列表,决定叠加优先级。 - 当应用提交新帧(如视图变化、动画更新)时,SurfaceFlinger 收到 `INVALIDATE` 消息,标记图层需更新[^1]。 2. **VSync 信号触发合成** - SurfaceFlinger 监听显示设备的 **垂直同步信号VSync)**,该信号以固定频率(如 60Hz)周期性发出。 - 当 VSync 信号到达时,SurfaceFlinger 启动合成流程(通过 `REFRESH` 消息触发)[^1][^2]。 3. **图像合成执行** - **硬件合成(HWC)优先**:若硬件支持(如 GPU 或专用显示处理器),SurfaceFlinger 优先使用硬件合成器,直接操作显示内存,减少 CPU/GPU 负载。 - **软件合成回退**:当图层数量超限或变换复杂(如旋转、透明度动画)时,退回到 GPU 软件合成[^1]。 - **混合策略**:使用 Alpha 混合、颜色空间转换等技术组合图层,确保透明效果正确渲染[^1]。 4. **输出到显示设备** - 合成后的帧通过 **DisplayDevice** 提交给显示设备(如屏幕),最终呈现给用户[^3]。 --- ### **二、VSync 信号的关键作用** 1. **同步机制** - VSync 将合成、渲染与显示刷新率对齐,避免 **画面撕裂**(部分旧帧/新帧同时显示)。 - 应用在 VSync 信号到来时开始绘制,SurfaceFlinger 在下一个 VSync 周期进行合成[^1][^2]。 2. **双缓冲/三缓冲机制** - **双缓冲**:前台缓冲区显示时,后台缓冲区准备下一帧。 - **三缓冲**:增加一个中间缓冲区,避免因帧未就绪导致掉帧(如应用绘制超时)。 3. **VSync 分发** - SurfaceFlinger 通过 **vsync-socket** 向应用分发 VSync 信号,协调应用绘制时机[^2]。 --- ### **三、性能优化机制** 1. **脏区域更新(Partial Updates)** - 仅重绘发生变化的屏幕区域,减少合成计算量[^1]。 2. **图层缓存** - 缓存静态图层(如壁纸),跳过重复合成[^1]。 3. **异步合成模式** - 允许合成与显示刷新并行执行,提升高负载场景流畅度。 --- ### **四、流程图解** ```mermaid graph LR A[应用提交新帧] --> B(INVALIDATE 消息) C[VSync 信号到达] --> D(REFRESH 消息) D --> E{硬件合成是否支持?} E -- 是 --> F[硬件合成器 HWC] E -- 否 --> G[GPU 软件合成] F/G --> H[混合图层并输出] H --> I[DisplayDevice 显示] ``` --- ### **典型问题分析** **Q: 若应用未在 VSync 周期内完成绘制会怎样?** A: 导致掉帧(Dropped Frame)。SurfaceFlinger 会继续使用上一帧合成,直到新帧就绪,用户可能感知卡顿。 **Q: 为什么旋转屏幕时卡顿更明显?** A: 旋转触发所有图层重建和重排,硬件合成可能退回到 GPU 软件路径,增加计算负载[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值