您的位置:首页 > 移动开发 > Android开发

Android VSync事件分发过程源码分析

2013-11-27 15:27 459 查看
在上一篇文章Android
VSync信号产生过程源码分析中分别介绍了VSync的两种产生方式,无论是通过硬件中断产生还是通过软件模拟产生,VSync事件最终都会交给EventThread线程来分发给所有VSync事件接收者。VSync事件接收者有很多,SurfaceFlinger就是其中一个重要的VSync事件接收者。那么EventThread线程是如何知道该将VSync分发给谁呢?EventThread线程有是如何将VSync事件分发给所有VSync事件接收者的呢?本文就针对这两个问题展开分析。我们知道VSync事件是由EventThread线程分发,而VSync事件接收者可能与EventThread线程同属一个进程,也可能分属不同的进程,这里就设计跨进程通信了,Android对VSync事件的分发采用Socket通信方式。



EventThread线程分发VSync事件

事件连接创建过程

对VSYNC等事件感兴趣的对象,比如MessageQueue,首先要通过EventThread::createEventConnection()来建立一个连接,实际上就是生成了一个EventThread::Connection对象,Connection只是双方业务上连接,而BitTube则是数据传输通道。



sp<EventThread::Connection> EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}
这里只是简单地构造一个Connection对象,Connection对象的构造过程如下:

EventThread::Connection::Connection(const sp<EventThread>& eventThread)
: count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}
在构造Connection对象时,构造了一个BitTube对象来初始化Connection对象的成员变量mChannel,从上图可以看出,BitTube类只是对Socket通信方式的封装,BitTube对象的构造过程如下:

BitTube::BitTube(): mSendFd(-1), mReceiveFd(-1)
{
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
int size = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
fcntl(sockets[0], F_SETFL, O_NONBLOCK);
fcntl(sockets[1], F_SETFL, O_NONBLOCK);
mReceiveFd = sockets[0];
mSendFd = sockets[1];
} else {
mReceiveFd = -errno;
ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
}
}


事件连接注册过程

当Connection对象第一次被强引用时,自动调用onFirstRef()函数来初始化该对象。

void EventThread::Connection::onFirstRef() {
mEventThread->registerDisplayEventConnection(this);
}
在onFirstRef()函数里主动调用EventThread::registerDisplayEventConnection()把自己加入到EventThread的成员变量mDisplayEventConnections中,mDisplayEventConnections是一个向量类型,保存所有需要接收VSync信号的连接Connection,这样EventThread线程在分发VSync事件时,就知道将VSync事件分发给谁了。对VSYNC信号感兴趣的人,通过registerDisplayEventConnection()函数将连接Connection注册到EventThread中。

status_t EventThread::registerDisplayEventConnection(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
//仅仅将注册的Connection添加到EventThread的成员变量mDisplayEventConnections中
mDisplayEventConnections.add(connection);
mCondition.broadcast();
return NO_ERROR;
}
EventThread的成员变量mDisplayEventConnections用于记录所有注册的Connection连接。

VSync事件分发过程

VSync事件最终在EventThread线程执行体threadLoop()中分发给各个监听者。

bool EventThread::threadLoop() {
nsecs_t timestamp;
DisplayEventReceiver::Event vsync;
//定义displayEventConnections向量,用于保存所有需要接收VSync事件的连接
Vector< wp<EventThread::Connection> > displayEventConnections;
do {
Mutex::Autolock _l(mLock);
//判断是否上报VSync
do {
// latch VSYNC event if any
timestamp = mVSyncTimestamp;
mVSyncTimestamp = 0;
//标示是否有客户端在等待VSync事件
bool waitForNextVsync = false;
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
// count ==-1 : one-shot event that fired this round / disabled
// count ==-2 : one-shot event that fired the round before
if (connection!=0 && connection->count >= 0) {
// at least one continuous mode or active one-shot event
waitForNextVsync = true;
break;
}
}
if (timestamp) {
if (!waitForNextVsync) {
//接收到VSync事件,但当前没有客户端需要接收VSync事件,所以关闭VSync事件源
disableVSyncLocked();
} else {
//如果有客户需要接收VSync事件,则跳出此循环,进入VSync事件分发阶段
break;
}
} else {
//等待接收VSync事件,并重新评估是否需要分发该事件或者是否需要关闭VSync事件源
if (waitForNextVsync) {
//如果有客户端需要接收VSync事件,则打开VSync事件源
enableVSyncLocked();
}
}
//等待VSync事件
if (mUseSoftwareVSync && waitForNextVsync) {
// h/w vsync cannot be used (screen is off), so we use
// a  timeout instead. it doesn't matter how imprecise this
// is, we just need to make sure to serve the clients
if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
}
} else {
mCondition.wait(mLock);
}
} while(true);
//当需要分发VSync时,跳出上面的while循环,
mDeliveredEvents++;
mLastVSyncTimestamp = timestamp;
// now see if we still need to report this VSYNC event
const size_t count = mDisplayEventConnections.size();
//遍历已注册的所有Connection,将需要接收VSync的Connection添加到displayEventConnections向量中
for (size_t i=0 ; i<count ; i++) {
bool reportVsync = false;
sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
//如果当前Connection已经死亡,则遍历下一个注册的Connection
if (connection == 0)
continue;
const int32_t count = connection->count;
if (count >= 1) {
if (count==1 || (mDeliveredEvents % count) == 0) {
// continuous event, and time to report it
reportVsync = true;
}
} else if (count >= -1) {
if (count == 0) {
// fired this time around
reportVsync = true;
}
connection->count--;
}
if (reportVsync) {
displayEventConnections.add(connection);
}
}
} while (!displayEventConnections.size());
//如果向量displayEventConnections的大小大于0,则将VSync信号分发给displayEventConnections中的Connection
//定义即将分发的VSync事件
vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
vsync.header.timestamp = timestamp;
vsync.vsync.count = mDeliveredEvents;
const size_t count = displayEventConnections.size();
//遍历displayEventConnections中的所有Connection
for (size_t i=0 ; i<count ; i++) {
sp<Connection> conn(displayEventConnections[i].promote());
// make sure the connection didn't die
if (conn != NULL) {
//发送VSync事件
status_t err = conn->postEvent(vsync);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
//这两个错误是指对方当前不接受事件,有可能是事件已满,放弃这次操作,不作处理
} else if (err < 0) {
//事件发送错误,则从Connection注册列表mDisplayEventConnections中移除该Connection
removeDisplayEventConnection(displayEventConnections[i]);
}
} else {
//Connection为空,则从Connection注册列表mDisplayEventConnections中移除该Connection
removeDisplayEventConnection(displayEventConnections[i]);
}
}
//VSync事件分发完毕,清空displayEventConnections向量
displayEventConnections.clear();
return true;
}
在EventThread线程中,通过遍历连接注册列表mDisplayEventConnections,将VSync事件分发给已注册,并且需要接收VSync事件的Connection。调用各个Connection的postEvent()函数来发送一个VSync事件:

status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
参数event描述的是一个VSync事件,Connection的成员变量mChannel指向BitTube对象,通过已创建的BitTube传输通道来发送VSync事件Event信息。

ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,Event const* events, size_t count)
{
return BitTube::sendObjects(dataChannel, events, count);
}
调用BitTube类的sendObjects()函数来发送一个VSync事件信息

ssize_t BitTube::sendObjects(const sp<BitTube>& tube,void const* events, size_t count, size_t objSize)
{
ssize_t numObjects = 0;
for (size_t i=0 ; i<count ; i++) {
const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
ssize_t size = tube->write(vaddr, objSize);
if (size < 0) {
// error occurred
return size;
} else if (size == 0) {
// no more space
break;
}
numObjects++;
}
return numObjects;
}
该函数可以发送多个事件对象,对于每一个事件对象的发送使用BitTube类的write()函数来完成。

ssize_t BitTube::write(void const* vaddr, size_t size)
{
ssize_t err, len;
do {
len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
err = len < 0 ? errno : 0;
} while (err == EINTR);
return err == 0 ? len : -err;
}
这里就采用BitTube对象中创建的Socket来发送一个事件信息。因此EventThread线程分发VSync事件是通过在Socket发送端mSendFd写入一个Event事件信息,这样对于监听在Socket接收端的VSync接收者就可以收到VSync事件信息Event了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: