前言:
vsync信号其实主要有两种,APP和SF两种。
(资料图)
两种类似的信号分别具有以下的作用:
1.APP类型,我们常说的Vsync信号其实指的就是这种类型。
2.SF类型,我感觉有可能是SurfaceFlinger的缩写,这个同步信号主要是通知进行数据buffer的合成。
本文主要探讨的主APP类型的Vsync信号,SF类型的会在另外一篇文章,View绘制流程中讲解。
一.整体流程简介
我把app-VSync的整个流程分为四大块:
第一块,APP侧发出请求信号,通知到SurfaceFlinger;
第二块,SurfaceFlinger收到通知后,作为消费者侧去缓存池中查询是否存在VSYNC,如果有,则通知APP侧。
第三块,SurfaceFlinger中的生产者逻辑,生产下一次的Vsync信号。
第四块,APP侧收到Vsync信号后进行处理,最终完成绘制流程。
整体的流程图如下图所示,后续文章也会按照这四大块流程去细讲。
二.客户端发出信号
2.1 java端流转
我们把代码的开始点设置为ViewRootImpl中的scheduleTraversals方法,如果想了解这个方法之前的流程,可以参看我的另外一篇文章:
View绘制流程2-安卓是如何执行measure/layout/draw三个绘制流程_失落夏天的博客-CSDN博客
scheduleTraversals是负责渲染流程的,界面上任何布局上的改动,最终都会执行这个方法进行刷新操作。scheduleTraversals会通过Choreographer的postCallback方法去请求Vsync信号并且设置回调方法。
mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Choreographer中的最终实现是postCallbackDelayedInternal方法:
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { ... synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { scheduleFrameLocked(now); } ... } }
这个方法会把回调加入到mCallbackQueues中,然后通过scheduleFrameLocked方法开始请求Vsync信号。
scheduleFrameLocked中又会进行层层传递,最终调用到native方法。传递关系如下:
scheduleFrameLocked(Choreographer.java)->scheduleVsyncLocked(Choreographer.java)->scheduleVsync(DisplayEventReceiver.java)->nativeScheduleVsync(DisplayEventReceiver.java)
2.2 native方法中的逻辑流转
nativeScheduleVsync在native层的注册是DisplayEventReceiver.cpp中的nativeScheduleVsync方法,方法中通过NativeDisplayEventReceiver的scheduleVsync来完成请求:
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { spreceiver = reinterpret_cast(receiverPtr); status_t status = receiver->scheduleVsync(); ...}
NativeDisplayEventReceiver是DisplayEventDispatcher的子类,scheduleVsync方法会执行到DisplayEventDispatcher中的scheduleVsync方法,调用DisplayEventReceiver的requestNextVsync继续请求流程。
status_t DisplayEventDispatcher::scheduleVsync() { if (!mWaitingForVsync) { ... status_t status = mReceiver.requestNextVsync(); ... mWaitingForVsync = true; ... } return OK;}
这里有一个本地变量mWaitingForVsync,如果请求了一次sync,就会改为true,接下来的Vsync请求,都不会传输到SurfaceFlinger一层了,避免重复无意义请求。只有等到收到Vsync信号的时候,才会改为false。
DisplayEventReceiver中,会交给mEventConnection处理:
status_t DisplayEventReceiver::requestNextVsync() { if (mEventConnection != nullptr) { mEventConnection->requestNextVsync(); return NO_ERROR; } return NO_INIT;}
mEventConnection其实是一个binder客户端,是在创建DisplayEventReceiver的时候通过binder方法创建的,其binder服务端实现在SurfaceFlinger进程侧的EventThread.cpp。
DisplayEventReceiver::DisplayEventReceiver( ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::EventRegistrationFlags eventRegistration) { spsf(ComposerService::getComposerService()); if (sf != nullptr) { mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration); ... }}
三.SurfaceFlinger端Vsync信号消费者
首先,SurfaceFlinger的总体结构图如下,SurfaceFlinger中存在一个Scheduler,Scheduler中存在多个VsyncDispatch。其中VSYNC-app负责所有APP的VSYNC信号的处理,本文主要讲的也是这个流程中的。
其次,下图是主流程图中的一部分,也是本章要讲的内容。
3.1 EventThread收到通知后,转发EventThread的工作线程
是接收方法如下,转发到mEventThread的requestNextVsync方法中。
binder::Status EventThreadConnection::requestNextVsync() { ATRACE_CALL(); mEventThread->requestNextVsync(this); return binder::Status::ok();}
我们接着看一下EventThread中的requestNextVsync方法:
void EventThread::requestNextVsync(const sp& connection) { ... if (connection->vsyncRequest == VSyncRequest::None) { connection->vsyncRequest = VSyncRequest::Single; mCondition.notify_all(); } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) { connection->vsyncRequest = VSyncRequest::Single; }}
这里的逻辑很简单,如果当前的VSYNC状态是None的话,释放锁mCondition。
这里既然notify_all,那么一定有地方wait等待锁,而等待的地方就是threadMain方法。
3.2 threadMain方法
这个方法算是整个Vsync流程的核心,它是一个无限循环的模式,其作用是不断的从mPendingEvents中获取Vsync信号,然后转交给APP端。并且在一次Vsync流程结束后,又通过VsyncSource请求下一次的Vsync信号。
threadMain方法是EventThread类初始化的时候创建的线程去执行的方法:
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS { std::unique_locklock(mMutex); threadMain(lock); });
我们看一下精简后的threadMain方法:
void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; //只要没有退出,就一直循环 while (mState != State::Quit) { 执行以下1-7的操作 }}
总体来说,分为以下四大步骤:
1.作为消费者尝试从mPendingEvents中获取Vsync信号,如果获取成功,则赋值给event。
std::optionalevent; //查看mPendingEvents中是否存在Vsync信号 if (!mPendingEvents.empty()) { event = mPendingEvents.front(); mPendingEvents.pop_front(); ... }
2.计算vsyncRequested的状态,只要客户端消费者的Connection保持连接,则vsyncRequested=true,并且上面步骤一获取到event的话,则把消费者的connection加入到consumers集合中。
bool vsyncRequested = false; //获取当前的状态,并且判断是否有客户端的消费者在请求,如果有则加入到consumers集合中 auto it = mDisplayEventConnections.begin(); while (it != mDisplayEventConnections.end()) { if (const auto connection = it->promote()) { //客户端还是处于请求的状态 vsyncRequested |= connection->vsyncRequest != VSyncRequest::None; if (event && shouldConsumeEvent(*event, connection)) { consumers.push_back(connection); } ++it; } else { it = mDisplayEventConnections.erase(it); } }
3.如果consumers集合不为空,则进行消费。把Vsync信号分发给消费者。(具体步骤我们下一小节中讲)
//如果消费者不为空,则通过dispatchEvent方法最终通知到APP一侧 if (!consumers.empty()) { dispatchEvent(*event, consumers); consumers.clear(); }
4.获取下一个状态
//mVSyncState不会为空,则主要是根据vsyncRequested来判断的。vsyncRequested上面计算的 State nextState; if (mVSyncState && vsyncRequested) { nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; } else { ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected"); nextState = State::Idle; }
5.进行判断,确定是否需要请求VSYNC信号。这一块挺有意思的,简单理解如下:
如果当前是VSYNC状态,下一个状态也是VSYNC状态,那么说明信号还没来,所以没必要重复发送。
如果当前是Idle状态,下一个状态是VSYNC状态,那么则要进行VSYNC信号请求。
如果当前是VSYNC状态,下一个状态也是Idle状态,那么说明信号已经来了,下一次的客户端请求还没来,所以不要进行VSYNC信号请求,则会进行取消操作。
if (mState != nextState) { if (mState == State::VSync) { mVSyncSource->setVSyncEnabled(false); } else if (nextState == State::VSync) { //如果下一个状态还是VSync,则继续去请求VSYNC信号 mVSyncSource->setVSyncEnabled(true); } mState = nextState; }
如何开始和结束去进行VSYNC信号获取的获取操作,我们第四章中讲,这个主要就是消费者逻辑了。
6.如果event为空,说明mPendingEvents中已经取光了,则进入休眠操作。
反之event不为空,说明mPendingEvents中也许还存在未消费的VSYNC信号,则contine继续消费。
//如果处理了event,那么说明此次已经拿到了Vsync信号,说明后面有可能还有,则继续拿 if (event) { continue; }
7.进入休眠或者超时之后主动模拟信号加入到mPendingEvents中。
//说明Vsync信号已经消费完了,则进入休眠模式,等到APP侧的下一次通知进行唤醒 // Wait for event or client registration/request. 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. const std::chrono::nanoseconds timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { if (mState == State::VSync) { ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName); std::string debugInfo = "VsyncSource debug info:\n"; mVSyncSource->dump(debugInfo); // Log the debug info line-by-line to avoid logcat overflow auto pos = debugInfo.find("\n"); while (pos != std::string::npos) { ALOGW("%s", debugInfo.substr(0, pos).c_str()); debugInfo = debugInfo.substr(pos + 1); pos = debugInfo.find("\n"); } } LOG_FATAL_IF(!mVSyncState); const auto now = systemTime(SYSTEM_TIME_MONOTONIC); const auto deadlineTimestamp = now + timeout.count(); const auto expectedVSyncTime = deadlineTimestamp + timeout.count(); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, ++mVSyncState->count, expectedVSyncTime, deadlineTimestamp)); } }
3.3 dispatchEvent方法把Vsync信号分发给消费者
首先遍历消费者,调用postEvent进行通知
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { ... switch (consumer->postEvent(copy)) { } }}
然后postEvent方法中,调用sendEvent进行信号的发送
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { ... auto size = DisplayEventReceiver::sendEvents(&mChannel, mPendingEvents.data(), mPendingEvents.size()); ...}
最终通过Socket的方法进行信号的发送,接受者就是APP侧了。
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count){ return gui::BitTube::sendObjects(dataChannel, events, count);}
四.SurfaceFlinger端生产者
上面讲到通过setVSyncEnabled方法去开始或者结束获取Vsync信号的操作。
4.1 获取VSYNC信号
setVSyncEnabled方法如下:
void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { mCallbackRepeater->start(mWorkDuration, mReadyDuration); } else { mCallbackRepeater->stop(); } mEnabled = enable;}
对应的其实就是mCallbackRepeater的start和stop方法,其实现类是DispSyncSource.cpp中的CallbackRepeater。
我们这里看到一个成员变量mWorkDuration,这个值其实就是控制Vscyn触发时间的。这个我们后续小节再讲,这里只是知道有这个值就好了。
4.2 把时间设置给Timer定时触发
start方法中,记录一下传入的workDuration时间,然后传递给mRegistration处理。
void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) { std::lock_guard lock(mMutex); mStarted = true; mWorkDuration = workDuration; mReadyDuration = readyDuration; auto const scheduleResult = mRegistration.schedule({.workDuration = mWorkDuration.count(), .readyDuration = mReadyDuration.count(), .earliestVsync = mLastCallTime.count()}); }
mRegistration的实现类是VSyncCallbackRegistration,其中schedule方法也是交给VSyncDispatchTimerQueue来处理:
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) { if (!mValidToken) { return std::nullopt; } return mDispatch.get().schedule(mToken, scheduleTiming);}
schedule方法中,进行一系列的合法判断,最终会交给 rearmTimerSkippingUpdateFor方法处理。
然后我们就可以看到rearmTimerSkippingUpdateFor中去调用setTimer方法去设置定时触发。
rearmTimerSkippingUpdateFor方法略,
setTimer方法如下:
void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) { mIntendedWakeupTime = targetTime; mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this), mIntendedWakeupTime); mLastTimerSchedule = mTimeKeeper->now();}
则到了targetTime之后,就会执行timerCallBack方法。
4.3 生成Vsync信号加入mPendingEvents
timerCallback方法如下:
void VSyncDispatchTimerQueue::timerCallback() { struct Invocation { std::shared_ptrcallback; nsecs_t vsyncTimestamp; nsecs_t wakeupTimestamp; nsecs_t deadlineTimestamp; }; std::vectorinvocations; { std::lock_guard lock(mMutex); auto const now = mTimeKeeper->now(); mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { auto& callback = it->second; auto const wakeupTime = callback->wakeupTime(); if (!wakeupTime) { continue; } auto const readyTime = callback->readyTime(); auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast(0)); if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) { callback->executing(); invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime, *readyTime}); } } mIntendedWakeupTime = kInvalidTime; rearmTimer(mTimeKeeper->now()); } for (auto const& invocation : invocations) { invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp, invocation.deadlineTimestamp); }
这里的核心逻辑其实就是遍历mCallbacks,然后分别回调。
那么mCallbacks是怎么添加的呢? CallbackRepeater创建的时候,回去注册 mRegistration,同时会传入CallbackRepeater::callback方法作为回调,所以mCallbacks其实就是CallbackRepeater::callback。
void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { ... mCallback(vsyncTime, wakeupTime, readyTime); ... }
很明显直接交给mCallback处理,所以我们又得看一下这个mCallback从何而来。
这个mCallback是CallbackRepeater创建时传入的DispSyncSource::onVsyncCallback方法:
mCallbackRepeater = std::make_unique(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::onVsyncCallback方法:
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}); }}
又是回调,这里很绕。这里的callback其实就是EventThread,仍然是在创建EventThread的时候设置的:
EventThread::EventThread(std::unique_ptrvsyncSource, android::frametimeline::TokenManager* tokenManager, InterceptVSyncsCallback interceptVSyncsCallback, ThrottleVsyncCallback throttleVsyncCallback, GetVsyncPeriodFunction getVsyncPeriodFunction) : mVSyncSource(std::move(vsyncSource)), 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); ...}
所以,终于可以看到尽头了。最终其实就是调用到EventThread的onVSyncEvent方法:
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) { std::lock_guardlock(mMutex); LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp)); mCondition.notify_all();}
这里我们看到,会生成一个VSync信号,加入到mPendingEvents集合中,并且发出通知,让threadMain去获取,从而完成了VSync信号的生产者流程。
画了如下的surfaceFlinger结构图,方便理解(非完整版):
五.APP层收到信号进行刷新
本章讲的主要流程如下图红圈所示:
5.1 APP端接受流程
3.3小节中讲到,SurfaceFlinger会通过BitTube的方式传递给APP侧Vsync信号。发送vscyn信号的方法在DisplayEventReceiver.cpp中,而接收方法也在这个类当中。而具体调用方则是DisplayEventDispatcher.cpp中的dispatchVsync方法。流程如下图所示:
5.2 dispathVsync分发流程
上面在handleEvent中,processPendingEvents获取到了Vsync信号VsyncEventData后,交给dispatchVsync方法负责处理。
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
dispatchVsync方法的实现者是android_view_DisplayEventReceiver.cpp,如下:
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, VsyncEventData vsyncEventData) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ... jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId.value, count, javaVsyncEventData); ...}
我们可以看到,先是把VsyncEventData转换为java可以接受的jobject对象,然后通过CallVoidMethod方法通知到java层中DisplayEventReceiver.java中的dispatchVsync方法。
5.3 java中流程流转
首先DisplayEventReceiver中dispatchVsync方法被调用:
// Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData); }
该方法中直接调用onVsync方法,调用到Choreographer.java中FrameDisplayEventReceiver下的onVsync方法:
@Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { try { ... if (timestampNanos > now) { timestampNanos = now; } if (mHavePendingVsync) { } else { mHavePendingVsync = true; } mTimestampNanos = timestampNanos; mFrame = frame; mLastVsyncEventData = vsyncEventData; Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
onVsync方法中,主要判断时间。如果timestampNanos>now,则是用当前时间。所以还是以方法的调用时间为准。然后通过handle转发到主线程中执行。
Message.obj=this,本身FrameDisplayEventReceiver又实现了Runnable接口,所以自然会执行FrameDisplayEventReceiver下的run方法:
@Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame, mLastVsyncEventData); }
这时候我们就看到,执行到了doFrame方法,而这个方法也是就是渲染流程的执行者。
5.4 如何触发handleEvent流程?
讲到这里,你或许有个疑问,上面流程中,如何执行到5.1中的handleEvent方法的呢?
主要是下图所示的流程:
如果你断点调试的时候,会发现下面所示的这个方法,竟然是主线程调用的:
DisplayEventReceiver.java // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, long frameTimelineVsyncId, long frameDeadline, long frameInterval) { onVsync(timestampNanos, physicalDisplayId, frame, new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval)); }
为什么用竟然呢?因为一般来看,应该是子线程等待接受SurfaceFlinger的信号,收到了信号后交给主线程处理,如果是主线程去等待,岂不是主线程阻塞了?
这里使用looper.addFd()方法,在该方法中,用到了一个epoll_ctl的机制,即对FD文件进行监听,当FD改变时触发主线程的回调。如果处理完回调任务,则会进入epoll_wait的阻塞,继续监听。
六.扩展问题
问:高频次请求vsync信号,会突破60FPS的限制吗?
答:不会。
首先ViewRootImpl中做了一层处理,哪怕16ms改变了很多View的布局,最终执行到了scheduleTraversals方法时,因为有如下的判断,所以都只会执行一次vsync信号的请求和注册一次回调,直至收到VSYNC信号。
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } }
取消限制:
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false;}
其次,2.2小节中讲到,native请求VSYNC信号时也有一次限制,等到VSYNC信号时是不会再次发送请求的。
status_t DisplayEventDispatcher::scheduleVsync() { if (!mWaitingForVsync) { ... status_t status = mReceiver.requestNextVsync(); ... mWaitingForVsync = true; ... } return OK;}
七.参考资料
https://www.jianshu.com/p/6083c590521b
https://www.jianshu.com/p/386bbb5fa29a //努比亚技术团队文章
八.声明
1.本文是原创,根据网上资料和阅读ASOP的源码之后得出的结论,如有问题,欢迎指出。
2.图中涉及到的流程图如果想要高清大图或者pos格式的原图,可以私信我。