EventThread线程对VSync的分发
EventThread线程对VSync的分发
前面提到,EventThread在接收到VSync后再将它们分发给感兴趣的注册者,分发的过程是在其线程循环threadLoop函数中完成的。读者也可以先阅读后面一节内容,先了解感兴趣的注册者如何得到VSync通知以及系统中可能存在哪些感兴趣的注册者后,再回来阅读本小节。
感兴趣的注册者首先需要创建到EventThread的连接,这个到EventThread的连接将保存到EventThread的列表中。创建连接的代码如下(下面的行56,参见文件EventThread.cpp):
由于Connection的父类中有RefBase,所以其重载的onFirstRef函数将被调用,后者又调用registerDisplayEventConnection函数将自己(即“连接”Connection)注册给EventThread(上面的行62);也就是说,每个连接创建时,都要将连接注册到EventThread中,以让EventThread给自己发送VSync事件通知。由于连接可能会失效,所以EventThread中维护的是一个连接的弱指针列表。在有新的连接注册后,需要通知(行63)给threadLoop循环,让其从睡眠中醒来。
EventThread的threadLoop函数的前面的代码如下:
在内嵌的do-while循环(上面的行135~184)中,若注册者指定了需要报告VSync(即行146处的Connection中的count大于0),且VSync时间戳不为0(行153),则跳出该do-while循环,往下执行准备分发VSync事件;若不需要分发,且原来的时间戳不为0,表示VSync还是激活状态,因此去关闭VSync(行157);若时间戳为0,可能VSync原来已经是未激活状态,但若需要分发,则激活VSync(行169);若屏幕关闭(不需刷新输出,VSync关闭)且需分发,那么将睡眠片刻超时后的时间作为VSync时间戳(行178、179),然后在下一个while循环中走到行153和160,跳出while循环,表示是软件模拟的VSync事件;否则,即屏幕打开和屏幕关闭但不需分发的两种情形,这时,将进入睡眠等待状态(行182)。在屏幕打开状态下,VSync很快就会到来(除非主动关闭了VSync),或者有新的感兴趣者进行了注册,或者注册者请求改变了VSync分发频率(见下一小节),这些都将被唤醒行182处的睡眠等待。在屏幕关闭且不需分发VSync的情况下,那么就可以让EventThread线程一直睡眠下去,不需醒来,直到屏幕打开后被唤醒再次开始进行do-while循环的工作。
在跳出第一个内嵌的循环后,表示有VSync需要分发报告,这时将计数器加1(下面的行187),记录下时间戳信息(行188);然后再次在for循环(行192~215)中检查注册者是否已经失效(行196)、报告频率(是否这次该给某个注册者报告,行200、201)等,若需要报告,则将该注册者添加到待报告列表displayEventConnections中(行213)。在行216,若待报告列表为空,则继续while循环,否则就往下执行,准备去分发VSync事件通知。
下面的代码是threadLoop的后面的代码。首先准备好DisplayEvent事件(当前也就只是VSync一种),包括类型和时间戳等信息(行219~221)。再接着,在for循环(行224~246)中,逐个向待处理队列中的连接发送DisplayEvent(VSync)事件(行228)。这就完成了对感兴趣的注册者的分发。
可见,threadLoop首先根据注册者和设备(屏幕是否关闭)等情况判断是否需要分发下一个VSync;在不需要分发(如屏幕关闭并且也没有接收者的情形)或完成任务后等待下一个硬件或软件模拟VSync到来时,则进入睡眠等待状态;当被唤醒(如VSync到来)后,若需要报告分发,则将接收者添加到待处理队列列表中,最后通过连接Connection的postEvent函数分发VSync显示事件给注册的接收者。
本文节选自《深入剖析Android系统》一书
杨长刚著
电子工业出版社出版