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

Posted Give.Me.Five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 event
            status_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 dispatch
                if (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 event
            eventPending = !mPendingEvents.isEmpty();
            if (eventPending) 
                // we have some other event to dispatch
                *event = mPendingEvents[0];
                mPendingEvents.removeAt(0);
            
                
        // find out connections waiting for events
        size_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 it
                    waitForVSync = 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 around
                            connection->count = -1;
                            signalConnections.add(connection);
                            added = true;
                         else if (connection->count == 1 ||
                                   (vsyncCount % connection->count) == 0) 
                            // continuous event, and time to report it
                            signalConnections.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 pending
        if (!timestamp && !eventPending) 
            // wait for something to happen
            if (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 交互分析的主要内容,如果未能解决你的问题,请参考以下文章

Android P 显示流程---Display设备初始化过程分析

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

Android P 显示流程分析---获取显示屏配置

Android P 显示流程分析--- buffer的生产消费者模式

Android P 显示流程分析--- buffer的生产消费者模式

Android画面显示流程分析