必讀:
Android 12(S) 影像顯示系統 - 開篇
一、前言
為了提高Android系統的UI互動速度和操作的流暢度,在Android 4.1中,引入了Project Butter,即“黃油計劃”。就像該計劃的名字那樣,Google期望通過這一新的機制可以讓Android系統擺脫UI互動時給使用者帶來的滯後感,從而像黃油一樣順滑。
當然優化是無止境的,Project Butter只是邁出了重要的第一步,後續的Android版本中陸續也有引入一些其它的優化機制,促進UI渲染效能的不斷提升。
Project Butter對Android Display系統進行了重構,引入了三個核心元素:VSync
、Triple Buffer
和Choreographer
。從這篇文章開始,我們就來看一看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硬體模組根據螢幕重新整理率產生。VSyncTracker
、VsyncPredictor
根據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對外提供addPresentFence
addHwVsyncTimestamp
方法,把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