1. 程式人生 > >SurfaceFlinger原理(二):Vsync事件的處理

SurfaceFlinger原理(二):Vsync事件的處理

  SurfaceFlinger內部有兩個EventThread,一個負責app端對Vsync訊號的監聽處理,一個負責SurfaceFlinger對Vsync訊號的監聽處理。SurfaceFlinger內部維持了一個MessageQueue,當SurfaceFlinger端的EventThread監測到Vsync事件,會觸發INVALIDATE操作,即當前的圖層失效了,需要重新計算重新整理。

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this
); }

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, true, "sf");
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);

/frameworks/native/services/surfaceflinger/MessageQueue.cpp

void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
    mEventThread = eventThread;
    mEvents = eventThread->createEventConnection();
    mEventTube = mEvents->getDataChannel();
    mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
            MessageQueue::cb_eventReceiver
, this); }

  每個EventThread內部都維持一個mDisplayEventConnections,記錄了所有跟這個EventThread的Connection物件的集合。app端通過createDisplayEventConnection構建一個Connection,SurfaceFlinger端通過setEventThread–>createEventConnection。app端的Connection可能不止一個,SurfaceFlinger端的Connection只有一個。   Connection的作用是什麼?先看看Connection的建構函式:

/frameworks/native/services/surfaceflinger/EventThread.cpp

EventThread::Connection::Connection(
        const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}

  mEventThread初始化為連線到的EventThread,即是將儲存到這個EventThread中的mDisplayEventConnections中。count值表示Connection是否有感興趣的事件(通常這個感興趣的事件就是Vsync)。-1表示感興趣的事件已經被處理或者沒有感興趣的事件(因為初始化為-1),0表示一次性的感興趣的事件,這種事件被處理後count值會變成-1,大於等於1表示是連續事件。mChannel是一個BitTube,可以將其理解是用socketpair呼叫建立的兩個互相連線的套接字,Android將其作為管道用,MessageQueue::setEventThread將監聽讀端的套接字的輸入事件,從而回調cb_eventReceiver進行處理。   EventThread的建構函式中,會對mVSyncEvent進行初始化,mVSyncEvent是一個長度為2的DisplayEventReceiver::Event陣列,用來儲存主螢幕(下標為0)和外界螢幕(下標為1)的Vsync事件的資訊,如id,時間戳,count值(這個count值表示接收到的Vsync事件數量)等。然後在onFirstRef中,EventThread會進入threadLoop迴圈。

/frameworks/native/services/surfaceflinger/EventThread.cpp

EventThread::EventThread(const sp<VSyncSource>& src)
    : mVSyncSource(src),
      mUseSoftwareVSync(false),
      mVsyncEnabled(false),
      mDebugVsyncEnabled(false),
      mVsyncHintSent(false) {

    for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
        mVSyncEvent[i].header.id = 0;
        mVSyncEvent[i].header.timestamp = 0;
        mVSyncEvent[i].vsync.count =  0;
    }
    struct sigevent se;
    se.sigev_notify = SIGEV_THREAD;
    se.sigev_value.sival_ptr = this;
    se.sigev_notify_function = vsyncOffCallback;
    se.sigev_notify_attributes = NULL;
    timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
}

  threadLoop看似很簡短,但其實內部比較複雜。

/frameworks/native/services/surfaceflinger/EventThread.cpp

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);
        if (err == -EAGAIN || err == -EWOULDBLOCK) {
            // The destination doesn't accept events anymore, it's probably
            // full. For now, we just drop the events on the floor.
            // FIXME: Note that some events cannot be dropped and would have
            // to be re-sent later.
            // Right-now we don't have the ability to do this.
            ALOGW("EventThread: dropping event (%08x) for connection %p",
                    event.header.type, conn.get());
        } else if (err < 0) {
            // handle any other error on the pipe as fatal. the only
            // reasonable thing to do is to clean-up this connection.
            // The most common error we'll get here is -EPIPE.
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;
}

  首先看EventThread::waitForEvent,該函式用來等待一個Connection發生感興趣的事件,即Vsync事件。我們從EventThread初始化開始分析,條理會比較清晰。初始化時,timestamp為0,會直接mDisplayEventConnections中尋找發生了Vsync的Connection,條件是遍歷mDisplayEventConnections中的所用Connection,若發現其count值是0或1或者接收到的Vsync事件數量能夠被Connection的count值整除,則認為發生了Vsync,將這個Connection加入到signalConnections中。根據Connection的count值的不同,一次性事件(count為0)發生的Connection會將其count值置為-1,而連續事件發生的Connection不需要重置。waitForVSync表示是否有一個Connection是否對Vsync感興趣,當一個不為null的Connection的count大於等於0時,waitForVSync就會被設為true。   初始化時,timestamp是0,waitForVSync為false,因此執行緒會阻塞在mCondition.wait中。mCondition喚醒的條件之一是由Vsync事件到來。

/frameworks/native/services/surfaceflinger/EventThread.cpp

// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
        DisplayEventReceiver::Event* event)
{
    Mutex::Autolock _l(mLock);
    Vector< sp<EventThread::Connection> > signalConnections;

    do {
        bool eventPending = false;
        bool waitForVSync = false;

        size_t vsyncCount = 0;
        nsecs_t timestamp = 0;
        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
                *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 ; i++) {
            sp<Connection> connection(mDisplayEventConnections[i].promote());
            if (connection != NULL) {
                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);
                }
            } else {
                // we couldn't promote this reference, the connection has
                // died, so clean-up!
                //Connection已經無效
                mDisplayEventConnections.removeAt(i);
                --i; --count;
            }
        }

        // Here we figure out if we need to enable or disable vsyncs
        if (timestamp && !waitForVSync) {
            // we received a VSYNC but we have no clients
            // don't report it, and disable VSYNC events
            disableVSyncLocked();
        } else if (!timestamp && waitForVSync) {
            // we have at least one client, so we want vsync enabled
            // (TODO: this function is called right after we finish
            // notifying clients of a vsync, so this call will be made
            // at the vsync rate, e.g. 60fps.  If we can accurately
            // track the current state we could avoid making this call
            // so often.)
            enableVSyncLocked();
        }

        // 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;
                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");
                    }
                    // 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(mLock);
            }
        }
    } while (signalConnections.isEmpty());

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

  Vsync怎麼產生的呢?之前有提到HWComposer的建構函式會註冊一些回撥函式到hwc層:hook_invalidate和hook_vsync。其中hook_vsync就是產生硬體Vsync後進行的回撥函式。產生硬體Vsync的程式碼在廠家的hwc HAL層程式碼中,我們直接看回調函式的程式碼。   HWComposer::vsync帶回了兩個引數:第一個引數是display id,第二個引數是Vsync產生的時間戳。mEventHandler表示的就是SurfaceFlinger。

/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

void HWComposer::vsync(int disp, int64_t timestamp) {
    if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
        {
            Mutex::Autolock _l(mLock);

            // There have been reports of HWCs that signal several vsync events
            // with the same timestamp when turning the display off and on. This
            // is a bug in the HWC implementation, but filter the extra events
            // out here so they don't cause havoc downstream.
            if (timestamp == mLastHwVSync[disp]) {
                ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                        timestamp);
                return;
            }

            mLastHwVSync[disp] = timestamp;
        }

        char tag[16];
        snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
        ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);

        mEventHandler.onVSyncReceived(disp, timestamp);
    }
}

  當對應的螢幕是主螢幕且已開啟Vsync時,通過DispSync::addResyncSample的返回值needsHwVsync決定要不要繼續開啟Vsync或者關閉Vsync。

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    bool needsHwVsync = false;

    { // Scope for the lock
        Mutex::Autolock _l(mHWVsyncLock);
        if (type == 0 && mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
        }
    }

    if (needsHwVsync) {
        enableHardwareVsync();
    } else {
        disableHardwareVsync(false);
    }
}

  DispSync::addResyncSample接收以個Vsync的事件戳作為引數,是怎麼計算出是否需要開啟Vsync的呢?mPrimaryDispSync內部維持了一個長度為32的時間戳陣列mResyncSamples,而addResyncSample要做的,就是將這次Vsync事件的事件戳加入到裡面去,重新更新Vsync模型,並根據結果決定是否開啟Vsync。mFirstResyncSample在時間戳總數未達到32時,記錄的是mResyncSamples的首個元素位置,也就是0;在時間戳總數達到32時,記錄的是插入新的時間戳的位置。mNumResyncSamples表示當前的時間戳總數,最大為32。mResyncSamples裡面的時間戳按從舊到新進行排列,總是保留最新的時間戳,如果時間戳數量大於32個的話,則新加入的時間戳會覆蓋掉時間最早的時間戳。updateModelLocked用來更新Vsync模型。   如果kIgnorePresentFences的值為true,則根據DispSyncThread是否存在Vsync事件回撥決定是否開啟Vsync,若存在則開啟;如果kIgnorePresentFences的值為false,週期mPeriod為0或者偏差mError大於閾值kErrorThreshold時,則需要開啟Vsync進行校正。

/frameworks/native/services/surfaceflinger/DispSync.cpp

bool DispSync::addResyncSample(nsecs_t timestamp) {
    Mutex::Autolock lock(mMutex);

    size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    mResyncSamples[idx] = timestamp;

    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
        mNumResyncSamples++;
    } else {
        mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
    }

    updateModelLocked();

    if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
        resetErrorLocked();
    }

    if (kIgnorePresentFences) {
        // If we don't have the sync framework we will never have
        // addPresentFence called.  This means we have no way to know whether
        // or not we're synchronized with the HW vsyncs, so we just request
        // that the HW vsync events be turned on whenever we need to generate
        // SW vsync events.
        return mThread->hasAnyEventListeners();
    }

    return mPeriod == 0 || mError > kErrorThreshold;
}

  當定義了巨集RUNNING_WITHOUT_SYNC_FRAMEWORK或者app Vsync相移和SurfaceFlinger vsync相移均為0時,kIgnorePresentFences 為true;否則為false。

/frameworks/native/services/surfaceflinger/DispSync.h

// Ignore present (retire) fences if the device doesn't have support for the
// sync framework, or if all phase offsets are zero.  The latter is useful
// because it allows us to avoid resync bursts on devices that don't need
// phase-offset VSYNC events.
#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
        (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
static const bool kIgnorePresentFences = true;
#else
static const bool kIgnorePresentFences = false;
#endif

  當樣本時間戳數量大於等於3時,才會更新Vsync模型。更新Vsync模型的方式如下。1.週期mPeriod:從最舊的時間戳起,用第二舊的時間戳減去最舊的時間戳得到期間Vsync間隔時間;然後用第三舊的時間戳減去第二舊的時間戳得到期間Vsync的間隔時間。。。直到得到時間戳總數減1數量(mNumResyncSamples - 1)的Vsync間隔時間總和,求取其平均值即為週期mPeriod 。2.相移mPhase:以mPeriod 為週期,算出其角速度scale=2pi/mPeriod ,對於mNumResyncSamples個時間戳,分別計算出它們的相移角度samplePhase=時間戳%週期*角速度。sampleAvgX為相移角度的cos值 的累加,sampleAvgY為相移角度的sin值的累加值。sampleAvgX和sampleAvgY分別為sampleAvgX和sampleAvgY的平均值。atan2(sampleAvgY, sampleAvgX)計算出平均每個時間戳的偏移角度,除以角速度就是相移mPhase,準確點叫相移時間。為確保mPhase為正數,當計算出的mPhase小於0時,為其加上mPeriod 得到一個新的mPhase值。最後通過updateModel將mPeriod 和mPhase設定到DispSyncThread裡面。

/frameworks/native/services/surfaceflinger/DispSync.cpp

void DispSync::updateModelLocked() {
    if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
        nsecs_t durationSum = 0;
        for (size_t i = 1; i < mNumResyncSamples; i++) {
            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
            size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
            durationSum += mResyncSamples[idx] - mResyncSamples[prev];
        }

        mPeriod = durationSum / (mNumResyncSamples - 1);

        double sampleAvgX = 0;
        double sampleAvgY = 0;
        double scale = 2.0 * M_PI / double(mPeriod);
        for (size_t i = 0; i < mNumResyncSamples; i++) {
            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
            nsecs_t sample = mResyncSamples[idx];
            double samplePhase = double(sample % mPeriod) * scale;
            sampleAvgX += cos(samplePhase);
            sampleAvgY += sin(samplePhase);
        }

        sampleAvgX /= double(mNumResyncSamples);
        sampleAvgY /= double(mNumResyncSamples);

        mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);

        if (mPhase < 0) {
            mPhase += mPeriod;
        }

        if (kTraceDetailedInfo) {
            ATRACE_INT64("DispSync:Period", mPeriod);
            ATRACE_INT64("DispSync:Phase", mPhase);
        }

        // Artificially inflate the period if requested.
        mPeriod += mPeriod * mRefreshSkipCount;

        mThread->updateModel(mPeriod, mPhase);
    }
}

    最初,DispSyncThread在threadLoop過程中會因為mPeriod為0而阻塞,updateModel會將其喚醒。

/frameworks/native/services/surfaceflinger/DispSync.cpp

    void updateModel(nsecs_t period, nsecs_t phase) {
        Mutex::Autolock lock(mMutex);
        mPeriod = period;
        mPhase = phase;
        mCond.signal();
    }

  那麼問題來了,mThread->hasAnyEventListeners返回的是false(這裡假定的情況是app和SurfaceFlingfer的Vsync相移為0),導致Vsync會進入關閉狀態,這樣剛產生了一次的Vsync又關掉了,什麼時候才會開啟Vsync呢?實際上,第一個Vsync是用來更新週期和相移時間用的,Vsync在恰當的時候開關,有利於節約電源,減少功耗。   當app或者SurfaceFlinger需要Vsync來協調更新介面時,都需要呼叫到EventThread::requestNextVsync時。表示當前的Connection對Vsync事件感興趣,這時會把Connection的count設為0,這時一直阻塞在條件變數mCondition的SurfaceFlinge端的EventThread會被喚醒。

/frameworks/native/services/surfaceflinger/EventThread.cpp

void EventThread::requestNextVsync(
        const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.broadcast();
    }
}

  回到EventThread::waitForEvent函式。由於有Connection的count已經設定成0,waitForVSync變成true,但是timestamp仍為0,於是會呼叫enableVSyncLocked的邏輯使能Vsync。

/frameworks/native/services/surfaceflinger/EventThread.cpp

// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
        DisplayEventReceiver::Event* event)
{
    Mutex::Autolock _l(mLock);
    Vector< sp<EventThread::Connection> > signalConnections;

    do {
        bool eventPending = false;
        bool waitForVSync = false;

        size_t vsyncCount = 0;
        nsecs_t timestamp = 0;
        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
                *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 ; i++) {
            sp<Connection> connection(mDisplayEventConnections[i].promote());
            if (connection != NULL) {
                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);
                }
            } else {
                // we couldn't promote this reference, the connection has
                // died, so clean-up!
                mDisplayEventConnections.removeAt(i);
                --i; --count;
            }
        }

        // Here we figure out if we need to enable or disable vsyncs
        if (timestamp && !waitForVSync) {
            // we received a VSYNC but we have no clients
            // don't report it, and disable VSYNC events
            disableVSyncLocked();
        } else if (!timestamp && waitForVSync) {
            // we have at least one client, so we want vsync enabled
            // (TODO: this function is called right after we finish
            // notifying clients of a vsync, so this call will be made
            // at the vsync rate, e.g. 60fps.  If we can accurately
            // track the current state we could avoid making this call
            // so often.)
            enableVSyncLocked();
        }

        // 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;
                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");
                    }
                    // 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(mLock);
            }
        }
    } while (signalConnections.isEmpty());

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

  mVSyncSource指的是DispSyncSource物件。

/frameworks/native/services/surfaceflinger/EventThread.cpp

void EventThread::enableVSyncLocked() {
    if (!mUseSoftwareVSync) {
        // never enable h/w VSYNC when screen is off
        if (!mVsyncEnabled) {
            mVsyncEnabled = true;
            mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
            mVSyncSource->setVSyncEnabled(true);
        }
    }
    mDebugVsyncEnabled = true;
    sendVsyncHintOnLocked();
}

  EventThread繼承自VSyncSource::Callback,這裡將mCallback 設定成EventThread型別的入參。

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
        Mutex::Autolock lock(mMutex);
        mCallback = callback;
    }

  DispSyncSource繼承自DispSync::Callback。

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    virtual void setVSyncEnabled(bool enable) {
        // Do NOT lock the mutex here so as to avoid any mutex ordering issues
        // with locking it in the onDispSyncEvent callback.
        if (enable) {
            status_t err = mDispSync->addEventListener(mPhaseOffset,
                    static_cast<DispSync::Callback*>(this));
            if (err != NO_ERROR) {
                ALOGE("error registering vsync callback: %s (%d)",
                        strerror(-err), err);
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 1);
        } else {
            status_t err = mDispSync->removeEventListener(
                    static_cast<DispSync::Callback*>(this));
            if (err != NO_ERROR) {
                ALOGE("error unregistering vsync callback: %s (%d)",
                        strerror(-err), err);
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 0);
        }
    }

/frameworks/native/services/surfaceflinger/DispSync.cpp

status_t DispSync::addEventListener(nsecs_t phase,
        const sp<Callback>& callback) {

    Mutex::Autolock lock(mMutex);
    return mThread->addEventListener(phase, callback);
}

  addEventListenerd第一個引數是EventThread使用的Vsync偏移,由VSYNC_EVENT_PHASE_OFFSET_NS或者SF_VSYNC_EVENT_PHASE_OFFSET_NS指定;第二個引數是是使用的DispSyncSource,將這兩個引數儲存在一個EventListener 物件中,並將EventListener 的mLastEventTime 設為當前事件減去半個Vsync週期的值,然後加入到mEventListeners的Vector中,然後喚醒DispSyncThread。

/frameworks/native/services/surfaceflinger/DispSync.cpp

    status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) {
        Mutex::Autolock lock(mMutex);

        for (size_t i = 0; i < mEventListeners.size(); i++) {
            if (mEventListeners[i].mCallback == callback) {
                return BAD_VALUE;
            }
        }

        EventListener listener;
        listener.mPhase = phase;
        listener.mCallback = callback;

        // We want to allow the firstmost future event to fire without
        // allowing any past events to fire.  Because
        // computeListenerNextEventTimeLocked filters out events within a half
        // a period of the last event time, we need to initialize the last
        // event time to a half a period in the past.
        listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2;

        mEventListeners.push(listener);

        mCond.signal();

        return NO_ERROR;
    }

  再看看DispSyncThread的threadLoop函式。第一次因為mPeriod == 0而導致的阻塞現在已經可以通行了。computeNextEventTimeLocked用來計算下一個 Vsync的時間戳。如果當前時間未到下一個 Vsync的時間戳,呼叫waitRelative等待相差的時間直到有人喚醒DispSyncThread。gatherCallbackInvocationsLocked收集所有符合要求的回撥,在fireCallbackInvocations中執行這些回撥。

/frameworks/native/services/surfaceflinger/DispSync.cpp

    virtual bool threadLoop() {
        status_t err;
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        nsecs_t nextEventTime = 0;

        while (true) {
            Vector<CallbackInvocation> callbackInvocations;

            nsecs_t targetTime = 0;

            { // Scope for lock
                Mutex::Autolock lock(mMutex);

                if (mStop) {
                    return false;
                }

                if (mPeriod == 0) {
                    err = mCond.wait(mMutex);
                    if (err != NO_ERROR) {
                        ALOGE("error waiting for new events: %s (%d)",
                                strerror(-err), err);
                        return false;
                    }
                    continue;
                }

                nextEventTime = computeNextEventTimeLocked(now);
                targetTime = nextEventTime;

                bool isWakeup = false;

                if (now < targetTime) {
                    err = mCond.waitRelative(mMutex, targetTime - now);

                    if (err == TIMED_OUT) {
                        isWakeup = true;
                    } else if (err != NO_ERROR) {
                        ALOGE("error waiting for next event: %s (%d)",
                                strerror(-err), err);
                        return false;
                    }
                }

                now = systemTime(SYSTEM_TIME_MONOTONIC);

                if (isWakeup) {
                    mWakeupLatency = ((mWakeupLatency * 63) +
                            (now - targetTime)) / 64;
                    if (mWakeupLatency > 500000) {
                        // Don't correct by more than 500 us
                        mWakeupLatency = 500000;
                    }
                    if (kTraceDetailedInfo) {
                        ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
                        ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
                    }
                }

                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }

        return false;
    }

/frameworks/native/services/surfaceflinger/DispSync.cpp

    Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
        Vector<CallbackInvocation> callbackInvocations;
        nsecs_t ref = now - mPeriod;

        for (size_t i = 0; i < mEventListeners.size(); i++) {
            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
                    ref);

            if (t < now) {
                CallbackInvocation ci;
                ci.mCallback = mEventListeners[i].mCallback;
                ci.mEventTime = t;
                callbackInvocations.push(ci);
                mEventListeners.editItemAt(i).mLastEventTime = t;
            }
        }

        return callbackInvocations;
    }

  回撥實際上是呼叫了DispSyncSource::onDispSyncEvent。而DispSyncSource::onDispSyncEvent會調到EventThread::onVSyncEvent。

/frameworks/native/services/surfaceflinger/DispSync.cpp

    void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
        for (size_t i = 0; i < callbacks.size(); i++) {
            callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
        }
    }

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    virtual void onDispSyncEvent(nsecs_t when) {
        sp<VSyncSource::Callback> callback;
        {
            Mutex::Autolock lock(mMutex);
            callback = mCallback;

            if (mTraceVsync) {
                mValue = (mValue + 1) % 2;
                ATRACE_INT(mVsyncEventLabel.string(), mValue);
            }
        }

        if (callback != NULL) {
            callback->onVSyncEvent(when);
        }
    }

&esmp; EventThread::onVSyncEvent會填充mVSyncEvent[0],然後喚醒EventThread執行緒。

/frameworks/native/services/surfaceflinger/EventThread.cpp

void EventThread::onVSyncEvent(nsecs_t timestamp) {
    Mutex::Autolock _l(mLock);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.broadcast();
}

&esmp; 在非同步呼叫enableVSyncLocked後,EventThread會阻塞在waitRelative中,阻塞時間在關屏狀態下為16ms,亮屏狀態為1s。如果EventThread::onVSyncEvent在超時時間內沒能喚醒EventThread ,則手動填充mVSyncEvent[0],使得流程可以繼續走下去。

        // 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;
                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");
                    }
                    // 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(mLock);
            }

  再回到EventThread::waitForEvent開頭,由於mVSyncEvent[0]的時間戳已經更新,所以timestamp的值不為0,然後將mVSyncEvent[0]的時間戳和Connection的count值分別重置為0和-1,將對應的Connection加入到signalConnections中。最終會退出waitForEvent中的do…while迴圈。   離開waitForEvent後就是遍歷signalConnections,然後分別呼叫其Connection::postEvent上報事件,以進行更新圖層或畫一幀的操作。