我们先看收到VSync事件是如何处理的,再看底层是怎样向上层通知VSync事件。
1.SurfaceFlinger如何处理Vsync事件
在SurfaceFlinger定义了一个消息队列的成员变量:
mutableMessageQueue mEventQueue;
MessageQueue是一个消息处理类,专门处理如下三种消息:
INVALIDATE, REFRESH, TRANSACTION。
这三个消息都与UI更新相关。SurfaceFlinger在自己的主线程中等待上述消息的到来,以便进行相应的处理,代码如下(后面我们会看到,VSync事件会触发上述消息):
bool SurfaceFlinger::threadLoop() {
waitForEvent();
return true;
}
其中waitForEvent又调用的MessageQueue的waitMessage函数:
void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}
所以SurfaceFlinger依赖MessageQueue截获上述消息,那又是通过怎样的流程向MessageQueue发送上述消息呢?换句话说,MessageQueue又是如何接收到上述三个消息的呢?
而这一切又是与EventThread类相关。通过查看MessageQueue的定义,可以看到,它定义了一个EventThread的成员变量,并通过setEventThread初始化,代码如下:
void MessageQueue::setEventThread(const sp& eventThread)
{
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEventTube = mEvents->getDataChannel();
mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
通过此接口,不仅获取了一个EventThread实例的引用,同时,通过EventThread创建一个IDisplayEventConnection对象,它代表了接收显示事件(主要是VSync事件以及HotPlug事件)的一个远程连接接收端,并通过Looper对象监听发生在此对象上的显示事件。在EventThread的线程循环中,等待VSync事件的发生,代码如下:
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 ; i& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
…
}
return true;
}
int MessageQueue::eventReceiver(int fd, int events) {
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
for (int i=0 ; idispatchInvalidate();
#else
mHandler->dispatchRefresh();
#endif
break;
}
}
}
return 1;
}
void MessageQueue::Handler::dispatchRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
void MessageQueue::Handler::dispatchInvalidate() {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
}
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case REFRESH:
android_atomic_and(~eventMaskRefresh, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case TRANSACTION:
android_atomic_and(~eventMaskTransaction, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
}
}
如上代码所示,实际上会执行SurfaceFlinger类里定义的回调函数,在那里面对开头提到的三种消息进行真正的处理,即对VSync事件的响应最终转变成对上述三种消息进行处理。
2.VSync事件产生流程分析
上述分析了,从等待接收VSync事件到最后处理VSync事件的过程。下面我们要看下VSync事件是如何产生的,即是如何通知SurfaceFlinger::waitEvent返回的。众所周知,VSync事件一般由硬件周期性产生,如果没有相应的硬件产生VSync事件,则通过软件模拟。下面主要看下从硬件产生VSync事件到触发MessageQueue处理VSync事件的过程。
首先,看下HWComposer的定义:
class HWComposer
{
public:
class EventHandler {
friend class HWComposer;
virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int disp, bool connected) = 0;
protected:
virtual ~EventHandler() {}
};
enum {
MAX_DISPLAYS = HWC_NUM_DISPLAY_TYPES + 1
};
HWComposer(
const sp& flinger,
EventHandler& handler);
…
}
// Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
mHwc = new HWComposer(this,
*static_cast(this));
HWComposer::HWComposer(
const sp& flinger,
EventHandler& handler)
: mFlinger(flinger),
mFbDev(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mVSyncCount(0), mDebugForceFakeVSync(false)
{
…
bool needVSyncThread = true;
// Note: some devices may insist that the FB HAL be opened before HWC.
int fberr = loadFbHalModule();
loadHwcModule();
…
if (mHwc) {
ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
(hwcApiVersion(mHwc) >> 24) & 0xff,
(hwcApiVersion(mHwc) >> 16) & 0xff);
if (mHwc->registerProcs) {
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext->procs.hotplug = &hook_hotplug;
else
mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
}
// don't need a vsync thread if we have a hardware composer
needVSyncThread = false;
// always turn vsync off when we start
eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
// the number of displays we actually have depends on the
// hw composer version
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
// 1.?? adds support for virtual displays
mNumDisplays = MAX_DISPLAYS;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// 1.1 adds support for multiple displays
mNumDisplays = NUM_PHYSICAL_DISPLAYS;
} else {
mNumDisplays = 1;
}
}
…
if (needVSyncThread) {
// we don't have VSYNC support, we need to fake it
mVSyncThread = new VSyncThread(*this);
}
}
void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
int64_t timestamp) {
cb_context* ctx = reinterpret_cast(
const_cast(procs));
ctx->hwc->vsync(disp, timestamp);
}
void HWComposer::vsync(int disp, int64_t timestamp) {
ATRACE_INT("VSYNC", ++mVSyncCount&1);
mEventHandler.onVSyncReceived(disp, timestamp);
Mutex::Autolock _l(mLock);
mLastHwVSync = timestamp;
}
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
if (mEventThread == NULL) {
// This is a temporary workaround for b/7145521. A non-null pointer
// does not mean EventThread has finished initializing, so this
// is not a correct fix.
ALOGW("WARNING: EventThread not started, ignoring vsync");
return;
}
if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
// we should only receive DisplayDevice::DisplayType from the vsync callback
mEventThread->onVSyncReceived(type, timestamp);
}
}
status_t SurfaceFlinger::readyToRun()
{
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
…
// start the EventThread
mEventThread = new EventThread(this);
mEventQueue.setEventThread(mEventThread);
// We're now ready to accept clients...
mReadyToRunBarrier.open();
// set initial conditions (e.g. unblank default device)
initializeDisplays();
…
return NO_ERROR;
}
void EventThread::onVSyncReceived(int type, nsecs_t timestamp) {
ALOGE_IF(type >= HWC_NUM_DISPLAY_TYPES,
"received vsync event for an invalid display (id=%d)", type);
Mutex::Autolock _l(mLock);
if (type < HWC_NUM_DISPLAY_TYPES) {
mVSyncEvent[type].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[type].header.id = type;
mVSyncEvent[type].header.timestamp = timestamp;
mVSyncEvent[type].vsync.count++;
mCondition.broadcast();
}
}
上述代码会触发EventThread的waitForEvent返回,从而开始对捕获的VSync事件进行处理的过程。
3. EventThread处理VSync的机制
现在我们回到EventThread本身,来看下是怎样侦测并通知VSync事件。
先从EventThread的threadLoop方法开始。
在线程循环中,它通过waitForEvent来等待一些事件到来,并进行处理。我们先看下,当有VSync或其他事件时,它会怎样处理:
bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp > signalConnections;
signalConnections = waitForEvent(&event);
…
}
首先看下waitForEvent函数的返回值,它会返回两个信息,一个是当前发生了什么事件,另一个是当前有多少个事件连接指向SurfaceFlinger,即对上述事件感兴趣的监听者,让我们回顾下SurfaceFlinger在初始化时,执行了MessageQueue的setEventThread方法,它的代码如下:
void MessageQueue::setEventThread(const sp& eventThread)
{
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEventTube = mEvents->getDataChannel();
mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
可以看到,它会创建一个事件连接,接收EventThread发送过来的信息。对于非SurfaceFlinger之外的监听者,一般是通过DisplayEventReceiver来创建事件连接的。当接收到事件后,将会把事件通知给每个监听者。当出现EAGAIN或EWOULDBLOCK错误时,丢弃当前事件。当出现如EPIPE错误时,说明监听者创建的事件连接已经丢失,将删除这个事件连接。
// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; i& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
..
ALOGW("EventThread: dropping event (%08x) for connection %p",
event.header.type, conn.get());
} else if (err < 0) {
…
removeDisplayEventConnection(signalConnections[i]);
}
}
return true;
往下看,如果没有VSync事件到来,再Check下是否有其他事件:
timestamp为零,说明此时还没有收到VSync事件,再检查mPendingEvent看是否有其他的事件需要处理:
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);
}
}
接下来,检查一遍当前有哪些事件连接是有效的,即从注册列表mDisplayEventConnections中检查。
下是否有其他事件: // find out connections waiting for events
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
当前有活跃连接,将符合条件的连接加入
…
} else {
否则,当前连接已经失效,应当删除
mDisplayEventConnections.removeAt(i);
--i; --count;
}
}
}
我们来看下,当有活跃连接时,如何将符合条件的连接加入到事件通知列表(signalConnections)中。如果当前有活跃连接,则看当前连接的count值,如果大于0,则说明有VSync事件需要等待,再者,如果timestamp不为零,则说明已经收到了VSync事件,需要根据connection->count的值,进行相应的处理。如果为零,则说明当前连接只接收一次VSync事件,下次不会接收了,即下次不需要通知它。当connection->count为1或当前VSync事件的count值为connection->count的倍数时,说明当前事件连接要不断接收VSync事件。
if (connection != NULL) {
bool added = false;
if (connection->count >= 0) {
waitForVSync = true;
if (timestamp) {
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) {
signalConnections.add(connection);
added = true;
}
}
}
当然,如果当前连接没有VSync事件接收,且此时又有其他事件发生,则也需要将事件发送给当前事件连接的接收端。
if (eventPending && !timestamp && !added) {
signalConnections.add(connection);
}
上面是决定要将事件发给哪些接收端,下面会再次确认下是否有必要开启Vsync,如果当前没有活跃事件连接接收VSync事件,则应该关闭VSync事件源。
// Here we figure out if we need to enable or disable vsyncs
if (timestamp && !waitForVSync) {
disableVSyncLocked();
} else if (!timestamp && waitForVSync) {
enableVSyncLocked();
}
如果没有VSync事件且也没有收到其他事件,但是此时仍然有连接在等待VSync事件,则做一个如下判断:当使用软件模拟VSync事件时,则创建一个VSync事件,每16ms触发一次。这种情况一般发生在屏幕关闭的情况。另外,还有一种情况是底层产生VSync事件的硬件出现故障,未按时发送VSync事件,则此时,为了系统刷图能继续下来,也模拟一个VSync事件,每1秒触发一次,此时UI刷新会非常卡顿。
if (!timestamp && !eventPending) {
// wait for something to happen
if (waitForVSync) {
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");
}
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = HWC_DISPLAY_PRIMARY;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
} else {
mCondition.wait(mLock);
}
}
4. 测试例子分析
代码位于frameworks/native/services/surfaceflinger/tests/vsync.cpp
在DisplayEventReceiver 的构造函数中,调用了SurfaceFlinger的createDisplayEventConnection,创建了一个监听SurfaceFlinger事件的连接。默认情况下,DisplayEventReceiver不接收Vsync事件,setVsyncRate(1)表示将接收VSync事件。int main(int argc, char** argv)
{
DisplayEventReceiver myDisplayEvent;
sp loop = new Looper(false);
loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
&myDisplayEvent);
myDisplayEvent.setVsyncRate(1);
do {
//printf("about to poll...\n");
int32_t ret = loop->pollOnce(-1);
…
} while (1);
return 0;
}
通过Looper机制,监听发生在这个事件连接上的事件,并调用回调函数receiver:
当屏幕打开时,下面打印的Sync信息就是硬件产生的,当屏幕关闭后,打印的VSync信息就是软件模拟的(软件模拟的,从打印数据来看,每次数据都会有一些偏差,不如硬件VSync信号那么精确)。
int receiver(int fd, int events, void* data)
{
DisplayEventReceiver* q = (DisplayEventReceiver*)data;
ssize_t n;
DisplayEventReceiver::Event buffer[1];
static nsecs_t oldTimeStamp = 0;
while ((n = q->getEvents(buffer, 1)) > 0) {
for (int i=0 ; i
5. Java层监听Vsync事件
在JNI层,frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp中,定义了NativeDisplayEventReceiver类,它为对应的Java类android.view.DisplayEventReceiver提供了监听底层VSync事件的机制。NativeDisplayEventReceiver的定义如下:
class NativeDisplayEventReceiver : public LooperCallback {
public:
NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverObj, const sp& messageQueue);
status_t initialize();
void dispose();
status_t scheduleVsync();
protected:
virtual ~NativeDisplayEventReceiver();
private:
jobject mReceiverObjGlobal;
sp mMessageQueue;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
};
在initialize方法中会建立一个事件连接,并通过mMessageQueue的Looper成员变量监听发生在该事件连接上的事件。另外,mReceiverObjGlobal表示对Java层DisplayEventReceiver对象的一个全局引用,保证虚拟机不会过早地对该Java对象进行垃圾回收。handleEvent将会根据情况调用dispatchVsync或dispatchHotplug,而这两个方法实际上会通过JNI调用Java层DisplayEventReceiver类相应的私有方法dispatchVsync和dispatchHotplug,这两个方法实际上会调用该类的公有接口:onVsync和onHotplug。而Java层类也可以通过scheduleVsync显式请求一个VSync事件。由于DisplayEventReceiver是一个抽象类,所有上层Java层的类如果想针对VSync事件做些响应,必须从该类继承,并实现它的onVSync方法,如android.view. Choreographer中的私有内部类FrameDisplayEventReceiver:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
…
public FrameDisplayEventReceiver(Looper looper) {
super(looper);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
…
}
…
}