VSync事件处理流程分析(Android4.3)

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

1.SurfaceFlinger如何处理Vsync事件

在SurfaceFlinger定义了一个消息队列的成员变量:

mutableMessageQueue mEventQueue;

MessageQueue是一个消息处理类,专门处理如下三种消息:

INVALIDATE, REFRESH, TRANSACTION。

这三个消息都与UI更新相关。SurfaceFlinger在自己的主线程中等待上述消息的到来,以便进行相应的处理,代码如下(后面我们会看到,VSync事件会触发上述消息):

bool SurfaceFlinger::threadLoop() {
    waitForEvent();
    return true;
}

其中waitForEvent又调用的MessageQueue的waitMessage函数:

void SurfaceFlinger::waitForEvent() {
    mEventQueue.waitMessage();
}

所以SurfaceFlinger依赖MessageQueue截获上述消息,那又是通过怎样的流程向MessageQueue发送上述消息呢?换句话说,MessageQueue又是如何接收到上述三个消息的呢?

而这一切又是与EventThread类相关。通过查看MessageQueue的定义,可以看到,它定义了一个EventThread的成员变量,并通过setEventThread初始化,代码如下:

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事件的发生,代码如下:

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& 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,代码如下:

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 ; idispatchInvalidate();
#else
                mHandler->dispatchRefresh();
#endif
                break;
            }
        }
    }
    return 1;
}

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

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事件进行处理:

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的定义:

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对象:

 // 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事件时调用的回调函数:

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);
    } 
}

 可以看到VSync事件要么从硬件产生,当底层硬件不存在时,则通过软件模拟出来。当从硬件中产生VSync事件时,会回调HWComposer::hook_vsync,其代码如下:

void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
        int64_t timestamp) {
    cb_context* ctx = reinterpret_cast(
            const_cast(procs));
    ctx->hwc->vsync(disp, timestamp);
}

这实际上会调用HWComposer的另外一个函数vsync,其代码如下:

void HWComposer::vsync(int disp, int64_t timestamp) {
    ATRACE_INT("VSYNC", ++mVSyncCount&1);
    mEventHandler.onVSyncReceived(disp, timestamp);
    Mutex::Autolock _l(mLock);
    mLastHwVSync = timestamp;
}

可以看到,它实际调用mEventHandler的onVSyncReceived函数,从上述SurfaceFlinger中对HWCompser对象的初始化传递的参数可以看出,mEventHandler指向的正是SurfaceFlinger自己,所以,它实际调用的是SurfaceFlinger的onVSyncReceived接口:

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    if (mEventThread == NULL) {
        // This is a temporary workaround for b/7145521.  A non-null pointer
        // does not mean EventThread has finished initializing, so this
        // is not a correct fix.
        ALOGW("WARNING: EventThread not started, ignoring vsync");
        return;
    }
    if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
        // we should only receive DisplayDevice::DisplayType from the vsync callback
        mEventThread->onVSyncReceived(type, timestamp);
    }
}

如代码所示,它进一步调用mEventThread的onVSyncReceived函数,它是EventThread的一个对象,在SurfaceFlinger的readyToRun函数中初始化:并为MessengeQueue设置了EventThread。

status_t SurfaceFlinger::readyToRun()
{
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    …

    // start the EventThread
    mEventThread = new EventThread(this);
    mEventQueue.setEventThread(mEventThread);

    // We're now ready to accept clients...
    mReadyToRunBarrier.open();

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    …
    return NO_ERROR;
}

下面接着看EventThread的onVsyncReceived函数:

void EventThread::onVSyncReceived(int type, nsecs_t timestamp) {
    ALOGE_IF(type >= HWC_NUM_DISPLAY_TYPES,
            "received vsync event for an invalid display (id=%d)", type);

    Mutex::Autolock _l(mLock);
    if (type < HWC_NUM_DISPLAY_TYPES) {
        mVSyncEvent[type].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
        mVSyncEvent[type].header.id = type;
        mVSyncEvent[type].header.timestamp = timestamp;
        mVSyncEvent[type].vsync.count++;
        mCondition.broadcast();
    }
}

上述代码会触发EventThread的waitForEvent返回,从而开始对捕获的VSync事件进行处理的过程。


3. EventThread处理VSync的机制

         现在我们回到EventThread本身,来看下是怎样侦测并通知VSync事件。

         先从EventThread的threadLoop方法开始。

在线程循环中,它通过waitForEvent来等待一些事件到来,并进行处理。我们先看下,当有VSync或其他事件时,它会怎样处理:

bool EventThread::threadLoop() {
    DisplayEventReceiver::Event event;
    Vector< sp > signalConnections;
    signalConnections = waitForEvent(&event);
    …
    }

首先看下waitForEvent函数的返回值,它会返回两个信息,一个是当前发生了什么事件,另一个是当前有多少个事件连接指向SurfaceFlinger,即对上述事件感兴趣的监听者,让我们回顾下SurfaceFlinger在初始化时,执行了MessageQueue的setEventThread方法,它的代码如下:

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发送过来的信息。对于非SurfaceFlinger之外的监听者,一般是通过DisplayEventReceiver来创建事件连接的。当接收到事件后,将会把事件通知给每个监听者。当出现EAGAIN或EWOULDBLOCK错误时,丢弃当前事件。当出现如EPIPE错误时,说明监听者创建的事件连接已经丢失,将删除这个事件连接。

// dispatch events to listeners...
    const size_t count = signalConnections.size();
    for (size_t i=0 ; i& 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) {
            …
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;

往下看,如果没有VSync事件到来,再Check下是否有其他事件:

timestamp为零,说明此时还没有收到VSync事件,再检查mPendingEvent看是否有其他的事件需要处理:

 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);
            }
        }

接下来,检查一遍当前有哪些事件连接是有效的,即从注册列表mDisplayEventConnections中检查。

下是否有其他事件:

 // find out connections waiting for events
        size_t count = mDisplayEventConnections.size();
        for (size_t i=0 ; i connection(mDisplayEventConnections[i].promote());
            if (connection != NULL) {
             当前有活跃连接,将符合条件的连接加入
…
            } else {
                否则,当前连接已经失效,应当删除
                mDisplayEventConnections.removeAt(i);
                --i; --count;
            }
        }

   }

我们来看下,当有活跃连接时,如何将符合条件的连接加入到事件通知列表(signalConnections)中。如果当前有活跃连接,则看当前连接的count值,如果大于0,则说明有VSync事件需要等待,再者,如果timestamp不为零,则说明已经收到了VSync事件,需要根据connection->count的值,进行相应的处理。如果为零,则说明当前连接只接收一次VSync事件,下次不会接收了,即下次不需要通知它。当connection->count为1或当前VSync事件的count值为connection->count的倍数时,说明当前事件连接要不断接收VSync事件。

 if (connection != NULL) {
                bool added = false;
                if (connection->count >= 0) {
                    waitForVSync = true;
                    if (timestamp) {
                        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) {
                            signalConnections.add(connection);
                            added = true;
                        }
                    }
                }

当然,如果当前连接没有VSync事件接收,且此时又有其他事件发生,则也需要将事件发送给当前事件连接的接收端。

              if (eventPending && !timestamp && !added) {
                    signalConnections.add(connection);
                }

上面是决定要将事件发给哪些接收端,下面会再次确认下是否有必要开启Vsync,如果当前没有活跃事件连接接收VSync事件,则应该关闭VSync事件源。

// Here we figure out if we need to enable or disable vsyncs
        if (timestamp && !waitForVSync) {
            disableVSyncLocked();
        } else if (!timestamp && waitForVSync) {
            enableVSyncLocked();
        }

如果没有VSync事件且也没有收到其他事件,但是此时仍然有连接在等待VSync事件,则做一个如下判断:当使用软件模拟VSync事件时,则创建一个VSync事件,每16ms触发一次。这种情况一般发生在屏幕关闭的情况。另外,还有一种情况是底层产生VSync事件的硬件出现故障,未按时发送VSync事件,则此时,为了系统刷图能继续下来,也模拟一个VSync事件,每1秒触发一次,此时UI刷新会非常卡顿。

if (!timestamp && !eventPending) {
            // wait for something to happen
            if (waitForVSync) {
                bool softwareSync = mUseSoftwareVSync;
                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
                    if (!softwareSync) {
                        ALOGW("Timed out waiting for hw vsync; faking it");
                    }
                    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
                    mVSyncEvent[0].header.id = HWC_DISPLAY_PRIMARY;
                    mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                    mVSyncEvent[0].vsync.count++;
                }
            } else {
                mCondition.wait(mLock);
            }
        }

4. 测试例子分析


代码位于frameworks/native/services/surfaceflinger/tests/vsync.cpp

在DisplayEventReceiver 的构造函数中,调用了SurfaceFlinger的createDisplayEventConnection,创建了一个监听SurfaceFlinger事件的连接。默认情况下,DisplayEventReceiver不接收Vsync事件,setVsyncRate(1)表示将接收VSync事件。

int main(int argc, char** argv)
{
    DisplayEventReceiver myDisplayEvent;


    sp loop = new Looper(false);
    loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
            &myDisplayEvent);

    myDisplayEvent.setVsyncRate(1);

    do {
        //printf("about to poll...\n");
        int32_t ret = loop->pollOnce(-1);
        …
    } while (1);

    return 0;
}

通过Looper机制,监听发生在这个事件连接上的事件,并调用回调函数receiver:

当屏幕打开时,下面打印的Sync信息就是硬件产生的,当屏幕关闭后,打印的VSync信息就是软件模拟的(软件模拟的,从打印数据来看,每次数据都会有一些偏差,不如硬件VSync信号那么精确)。

int receiver(int fd, int events, void* data)
{
    DisplayEventReceiver* q = (DisplayEventReceiver*)data;

    ssize_t n;
    DisplayEventReceiver::Event buffer[1];

    static nsecs_t oldTimeStamp = 0;

    while ((n = q->getEvents(buffer, 1)) > 0) {
        for (int i=0 ; i

5. Java层监听Vsync事件

在JNI层,frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp中,定义了NativeDisplayEventReceiver类,它为对应的Java类android.view.DisplayEventReceiver提供了监听底层VSync事件的机制。NativeDisplayEventReceiver的定义如下:

class NativeDisplayEventReceiver : public LooperCallback {
public:
    NativeDisplayEventReceiver(JNIEnv* env,
            jobject receiverObj, const sp& messageQueue);

    status_t initialize();
    void dispose();
    status_t scheduleVsync();

protected:
    virtual ~NativeDisplayEventReceiver();

private:
    jobject mReceiverObjGlobal;
    sp mMessageQueue;
    DisplayEventReceiver mReceiver;
    bool mWaitingForVsync;

    virtual int handleEvent(int receiveFd, int events, void* data);
    bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
    void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
    void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
};

在initialize方法中会建立一个事件连接,并通过mMessageQueue的Looper成员变量监听发生在该事件连接上的事件。另外,mReceiverObjGlobal表示对Java层DisplayEventReceiver对象的一个全局引用,保证虚拟机不会过早地对该Java对象进行垃圾回收。handleEvent将会根据情况调用dispatchVsync或dispatchHotplug,而这两个方法实际上会通过JNI调用Java层DisplayEventReceiver类相应的私有方法dispatchVsync和dispatchHotplug,这两个方法实际上会调用该类的公有接口:onVsync和onHotplug。而Java层类也可以通过scheduleVsync显式请求一个VSync事件。由于DisplayEventReceiver是一个抽象类,所有上层Java层的类如果想针对VSync事件做些响应,必须从该类继承,并实现它的onVSync方法,如android.view. Choreographer中的私有内部类FrameDisplayEventReceiver:

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        …

        public FrameDisplayEventReceiver(Looper looper) {
            super(looper);
        }

        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
             …
        }

        …
    }








你可能感兴趣的:(Android研究)