从Invalidate到Draw的辗转历程

以android Q的源码为例子,一步步分析invalidate的调用流程。

在写自定义控件的时候时常会用到 invalide 方法,都知道调用 invalide 后会回调Draw方法,但其中的辗转历程鲜有人知,为了搞清这个流程,我从android Q 源码入手分析了整个调用流程。在此记录一下,省得以后忘了

1.App Call SufaceFlinger

1.任何的View的invalidate方法最终都会调用到ViewRootImpl.java的invalidate()或者invalidateChildInParent,区别只是mDirty的大小,这个mDirty表示这个区域需要重绘

frameworks/base/core/java/android/view/ViewRootImpl.java

2.scheduleTraversals的实现如下

frameworks/base/core/java/android/view/ViewRootImpl.java

3.这里需要注意的是一个插入同步屏障的过程,插入同步屏障后,只有异步的消息才能在MessageQeue循环,app这边 Handler之类的全部失去效果,所以在Traversals执行或者取消的时候会马上移除,如下所示

frameworks/base/core/java/android/view/ViewRootImpl.java

4.scheduleTraversals,最主要的功能是调用 Choreographer 注册一个同步信号的监听,回调,注意此时的类型为Choreographer.CALLBACK_TRAVERSAL Choreographer.postCallbackDelayedInternal如下

frameworks/base/core/java/android/view/Choreographer.java

5.可以看到可能由于卡顿的问题,当前时间已经超过了该请求的预期执行时间 话会直接调用scheduleFrameLocked 而未到达的话则会发送一个异步消息( 与前面的 postSyncBarrier相呼应 ),到点之再执行scheduleFrameLocked

frameworks/base/core/java/android/view/Choreographer.java

6.这里可以看到,在使用同步信号的时候会调用scheduleVsyncLocked,而不使用同步信号的时候由自己发出,目前来说都是基本都是使用同步信号的,因为同步信号可以更好的和surfaceflinger以及显示器一起获得更好的显示的效果。其中的scheduleVsyncLocked调用的是FrameDisplayEventReceiver( FrameDisplayEventReceiver 继承自 DisplayEventReceiver )的scheduleVsync,他是一个native实现,具体实现继续往下看

frameworks/base/core/java/android/view/DisplayEventReceiver.java

7.构造方法中nativeInit对应的Native实现

frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

8.可以看到在init方法里创建了一个NativeDisplayEventReceiver类,并且对他进行了初始化,构造方法如下,需要注意的地方是构造方法法中继续调用了父类DisplayEventDispatcher的构造方法

frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

9.需要注意的地方是DisplayEventDispatcher 在构造方法中对mReceiver进行了初始化

frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp

10.mReceiver的赋值是调用的他的构造方法,方法如下

frameworks/native/libs/gui/DisplayEventReceiver.cpp

11.非常需要注意的地方时DisplayEventReceiver的构造方法,这里向ISurfaceComposer也就是sufacefiinger的binder接口创建了一个DsplayEventConnection,然后创建了一BitTube,其实就是一对Socket,并且把他通过binder传递给了sufaceflinger,这样 sufaceflinger就可以向app发送VSYNC信号了,即建立起来了消息接收部分

12.再次回到 第7部分的 nativeInit 部分,其中的init方法实际上是调用 DisplayEventDispatcher 的init方法,具体如下

frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp

13.可以看到,这里向looper添加了一个fd,这个fd正是第10节中的BitTube的接收端,而DisplayEventDispatcher 继承自 LooperCallback ,因此每当收到VSYNC信号便会调用他的callback,如下

frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp

14.至此,app端口从sufaceflinger接收VSYNC信号的部分已经分析完毕,现在继续回到第9节scheduleVsyncLocked,也就是请求VSYNC信号部分, scheduleVsyncLocked 最终调用的native入口是

frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

15.接上面的调用入口receiver.scheduleVsync调用

frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp

frameworks/native/services/displayservice/DisplayEventReceiver.cpp

可以看到最终同步信号的请求是传递到了mEventConnection ,这是一个binder接口,由sufaceflinger实现,

17.小结,从上面的分析可以知道,invalidade在系统使用VSYNC信号的情况下,最终通过binder请求到surfaceflinger,只有收到 surfaceflinger 的socket消息后才会进行绘制操作。也就是调用java的draw方法

2.SurfaceFlinger Call App

16.现在开始分析surfaceflinger部分,回到第10节的createDisplayEventConnection,这个地方的实现为surfaceflinger.cpp,因为surfaceflinger继承自 BnSurfaceComposer ,而他是一个binder类,因此调用最终到了

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

17.SurfaceFlinger 中有两股同步信号,他们都是源自硬件或者软件,为了让渲染和合成可以错开,增加资源利用率和减少延迟(我是这么理解的),收到源信号后会分成两股,具有不同的时间偏移量,对应的会有两个不同的ConnectionHandle以及EventThread

frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp

18.可以看到最终是调用了EventThread 里的createEventConnection

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

19.这里需要关注的是EventThreadConnection 继承自智能指针,在第一次被引用的时候调用了mEventThread->registerDisplayEventConnection,实际上是把自己添加到了EventThread里的mDisplayEventConnections中

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

20.再次回到第15节中的同步信号请求,对应的binder远程实现为

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

21.EventThread 中同步信号的接收来自,onVSyncEvent这个方法,他是由监听到硬件或者软件的Vsync信号触发的

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

22.可以看到这里把VSync信号封装成了VSyncEvent,然后放到了mPendingEvents,而 mPendingEvents 是由一个主循环监听的

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

23.当收到vsyn信号后,EventThread的主消息循环将会被唤醒,然后根据conection中的标志位判断是否要分发给对应的连接->也就是app的window

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

frameworks/native/libs/gui/DisplayEventReceiver.cpp

24.当Surfaceflinger发出Vysnc消息后, DisplayEventDispatcher 里的handleEvent即可收到通知(见第13节),然后发消息发给

frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

25.NativeDisplayEventReceiver的dispatchVsync 将会回调到java的 DisplayEventReceiver 中的dispatchVsync

frameworks/base/core/java/android/view/DisplayEventReceiver.java

26.简单的几次跳转之后,通过发送异步Message又回到Choreographer中的doFrame方法中

frameworks/base/core/java/android/view/Choreographer.java

27.doFrame 方法调用后会根据时间选择是否调用doCallbacks,调用 doCallbacks 的时候也不是一股脑把ViewRootImpl的所有callbck都调用了,只有到点了的Callback才会被取出。取出后最终执行了Run方法,也就是回到了梦开始的地方

/frameworks/base/core/java/android/view/ViewRootImpl.java

28.doTraversal()里移除了scheduleTraversals添加的MessageQueue的同步屏障,也就是说这时候可以继续开心的使用handler了,并且performTraversals 就是我们熟悉的绘制流程 measure和layout和draw了

总结

Invalidate ->Choreographer->Native Event发送->binder->SurfaceFlinger->等待同步信号->Socket-> Native Event接收-> Choreographer ->draw

时序图如下(看不清可以右键标签页打开)