Android 12(S) 影像顯示系統 - SurfaceFlinger之VSync-上篇(十六)

二的次方發表於2022-04-19

必讀:

Android 12(S) 影像顯示系統 - 開篇


 

一、前言


為了提高Android系統的UI互動速度和操作的流暢度,在Android 4.1中,引入了Project Butter,即“黃油計劃”。就像該計劃的名字那樣,Google期望通過這一新的機制可以讓Android系統擺脫UI互動時給使用者帶來的滯後感,從而像黃油一樣順滑。

當然優化是無止境的,Project Butter只是邁出了重要的第一步,後續的Android版本中陸續也有引入一些其它的優化機制,促進UI渲染效能的不斷提升。

Project Butter對Android Display系統進行了重構,引入了三個核心元素:VSyncTriple BufferChoreographer。從這篇文章開始,我們就來看一看VSync的實現機制。

關於螢幕重新整理機制,有一張很經典的圖片:

整個顯示過程就是:

  • CPU計算螢幕需要的資料,然後交給GPU。
  • GPU對影像進行處理繪製,然後存到快取區。
  • display再從這個快取區讀取資料,顯示出來。

如果螢幕的重新整理率是60Hz,每一幀都是重複這個工作,也就是1秒中需要60次這樣迴圈操作,每次操作需要的時間就約等於16.6ms。也就是我們常說的Android系統中,會每隔16.6ms重新整理一次螢幕。

可以看到,16.6ms一到,系統就傳送了VSync訊號,然後螢幕會從快取區獲取了新的一幀影像並顯示出來,與此同時,CPU也開始了下一幀資料的計算,然後計算好交給GPU,最後放到快取區,等待下一次VSync訊號。

 

在閱讀這篇文章前,推薦閱讀一篇我轉載的文章:聊聊Android螢幕重新整理機制 - Vsync / Double Buffer / Triple Buffer / 掉幀 / 撕裂

 

二、VSYNC訊號的產生


 

2.1 VSync訊號機制的邏輯是從哪裡開始初始化的呢?

在前面的文章 Android 12(S) 影像顯示系統 - SurfaceFlinger的啟動和訊息佇列處理機制(四)中我們在講解SurfaceFlinger::init方法時,init會去初始化HWComposer並註冊回撥函式,如下摘錄的程式碼:

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::init() {
    // 建立HWComposer物件並傳入一個name屬性,再通過mCompositionEngine->setHwComposer設定物件屬性。
    mCompositionEngine->setTimeStats(mTimeStats);
    mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
    mCompositionEngine->getHwComposer().setCallback(this); // 這裡的this就是SurfaceFlinger物件本身,因為它實現了HWC2::ComposerCallback回撥介面
}

HWC2::ComposerCallback中定義了 VSYNC訊號、插拔顯示器等的回撥事件方法,如下:

[/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.h]
struct ComposerCallback {
    virtual void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) = 0; // 熱插拔事件
    virtual void onComposerHalRefresh(hal::HWDisplayId) = 0; // refresh 重新整理事件
    virtual void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, // VSYNC訊號事件
                                    std::optional<hal::VsyncPeriodNanos>) = 0;
    ...
};

根據HWC2::ComposerCallback的設計邏輯,SurfaceFlinger::init方法中設定完HWC的回撥後,會立即收到一個Hotplug事件,並在SurfaceFlinger::onComposerHalHotplug中去處理,因此流程就走到了:

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
                                          hal::Connection connection) {
    ...
    if (std::this_thread::get_id() == mMainThreadId) {
        // Process all pending hot plug events immediately if we are on the main thread.
        processDisplayHotplugEventsLocked(); // 主執行緒中去處理 hot plug evnets
    }
}

再看processDisplayHotplugEventsLocked的程式碼:

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
        if (event.connection == hal::Connection::CONNECTED) {
                if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
                    initScheduler(state); // 初始化Scheduler
                }
                .....
}

上述程式碼我們只關心和VSync信後相關的邏輯,那就是呼叫了initShceduler

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
    if (mScheduler) { // 判斷mScheduler是否為空,避免重複初始化
        // In practice it's not allowed to hotplug in/out the primary display once it's been
        // connected during startup, but some tests do it, so just warn and return.
        ALOGW("Can't re-init scheduler");
        return;
    }
    const auto displayId = displayState.physical->id;
    scheduler::RefreshRateConfigs::Config config =
            {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
             .frameRateMultipleThreshold =
                     base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
    // 重新整理率的配置資訊,裡面包含了當前的螢幕刷頻率。重新整理週期等資訊
    mRefreshRateConfigs =
            std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
                                                            displayState.physical->activeMode
                                                                    ->getId(),
                                                            config);
    // currRefreshRate是一個Fps Object,其中儲存了重新整理率fps和重新整理週期period
    const auto currRefreshRate = displayState.physical->activeMode->getFps();
    mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
                                                                      hal::PowerMode::OFF);
    // mVsyncConfiguration 是一個 VsyncConfiguration object
    // VsyncConfiguration 類中封裝了不同重新整理率下的VSYNC配置資訊。app phase 就是vsyncSrc偏移量,sf phase 是sfVsyncSrc偏移量,
    mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate);
    // VsyncModulator object,VSYNC調製器,根據事務排程和重新整理率的變化調整VSYNC偏移量。 
    mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());

    // 建立Scheduler object
    mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
    const auto configs = mVsyncConfiguration->getCurrentConfigs();
    const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
    // 建立一個Connection named "app"
    mAppConnectionHandle =
            mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                         /*workDuration=*/configs.late.appWorkDuration,
                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                         impl::EventThread::InterceptVSyncsCallback());
    // 建立一個Connection named "appSf" 
    mSfConnectionHandle =
            mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
                                         /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                         [this](nsecs_t timestamp) {
                                             mInterceptor->saveVSyncEvent(timestamp);
                                         });
    //initVsync主要作用是繫結一個回撥函式 MessageQueue::vsyncCallback 到VSyncDispatch上,回撥名字"sf"
    mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
                           configs.late.sfWorkDuration);

    mRegionSamplingThread =
            new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables());
    mFpsReporter = new FpsReporter(*mFrameTimeline, *this);

    mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
                                            displayState.physical->activeMode->getId(),
                                            vsyncPeriod);
    static auto ignorePresentFences =
            base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false);
    mScheduler->setIgnorePresentFences(
            ignorePresentFences ||
            getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE));
}

我們可以dumpsys SurfaceFlinger看一看,VSyncDispatch上都繫結了哪些Callbacks,如下資訊:有三個“sf”,"appSf", "app"是不是和我們initShceduler

程式碼中的邏輯冥冥之中有點呼應了...

VSyncDispatch:
	Timer:
		DebugState: Waiting
	mTimerSlack: 0.50ms mMinVsyncDistance: 3.00ms
	mIntendedWakeupTime: 9223369916416.00ms from now
	mLastTimerCallback: 4215.62ms ago mLastTimerSchedule: 4215.54ms ago
	Callbacks:
		sf:  
			workDuration: 15.67ms readyDuration: 0.00ms earliestVsync: -11799.97ms relative to now
			mLastDispatchTime: 4200.02ms ago
		appSf:
			workDuration: 16.67ms readyDuration: 15.67ms earliestVsync: -2153016.50ms relative to now
			mLastDispatchTime: 2153016.50ms ago
		app:  
			workDuration: 16.67ms readyDuration: 15.67ms earliestVsync: -4183.37ms relative to now
			mLastDispatchTime: 4183.37ms ago

對前面的流程小結一下,大概如下:

接下來我們深入initShceduler細節,看看每一步驟都具體做了什麼工作呢?

 

2.2 建立Scheduler物件都做了啥子?

開啟建立之旅....

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
    ...
    // start the EventThread
    mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); //在DefaultFactory中去執行建立操作
    ...
}

DefaultFactory中也很簡單,SurfaceFlinger有實現ISchedulerCallback回撥方法,引數callback指向一個SurfaceFlinger物件,引數configs是重新整理率的資訊

[ /frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp]
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
        const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) {
    return std::make_unique<Scheduler>(configs, callback); // 建立Scheduler物件,callback指向一個SurfaceFlinger Object
}

進到Scheduler的建構函式,三個建構函式依次呼叫,初始化必要成員變數。

[/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp]
Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
      : Scheduler(configs, callback,
                  {.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
                   .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
}

Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback,
                     Options options)
      : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback,//createVsyncSchedule是主要的邏輯
                  createLayerHistory(configs), options) {
    ...
}

Scheduler::Scheduler(VsyncSchedule schedule, const scheduler::RefreshRateConfigs& configs,
                     ISchedulerCallback& schedulerCallback,
                     std::unique_ptr<LayerHistory> layerHistory, Options options)
      : mOptions(options),
        mVsyncSchedule(std::move(schedule)),
        mLayerHistory(std::move(layerHistory)),
        mSchedulerCallback(schedulerCallback),
        mRefreshRateConfigs(configs),
        mPredictedVsyncTracer(
                base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
                        ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
                        : nullptr) {
    mSchedulerCallback.setVsyncEnabled(false);// 注意這裡,設定了 VSync Enable False,關閉了硬體VSync
}

Scheduler建構函式中,最重要的一個步驟就是去呼叫了createVsyncSchedule方法,這是一個核心方法,在其中建立和初始化了和VSync訊號產生、分發相關的類物件和執行邏輯。

本文作者@二的次方  2022-04-18 釋出於部落格園

[/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp]
Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) {
    auto clock = std::make_unique<scheduler::SystemClock>();
    auto tracker = createVSyncTracker();  // 建立VSyncTracker物件
    auto dispatch = createVSyncDispatch(*tracker); // 建立VSyncDispatch物件

    // TODO(b/144707443): Tune constants.
    constexpr size_t pendingFenceLimit = 20;
    auto controller =                   // 建立VSyncReactor物件
            std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit,
                                                      supportKernelTimer); 
    return {std::move(controller), std::move(tracker), std::move(dispatch)}; // 把tracker,dispatch,controller封裝在一個VsyncSchedule strcut中
}

createVsyncSchedule方法最終返回了一個VsyncSchedule結構體物件。VsyncSchedule是一個結構體型別,含有三個成員變數:controller、tracker、dispatch,這三個成員在 VSync機制中分別發揮不同作用,等到下面再分析。

[/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.h]
struct VsyncSchedule {
    std::unique_ptr<scheduler::VsyncController> controller;
    std::unique_ptr<scheduler::VSyncTracker> tracker;
    std::unique_ptr<scheduler::VSyncDispatch> dispatch;
};

 

2.2.1 先看建立VSyncTracker做了啥?

[/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp]
std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() {
    // TODO(b/144707443): Tune constants.
    constexpr int kDefaultRate = 60;
    constexpr auto initialPeriod = std::chrono::duration<nsecs_t, std::ratio<1, kDefaultRate>>(1);
    constexpr nsecs_t idealPeriod =
            std::chrono::duration_cast<std::chrono::nanoseconds>(initialPeriod).count();
    constexpr size_t vsyncTimestampHistorySize = 20;
    constexpr size_t minimumSamplesForPrediction = 6; // 為了預測、模擬VSync最少需要取樣的個數
    constexpr uint32_t discardOutlierPercent = 20;
    return std::make_unique<scheduler::VSyncPredictor>(idealPeriod, vsyncTimestampHistorySize,
                                                       minimumSamplesForPrediction,
                                                       discardOutlierPercent);
}

實際建立的是一個實現類VsyncPredictor物件,VSyncTracker是一個基於歷史Vsync時間資料提供未來Vsync訊號時間估計的介面,VsyncPredictor實現了VSyncTracker中的方法。

[/frameworks/native/services/surfaceflinger/Scheduler/VSyncTracker.h]
class VSyncTracker { //虛基類,介面類,VSyncTracker是一個基於歷史Vsync時間資料提供未來Vsync訊號時間估計的介面。

[ /frameworks/native/services/surfaceflinger/Scheduler/VSyncPredictor.h]
class VSyncPredictor : public VSyncTracker { //實現VSyncTracker的方法

其中有2個方法,新增 取樣的vsync 時間戳,一般來自HWVsync,基於這些Vsync時間資料來訓練一個模擬的VSync模型,從而達到預測未來VSync時間的目的。

    /*
     * Adds a known timestamp from a vsync timing source (HWVsync signal, present fence)
     * to the model.
     */
    virtual bool addVsyncTimestamp(nsecs_t timestamp) = 0;

    /*
     * Access the next anticipated vsync time such that the anticipated time >= timePoint.
     * This will always give the best accurate at the time of calling; multiple
     * calls with the same timePoint might give differing values if the internal model
     * is updated.
     */
    virtual nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const = 0;

至於如何計算、預測的,本文不做講解。


我的理解是:VSync訊號是由HWC硬體模組根據螢幕重新整理率產生。VSyncTrackerVsyncPredictor根據HWC產生的硬體VSync訊號,訓練了一個模擬的VSync事件源,可以預測vsync事件的時間點。


 

2.2.2 建立VSyncDispatch做了啥子呢?

先瞅瞅程式碼吧,很簡單建立了一個VSyncDispatchTimerQueue物件,這又是個什麼鬼?

[/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp]
std::unique_ptr<scheduler::VSyncDispatch> createVSyncDispatch(scheduler::VSyncTracker& tracker) {
    // TODO(b/144707443): Tune constants.
    constexpr std::chrono::nanoseconds vsyncMoveThreshold = 3ms;
    constexpr std::chrono::nanoseconds timerSlack = 500us;
    return std::make_unique<
            scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), tracker,
                                                timerSlack.count(), vsyncMoveThreshold.count());
}

先看看定義吧

[/frameworks/native/services/surfaceflinger/Scheduler/VSyncDispatch.h]
class VSyncDispatch { // 用於分發和系統VSync事件相關的回撥事件

[/frameworks/native/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp]
// VSyncDispatchTimerQueue是一個類,它將使用單個計時器佇列按照VSyncDispatch介面排程回撥。
class VSyncDispatchTimerQueue : public VSyncDispatch { 

根據程式碼註釋和基本的邏輯,我大概理解的是:

VSyncDispatchTimerQueue(VSyncDispatch)負責分發VSync回撥事件,需要接收VSync事件的模組可以通過registerCallback向其中註冊回撥函式,所有的回撥都儲存在了CallbackMap mCallbacks,當到了VSync發生的時間就會遍歷註冊的回撥,把VSync事件分發出去。

 

2.2.3 還建立了一個VsyncController物件

    auto controller =
            std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit,
                                                      supportKernelTimer);

VSyncReactor繼承了VsyncController並實現其中的方法,VSyncReactor中含有一個VSyncTracker成員。看它的程式碼,VSyncReactor對外提供addPresentFenceaddHwVsyncTimestamp方法,把HWVsync signal, present fence的vsync timing source傳遞給VSyncTracker用於VSync model的訓練。

 

這一塊的邏輯,涉及到各種類,看起來很是紛繁複雜,我自己都繞來繞去看暈了,對於大多數人來說,這塊的邏輯是不會去修改的,那我也就簡單看看吧。

本文中很多流程也是自己猜測的,大概也不正確吧

 

簡單總結下上面的各種類的作用:

介面類 實現類 作用
VSyncTracker VSyncPredictor 根據取樣的硬體VSync,建立一個模擬的VSync模型,基於歷史Vsync時間資料來預測未來Vsync訊號發生的時間點
VSyncDispatch VSyncDispatchTimerQueue 分發VSync回撥事件
VsyncController VSyncReactor 配合VSyncTracker進行硬體VSync的取樣

本文作者@二的次方  2022-04-18 釋出於部落格園

看到這裡有個疑問:VSync事件具體是從哪裡分發出去的呢?

當某一些邏輯需要使用VSync事件驅動時,一般會去呼叫:

VSyncDispatchTimerQueue::schedule ==> VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor==> VSyncDispatchTimerQueue::setTimer

比如下面就是invalidate的呼叫棧資訊

11-13 01:15:27.751   225   624 E SurfaceFlinger: stackdump:#00 pc 000c405f  /system/bin/surfaceflinger (android::scheduler::VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(long long, std::__1::__hash_map_iterator<std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<android::StrongTyping<unsigned int, android::scheduler::CallbackTokenTag, android::Compare, android::Hash>, std::__1::shared_ptr<android::scheduler::VSyncDispatchTimerQueueEntry> >, void*>*> > const&)+686)
11-13 01:15:27.751   225   624 E SurfaceFlinger: stackdump:#01 pc 000c4a99  /system/bin/surfaceflinger (android::scheduler::VSyncDispatchTimerQueue::schedule(android::StrongTyping<unsigned int, android::scheduler::CallbackTokenTag, android::Compare, android::Hash>, android::scheduler::VSyncDispatch::ScheduleTiming)+728)
11-13 01:15:27.751   225   624 E SurfaceFlinger: stackdump:#02 pc 000c5057  /system/bin/surfaceflinger (android::scheduler::VSyncCallbackRegistration::schedule(android::scheduler::VSyncDispatch::ScheduleTiming)+40)
11-13 01:15:27.751   225   624 E SurfaceFlinger: stackdump:#03 pc 000b9beb  /system/bin/surfaceflinger (android::impl::MessageQueue::invalidate()+90)

setTimer中會去設定一個定時器,定時時間到來時,就會回撥 VSyncDispatchTimerQueue::timerCallback,在這個函式中遍歷所有的callbacks,進行VSync事件分發。

 

那還有一個問題:都有哪些模組或邏輯使用VSyncDispatchTimerQueue::registerCallback註冊了回撥來監聽VSync事件呢?

 

我們再回到SurfaceFlinger中的initScheduler方法,繼續之前的分析

 

2.3 createConnection是何方神聖?

mAppConnectionHandle =
            mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                         /*workDuration=*/configs.late.appWorkDuration,
                                         /*readyDuration=*/configs.late.sfWorkDuration,
                                         impl::EventThread::InterceptVSyncsCallback());

先看看程式碼吧

Scheduler::ConnectionHandle Scheduler::createConnection(
        const char* connectionName, frametimeline::TokenManager* tokenManager,
        std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration); //建立了一個DispSyncSource物件
    auto throttleVsync = makeThrottleVsyncCallback();
    auto getVsyncPeriod = makeGetVsyncPeriodFunction();
    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager, // 建立了一個EventThread物件
                                                           std::move(interceptCallback),
                                                           std::move(throttleVsync),
                                                           std::move(getVsyncPeriod));
    return createConnection(std::move(eventThread));
}

上面的方法中幹了兩件大事:建立DispSyncSource物件和EventThread物件

 

建立DispSyncSource物件做了啥?

std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
        const char* name, std::chrono::nanoseconds workDuration,
        std::chrono::nanoseconds readyDuration, bool traceVsync) {
    // mVsyncSchedule.dispatch 就是在Scheduler建立時,建立的VSyncDispatchTimerQueue物件
    return std::make_unique<scheduler::DispSyncSource>(*mVsyncSchedule.dispatch, workDuration,
                                                       readyDuration, traceVsync, name);
}

再看DispSyncSource的建構函式:

DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
                               std::chrono::nanoseconds workDuration,
                               std::chrono::nanoseconds readyDuration, bool traceVsync,
                               const char* name)
      : mName(name),
        mValue(base::StringPrintf("VSYNC-%s", name), 0),
        mTraceVsync(traceVsync),
        mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
        mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
        mReadyDuration(readyDuration) {
    mCallbackRepeater =
            std::make_unique<CallbackRepeater>(vSyncDispatch,
                                               std::bind(&DispSyncSource::onVsyncCallback, this,
                                                         std::placeholders::_1,
                                                         std::placeholders::_2,
                                                         std::placeholders::_3),
                                               name, workDuration, readyDuration,
                                               std::chrono::steady_clock::now().time_since_epoch());
}

DispSyncSource中初始化了一些成員變數,建立了一個 物件

CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
                     std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
                     std::chrono::nanoseconds notBefore)
          : mName(name),
            mCallback(cb), // 儲存回撥函式,指向 DispSyncSource::onVsyncCallback
            mRegistration(dispatch,  //   mRegistration是一個VSyncCallbackRegistration物件,繫結了回撥到CallbackRepeater::callback函式
                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
                                    std::placeholders::_2, std::placeholders::_3),
                          mName),
            mStarted(false),
            mWorkDuration(workDuration),
            mReadyDuration(readyDuration),
            mLastCallTime(notBefore) {}

VSyncCallbackRegistration建構函式,

VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
                                                     VSyncDispatch::Callback const& callbackFn,
                                                     std::string const& callbackName)
      : mDispatch(dispatch),
        mToken(dispatch.registerCallback(callbackFn, callbackName)), // 註冊了回撥,callbackFn指向CallbackRepeater::callback
        mValidToken(true) {}

上面的流程就可以看到:最終呼叫了 VSyncDispatchTimerQueue::registerCallback 函式,並且這個回撥函式繫結的是 CallbackRepeater::callback

void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
        ...
        mCallback(vsyncTime, wakeupTime, readyTime); // mCallback 指向 DispSyncSource::onVsyncCallback
       ...
    }

DispSyncSource::onVsyncCallback繼續分發

[/frameworks/native/services/surfaceflinger/Scheduler/DispSyncSource.cpp]
void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
                                     nsecs_t readyTime) {
    VSyncSource::Callback* callback;
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
    }
    ....
    if (callback != nullptr) {
        callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
    }
}

 

DispSyncSource中mCallback是誰設定的呢?指向哪裡? 答案是 EventThread ,稍後我們來看

 

Scheduler::createConnection建立完DispSyncSource後,馬上去建立了一個EventThread物件,並且把DispSyncSource物件作為引數傳遞過去了

看看EventThread的建構函式

[/frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp]
EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                         android::frametimeline::TokenManager* tokenManager,
                         InterceptVSyncsCallback interceptVSyncsCallback,
                         ThrottleVsyncCallback throttleVsyncCallback,
                         GetVsyncPeriodFunction getVsyncPeriodFunction)
      : mVSyncSource(std::move(vsyncSource)), // 儲存 DispVSyncSource 物件
        mTokenManager(tokenManager),
        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
        mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
        mThreadName(mVSyncSource->getName()) {

    LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
            "getVsyncPeriodFunction must not be null");

    mVSyncSource->setCallback(this); // 為 DispVSyncSource 設定回撥
    // 開啟新執行緒,執行threadMain
    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
        std::unique_lock<std::mutex> lock(mMutex);
        threadMain(lock);
    });
    ...
}

 

所以最終VSync事件會來到 EventThread::onVSyncEvent 中,該方法會把事件封裝後存到 mPendingEvents 並喚醒 EventThread::threadMain 做進一步的後續處理。

 

簡單總結下整個 VSync事件 回撥的流程:

 

實際驗證一下,列印呼叫棧資訊:是不是個上面的流程圖一致 ?

11-13 01:15:27.168   223   464 E EventThread: stackdump:#00 pc 000b49e9  /system/bin/surfaceflinger (android::impl::EventThread::onVSyncEvent(long long, long long, long long)+88)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#01 pc 000b3267  /system/bin/surfaceflinger (android::scheduler::DispSyncSource::onVsyncCallback(long long, long long, long long)+122)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#02 pc 000b381b  /system/bin/surfaceflinger (std::__1::__function::__func<std::__1::__bind<void (android::scheduler::DispSyncSource::*)(long long, long long, long long), android::scheduler::DispSyncSource*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&>, std::__1::allocator<std::__1::__bind<void (android::scheduler::DispSyncSource::*)(long long, long long, long long), android::scheduler::DispSyncSource*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&> >, void (long long, long long, long long)>::operator()(long long&&, long long&&, long long&&)+52)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#03 pc 000b387b  /system/bin/surfaceflinger (android::scheduler::CallbackRepeater::callback(long long, long long, long long)+86)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#04 pc 000b396f  /system/bin/surfaceflinger (std::__1::__function::__func<std::__1::__bind<void (android::scheduler::CallbackRepeater::*)(long long, long long, long long), android::scheduler::CallbackRepeater*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&>, std::__1::allocator<std::__1::__bind<void (android::scheduler::CallbackRepeater::*)(long long, long long, long long), android::scheduler::CallbackRepeater*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&> >, void (long long, long long, long long)>::operator()(long long&&, long long&&, long long&&)+52)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#05 pc 000c3d57  /system/bin/surfaceflinger (android::scheduler::VSyncDispatchTimerQueue::timerCallback()+738)
11-13 01:15:27.168   223   464 E EventThread: stackdump:#06 pc 000c3675  /system/bin/surfaceflinger (android::scheduler::Timer::dispatch()+580)

 

 

這樣通過前面的一系列流程的跟蹤,大體理清楚了 VSync Event通過層層callback,最終來到了EventThread::onVSyncEvent 中進行處理。當然後面如何通知到 SF & APP之後再慢慢分析。

 

我們再回到SurfaceFlinger中的initScheduler方法,繼續之前的分析

SurfaceFlinger::initScheduler方法中,連續建立了2個 Connection ,一個名字是“app”,一個名字是“appSf”,每個Connection都有各自對應一個EventThread。

 

2.4 mEventQueue->initVsync 這又做了啥

mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
                           configs.late.sfWorkDuration);

看看initVsync的定義吧

[/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp]
void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
                             frametimeline::TokenManager& tokenManager,
                             std::chrono::nanoseconds workDuration) {
    setDuration(workDuration);
    mVsync.tokenManager = &tokenManager;
    mVsync.registration = std::make_unique<
            scheduler::VSyncCallbackRegistration>(dispatch, // 向 VSyncDispatch 中註冊回撥,繫結到 MessageQueue::vsyncCallback 
                                                  std::bind(&MessageQueue::vsyncCallback, this,
                                                            std::placeholders::_1,
                                                            std::placeholders::_2,
                                                            std::placeholders::_3),
                                                  "sf");
}

是不是和前面講的CallbackRepeater的很相似的處理邏輯,通過構建VSyncCallbackRegistration物件,向VsyncDispatch中註冊了回撥,而且名字是“sf”,這樣MessageQueue::vsyncCallback中就可以收到 vsync event了

 

實際驗證一下,列印呼叫棧資訊:是不是和分析一致 ?

11-13 01:15:43.899   224   529 E SurfaceFlinger: stackdump:#00 pc 000b9837  /system/bin/surfaceflinger (android::impl::MessageQueue::vsyncCallback(long long, long long, long long)+134)
11-13 01:15:43.899   224   529 E SurfaceFlinger: stackdump:#01 pc 000b9f63  /system/bin/surfaceflinger (std::__1::__function::__func<std::__1::__bind<void (android::impl::MessageQueue::*)(long long, long long, long long), android::impl::MessageQueue*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&>, std::__1::allocator<std::__1::__bind<void (android::impl::MessageQueue::*)(long long, long long, long long), android::impl::MessageQueue*, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&> >, void (long long, long long, long long)>::operator()(long long&&, long long&&, long long&&)+52)
11-13 01:15:43.900   224   529 E SurfaceFlinger: stackdump:#02 pc 000c3ccf  /system/bin/surfaceflinger (android::scheduler::VSyncDispatchTimerQueue::timerCallback()+714)
11-13 01:15:43.900   224   529 E SurfaceFlinger: stackdump:#03 pc 000c3605  /system/bin/surfaceflinger (android::scheduler::Timer::dispatch()+580)

 

 

 

 

看到這裡,是不是就清楚了,文章開頭,dumpsys SurfaceFlinger 看到的 VSyncDispatch 中的三個回撥(sf, appSf, app)是怎麼來的了

VSyncDispatch:
	Timer:
		DebugState: Waiting
	mTimerSlack: 0.50ms mMinVsyncDistance: 3.00ms
	mIntendedWakeupTime: 9223369916416.00ms from now
	mLastTimerCallback: 4215.62ms ago mLastTimerSchedule: 4215.54ms ago
	Callbacks: 三個回撥
		sf:  
			workDuration: 15.67ms readyDuration: 0.00ms earliestVsync: -11799.97ms relative to now
			mLastDispatchTime: 4200.02ms ago
		appSf:
			workDuration: 16.67ms readyDuration: 15.67ms earliestVsync: -2153016.50ms relative to now
			mLastDispatchTime: 2153016.50ms ago
		app:  
			workDuration: 16.67ms readyDuration: 15.67ms earliestVsync: -4183.37ms relative to now

 

 

總結重點

收到vsync events的彙集到了兩個地方:

1. MessageQueue::vsyncCallback  ==> VSYNC-sf

2. EventThread::onVSyncEvent  ==> VSYNC-app  & VSYNC-appSf

 

有個疑問:VSyncDispatch 中的三個回撥(sf, appSf, app),他們的用途又是什麼呢?或者說他們產生的回撥用來驅動去做什麼事情呢?

 

三、小結

這篇文章,主要分析了VSync相關的一些初始化的過程,包括和 vsync event的產生和分發相關的元件及事件回撥的流程。

當然,關於vsync的很多細節還是沒分析清楚,也有很多疑問沒解決。再接下來的文章中會再繼續研究,看看能不能得到更多的啟發與理解。

 

參考:

https://juejin.cn/post/6844904013914374152

https://juejin.cn/post/7045996528942448648

https://blog.csdn.net/houliang120/article/details/50908098

相關文章