AndroidQ SurfaceFlinger進程對Vsync的接收與分發(下)

上一篇文章分析到了SurfaceFlinger進程接收到來自硬件的Vsync的處理流程,主要是在EventThread內部線程的threadMain函數中,這個函數中主要分析了對接收到的事件的處理,並沒有分析它的來源,導致遺留了兩個問題:1.mPendingEvents裏的事件是怎麼來的,2.setVSyncEnabled函數的具體作用

setVSyncEnabled函數的作用也分析了一部分,主要是添加或者移除監聽器,它監聽的是什麼?是來自DispSync內部線程DispSyncThread捕捉到的Vsync,我們這篇文章要分析的是DispSyncThread對捕捉到Vsync信號之後的內部處理,DispSyncThread的threadLoop中會開啓一個死循環,在捕捉到Vsync之後會通知監聽器,所以本篇文章的分析分爲兩步:1.DispSyncThread如何捕捉Vsync,2.捕捉到Vsync之後如何通知監聽器

首先來看步驟1,想要知道DispSyncThread如何捕捉Vsync必須先知道Vsync如何發送的,如何到DispSyncThread中的:

先來看看SurfaceFlinger的定義:

class SurfaceFlinger : public BnSurfaceComposer,
                       public PriorityDumper,
                       private IBinder::DeathRecipient,
                       private HWC2::ComposerCallback

SurfaceFlinger繼承BnSurfaceComposer,作爲Binder Bn端,另外還實現了一個Callback,HWC2::ComposerCallback

我們來看看這個Callback定義:

//HWC2.h
class ComposerCallback {
 public:
    virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
                                   Connection connection) = 0;
    virtual void onRefreshReceived(int32_t sequenceId,
                                   hwc2_display_t display) = 0;
    virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
                                 int64_t timestamp) = 0;
    virtual ~ComposerCallback() = default;
};

注意看它定義的三個回調函數,分別對應三種事件類型,熱插拔,屏幕刷新,Vsync信號,surfaceflinger實現了這三個回調方法,並且在init函數中通過如下代碼最終將自己註冊到了Hwc2的ComposerCallbackBridge中

mCompositionEngine->getHwComposer().registerCallback(this,
getBE().mComposerSequenceId);
來看看ComposerCallbackBridge的定義

class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:
    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
            : mCallback(callback), mSequenceId(sequenceId) {}

    Return<void> onHotplug(Hwc2::Display display,
                           IComposerCallback::Connection conn) override
    {
        HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
        mCallback->onHotplugReceived(mSequenceId, display, connection);
        return Void();
    }

    Return<void> onRefresh(Hwc2::Display display) override
    {
        mCallback->onRefreshReceived(mSequenceId, display);
        return Void();
    }

    Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
    {
        mCallback->onVsyncReceived(mSequenceId, display, timestamp);
        return Void();
    }

我們可以看到ComposerCallbackBridge中有三個函數依次對應ComposerCallback中的三個回調函數,剛好ComposerCallbackBridge的某個函數被調用之後就會調到surfaceFlinger對應的某個回調函數中

而ComposerCallbackBridge的幾個函數則是通過hal從硬件調用過來的,看不了代碼也沒必要進行分析,大概調用棧爲:

hardware->BHwBinder->BnHwComposerCallback::onTransact->BnHwComposerCallback::_hidl_onVsync->ComposerCallbackBridge::onVsync->SurfaceFlinger::onVsyncReceived

所以SurfaceFlinger的onVsyncReceived函數最終接收的就是來自硬件的Vsync信號

繼續來看看SurfaceFlinger的onVsyncReceived函數具體實現:

onVsyncReceived

void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                     int64_t timestamp) {
    
    ......
    bool periodChanged = false;
    mScheduler->addResyncSample(timestamp, &periodChanged);
    if (periodChanged) {
        mVsyncModulator.onRefreshRateChangeDetected();
    }
}

接着調用mScheduler的addResyncSample函數

void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) {
    bool needsHwVsync = false;
    *periodChanged = false;
    { // Scope for the lock
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged);
        }
    }
	.....
}

mPrimaryDispSync類型爲DispSync,DispSync內部有一個線程DispSyncThread

DispSync.addResyncSample

bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
    ......
    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
    ......
}

這個線程是surfaceFlinger進程中處理Vsync的源頭,調用DispSyncThread的updateModel函數

mThread->updateModel

void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
        ......
        mCond.signal();
    }

通過C++的條件變量喚醒處於wait狀態的線程

到這裏第一步DispSyncThread捕捉Vsync分析完了,來看第二步,DispSyncThread的threadLoop函數

DispSyncThread.threadLoop

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

        while (true) {
			....
            std::vector<CallbackInvocation> callbackInvocations;

           		.....

                if (mPeriod == 0) {
                    err = mCond.wait(mMutex);
                    if (err != NO_ERROR) {
                        
                        return false;
                    }
                    continue;
                }

                targetTime = computeNextEventTimeLocked(now);

                bool isWakeup = false;
               
                if (now < targetTime) {
                    if (targetTime == INT64_MAX) {
                        err = mCond.wait(mMutex);
                    } else {
                        
                        err = mCond.waitRelative(mMutex, targetTime - now);
                    }
				.....

                now = systemTime(SYSTEM_TIME_MONOTONIC);
				......
                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

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

        return false;
    }

DispSyncThread在啓動時就會開啓死循環,當沒有事件時調用mCond.wait陷入wait狀態,其實DispSyncThread和上一篇文章分析的EventThread內部線程是同樣的工作機制,同樣的死循環,依靠喚醒/等待完成所有工作,

DispSyncThread被喚醒之後,首先得到下一個Vsync信號的時間,如果大於當前時間now,則會繼續等待,否則會調用gatherCallbackInvocationsLocked函數從mEventListeners中獲取處理Vsync時間小於當前時間的監聽器,獲取之後再調用fireCallbackInvocations函數,此函數中再調用所以監聽器的onDispSyncEvent函數

onDispSyncEvent這個回調函數我們上一篇文章分析過,是由DispSyncSource實現的,

DispSyncSource.onDispSyncEvent

void DispSyncSource::onDispSyncEvent(nsecs_t when) {
    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
		....

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

DispSyncSource的onDispSyncEvent函數中又調用了回調函數onVSyncEvent,而onVSyncEvent這個回調則是由EventThread實現的,是在EventThread的構造函數中註冊到DispSyncSource的
mVSyncSource->setCallback(this);

繼續看EventThread的onVSyncEvent函數

EventThread.onVSyncEvent

void EventThread::onVSyncEvent(nsecs_t timestamp) {
    ......
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count));
    mCondition.notify_all();
}

終於看到我們遺留的第一個問題了:mPendingEvents的事件是怎麼來的?mPendingEvents中的事件是在DispSyncThread收到Vsync之後填充的,這裏調用makeVSync構造了一個事件

makeVSync

DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
                                      uint32_t count) {
    DisplayEventReceiver::Event event;
    event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
    event.vsync.count = count;
    return event;
}

構造了一個DisplayEventReceiver::Event類型事件,類型爲DISPLAY_EVENT_VSYNC,還有displayId,時間戳以及接收到的次數

我們可以發現VSync並不是一個實際的信號,更像是一條通知,EventThread收到通知之後自己構造一個Event,然後發送出去

VSync類型事件構造好了之後通過條件變量喚醒陷入wait狀態的EventThread內部線程,這個線程的作用在前一篇文章就分析了,它會從mPendingEvents中拿到最頭部事件調用dispatchEvent將事件分發給感興趣的監聽者,感興趣的監聽者即是向EventThread請求了Vsync的EventThreadConnection

dispatchEvent的實現很簡單,最終就是通過gui::BitTube的sendObjects函數向mSendFd中寫入數據,另一端監聽了mReceiveFd的進程就能夠收到消息,知道Vsync到來了,然後完成繪製工作

而我們遺留的問題2:setVSyncEnabled的作用就是開啓或關閉對DispSyncThread發送的Vsync通知的監聽,當我們不需要繪製UI時例如滅屏就會調用setVSyncEnabled(false)關閉監聽,這樣EventThread中就收不到任何Vsync事件,並通過條件變量的wait函數陷入等待

到這裏通過四篇文章就大概分析完了VSync機制的工作原理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章