Android P 显示流程分析(三)---EventThread MessageQueue 交互分析

2024-04-20 06:32

本文主要是介绍Android P 显示流程分析(三)---EventThread MessageQueue 交互分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上篇分析SurfaceFlinger的init()里创建了几个线程,主要用于界面刷新。里面涉及了一个EventThread和MessageQueue。我们来看看像界面刷新这种高频的事件通知及处理,Google是如何设计的。

EventThread的初始化

EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName){//创建一个线程,实际做事的也是这个线程处理的mThread = std::thread(&EventThread::threadMain, this);...                    
}                         

创建connection

其它一些线程需要将事件推给EventThread去处理,需要中间有一个连接者与EventThread交互,EventThread里面就创建出来了一个内部类Connection,负责连接交互的工作

sp<BnDisplayEventConnection> EventThread::createEventConnection() const {return new Connection(const_cast<EventThread*>(this));
}
class Connection : public BnDisplayEventConnection {
public:virtual status_t postEvent(const DisplayEventReceiver::Event& event);
private:void requestNextVsync() override; 
}

上篇SurfaceFlinger.init()中实例化一个EventThread之后,就调用了mEventQueue->setEventThread(mSFEventThread.get()),

void MessageQueue::setEventThread(android::EventThread* eventThread) {
...mEventThread = eventThread;mEvents = eventThread->createEventConnection();
...
}
sp<BnDisplayEventConnection> EventThread::createEventConnection() const {return new Connection(const_cast<EventThread*>(this));
}    

MessageQueue中的mEvents就是一个connection对象。就是它就将MessageQueue与EventThread连接起来了。
我们再来看看EventHandler 的那个线程启动之后,做了哪些事情:

void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {std::unique_lock<std::mutex> lock(mMutex);while (mKeepRunning) {DisplayEventReceiver::Event event;Vector<sp<EventThread::Connection> > signalConnections;signalConnections = waitForEventLocked(&lock, &event);// dispatch events to listeners...const size_t count = signalConnections.size();for (size_t i = 0; i < count; i++) { const sp<Connection>& conn(signalConnections[i]);// now see if we still need to report this eventstatus_t err = conn->postEvent(event);if (err == -EAGAIN || err == -EWOULDBLOCK) {ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,conn.get());} else if (err < 0) {removeDisplayEventConnectionLocked(signalConnections[i]);}}}
}

总体来说是获取事件,将获取到的事件放到BitTube中去,具体的获取事件的waitForEventLocked是如何做的呢?

Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {Vector<sp<EventThread::Connection> > signalConnections;while (signalConnections.isEmpty() && mKeepRunning) {for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {timestamp = mVSyncEvent[i].header.timestamp;if (timestamp) {// we have a vsync event to dispatchif (mInterceptVSyncsCallback) {mInterceptVSyncsCallback(timestamp);}*event = mVSyncEvent[i];mVSyncEvent[i].header.timestamp = 0;vsyncCount = mVSyncEvent[i].vsync.count;break;}} if (!timestamp) {// no vsync event, see if there are some other eventeventPending = !mPendingEvents.isEmpty();if (eventPending) {// we have some other event to dispatch*event = mPendingEvents[0];mPendingEvents.removeAt(0);}}        // find out connections waiting for eventssize_t count = mDisplayEventConnections.size();for (size_t i = 0; i < count;) {sp<Connection> connection(mDisplayEventConnections[i].promote()); if (connection != nullptr) {bool added = false;if (connection->count >= 0) {// we need vsync events because at least// one connection is waiting for itwaitForVSync = true;if (timestamp) {// we consume the event only if it's time// (ie: we received a vsync event)if (connection->count == 0) {// fired this time aroundconnection->count = -1;signalConnections.add(connection);added = true;} else if (connection->count == 1 ||(vsyncCount % connection->count) == 0) {// continuous event, and time to report itsignalConnections.add(connection);added = true;}}}if (eventPending && !timestamp && !added) {// we don't have a vsync event to process// (timestamp==0), but we have some pending// messages.signalConnections.add(connection);}++i; } else {// we couldn't promote this reference, the connection has// died, so clean-up!mDisplayEventConnections.removeAt(i);--count;}}   ...// note: !timestamp implies signalConnections.isEmpty(), because we// don't populate signalConnections if there's no vsync pendingif (!timestamp && !eventPending) {// wait for something to happenif (waitForVSync) {// This is where we spend most of our time, waiting// for vsync events and new client registrations.//// If the screen is off, we can't use h/w vsync, so we// use a 16ms timeout instead.  It doesn't need to be// precise, we just need to keep feeding our clients.//// We don't want to stall if there's a driver bug, so we// use a (long) timeout when waiting for h/w vsync, and// generate fake events when necessary.bool softwareSync = mUseSoftwareVSync;auto timeout = softwareSync ? 16ms : 1000ms;if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {if (!softwareSync) {ALOGW("Timed out waiting for hw vsync; faking it");}// FIXME: how do we decide which display id the fake// vsync came from ?mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);mVSyncEvent[0].vsync.count++;}} else {// Nobody is interested in vsync, so we just want to sleep.// h/w vsync should be disabled, so this will wait until we// get a new connection, or an existing connection becomes// interested in receiving vsync again.mCondition.wait(*lock);}}}// here we're guaranteed to have a timestamp and some connections to signal// (The connections might have dropped out of mDisplayEventConnections// while we were asleep, but we'll still have strong references to them.)return signalConnections;
}                     

waitForEventLocked 就如果vsyncEvent和pendingEvent里已经存在事件,就将其取出指定给event,然后遍历出所有的mDisplayEventConnections, 找且需要的connection, 将他们一一添加到signalConnections中, 如果没有找到需要connection, 就设置mCondition.wait(*lock), 条件加锁等待,直到此条件被唤醒。
我们上面EventThread的threadMain分析到将获取的signalConnections中的connection遍历出来,然后将通过调用 connection的postEvent 将event事件加入到BitTube中。

MessageQueue的作用

surfaceFlinger很多事件都是通过MessageQueue来处理的,SurfaceFlinger里的mEventQueue就是MessageQueue的对象指针。

void SurfaceFlinger::waitForEvent() {mEventQueue->waitMessage();
}
void SurfaceFlinger::signalTransaction() {mEventQueue->invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {mEventQueue->invalidate();
}
void SurfaceFlinger::signalRefresh() {mRefreshPending = true;mEventQueue->refresh();
}
void SurfaceFlinger::run() {do {waitForEvent();} while (true);
}

以上这些都是通过MessageQueue去调用实现的。那我们再具体看看MessageQueue里是如何实现的。

void MessageQueue::invalidate() {mEvents->requestNextVsync();
}
void EventThread::Connection::requestNextVsync() {mEventThread->requestNextVsync(this);
}
void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {std::lock_guard<std::mutex> lock(mMutex);if (connection->count < 0) {connection->count = 0;mCondition.notify_all();}
}

invalidate 主要是为了唤醒waitForEventLocked , 让EventThread继续执行。

void MessageQueue::refresh() {mHandler->dispatchRefresh();
}
void MessageQueue::Handler::dispatchRefresh() {if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));}
}
void MessageQueue::Handler::handleMessage(const Message& message) {switch (message.what) {...case REFRESH:android_atomic_and(~eventMaskRefresh, &mEventMask);mQueue.mFlinger->onMessageReceived(message.what);break;}
}
void SurfaceFlinger::onMessageReceived(int32_t what) {... case MessageQueue::REFRESH: {handleMessageRefresh();break;}
}
void SurfaceFlinger::handleMessageRefresh() {ATRACE_CALL();mRefreshPending = false;nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);preComposition(refreshStartTime);rebuildLayerStacks();setUpHWComposer();doDebugFlashRegions();doTracing("handleRefresh");logLayerStats();doComposition();postComposition(refreshStartTime);mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);mHadClientComposition = false;for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {const sp<DisplayDevice>& displayDevice = mDisplays[displayId];mHadClientComposition = mHadClientComposition ||getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());}mVsyncModulator.onRefreshed(mHadClientComposition);mLayersWithQueuedFrames.clear();
}    	   

最后调用到了SurfaceFlinger的handleMessageRefresh(), 里面涉及到图层的合成了。
到这里EventThread和MessageQueue就分析完了。

这篇关于Android P 显示流程分析(三)---EventThread MessageQueue 交互分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/919518

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57