中易网

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

答案:2  悬赏:50  
解决时间 2021-04-27 23:11
什么原因会引发displayeventreceiver一直在运行
最佳答案
们先看收到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)
{
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 > signalConnections;
signalConnections = waitForEvent(&event);

// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; i const sp& 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 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& 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(this));

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

[cpp] view plain copy
HWComposer::HWComposer(
const sp& 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 = loadFbHalModule();
loadHwcModule();

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);
}
}
全部回答
支持一下感觉挺不错的
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
跳电后,电脑开不了机了,而且键盘没的反应,
海尔冰箱bcd-195kaSA使用
魔兽世界FS的PVE和PVE天赋
开个什么样的店比较受大家欢迎
脑瓜急转弯
卡卡和C罗名字的英文读音
中国农业发展银行扶沟支行我想知道这个在什么
clannad1.2季 720p
惠迪生净水器的立式好 还是台式的好些呢?
电脑链接问题求助网友!!!
谁帮我翻译一下!
DNF漫游用什么武器
网恋可信程度是多少呢
深圳天音通信发展有限公司和中粮福临门待遇那
HTC hero 通话时会自动屏保吗
推荐资讯
有誰用过玫瑰精油?说说你的心得吧…
**部痛为什么?
谁有MAYA中文界面的图片啊?
夏天听什么歌
喜糖铺子安福店地址在什么地方,想过去办事
空间访客出现匿名人,怎样使用照妖镜,?
第一次抓癞蛤蟆又放生了会被拘留吗
240分钟÷前市9:30到看盘时为止的分钟数)×
ImageReady 怎样切片?
东申玻璃地址在什么地方,想过去办事
谁知道哪能借钱吗?私人的
为什么不能充元宝?难道不准rmb玩家玩?不是
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?