GUI系统之SurfaceFlinger(13)VSync信号的处理

本文深入剖析了Android系统中SurfaceFlinger模块如何处理VSync信号。从建立连接到信号处理,再到最终屏幕显示,全面解析了涉及的关键函数及其工作流程。

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

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

GUI系统之SurfaceFlinger章节目录:
blog.youkuaiyun.com/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的所有功能,接下来的几个小节我们将详细分析它们,各个击破

<think>我们正在讨论如何向SurfaceFlinger的onTransaction发送消息。首先,需要理解SurfaceFlingerAndroid系统中负责合成和输出显示内容的核心服务。`onTransaction`是SurfaceFlinger处理事务(transaction)的函数,这些事务通常包括层(layer)状态的变化(如位置、大小、透明度等)。在Android系统中,客户端(如应用)通过Binder IPC与SurfaceFlinger通信,而事务通常是通过`SurfaceComposerClient`和`SurfaceControl`来提交的。 但是,直接向`onTransaction`发送消息并不是常规做法。通常,我们通过Android的框架API(如`SurfaceControl.Transaction`)来创建和提交事务。这些事务会被SurfaceFlinger在下一个VSync周期处理,最终会调用到`onTransaction`函数。 如果你想在系统内部(例如在系统服务或测试代码中)直接触发`onTransaction`,你可能需要调用SurfaceFlinger的相关接口。但请注意,这通常需要系统权限,并且可能涉及到跨进程通信。 ### 步骤 1. **获取SurfaceFlinger服务**:通过`defaultServiceManager()`获取到SurfaceFlinger的Binder接口。 2. **构造事务**:创建一个`Transaction`对象,其中包含需要更新的层状态。 3. **提交事务**:将事务提交给SurfaceFlinger。 然而,直接调用`onTransaction`是不推荐的,因为它是一个内部函数。通常,我们使用`SurfaceComposerClient`的API来提交事务。 ### 示例代码(C++) 以下是一个简单的示例,展示如何使用`SurfaceComposerClient`提交一个事务: ```cpp #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> using namespace android; sp<SurfaceComposerClient> client = new SurfaceComposerClient(); // 假设你已经有一个有效的SurfaceControl指针(sp<SurfaceControl>) sp<SurfaceControl> surfaceControl = ...; // 通过client->createSurface获取 SurfaceComposerClient::Transaction t; t.setPosition(surfaceControl, 100, 200); t.apply(); ``` 上述代码中,`t.apply()`会将该事务提交到SurfaceFlinger,最终在SurfaceFlinger的主线程中处理,会调用到`onTransaction`。 ### 注意事项 - 权限:需要系统权限(如`android.permission.ACCESS_SURFACE_FLINGER`),通常只有系统应用或系统服务才能使用。 - 进程:你的代码必须运行在具有足够权限的进程(如system_server进程或具有root权限的进程)。 ### 替代方法:使用服务调用 如果你确实需要直接调用SurfaceFlinger的服务接口,你可以通过获取`ISurfaceComposer`接口来调用`setTransactionState`方法,这相当于提交事务。例如: ```cpp sp<ISurfaceComposer> composer = ComposerService::getComposerService(); Vector<ComposerState> stateVector; Vector<DisplayState> displayVector; uint32_t flags = 0; sp<IBinder> handle; composer->setTransactionState(stateVector, displayVector, flags, handle); ``` 但这种方法更底层,需要构建`ComposerState`和`DisplayState`,通常不推荐直接使用。 ### 总结 常规做法是使用`SurfaceComposerClient::Transaction`来提交事务,而不是直接调用`onTransaction`。如果你有特殊需求(如调试或内部测试),可能需要通过反射或直接调用内部接口,但这需要系统权限,并且可能在不同Android版本上不兼容。 §§相关问题§§ 1. 如何在Android中创建SurfaceControl对象? 2. SurfaceFlinger的事务处理流程是怎样的? 3. 如何调试SurfaceFlinger的事务提交? 4. 在非系统应用中如何提交事务到SurfaceFlinger?</think>在 Android 系统中,`SurfaceFlinger` 的 `onTransaction()` 是处理图形事务的核心方法,通常通过 Binder IPC 机制接收事务请求。以下是发送消息的几种方法: ### 1. **通过 SurfaceComposerClient (推荐)** 这是标准的应用层调用方式,使用 `SurfaceControl.Transaction` 提交事务: ```java // 创建事务 SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); transaction.setPosition(surfaceControl, x, y) // 示例:设置图层位置 .setAlpha(surfaceControl, alpha) // 设置透明度 .apply(); // 提交到 SurfaceFlinger // 最终会触发 SurfaceFlinger::onTransaction() ``` ### 2. **直接调用 SurfaceFlinger 服务 (系统权限)** 需要系统签名或 root 权限,通过 Binder 直接调用: ```cpp // C++ 示例 (运行在系统进程) sp<ISurfaceComposer> composer = ComposerService::getComposerService(); Vector<ComposerState> states; Vector<DisplayState> displays; uint32_t flags = 0; composer->setTransactionState(states, displays, flags); // 触发 onTransaction() ``` ### 3. **使用 SurfaceFlinger 的 TransactionQueue** 内部线程通过 `scheduleCommit()` 触发: ```cpp // 在 SurfaceFlinger 线程中 mScheduler->scheduleCommit(); // 触发事务处理循环 mEventQueue->invalidate(); // 唤醒主线程 // 最终调用 handleTransaction() -> onTransaction() ``` ### 关键注意事项 1. **权限要求**: - 应用层:需要 `android.permission.ACCESS_SURFACE_FLINGER` - 系统层:需系统签名或 `platform` 签名 2. **同步机制**: - 事务通过 `setTransactionState()` 提交到 `TransactionQueue` - VSync 信号触发 `onTransaction()` 处理队列 3. **调试方法**: ```shell adb shell dumpsys SurfaceFlinger --transaction ``` ### 执行流程 ``` 应用层 Transaction.apply() ↓ Binder IPC: setTransactionState()SurfaceFlinger::setTransactionState() ↓ TransactionQueue.push()VSync 信号到来 ↓ SurfaceFlinger::onTransaction() // 处理事务 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值