天天看点

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

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

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

EventThread线程分发VSync事件

事件连接创建过程

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

Android VSync事件分发过程源码分析
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了。

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

继续阅读