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 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& src)
: mVSyncSource(src),
mUseSoftwareVSync(false),
mVsyncEnabled(false),
mDebugVsyncEnabled(false),
mVsyncHintSent(false) {
for (int32_t i=0 ; 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 > signalConnections;
signalConnections = waitForEvent(&event);
// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; iconst sp& 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::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
Vector< sp > signalConnections;
do {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
for (int32_t i=0 ; iif (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(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::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
Vector< sp > signalConnections;
do {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
for (int32_t i=0 ; iif (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(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(this));
mVSyncSource->setVSyncEnabled(true);
}
}
mDebugVsyncEnabled = true;
sendVsyncHintOnLocked();
}
EventThread继承自VSyncSource::Callback,这里将mCallback 设置成EventThread类型的入参。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
virtual void setCallback(const sp& 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(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(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& 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 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 gatherCallbackInvocationsLocked(nsecs_t now) {
Vector 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& 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进行校正。