1. 前言
忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
-- 服装学院的IT男
本篇为 VSync 系列的第五篇,上一篇已经对EventThread::threadMain
有了个大概的印象,本篇来看看应用请求VSync
后是如何接收到VSync
的流程。
本系列为之前学习 SurfaceFlinger 整理的一些笔记,现在分享出来,希望能帮助到有需要的同学。 代码基于 Android 13 ,虽然最新源码源码中部分逻辑已经了,但总体思路还是没有变的,不影响对 VSync 整体逻辑的理解。
VSync 系列目录:
正文
应用请求VSYNC-app
都会执行到EventThread::requestNextVsync
方法,现在是应用首次请求所以现在的请求类型肯定是VSyncRequest::None
。
# EventThread.cpp
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
......
// 1. 现在是VSyncRequest::None
if (connection->vsyncRequest == VSyncRequest::None) {
// 2. 设置为 Single
connection->vsyncRequest = VSyncRequest::Single;
// 3. 并唤醒等待的线程
mCondition.notify_all();
} else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
connection->vsyncRequest = VSyncRequest::Single;
}
}
此时,EventThread 中的等待线程被唤醒,EventThread::threadMain
开始执行。
1. 第一次执行 EventThread::threadMain
# EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
// 定义一个要消费 Vsync 事件的集合
DisplayEventConsumers consumers;
// 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
while (mState != State::Quit) {
std::optional<DisplayEventReceiver::Event> event;
// mPendingEvents 为空不执行
if (!mPendingEvents.empty()) {
......
}
// 是否有应用请求了 vsync
bool vsyncRequested = false;
// 遍历mDisplayEventConnections的各个链接
// Find connections that should consume this event.
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
if (const auto connection = it->promote()) {
// 只要应用链接的集合里有一个应用申请了, syncRequested 就为true
// * 1. 所以当前请求类型已经是 Single 了,所以 vsyncRequested被设置为true
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
// 当前没有event,下面不执行
if (event && shouldConsumeEvent(*event, connection)) {
// 消耗则添加到 consumers 集合
consumers.push_back(connection);
}
++it;
} else {
it = mDisplayEventConnections.erase(it);
}
}
// 现在 consumers 还是空
if (!consumers.empty()) {
......
}
{
// 定义当前线程的下一个状态
State nextState;
// mVSyncState 不为null,vsyncRequested 现在是true
if (mVSyncState && vsyncRequested) {
// * 2. 有应用申请的话则 nextState = State::VSync
nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
nextState = State::Idle;
}
// 第一次执行的时候,mState = Idle ,nextState = VSync 所以不相等
if (mState != nextState) {
if (mState == State::VSync) {
mVSyncSource->setVSyncEnabled(false);
} else if (nextState == State::VSync) {
// * 3. 当前条件走这,打开 Vsync-app
mVSyncSource->setVSyncEnabled(true);
}
// 状态同步,设置为State::VSync
mState = nextState;
}
// 目前没有event
if (event) {
continue;
}
if (mState == State::Idle) {
mCondition.wait(lock);
} else {
// Generate a fake VSYNC after a long timeout in case the driver stalls. When the
// display is off, keep feeding clients at 60 Hz.
// 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒
// * 4. 当前逻辑在这.开始超时等待
const std::chrono::nanoseconds timeout =
mState == State::SyntheticVSync ? 16ms : 1000ms;
if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
......// 超时处理,暂时忽略
}
......// 超时处理,暂时忽略
}
}
}
}
对于这次执行的逻辑代码里有一些针对性的注释,然后关键点有4个,再解释一下:
-
- 在
EventThread::requestNextVsync
中,已将对应连接的vsyncRequest
设置为VSyncRequest::Single
,因此vsyncRequested
为 true,表示有应用请求了 VSync。
- 在
-
- 由于
vsyncRequested
为 true,nextState
被设置为State::VSync
。
- 由于
-
- 这里是关键,
由于 mState
和nextState
不相等,并且nextState = State::VSync
,这个时候表示当前线程本来是闲置状态,则VSYNC-app
也处于关闭状态,现在有应用请求了VSYNC-app
所以要开启VSYNC-app
的发送。 曾将VsyncDispatch
比作VSync
的信号泵,它本处于关闭状态,现在需要他工作了,所以需要“插电,打开开关”
- 这里是关键,
-
- 由于第 3 步的执行,现在需要进入超时等待,正常情况不会触发后续的超时处理,因为在下一个
VSYNC-app
来临的时候就会被再次唤醒
- 由于第 3 步的执行,现在需要进入超时等待,正常情况不会触发后续的超时处理,因为在下一个
上述 4 点是首次执行的关键,第 3 步尤为重要,是后续VSync
请求处理的逻辑基础,否则难以理解第 4 步的超时等待机制。
接下来,深入分析 DispSyncSource::setVSyncEnabled
的具体实现。
2. DispSyncSource::setVSyncEnabled 启动/关闭 VSYNC-app
软件VSync 是按需的所以也有不需要的时候,DispSyncSource::setVSyncEnabled
就是控制VSYNC-app
是启动还是关闭的方法。
# DispSyncSource.cpp
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
// 启动流转
mCallbackRepeater->start(mWorkDuration, mReadyDuration);
} else {
mCallbackRepeater->stop();
}
mEnabled = enable;
}
DispSyncSource
持有一个CallbackRepeater
对象有start
和stop
2个控制VSYNC-app
是否轮转的方法,同时还有一个CallbackRepeater::callback
用于接收VSYNC-app
计时结束回调的方法。
2.1 VSYNC-app 开始轮转
void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
std::lock_guard lock(mMutex);
// 表示处于工作状态
mStarted = true;
// 2个时间的赋值
mWorkDuration = workDuration;
mReadyDuration = readyDuration;
// 开始定时任务
auto const scheduleResult =
mRegistration.schedule({.workDuration = mWorkDuration.count(),
.readyDuration = mReadyDuration.count(),
.earliestVsync = mLastCallTime.count()});
LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
}
mStarted 这个变量代表当前 VSYNC-app 的申请产生是否处于工作状态。
这里调用了VSyncCallbackRegistration::schedule
方法,参数是根据几个时间构造了1个ScheduleTiming
对象。这些时间将参与计算下一次定时多久,
也就是计算出下一个VSYNC-app
是什么时候。
# VSyncDispatchTimerQueue.cpp
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mValidToken) {
return std::nullopt;
}
// mToken 代表是 app appsf sf 的哪一个
return mDispatch.get().schedule(mToken, scheduleTiming);
}
ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
ScheduleTiming scheduleTiming) {
ScheduleResult result;
{
std::lock_guard lock(mMutex);
// 根据token确认是谁请求的 3个: app appsf sf
auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
return result;
}
// 拿到对应的 VSyncDispatchTimerQueueEntry
auto& callback = it->second;
// 获取当前时间
auto const now = mTimeKeeper->now();
......
// 执行3个参数的 schedule 方法
// 重点* 1. 计算出下一个 wakeupTime
result = callback->schedule(scheduleTiming, mTracker, now);
if (!result.has_value()) {
return result;
}
// 重点* 2. 如果符合条件,就开始触发定时
if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
rearmTimerSkippingUpdateFor(now, it);
}
}
return result;
}
-
- 这里一共执行了 3 个
schedule
方法需要注意区分,重点1出,这里现在以黑盒形式了解。ScheduleTiming
这个类下面是3个关键时间,VSyncDispatchTimerQueueEntry::schedule
方法就是根据这3个时间,计算出下一次软件层的VSYNC-app
是什么时候,这个时间就保存在VSyncDispatchTimerQueueEntry
的mArmedInfo
中。
- 这里一共执行了 3 个
-
- 在重点2处,因为重点 1 的执行,
mArmedInfo
下已保存了下次唤醒时间,callback->wakeupTime()
其实就是从mArmedInfo
下获取时间的。
- 在重点2处,因为重点 1 的执行,
VSyncDispatchTimerQueueEntry::wakeupTime
方法 。
# VSyncDispatchTimerQueue.cpp
std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
if (!mArmedInfo) {
return {};
}
// 返回下次唤醒时间
return {mArmedInfo->mActualWakeupTime};
}
然后拿mActualWakeupTime
和mIntendedWakeupTime
比较。这个mIntendedWakeupTime
表示定下次被唤醒的时间,这里可能会有个困扰:wakeupTime 是唤醒时间,mIntendedWakeupTime
又是唤醒时间,这是啥意思。
2.2 wakeupTime 和 mIntendedWakeupTime
-
mIntendedWakeupTime 是 VSyncDispatchTimerQueue 下的成员变量,节拍器是靠定时器完成
SW-VSYNC
的产生的,所以这个mIntendedWakeupTime
代表是下一次计时器结束的时间。mIntendedWakeupTime
的赋值是在启动定时器的时候,当定时到了之后又会被赋值为无穷大。 -
wakeupTime(mArmedInfo->mActualWakeupTime)这个是属于
VSyncDispatchTimerQueueEntry
下的变量。代表的是这个 VSyncDispatchTimerQueueEntry 下次唤醒的时间,根据目前的信息,一共是有3个 :app appsf sf 。
目前是以一个应用请求VSYNC-app
的场景分析的,那假设appsf
和sf
都没有申请,那mIntendedWakeupTime
就等于wakeupTime
。但是正常手机上,app``sf
都是在请求SW-VSYNC
,那这个时候 mIntendedWakeupTime到底是等于哪个
VSyncDispatchTimerQueueEntry的 wakeupTime
就要看是谁设置的定时任务了。
谁先设置了定时任务就会把谁的wakeupTime
设置给mIntendedWakeupTime
。后申请SW-VSYNC
的VSyncDispatchTimerQueueEntry
会因为定时器已经触发了,而不会再触发定时任务了,也就不会把wakeupTime
设置给mIntendedWakeupTime
了,这个时候的mIntendedWakeupTime
就是上一个申请SW-VSYNC
的VSyncDispatchTimerQueueEntry
的wakeupTime
。
正常来说应用先绘制才会有SurfaceFlinger
合成的需求,所以app
是先与sf
申请的,所以当sf
请求VSYNC-sf
的时候想触发定时任务,这个时候会发生定时任务已经执行了(app触发的)。
要区分wakeupTime
和mIntendedWakeupTime
的区别要从各自所属的对象,以及赋值的时间。
3. 定时 rearmTimerSkippingUpdateFor
继续回到主流程,第一次执行mIntendedWakeupTime
还没被赋值,所以是无穷大,所以wakeupTime < mIntendedWakeupTime
满足条件执行rearmTimerSkippingUpdateFor
方法来触发定时。
# VSyncDispatchTimerQueue.cpp
void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
// 定义一个最小时间
std::optional<nsecs_t> min;
std::optional<nsecs_t> targetVsync;
std::optional<std::string_view> nextWakeupName;
// 遍历 3个 app appsf sf 要不要定时
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
// 拿到对应的 entry
auto& callback = it->second;
// 如果有 wakeupTime 才会继续,否则当前的这个回调就不管了
if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
continue;
}
if (it != skipUpdateIt) {
callback->update(mTracker, now);
}
// 拿到对应的 wakeupTime 时间
auto const wakeupTime = *callback->wakeupTime();
// 取3个里最小的 wakeupTime 赋值给 min
if (!min || *min > wakeupTime) {
nextWakeupName = callback->name();
min = wakeupTime;
targetVsync = callback->targetVsync();
}
}
// 有一个定时时间,并且小于 mIntendedWakeupTime 才需要开启定时任务
if (min && min < mIntendedWakeupTime) {
if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
"us; VSYNC in ", ns2us(*targetVsync - now), "us");
ATRACE_NAME(trace.c_str());
}
// * 设置定时任务
setTimer(*min, now);
} else {
ATRACE_NAME("cancel timer");
// 取消定时
cancelTimer();
}
}
min && min < mIntendedWakeupTime
满足才会走setTimer
开始设置定时任务,第一次执行且只有app
请求的话,这个min
就是2.1
计算出的下一次VSYNC-app
的时间,mIntendedWakeupTime
是无穷大,所以满足条件走setTimer
。
# VSyncDispatchTimerQueue.cpp
void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
// 设置时间,赋值后就不是无穷大了
mIntendedWakeupTime = targetTime;
// 触发定时任务
// 时间到了就执行 VSyncDispatchTimerQueue::timerCallback
mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
mIntendedWakeupTime);
mLastTimerSchedule = mTimeKeeper->now();
}
这个方法就是软件层 VSync 产生的关键了:
-
- mIntendedWakeupTime 在这里被赋值,值就是下一次定时时间,是app appsf sf 中最近一次的 WakeupTime
-
- 开启定时任务,定时的时间为 mIntendedWakeupTime ,所以说 mIntendedWakeupTime 就是下一次的定时结束时间
-
- 定时接触后触发 VSyncDispatchTimerQueue::timerCallback ,由这个回调开始触发 SW-VSYNC 的产生
这部分的逻辑如下:(cancelTimer部分暂时可以不看)
4. 定时结束回调处理 VSyncDispatchTimerQueue::timerCallback
定时时间到后,会执行VSyncDispatchTimerQueue::timerCallback
。
# VSyncDispatchTimerQueue.cpp
// 定时到了,回调执行当前 (定时到了走会走到这,但是内部会区分 app appsf sf,有各自的处理)
void VSyncDispatchTimerQueue::timerCallback() {
ATRACE_CALL();
// 定义结构体
struct Invocation {
std::shared_ptr<VSyncDispatchTimerQueueEntry> callback; // 注意这个变量(app appsf sf对应的回调Entry)
nsecs_t vsyncTimestamp;
nsecs_t wakeupTimestamp;
nsecs_t deadlineTimestamp;
};
// 处理 SW-VSYNC 的Entry集合
std::vector<Invocation> invocations;
......
{
std::lock_guard lock(mMutex);
auto const now = mTimeKeeper->now();
mLastTimerCallback = now;
// 遍历 callback (app appsf sf)
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
// 拿到Entry
auto& callback = it->second;
// 拿到其wakeupTime
auto const wakeupTime = callback->wakeupTime();
// 1. 没有对应的定时时间,说明不关心 VSync ,则不需要处理
if (!wakeupTime) {
continue;
}
auto const readyTime = callback->readyTime();
// 这个值肯定大于 0
auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
// wakeupTime = mIntendedWakeupTime 所以后面加了一点时间,就符合if
// 这里我认为是因为代码执行需要时间,所以需要加上一个容错值
if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
// 2. 执行 里面会调用 mArmedInfo.reset 也就是设置为 null
callback->executing();
// 3. 把要执行回调的放到 invocations 下
invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
*wakeupTime, *readyTime});
}
......
}
// 4. 设置为无穷大
mIntendedWakeupTime = kInvalidTime;
// 5. 再启动定时,但是因为 executing 的时候会把 mArmedInfo 时间被置空,所以会 continue
rearmTimer(mTimeKeeper->now());
.....
}
for (auto const& invocation : invocations) {
// 6. 执行回调 (VSyncDispatchTimerQueueEntry::callback)
invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
invocation.deadlineTimestamp);
......
}
}
-
- 对应的 VSyncDispatchTimerQueueEntry 如果没有申请 VSync 则 wakeupTime 为 null 也就不需要执行后续逻辑
-
- 这次定时到了,VSyncDispatchTimerQueueEntry 对应的定时结构体 mArmedInfo 相关的时间就无效了,所以将其重置(为null)
-
- 构建出一个 Invocation 对象放到集合 invocations 中,VSyncDispatchTimerQueueEntry 现在被叫做 callback 也保存在这个结构体中
-
- mIntendedWakeupTime 被设置成无穷大,因为这次定时结束了,mIntendedWakeupTime 这个时候也没有了意义,所以被设置为无穷大
-
- 再次启动定时,如果说 app sf 都请求了 SW-VSYNC ,但是各自的 wakeupTime 不一样,那这个时候只有满足条件的才能执行 2,3 两步,然后产生对应的 VSync,而不满足条件的则说明当前定时结束的视觉不是他的 SW-VSYNC 时间,所以需要继续定时。
-
- 这里就是把触发这个 wakeupTime 是当前时间的回调了。以当前分析的场景来说,就是应用的第一次 VSYNC-app 要产生了。
4.1 第一次 VSYNC-app 产生
VSyncDispatchTimerQueueEntry 定义在 VSyncDispatchTimerQueue.cpp 下
# VSyncDispatchTimerQueue.cpp
void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
nsecs_t deadlineTimestamp) {
{
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = true;
}
// 实际上调的是 mCallback ,构建时赋值
mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = false;
mCv.notify_all();
}
这块回调的执行,在理解VSync-2-app,appsf sf注册回调已经介绍过了:
4.1.1 继续申请 VSYNC-app
根据之前的分析,回调会执行到CallbackRepeater::callback
中,这个方法很重要,处理继续回调VSYNC-app
外,还会触发下一次VSYNC-app
的申请。
# DispSyncSource.cpp
class CallbackRepeater {
......
private:
void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
......
// 重点* 1. 间接执行 DispSyncSource::onVsyncCallback
mCallback(vsyncTime, wakeupTime, readyTime);
{
std::lock_guard lock(mMutex);
// 如果处于关闭状态则返回
if (!mStarted) {
ATRACE_NAME("callback return not mRegistration.schedule");
return;
}
// 重点* 2. 请求 VSync
auto const scheduleResult =
mRegistration.schedule({.workDuration = mWorkDuration.count(),
.readyDuration = mReadyDuration.count(),
.earliestVsync = vsyncTime});
}
}
}
执行 CallbackRepeater::callback 的时候会做2件事:
-
- 执行 mCallback 然后会触发 DispSyncSource::onVsyncCallback 的执行
-
- 如果 DispSyncSource 还处于打开状态的话,则触发申请下一次的 VSync 的申请
mStarted
现在是true
,所以还会继续申请VSync
。
4.1.2 产生 VSYNC-app
然后一路回调,会调用到DispSyncSource::onVsyncCallback
方法。
# DispSyncSource.cpp
void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
nsecs_t readyTime) {
VSyncSource::Callback* callback;
{
std::lock_guard lock(mCallbackMutex);
callback = mCallback;
}
// Vsync-app trace的控制
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
}
if (callback != nullptr) {
// 传递到EventThread
callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
}
}
根据之前的分析,执行的就是EventThread::onVSyncEvent
。
# EventThread.cpp
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
// 1. 构建一个event添加到mPendingEvents
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
vsyncData.expectedPresentationTime,
vsyncData.deadlineTimestamp));
// 2. 环境线程
mCondition.notify_all();
}
这里就往mPendingEvents
里添加了一个Event
,然后又唤醒了线程。
之前分析到 EventThread::threadMain 方法最后是发现进入了超时等待,也就是“第4步”,现在就和它对应上来了。
5. 第二次执行 EventThread::threadMain
线程又被唤醒了,所以又要看EventThread::threadMain
方法了。
# EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
// 定义一个要消费 Vsync 事件的集合
DisplayEventConsumers consumers;
// 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
while (mState != State::Quit) {
std::optional<DisplayEventReceiver::Event> event;
// Determine next event to dispatch.
// 现在里面有值了
if (!mPendingEvents.empty()) {
// 取第一个值给event
event = mPendingEvents.front();
// 移除
mPendingEvents.pop_front();
// 这部分可忽略,正常情况不影响主流程
switch (event->header.type) {
......
}
}
// 是否有应用请求了 vsync
bool vsyncRequested = false;
// 2. 开始遍历mDisplayEventConnections的各个链接
// Find connections that should consume this event.
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
if (const auto connection = it->promote()) {
// 只要应用链接的集合里有一个应用申请了, syncRequested 就为true
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
// 是否要消耗event (见2.6.1 )
if (event && shouldConsumeEvent(*event, connection)) {
// 添加到 consumers 集合
consumers.push_back(connection);
}
++it;
} else {
it = mDisplayEventConnections.erase(it);
}
}
if (!consumers.empty()) {
// 3. 派发到应用端(见2.6.2)
dispatchEvent(*event, consumers);
// 置空
consumers.clear();
}
{
// 4. 状态处理
// 定义当前线程的下一个状态
State nextState;
if (mVSyncState && vsyncRequested) {
// 还是设置为 nextState = State::VSync
nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
nextState = State::Idle;
}
// mState 本来就是State::VSync,所以不执行内部逻辑
if (mState != nextState) {
......
}
if (event) {
// 有事件则重头开始执行
continue;
}
// 这次在上面 continue 了,就不会走进后面的等待逻辑了。
// Wait for event or client registration/request.
if (mState == State::Idle) {
// 当状态为Idle时,无期限等待
mCondition.wait(lock);
} else {
// Generate a fake VSYNC after a long timeout in case the driver stalls. When the
// display is off, keep feeding clients at 60 Hz.
// 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒
const std::chrono::nanoseconds timeout =
mState == State::SyntheticVSync ? 16ms : 1000ms;
if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
......// 超时处理,暂时忽略
}
......// 超时处理,暂时忽略
}
}
}
}
这一次执行的逻辑和前一次就有很大的区别了。
5.1 EventThread::shouldConsumeEvent
# EventThread.cpp
bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
const sp<EventThreadConnection>& connection) const {
......
switch (event.header.type) {
......
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
case VSyncRequest::None:
return false;
case VSyncRequest::SingleSuppressCallback:
// SingleSuppressCallback --> None
connection->vsyncRequest = VSyncRequest::None;
return false;
case VSyncRequest::Single: {
if (throttleVsync()) {
return false;
}
// Single -- > SingleSuppressCallback
connection->vsyncRequest = VSyncRequest::SingleSuppressCallback;
return true;
}
case VSyncRequest::Periodic:
if (throttleVsync()) {
return false;
}
return true;
default:
// We don't throttle vsync if the app set a vsync request rate
// since there is no easy way to do that and this is a very
// rare case
return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
}
......
default:
return false;
}
}
就是对应用链接的 vsyncRequest 做判断,代码看着多但是逻辑很简单
如果应用请求了VSYNC-app
那就会返回true
,同时设置一下connection->vsyncRequest
请求状态的值
5.2 派发 VSync 到应用端
# EventThread.cpp
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
// 遍历消费集合(哪些应用申请了VSync)
for (const auto& consumer : consumers) {
// 拷贝event
DisplayEventReceiver::Event copy = event;
......
// 发送事件
switch (consumer->postEvent(copy)) {
......
}
}
}
这里的逻辑很简单,就是发送一个VSYNC
的事件,看看后续处理
# EventThread.cpp
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
constexpr auto toStatus = [](ssize_t size) {
return size < 0 ? status_t(size) : status_t(NO_ERROR);
};
ATRACE_CALL();
......
// 通过socket 同信的方式发送到应用到
auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return toStatus(size);
}
到这里,应用端的Choreographer$FrameDisplayEventReceiver::onVsync
就会执行一次回调了,也就是一次VSync
来了,应用可以绘制UI
了。
感觉逻辑到这似乎结束了,毕竟应用都收到
但是还有2个点
-
- 这一次分析 EventThread::threadMain 方法的时候最终是执行了 “continue” 说明还要再执行一次 EventThread::threadMain 方法
-
- 4.1.1 小节说了这次 VSYNS-app 产生的时候又触发申请了下一次的
5.3 continue 再次执行 while
由于执行了 continue ,所以又回到了 EventThread::threadMain 方法的下一次 while 语句。
# EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
// 定义一个要消费 Vsync 事件的应用集合
DisplayEventConsumers consumers;
// 只要状态不是退出,则一直循环执行(没任务的时候内部会等待)
while (mState != State::Quit) {
// 定义 event
std::optional<DisplayEventReceiver::Event> event;
// mPendingEvents 的唯一事件上一次执行的时候被移除了,现在是空
if (!mPendingEvents.empty()) {
......
}
// 是否有应用请求了 vsync
bool vsyncRequested = false;
// Find connections that should consume this event.
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
if (const auto connection = it->promote()) {
// 当前应用为 SingleSuppressCallback 了,所以 vsyncRequest 还是true
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
// 当前没有event,下面不执行
if (event && shouldConsumeEvent(*event, connection)) {
......
}
++it;
} else {
it = mDisplayEventConnections.erase(it);
}
}
// 为空
if (!consumers.empty()) {
......
}
{
// vsyncRequested = true
State nextState;
if (mVSyncState && vsyncRequested) {
// 设置 nextState = State::VSync
nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
nextState = State::Idle;
}
// 相同都为 State::VSync
if (mState != nextState) {
......
}
// 目前没有event
if (event) {
continue;
}
// Wait for event or client registration/request.
if (mState == State::Idle) {
// 当状态为Idle时,无期限等待
mCondition.wait(lock);
} else {
// 根据当前状态设置超时时间:若为合成VSYNC状态则设置较短超时(16毫秒),其他情况设置为1000毫秒
const std::chrono::nanoseconds timeout =
mState == State::SyntheticVSync ? 16ms : 1000ms;
//再次进入等待
if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
......// 超时处理,暂时忽略
}
......// 超时处理,暂时忽略
}
}
}
}
这一次啥也没干,陷入了等待,等啥呢? 之前说VSyncRequest
的几个枚举值的时候说了VSyncRequest::Single
会触发2次VSync
,现在只看到了一次,第二次呢?
第二次就是 4.1.1 触发的再一次申请VSYNC-app
,篇幅原因,下一篇看第二次VSync
的流程。
参考