必读:

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

Android 12(S) 图像显示系统 - SurfaceFlinger之VSync-上篇(十六)的更多相关文章

  1. Android 12(S) 图像显示系统 - SurfaceFlinger 之 VSync - 中篇(十七)

    必读: Android 12(S) 图像显示系统 - 开篇 1 前言 这一篇文章,将继续讲解有关VSync的知识,前一篇文章 Android 12(S) 图像显示系统 - SurfaceFlinger ...

  2. Android 12(S) 图像显示系统 - SurfaceFlinger GPU合成/CLIENT合成方式 - 随笔1

    必读: Android 12(S) 图像显示系统 - 开篇 一.前言 SurfaceFlinger中的图层选择GPU合成(CLIENT合成方式)时,会把待合成的图层Layers通过renderengi ...

  3. Android 12(S) 图像显示系统 - drm_hwcomposer 简析(上)

    必读: Android 12(S) 图像显示系统 - 开篇 前言 Android源码中有包含drm_hwcomposer:/external/drm_hwcomposer/ drm_hwcompose ...

  4. Android 12(S) 图像显示系统 - GraphicBuffer同步机制 - Fence

    必读: Android 12(S) 图像显示系统 - 开篇 一.前言 前面的文章中讲解Android BufferQueue的机制时,有遇到过Fence,但没有具体讲解.这篇文章,就针对Fence这种 ...

  5. Android 12(S) 图像显示系统 - 基础知识之 BitTube

    必读: Android 12(S) 图像显示系统 - 开篇 一.基本概念 在Android显示子系统中,我们会看到有使用BitTube来进行跨进程数据传递.BitTube的实现很简洁,就是一对&quo ...

  6. Android 12(S) 图像显示系统 - HWC HAL 初始化与调用流程

    必读: Android 12(S) 图像显示系统 - 开篇 接口定义 源码位置:/hardware/interfaces/graphics/composer/ 在源码目录下可以看到4个版本的HIDL ...

  7. Android 12(S) 图像显示系统 - drm_hwcomposer 简析(下)

    必读: Android 12(S) 图像显示系统 - 开篇 合成方式 合成类型的定义:/hardware/interfaces/graphics/composer/2.1/IComposerClien ...

  8. Android 12(S) 图形显示系统 - SurfaceFlinger的启动和消息队列处理机制(四)

    1 前言 SurfaceFlinger作为Android图形显示系统处理逻辑的核心单元,我们有必要去了解其是如何启动,初始化及进行消息处理的.这篇文章我们就来简单分析SurfaceFlinger这个B ...

  9. Android 12(S) 图形显示系统 - BufferQueue/BLASTBufferQueue之初识(六)

    题外话 你有没有听见,心里有一声咆哮,那一声咆哮,它好像在说:我就是要从后面追上去! 写文章真的好痛苦,特别是自己对这方面的知识也一知半解就更加痛苦了.这已经是这个系列的第六篇了,很多次都想放弃了,但 ...

随机推荐

  1. Kernel Pwn基础教程之 Double Fetch

    一.前言 Double Fetch是一种条件竞争类型的漏洞,其主要形成的原因是由于用户态与内核态之间的数据在进行交互时存在时间差,我们在先前的学习中有了解到内核在从用户态中获取数据时会使用函数copy ...

  2. 到底为什么不建议使用SELECT *?

    "不要使用SELECT *"几乎已经成为了MySQL使用的一条金科玉律,就连<阿里Java开发手册>也明确表示不得使用*作为查询的字段列表,更是让这条规则拥有了权威的加 ...

  3. Java基础 - 注解详解

    What - 什么是注解?        Annontation是Java5开始引入的新特征,中文名称叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素( ...

  4. JavaScript 事件循环(1) —— 从 setTimeout 说起

    转变认知 setTimeout 可能是很多前端工程师爱用的方法,它可以使得一段代码延迟执行,例如: setTimeout(() => console.log('A'), 1000); // 在1 ...

  5. kafka如何保证不重复消费又不丢失数据_Kafka写入的数据如何保证不丢失?

    我们暂且不考虑写磁盘的具体过程,先大致看看下面的图,这代表了 Kafka 的核心架构原理. Kafka 分布式存储架构 那么现在问题来了,如果每天产生几十 TB 的数据,难道都写一台机器的磁盘上吗?这 ...

  6. 使用 Spring Cloud 有什么优势?

    使用 Spring Boot 开发分布式微服务时,我们面临以下问题 与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题. 服务发现-服务发现工具管理群集中的流程和服务如何查找 ...

  7. 攻防世界 web_php_include

    Web_php_include 进入题目源码直接出来了 <?php show_source(__FILE__); echo $_GET['hello']; $page=$_GET['page'] ...

  8. React 可视化开发工具 shadow-widget 的非可视开发方法

    Shadow Widget 提倡在可视设计器中开发用户界面,输出转义标签,而非 JSX.许多童鞋可能不知道 SW 同样支持用 JSX 设计界面,开发体验比原生 React 编程好出很多,本文就介绍这方 ...

  9. 何使用派生类指针指向基类,即downcast向下转型?

    基类指针指向派生类,我们已经很熟了.假如我们想用派生类反过来指向基类,就需要有两个要求:1)马克-to-win:基类指针开始时指向派生类,2)我们还需要清清楚楚的转型一下. if you want t ...

  10. vue配置请求转发解决跨域问题

    通过nodejs的请求转发到后台,前端地址:http://localhost:8080   后端地址:http://localhost:8081 vue.config.js内容如下: let prox ...