【Android】Framework笔记——View的绘制流程(二)


之前一篇文章讲到在 ViewRootImpl 的 setView 方法中调用 requestLayout 后经过一系列过程完成了整个 View 的测量布局及绘制流程。但是 draw 方法中的 canvas 又是怎么来的呢?

Canvas 的来源

我们都知道,draw 的调用是在 ViewRootImpl 中的 performDraw 方法中调用的,此时还没有传入 Canvas 对象,而它内部调用了 ViewRootImpl 的 draw 方法,让我们看看这个方法的实现:

可以看出,Android 共有两种绘制方式——硬件绘制和软件绘制。

我们先研究软件绘制的代码,让我们看到 drawSoftware 方法:

可以看出来,它的 canvas 是通过 Surface 的 lockCanvas 所得到的,之后我们就可以通过这个 Canvas 上调用其提供的绘制 API 在 Surface 上进行绘制了。

获得 canvas 后,这里对其调用了 translate 方法进行了偏移,之后调用了 View.draw 并传入了我们前面获得的 canvas。看来这就是我们的 Canvas 的来源了。

那么 Surface 与 Canvas 究竟是什么呢?下面我们讨论一下 Canvas、Surface、SurfaceFlinger 到底是什么:

Canvas、Surface、SurfaceFlinger

Canvas、Surface、SurfaceFlinger 与硬件协同作用,共同完成了我们的绘图任务,它们之间通过 Buffer 进行交互,负责不同的职责:

  • Surface 可以理解为一个画布,在程序角度来说就是对应了一个缓冲区,通过它可以与 BufferQueue 进行交互从而拿到缓冲区进行写入数据,具体过程如下:
    • 它首先将 Buffer 从 BufferQueue 中通过 dequeueBuffer取出,通过 Canvas 提供给上层
    • 上层绘制完成后会 enqueueBuffer 放回 BufferQueue
    • SurfaceFlinger 会通过 dequeueBuffer 拿走这个 Buffer,将各个 Surface 的 Buffer 进行合成,再将其交给屏幕显示。
    • SurfaceFlinger 使用完这个 Buffer 之后就会通过 enqueueBuffer 将其放回 BufferQueue 从而实现 Buffer 的循环使用。
  • Canvas 可以理解为画笔,我们可以通过它所提供的 API 在它所对应的画布 Surface 提供的 Buffer 上绘图,如 drawBitmapdrawRect 等等...
  • SurfaceFlinger 是一个系统服务,负责了 Buffer 的合成,它可以将界面中各个 Surface 中的 Buffer 进行合成,合成为一个完整的 Buffer 数据,之后交由屏幕进行显示。

Surface 的创建过程

那么,我们来研究一下,mSurface 究竟是何时被创建并交给我们的 ViewRootImpl 的。在调用了 ViewRootImpl 的 requestLayout 方法中完成了 View 的测量布局绘制的流程后,View 还没有真正的被添加到 WindowManager 中,仅仅是将其添加到了 WindowManagerGlobal 中,之后,其实又调用到了 ViewRootImpl 中的 mWindowSession.addToDisplay,通知远程的 WMS 进行窗口的添加。

这里 mWindowSession 是一个 Binder 对象,它最终会通过 IPC 调用到 WMS 中的 addWindow 方法。

可以看到,这里先构建了一个 WindowState 对象,之后调用了 WindowState 的 attach 方法,之后以调用的 client 的 Binder 作为 key 将其放入了 mWindowMap,最后调用了其 token 下的 addWindow 方法。

与 SurfaceFlinger 建立连接

这个 WindowState 的 attach 方法其实就是 Window 与 SurfaceFlinger 相关联的起点,而 WindowState 的 attach 方法又调用到了 Session.windowAddedLocked 方法。

windowAddedLocked 方法中构建了一个 SurfaceSession 对象,而 SurfaceSession 的构造函数中实际上是调用了 nativeCreate 方法在 Native 层构建了一个 SurfaceComposerClient 对象,并返回了其在 Native 层对象的地址。

这个 SurfaceComposerClient 对象其实就是应用与 SurfaceFlinger 进行沟通的桥梁,它在整个应用程序中只有一个实例。在对它初次使用的时候会调用到 onFirstRef 方法:

上面代码中的 sf 就是 SurfaceFlinger,通过 IPC 调用了它的 createScopedConnection 方法从而创建了一个 ISurfaceComposerClient 对象。

在 createScopedConnection 的实现中,它其实是构建了一个 Client 对象,这个对象实现了 ISurfaceComposerClient 内的虚函数,是一个可用于 IPC 的对象。SurfaceComposerClient 可以通过它与 SurfaceFlinger 进行通信。

Client 大致结构如下:

可以看出来,它是一个 Native 层的 Binder 对象,通过 Client 我们就可以与 SurfaceFlinger 进行通信了。

创建 Surface

每个 ViewRootImpl 中含有一个 mSurface 对象,也就是说一个 ViewRootImpl 对应了一个 Surface。ViewRootImpl 被创建时其实就创建了 mSurface,但 Surface 的构造函数其实是空的,说明此时这个 Surface 还不能被使用:

我们回到 View 的测量、布局、绘制前所调用到的 performTraversals 方法:

可以看出来,在三大流程之前调用了 relayoutWindow 方法,这个过程中其实就实现了 Surface 的具体创建流程

它调用到了 Session.relayout 方法,其中就将 mSurface 参数传递了过去。

而这个 WindowSession 我们都知道是个 Binder 对象,它最终调用了 WMS 的 relayoutWindow 方法:

可以看到这里调用到了 createSurfaceControl 方法:

它首先调用 createSurfaceLocked 方法构建了一个 SurfaceControl,之后调用了 SurfaceControl.getSurface 方法获取到了 Surface 对象。

SurfaceControl 的创建

在 winAnimator 的 createSurfaceLocked 方法中实际上是调用了 SurfaceControl 的构造函数,而 SurfaceControl 构造函数中实际上是调用了 Native 层的 nativeCreate 方法,并持有了其 Native 层对象的地址。

可以看到,这里最后调用到了之前建立连接时创建的 Client 的 createSurface 方法:

这里通过了 Client 最后调用到了 SurfaceFlinger 的 createLayer 方法。

其实我们客户端的 Surface 在 SurfaceFlinger 中看来叫做 Layer,因此这里的方法叫做 createLayer

Layer 有很多类型,其中一般的 Layer 最后会调用到 createNormalLayer 方法:

这里主要的操作是创建了一个 Layer 对象,并将 outLayer 所指向的对象改为了真正的 Layer 对象。并且将 Layer 的 Handle 及 IGraphicBufferProducer 通过指针传递回给了 SurfaceControl。这里的 IGraphicBufferProducer 会在创建 Surface 时用到。

Surface 的 native 对象的创建

那么我们再来看看,Surface 对象是如何被修改为可用的,我们看到 SurfaceControl.getSurface 方法:

它调用到了 outSurface 对象的 copyFrom 方法,看来这里是一个内存拷贝的操作:

首先,它通过 SurfaceControl 获取到了其 native 对象的地址,然后调用到了 nativeGetFromSurfaceControl 这一 Native 方法,之后通过 setNativeObjectLocked 方法将前面方法所得到的新 native 对象的地址设置到了当前 Surface。

我们先看看 nativeGetFromSurfaceControl 方法:

这里直接通过 Native 下 SurfaceControl 的 getSurface 方法传入构造函数构造了一个 Native 下的 Surface 对象:

最后调用到的其实是 generateSurfaceLocked 方法:

它其实是通过 mGraphicBufferProducer 构建了一个新的 Surface 对象,之后将其返回。这个 mGraphicBufferProducer 是之前创建 SurfaceControl 时所创建的 BufferLayer 的一个成员变量,看名字应该能猜出来 Surface 可以通过它创建 Buffer。

这段可能比较乱,可以用下面的图来表达 Surface、SurfaceControl、SurfaceFlinger 及 GraphicBufferProducer 的关系:

image-20190724213754758

参考资料

Android图形显示系统(一)

Android的UI显示原理之Surface的创建


Android Developer in GDUT