SurfaceFlinger內部有兩個EventThread,一個負責app端對Vsync信號的監聽處理,一個負責SurfaceFlinger對Vsync信號的監聽處理。SurfaceFlinger內部維持了一個MessageQueue,當SurfaceFlinger端的EventThread監測到Vsync事件,會觸發INVALIDATE操作,即當前的圖層失效了,需要重新計算刷新。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::onFirstRef()
{
mEventQueue.init(this);
}
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread);
/frameworks/native/services/surfaceflinger/MessageQueue.cpp
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEventTube = mEvents->getDataChannel();
mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
每個EventThread內部都維持一個mDisplayEventConnections,記錄了所有跟這個EventThread的Connection對象的集合。app端通過createDisplayEventConnection構建一個Connection,SurfaceFlinger端通過setEventThread–>createEventConnection。app端的Connection可能不止一個,SurfaceFlinger端的Connection只有一個。
Connection的作用是什麼?先看看Connection的構造函數:
/frameworks/native/services/surfaceflinger/EventThread.cpp
EventThread::Connection::Connection(
const sp<EventThread>& eventThread)
: count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}
mEventThread初始化爲連接到的EventThread,即是將保存到這個EventThread中的mDisplayEventConnections中。count值表示Connection是否有感興趣的事件(通常這個感興趣的事件就是Vsync)。-1表示感興趣的事件已經被處理或者沒有感興趣的事件(因爲初始化爲-1),0表示一次性的感興趣的事件,這種事件被處理後count值會變成-1,大於等於1表示是連續事件。mChannel是一個BitTube,可以將其理解是用socketpair調用創建的兩個互相連接的套接字,Android將其作爲管道用,MessageQueue::setEventThread將監聽讀端的套接字的輸入事件,從而回調cb_eventReceiver進行處理。
EventThread的構造函數中,會對mVSyncEvent進行初始化,mVSyncEvent是一個長度爲2的DisplayEventReceiver::Event數組,用來存儲主屏幕(下標爲0)和外界屏幕(下標爲1)的Vsync事件的信息,如id,時間戳,count值(這個count值表示接收到的Vsync事件數量)等。然後在onFirstRef中,EventThread會進入threadLoop循環。
/frameworks/native/services/surfaceflinger/EventThread.cpp
EventThread::EventThread(const sp<VSyncSource>& src)
: mVSyncSource(src),
mUseSoftwareVSync(false),
mVsyncEnabled(false),
mDebugVsyncEnabled(false),
mVsyncHintSent(false) {
for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[i].header.id = 0;
mVSyncEvent[i].header.timestamp = 0;
mVSyncEvent[i].vsync.count = 0;
}
struct sigevent se;
se.sigev_notify = SIGEV_THREAD;
se.sigev_value.sival_ptr = this;
se.sigev_notify_function = vsyncOffCallback;
se.sigev_notify_attributes = NULL;
timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
}
threadLoop看似很簡短,但其實內部比較複雜。
/frameworks/native/services/surfaceflinger/EventThread.cpp
bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp<EventThread::Connection> > signalConnections;
signalConnections = waitForEvent(&event);
// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Connection>& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
// The destination doesn't accept events anymore, it's probably
// full. For now, we just drop the events on the floor.
// FIXME: Note that some events cannot be dropped and would have
// to be re-sent later.
// Right-now we don't have the ability to do this.
ALOGW("EventThread: dropping event (%08x) for connection %p",
event.header.type, conn.get());
} else if (err < 0) {
// handle any other error on the pipe as fatal. the only
// reasonable thing to do is to clean-up this connection.
// The most common error we'll get here is -EPIPE.
removeDisplayEventConnection(signalConnections[i]);
}
}
return true;
}
首先看EventThread::waitForEvent,該函數用來等待一個Connection發生感興趣的事件,即Vsync事件。我們從EventThread初始化開始分析,條理會比較清晰。初始化時,timestamp爲0,會直接mDisplayEventConnections中尋找發生了Vsync的Connection,條件是遍歷mDisplayEventConnections中的所用Connection,若發現其count值是0或1或者接收到的Vsync事件數量能夠被Connection的count值整除,則認爲發生了Vsync,將這個Connection加入到signalConnections中。根據Connection的count值的不同,一次性事件(count爲0)發生的Connection會將其count值置爲-1,而連續事件發生的Connection不需要重置。waitForVSync表示是否有一個Connection是否對Vsync感興趣,當一個不爲null的Connection的count大於等於0時,waitForVSync就會被設爲true。
初始化時,timestamp是0,waitForVSync爲false,因此線程會阻塞在mCondition.wait中。mCondition喚醒的條件之一是由Vsync事件到來。
/frameworks/native/services/surfaceflinger/EventThread.cpp
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
Vector< sp<EventThread::Connection> > signalConnections;
do {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
*event = mVSyncEvent[i];
mVSyncEvent[i].header.timestamp = 0;
vsyncCount = mVSyncEvent[i].vsync.count;
break;
}
}
if (!timestamp) {
// no vsync event, see if there are some other event
eventPending = !mPendingEvents.isEmpty();
if (eventPending) {
// we have some other event to dispatch
*event = mPendingEvents[0];
mPendingEvents.removeAt(0);
}
}
// find out connections waiting for events
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
bool added = false;
if (connection->count >= 0) {
// we need vsync events because at least
// one connection is waiting for it
waitForVSync = true;
if (timestamp) {
// we consume the event only if it's time
// (ie: we received a vsync event)
if (connection->count == 0) {
// fired this time around
connection->count = -1;
signalConnections.add(connection);
added = true;
} else if (connection->count == 1 ||
(vsyncCount % connection->count) == 0) {
// continuous event, and time to report it
signalConnections.add(connection);
added = true;
}
}
}
if (eventPending && !timestamp && !added) {
// we don't have a vsync event to process
// (timestamp==0), but we have some pending
// messages.
signalConnections.add(connection);
}
} else {
// we couldn't promote this reference, the connection has
// died, so clean-up!
//Connection已經無效
mDisplayEventConnections.removeAt(i);
--i; --count;
}
}
// Here we figure out if we need to enable or disable vsyncs
if (timestamp && !waitForVSync) {
// we received a VSYNC but we have no clients
// don't report it, and disable VSYNC events
disableVSyncLocked();
} else if (!timestamp && waitForVSync) {
// we have at least one client, so we want vsync enabled
// (TODO: this function is called right after we finish
// notifying clients of a vsync, so this call will be made
// at the vsync rate, e.g. 60fps. If we can accurately
// track the current state we could avoid making this call
// so often.)
enableVSyncLocked();
}
// note: !timestamp implies signalConnections.isEmpty(), because we
// don't populate signalConnections if there's no vsync pending
if (!timestamp && !eventPending) {
// wait for something to happen
if (waitForVSync) {
// This is where we spend most of our time, waiting
// for vsync events and new client registrations.
//
// If the screen is off, we can't use h/w vsync, so we
// use a 16ms timeout instead. It doesn't need to be
// precise, we just need to keep feeding our clients.
//
// We don't want to stall if there's a driver bug, so we
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
// FIXME: how do we decide which display id the fake
// vsync came from ?
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
} else {
// Nobody is interested in vsync, so we just want to sleep.
// h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
//初始化時會阻塞於此
mCondition.wait(mLock);
}
}
} while (signalConnections.isEmpty());
// here we're guaranteed to have a timestamp and some connections to signal
// (The connections might have dropped out of mDisplayEventConnections
// while we were asleep, but we'll still have strong references to them.)
return signalConnections;
}
Vsync怎麼產生的呢?之前有提到HWComposer的構造函數會註冊一些回調函數到hwc層:hook_invalidate和hook_vsync。其中hook_vsync就是產生硬件Vsync後進行的回調函數。產生硬件Vsync的代碼在廠家的hwc HAL層代碼中,我們直接看回調函數的代碼。
HWComposer::vsync帶回了兩個參數:第一個參數是display id,第二個參數是Vsync產生的時間戳。mEventHandler表示的就是SurfaceFlinger。
/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
void HWComposer::vsync(int disp, int64_t timestamp) {
if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
{
Mutex::Autolock _l(mLock);
// There have been reports of HWCs that signal several vsync events
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
if (timestamp == mLastHwVSync[disp]) {
ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
timestamp);
return;
}
mLastHwVSync[disp] = timestamp;
}
char tag[16];
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
mEventHandler.onVSyncReceived(disp, timestamp);
}
}
當對應的屏幕是主屏幕且已打開Vsync時,通過DispSync::addResyncSample的返回值needsHwVsync決定要不要繼續打開Vsync或者關閉Vsync。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
bool needsHwVsync = false;
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (type == 0 && mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
}
}
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
DispSync::addResyncSample接收以個Vsync的事件戳作爲參數,是怎麼計算出是否需要開啓Vsync的呢?mPrimaryDispSync內部維持了一個長度爲32的時間戳數組mResyncSamples,而addResyncSample要做的,就是將這次Vsync事件的事件戳加入到裏面去,重新更新Vsync模型,並根據結果決定是否開啓Vsync。mFirstResyncSample在時間戳總數未達到32時,記錄的是mResyncSamples的首個元素位置,也就是0;在時間戳總數達到32時,記錄的是插入新的時間戳的位置。mNumResyncSamples表示當前的時間戳總數,最大爲32。mResyncSamples裏面的時間戳按從舊到新進行排列,總是保留最新的時間戳,如果時間戳數量大於32個的話,則新加入的時間戳會覆蓋掉時間最早的時間戳。updateModelLocked用來更新Vsync模型。
如果kIgnorePresentFences的值爲true,則根據DispSyncThread是否存在Vsync事件回調決定是否開啓Vsync,若存在則開啓;如果kIgnorePresentFences的值爲false,週期mPeriod爲0或者偏差mError大於閾值kErrorThreshold時,則需要開啓Vsync進行校正。
/frameworks/native/services/surfaceflinger/DispSync.cpp
bool DispSync::addResyncSample(nsecs_t timestamp) {
Mutex::Autolock lock(mMutex);
size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
mResyncSamples[idx] = timestamp;
if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
mNumResyncSamples++;
} else {
mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
}
updateModelLocked();
if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
resetErrorLocked();
}
if (kIgnorePresentFences) {
// If we don't have the sync framework we will never have
// addPresentFence called. This means we have no way to know whether
// or not we're synchronized with the HW vsyncs, so we just request
// that the HW vsync events be turned on whenever we need to generate
// SW vsync events.
return mThread->hasAnyEventListeners();
}
return mPeriod == 0 || mError > kErrorThreshold;
}
當定義了宏RUNNING_WITHOUT_SYNC_FRAMEWORK或者app Vsync相移和SurfaceFlinger vsync相移均爲0時,kIgnorePresentFences 爲true;否則爲false。
/frameworks/native/services/surfaceflinger/DispSync.h
// Ignore present (retire) fences if the device doesn't have support for the
// sync framework, or if all phase offsets are zero. The latter is useful
// because it allows us to avoid resync bursts on devices that don't need
// phase-offset VSYNC events.
#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
(VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
static const bool kIgnorePresentFences = true;
#else
static const bool kIgnorePresentFences = false;
#endif
當樣本時間戳數量大於等於3時,纔會更新Vsync模型。更新Vsync模型的方式如下。1.週期mPeriod:從最舊的時間戳起,用第二舊的時間戳減去最舊的時間戳得到期間Vsync間隔時間;然後用第三舊的時間戳減去第二舊的時間戳得到期間Vsync的間隔時間。。。直到得到時間戳總數減1數量(mNumResyncSamples - 1)的Vsync間隔時間總和,求取其平均值即爲週期mPeriod 。2.相移mPhase:以mPeriod 爲週期,算出其角速度scale=2pi/mPeriod ,對於mNumResyncSamples個時間戳,分別計算出它們的相移角度samplePhase=時間戳%週期*角速度。sampleAvgX爲相移角度的cos值的累加,sampleAvgY爲相移角度的sin值的累加值。sampleAvgX和sampleAvgY分別爲sampleAvgX和sampleAvgY的平均值。atan2(sampleAvgY, sampleAvgX)計算出平均每個時間戳的偏移角度,除以角速度就是相移mPhase,準確點叫相移時間。爲確保mPhase爲正數,當計算出的mPhase小於0時,爲其加上mPeriod 得到一個新的mPhase值。最後通過updateModel將mPeriod 和mPhase設置到DispSyncThread裏面。
/frameworks/native/services/surfaceflinger/DispSync.cpp
void DispSync::updateModelLocked() {
if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
nsecs_t durationSum = 0;
for (size_t i = 1; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
durationSum += mResyncSamples[idx] - mResyncSamples[prev];
}
mPeriod = durationSum / (mNumResyncSamples - 1);
double sampleAvgX = 0;
double sampleAvgY = 0;
double scale = 2.0 * M_PI / double(mPeriod);
for (size_t i = 0; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
nsecs_t sample = mResyncSamples[idx];
double samplePhase = double(sample % mPeriod) * scale;
sampleAvgX += cos(samplePhase);
sampleAvgY += sin(samplePhase);
}
sampleAvgX /= double(mNumResyncSamples);
sampleAvgY /= double(mNumResyncSamples);
mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
if (mPhase < 0) {
mPhase += mPeriod;
}
if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
ATRACE_INT64("DispSync:Phase", mPhase);
}
// Artificially inflate the period if requested.
mPeriod += mPeriod * mRefreshSkipCount;
mThread->updateModel(mPeriod, mPhase);
}
}
最初,DispSyncThread在threadLoop過程中會因爲mPeriod爲0而阻塞,updateModel會將其喚醒。
/frameworks/native/services/surfaceflinger/DispSync.cpp
void updateModel(nsecs_t period, nsecs_t phase) {
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = phase;
mCond.signal();
}
那麼問題來了,mThread->hasAnyEventListeners返回的是false(這裏假定的情況是app和SurfaceFlingfer的Vsync相移爲0),導致Vsync會進入關閉狀態,這樣剛產生了一次的Vsync又關掉了,什麼時候纔會開啓Vsync呢?實際上,第一個Vsync是用來更新週期和相移時間用的,Vsync在恰當的時候開關,有利於節約電源,減少功耗。
當app或者SurfaceFlinger需要Vsync來協調更新界面時,都需要調用到EventThread::requestNextVsync時。表示當前的Connection對Vsync事件感興趣,這時會把Connection的count設爲0,這時一直阻塞在條件變量mCondition的SurfaceFlinge端的EventThread會被喚醒。
/frameworks/native/services/surfaceflinger/EventThread.cpp
void EventThread::requestNextVsync(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
if (connection->count < 0) {
connection->count = 0;
mCondition.broadcast();
}
}
回到EventThread::waitForEvent函數。由於有Connection的count已經設置成0,waitForVSync變成true,但是timestamp仍爲0,於是會調用enableVSyncLocked的邏輯使能Vsync。
/frameworks/native/services/surfaceflinger/EventThread.cpp
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
Vector< sp<EventThread::Connection> > signalConnections;
do {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
*event = mVSyncEvent[i];
mVSyncEvent[i].header.timestamp = 0;
vsyncCount = mVSyncEvent[i].vsync.count;
break;
}
}
if (!timestamp) {
// no vsync event, see if there are some other event
eventPending = !mPendingEvents.isEmpty();
if (eventPending) {
// we have some other event to dispatch
*event = mPendingEvents[0];
mPendingEvents.removeAt(0);
}
}
// find out connections waiting for events
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
bool added = false;
if (connection->count >= 0) {
// we need vsync events because at least
// one connection is waiting for it
waitForVSync = true;
if (timestamp) {
// we consume the event only if it's time
// (ie: we received a vsync event)
if (connection->count == 0) {
// fired this time around
connection->count = -1;
signalConnections.add(connection);
added = true;
} else if (connection->count == 1 ||
(vsyncCount % connection->count) == 0) {
// continuous event, and time to report it
signalConnections.add(connection);
added = true;
}
}
}
if (eventPending && !timestamp && !added) {
// we don't have a vsync event to process
// (timestamp==0), but we have some pending
// messages.
signalConnections.add(connection);
}
} else {
// we couldn't promote this reference, the connection has
// died, so clean-up!
mDisplayEventConnections.removeAt(i);
--i; --count;
}
}
// Here we figure out if we need to enable or disable vsyncs
if (timestamp && !waitForVSync) {
// we received a VSYNC but we have no clients
// don't report it, and disable VSYNC events
disableVSyncLocked();
} else if (!timestamp && waitForVSync) {
// we have at least one client, so we want vsync enabled
// (TODO: this function is called right after we finish
// notifying clients of a vsync, so this call will be made
// at the vsync rate, e.g. 60fps. If we can accurately
// track the current state we could avoid making this call
// so often.)
enableVSyncLocked();
}
// note: !timestamp implies signalConnections.isEmpty(), because we
// don't populate signalConnections if there's no vsync pending
if (!timestamp && !eventPending) {
// wait for something to happen
if (waitForVSync) {
// This is where we spend most of our time, waiting
// for vsync events and new client registrations.
//
// If the screen is off, we can't use h/w vsync, so we
// use a 16ms timeout instead. It doesn't need to be
// precise, we just need to keep feeding our clients.
//
// We don't want to stall if there's a driver bug, so we
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
// FIXME: how do we decide which display id the fake
// vsync came from ?
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
} else {
// Nobody is interested in vsync, so we just want to sleep.
// h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
mCondition.wait(mLock);
}
}
} while (signalConnections.isEmpty());
// here we're guaranteed to have a timestamp and some connections to signal
// (The connections might have dropped out of mDisplayEventConnections
// while we were asleep, but we'll still have strong references to them.)
return signalConnections;
}
mVSyncSource指的是DispSyncSource對象。
/frameworks/native/services/surfaceflinger/EventThread.cpp
void EventThread::enableVSyncLocked() {
if (!mUseSoftwareVSync) {
// never enable h/w VSYNC when screen is off
if (!mVsyncEnabled) {
mVsyncEnabled = true;
mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
mVSyncSource->setVSyncEnabled(true);
}
}
mDebugVsyncEnabled = true;
sendVsyncHintOnLocked();
}
EventThread繼承自VSyncSource::Callback,這裏將mCallback 設置成EventThread類型的入參。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
Mutex::Autolock lock(mMutex);
mCallback = callback;
}
DispSyncSource繼承自DispSync::Callback。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
virtual void setVSyncEnabled(bool enable) {
// Do NOT lock the mutex here so as to avoid any mutex ordering issues
// with locking it in the onDispSyncEvent callback.
if (enable) {
status_t err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
strerror(-err), err);
}
//ATRACE_INT(mVsyncOnLabel.string(), 1);
} else {
status_t err = mDispSync->removeEventListener(
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error unregistering vsync callback: %s (%d)",
strerror(-err), err);
}
//ATRACE_INT(mVsyncOnLabel.string(), 0);
}
}
/frameworks/native/services/surfaceflinger/DispSync.cpp
status_t DispSync::addEventListener(nsecs_t phase,
const sp<Callback>& callback) {
Mutex::Autolock lock(mMutex);
return mThread->addEventListener(phase, callback);
}
addEventListenerd第一個參數是EventThread使用的Vsync偏移,由VSYNC_EVENT_PHASE_OFFSET_NS,SF_VSYNC_EVENT_PHASE_OFFSET_NS指定;第二個參數是是使用的DispSyncSource,將這兩個參數保存在一個EventListener 對象中,並將EventListener 的mLastEventTime 設爲當前事件減去半個Vsync週期的值,然後加入到mEventListeners的Vector中,然後喚醒DispSyncThread。
/frameworks/native/services/surfaceflinger/DispSync.cpp
status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) {
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < mEventListeners.size(); i++) {
if (mEventListeners[i].mCallback == callback) {
return BAD_VALUE;
}
}
EventListener listener;
listener.mPhase = phase;
listener.mCallback = callback;
// We want to allow the firstmost future event to fire without
// allowing any past events to fire. Because
// computeListenerNextEventTimeLocked filters out events within a half
// a period of the last event time, we need to initialize the last
// event time to a half a period in the past.
listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2;
mEventListeners.push(listener);
mCond.signal();
return NO_ERROR;
}
再看看DispSyncThread的threadLoop函數。第一次因爲mPeriod == 0而導致的阻塞現在已經可以通行了。computeNextEventTimeLocked用來計算下一個 Vsync的時間戳。如果當前時間未到下一個 Vsync的時間戳,調用waitRelative等待相差的時間直到有人喚醒DispSyncThread。gatherCallbackInvocationsLocked收集所有符合要求的回調,在fireCallbackInvocations中執行這些回調。
/frameworks/native/services/surfaceflinger/DispSync.cpp
virtual bool threadLoop() {
status_t err;
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t nextEventTime = 0;
while (true) {
Vector<CallbackInvocation> callbackInvocations;
nsecs_t targetTime = 0;
{ // Scope for lock
Mutex::Autolock lock(mMutex);
if (mStop) {
return false;
}
if (mPeriod == 0) {
err = mCond.wait(mMutex);
if (err != NO_ERROR) {
ALOGE("error waiting for new events: %s (%d)",
strerror(-err), err);
return false;
}
continue;
}
nextEventTime = computeNextEventTimeLocked(now);
targetTime = nextEventTime;
bool isWakeup = false;
if (now < targetTime) {
err = mCond.waitRelative(mMutex, targetTime - now);
if (err == TIMED_OUT) {
isWakeup = true;
} else if (err != NO_ERROR) {
ALOGE("error waiting for next event: %s (%d)",
strerror(-err), err);
return false;
}
}
now = systemTime(SYSTEM_TIME_MONOTONIC);
if (isWakeup) {
mWakeupLatency = ((mWakeupLatency * 63) +
(now - targetTime)) / 64;
if (mWakeupLatency > 500000) {
// Don't correct by more than 500 us
mWakeupLatency = 500000;
}
if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
}
}
callbackInvocations = gatherCallbackInvocationsLocked(now);
}
if (callbackInvocations.size() > 0) {
fireCallbackInvocations(callbackInvocations);
}
}
return false;
}
/frameworks/native/services/surfaceflinger/DispSync.cpp
Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
Vector<CallbackInvocation> callbackInvocations;
nsecs_t ref = now - mPeriod;
for (size_t i = 0; i < mEventListeners.size(); i++) {
nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
ref);
if (t < now) {
CallbackInvocation ci;
ci.mCallback = mEventListeners[i].mCallback;
ci.mEventTime = t;
callbackInvocations.push(ci);
mEventListeners.editItemAt(i).mLastEventTime = t;
}
}
return callbackInvocations;
}
回調實際上是調用了DispSyncSource::onDispSyncEvent。而DispSyncSource::onDispSyncEvent會調到EventThread::onVSyncEvent。
/frameworks/native/services/surfaceflinger/DispSync.cpp
void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
for (size_t i = 0; i < callbacks.size(); i++) {
callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
}
}
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
virtual void onDispSyncEvent(nsecs_t when) {
sp<VSyncSource::Callback> callback;
{
Mutex::Autolock lock(mMutex);
callback = mCallback;
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
ATRACE_INT(mVsyncEventLabel.string(), mValue);
}
}
if (callback != NULL) {
callback->onVSyncEvent(when);
}
}
EventThread::onVSyncEvent會填充mVSyncEvent[0],然後喚醒EventThread線程。
/frameworks/native/services/surfaceflinger/EventThread.cpp
void EventThread::onVSyncEvent(nsecs_t timestamp) {
Mutex::Autolock _l(mLock);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
mCondition.broadcast();
}
在異步調用enableVSyncLocked後,EventThread會阻塞在waitRelative中,阻塞時間在關屏狀態下爲16ms,亮屏狀態爲1s。如果EventThread::onVSyncEvent在超時時間內沒能喚醒EventThread,則手動填充mVSyncEvent[0],使得流程可以繼續走下去。
// note: !timestamp implies signalConnections.isEmpty(), because we
// don't populate signalConnections if there's no vsync pending
if (!timestamp && !eventPending) {
// wait for something to happen
if (waitForVSync) {
// This is where we spend most of our time, waiting
// for vsync events and new client registrations.
//
// If the screen is off, we can't use h/w vsync, so we
// use a 16ms timeout instead. It doesn't need to be
// precise, we just need to keep feeding our clients.
//
// We don't want to stall if there's a driver bug, so we
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
// FIXME: how do we decide which display id the fake
// vsync came from ?
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
} else {
// Nobody is interested in vsync, so we just want to sleep.
// h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
mCondition.wait(mLock);
}
再回到EventThread::waitForEvent開頭,由於mVSyncEvent[0]的時間戳已經更新,所以timestamp的值不爲0,然後將mVSyncEvent[0]的時間戳和Connection的count值分別重置爲0和-1,將對應的Connection加入到signalConnections中。最終會退出waitForEvent中的do…while循環。
離開waitForEvent後就是遍歷signalConnections,然後分別調用其Connection::postEvent上報事件,以進行更新圖層或畫一幀的操作。這種基於Vsync模型的Vsync信號會一直發出來,直到沒有Connection對Vsync感興趣爲止,這個從執行disableVSyncLocked的條件可以看出,當Vsync回調使得timestamp不爲0時,這是卻沒有感興趣的Connection(不需要刷新圖層),則調用disableVSyncLocked移除回調,之後自然就沒有可用的signalConnections了。
可以看到,enableVSyncLocked/disableVSyncLocked並不會直接控制硬件Vsync的開關,而是基於EventThread的Vsync虛擬化進行模擬的Vsync輸出,只有到模擬的Vsync和物理的Vsync有較大誤差時,纔會重新開啓物理Vsync進行校正。