问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

什么原因会引发displayeventreceiver一直在运行

发布网友 发布时间:2022-04-30 17:05

我来回答

1个回答

热心网友 时间:2022-06-28 02:53

们先看收到VSync事件是如何处理的,再看底层是怎样向上层通知VSync事件。

1.SurfaceFlinger如何处理Vsync事件
在SurfaceFlinger定义了一个消息队列的成员变量:
mutableMessageQueue mEventQueue;
MessageQueue是一个消息处理类,专门处理如下三种消息:
INVALIDATE, REFRESH, TRANSACTION。
这三个消息都与UI更新相关。SurfaceFlinger在自己的主线程中等待上述消息的到来,以便进行相应的处理,代码如下(后面我们会看到,VSync事件会触发上述消息):
[cpp] view plain copy
bool SurfaceFlinger::threadLoop() {
waitForEvent();
return true;
}

其中waitForEvent又调用的MessageQueue的waitMessage函数:
[cpp] view plain copy
void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}

所以SurfaceFlinger依赖MessageQueue截获上述消息,那又是通过怎样的流程向MessageQueue发送上述消息呢?换句话说,MessageQueue又是如何接收到上述三个消息的呢?
而这一切又是与EventThread类相关。通过查看MessageQueue的定义,可以看到,它定义了一个EventThread的成员变量,并通过setEventThread初始化,代码如下:

[cpp] view plain copy
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);
}

通过此接口,不仅获取了一个EventThread实例的引用,同时,通过EventThread创建一个IDisplayEventConnection对象,它代表了接收显示事件(主要是VSync事件以及HotPlug事件)的一个远程连接接收端,并通过Looper对象监听发生在此对象上的显示事件。在EventThread的线程循环中,等待VSync事件的发生,代码如下:
[cpp] view plain copy
bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp<EventThread::Connection> > signalConnections;
signalConnections = waitForEvent(&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 event
status_t err = conn->postEvent(event);

}
return true;
}

在waitForEvent中,检测VSync事件,Connection::postEvent(DisplayEventReceiver::sendEvents)则将检测到的VSync事件发送给监听者。前面提到,通过Looper对象监听发生的VSync事件,它会调用回调函数MessageQueue::cb_eventReceiver,它实际会调用MessageQueue::eventReceiver,代码如下:

[cpp] view plain copy
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) {
#if INVALIDATE_ON_VSYNC
mHandler->dispatchInvalidate();
#else
mHandler->dispatchRefresh();
#endif
break;
}
}
}
return 1;
}

对于VSync事件的处理,会调用MessageQueue::Handler::dispatchInvalidate()或MessageQueue::Handler::dispatchRefresh(),代码如下:

[cpp] view plain copy
void MessageQueue::Handler::dispatchRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}

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

最终在如下消息处理函数中,对VSync事件进行处理:

[cpp] view plain copy
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;
case TRANSACTION:
android_atomic_and(~eventMaskTransaction, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
}
}

如上代码所示,实际上会执行SurfaceFlinger类里定义的回调函数,在那里面对开头提到的三种消息进行真正的处理,即对VSync事件的响应最终转变成对上述三种消息进行处理。

2.VSync事件产生流程分析
上述分析了,从等待接收VSync事件到最后处理VSync事件的过程。下面我们要看下VSync事件是如何产生的,即是如何通知SurfaceFlinger::waitEvent返回的。众所周知,VSync事件一般由硬件周期性产生,如果没有相应的硬件产生VSync事件,则通过软件模拟。下面主要看下从硬件产生VSync事件到触发MessageQueue处理VSync事件的过程。
首先,看下HWComposer的定义:

[cpp] view plain copy
class HWComposer
{
public:
class EventHandler {
friend class HWComposer;
virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int disp, bool connected) = 0;
protected:
virtual ~EventHandler() {}
};

enum {
MAX_DISPLAYS = HWC_NUM_DISPLAY_TYPES + 1
};

HWComposer(
const sp<SurfaceFlinger>& flinger,
EventHandler& handler);

}

可以看到,HWComposer::EventHandler定义了通知VSync事件的回调接口。而SurfaceFlinger是实现了上述接口。所以问题变成,当底层硬件发生VSync事件时,会回调一个EventHandler对象的onVSyncReceived函数。
实际上,在HWComposer的构造函数中,注册了底层hwcomposer硬件发送VSync事件的回调函数,首先,在SurfaceFlinger的readyToRun函数中,新建了一个HWComposer对象:

[cpp] view plain copy
// Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
mHwc = new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this));

接着在HWComposer的构造函数中,注册了hwcomposer回报VSync事件时调用的回调函数:

[cpp] view plain copy
HWComposer::HWComposer(
const sp<SurfaceFlinger>& flinger,
EventHandler& handler)
: mFlinger(flinger),
mFbDev(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mVSyncCount(0), mDebugForceFakeVSync(false)
{


bool needVSyncThread = true;

// Note: some devices may insist that the FB HAL be opened before HWC.
int fberr = loadFbHalMole();
loadHwcMole();

if (mHwc) {
ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
(hwcApiVersion(mHwc) >> 24) & 0xff,
(hwcApiVersion(mHwc) >> 16) & 0xff);
if (mHwc->registerProcs) {
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext->procs.hotplug = &hook_hotplug;
else
mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
}

// don't need a vsync thread if we have a hardware composer
needVSyncThread = false;
// always turn vsync off when we start
eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);

// the number of displays we actually have depends on the
// hw composer version
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
// 1.?? adds support for virtual displays
mNumDisplays = MAX_DISPLAYS;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// 1.1 adds support for multiple displays
mNumDisplays = NUM_PHYSICAL_DISPLAYS;
} else {
mNumDisplays = 1;
}
}



if (needVSyncThread) {
// we don't have VSYNC support, we need to fake it
mVSyncThread = new VSyncThread(*this);
}
}
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
文件密使无法恢复解密,请高手帮忙 加密文件打不开了,请教高手..急需用那些文件 跪求电脑高手帮忙解决文件加密问题,我把所有积分给他。 我的优盘是联想的,用自带的加密软件加密后,忘了密码,请教高手,怎么解密... pe pb是什么 抱着柴火去火跟前猜谜语 关于租用办公室房产税如何计算与缴纳的问题 一个人抱着柴火前方是火是打一成语的谜语 ...前男友跟别的女人抱一起的时候,放的背景纯音乐出自哪里 ...从前男友家出来后被阿苏接上车,在车上的背景音乐是什么,在哪里有下... 英雄无敌7怎么修改英雄属性 建筑及英雄属性修改方法 医保报销是打到工资卡还是医保卡 龙族幻想自研料理蛋卷怎么弄 英雄无敌7选项里的“除错”页面在哪弊按钮在哪 医院报销钱打到了医保卡怎么拿出来 英雄无敌7怎么挖宝 魔法门之英雄无敌7挖掘宝物攻略 龙族幻想学习完味增汤后怎么再次打开平板 英雄无敌7烈火试练怎么开启控制台,谢谢帮忙 龙族幻想自研料理汉堡怎么弄 龙族幻想西湖牛肉羹制作步骤和材料有什么? 为什么英雄无敌7文件改了还是出不来内置修改器 孙策有4个子女,4个弟弟,为何偏偏选择孙权作为自己的继承人? 美国公民护照在中国丢失最快多久能办出来。 龙族幻想新增自研食谱佛跳墙和另一个烤制食物怎么弄? 《英雄无敌7》自带修改器使用方法 自带修改器怎么用 简述孙策的英雄故事 龙族幻想行政主厨那两个自研是什么? 美国公民护照在中国损坏补办需要什么相关材料 魔法门之英雄无敌7内置作弊器怎么开启方法解析 孙策为什么会选择孙权作为自己的继承人? 《英雄无敌7》最终战役解锁方法 最终战役怎么解锁 黑桃无敌英雄技能点如何重置 松下xqb75-q702u洗衣机怎么用 第一次洗衣服 不知道洗衣服的步骤 英雄无敌6控制台打开不了 c语言:学生成绩统计系统,我这个程序哪有错啊??? 报销的钱打入医保卡 一个vb题??? 《魔法门之英雄无敌7》内置作弊器MMH7修改器开启方法 英雄无敌7怎么挖宝 魔法门之英雄无敌7挖掘 英雄无敌7烈火试炼英雄怎么修改 少年电影讲的是什么 少年电影剧情解析 英雄无敌7 1.2升级档出错怎么办 出错的解决办法 再见吧少年剧情解析 电影少年侦探剧情解析 如何评价张子枫主演的《再见,少年》中的剧情? 网络少年剧情简介 电影《再见,少年》上映,这部电影是讲述什么故事的? 网络少年的剧情简介 《漂流少年》解析是什么? 《神雕侠侣》小龙女和公孙止结婚在哪一集