3.2 、应用 程序对窗口的控制和画图php
Surface 建立之后,应用程序就能够在 buffer 中画图了,这里就面对着两个问题了,一个是怎么知道在哪一个 buffer 上来画图,还一个就是画图之后如何通知 SurfaceFlinger 来进行 flip 。除了画图以外,若是咱们移动窗口以及改变窗口大小的时候,如何告诉SurfaceFlinger 来进行处理呢 ?在明白这些问题以前,首先咱们要了解 SurfaceFlinger 这个服务 是如何运做的:java
从类图中能够看到 SurfaceFlinger 是一个线程类,它继承了 Thread 类。当建立 SurfaceFlinger 这个服务的时候会启动一个SurfaceFlinger 监听线程,这个线程会一直等待事件的发生,好比说须要进行 sruface flip ,或者说窗口位置大小发生了变化等等,一旦产生这些事件, SurfaceComposerClient 就会经过 IBinder 发出信号,这个线程就会结束等待处理这些事件,处理完成之后会继续等待,如此循环。ide
SurfaceComposerClient 和 SurfaceFlinger 是经过 SurfaceFlingerSynchro 这个类来同步信号的,其实说穿了就是一个条件变量。监听线程等待条件的值变成 OPEN ,一旦变成 OPEN 就结束等待并将条件置成 CLOSE 而后进行事件处理,处理完成之后再继续等待条件的值变成OPEN ,而 Client 的 Surface 一旦改变就经过 IBinder 通知 SurfaceFlinger 将条件变量的值变成 OPEN ,并唤醒等待的线程,这样就经过线程类和条件变量实现了一个动态处理机制。post
了解了 SurfaceFlinger 的事件机制咱们再回头看看前面提到的问题了。首先在对 Surface 进行画图以前必须锁定 Surface 的 layer ,实际上就是锁定了 Layer_cblk_t 里的 swapstate 这个变量。 SurfaceComposerClient 经过 swapsate 的值来肯定要使用哪一个 buffer 画图,若是 swapstate 是下面的值就会阻塞 Client ,就不翻译了直接 copy 过来:ui
// We block the client if:this
// eNextFlipPending: we've used both buffers already, so we need tospa
// wait for one to become availlable..net
// eResizeRequested: the buffer we're going to acquire is being线程
// resized. Block until it is done.翻译
// eFlipRequested && eBusy: the buffer we're going to acquire is
// currently in use by the server.
// eInvalidSurface: this is a special case, we don't block in this
// case, we just return an error.
因此应用程序先调用 lockSurface() 锁定 layer 的 swapstate ,并得到画图的 buffer 而后就能够在上面进行画图了,完成之后就会调用 unlockSurfaceAndPost() 来通知 SurfaceFlinger 进行 Flip 。或者仅仅调用 unlockSurface() 而不通知 SurfaceFlinger 。
通常来讲画图的过程须要重绘 Surface 上的全部像素,由于通常状况下显示事后的像素是不作保存的,不过也能够经过设定来保存一些像素,而只绘制部分像素,这里就涉及到像素的拷贝了,须要将 Front buffer 的内容拷贝到 Back buffer 。在 SurfaceFlinger 服务实现中像素的拷贝是常常须要进行的操做,并且还可能涉及拷贝过程的转换,好比说屏幕的旋转,翻转等一系列操做。所以 Android 提供了拷贝像素的 hal ,这个也多是咱们未来须要实现的,由于用硬件完成像素的拷贝,以及拷贝过程当中可能的矩阵变换等操做,比用 memcpy 要有效率并且节省资源。这个 HAL 头文件 在: /hardware/libhardware/hardware/include/copybit.h
窗口状态变化的处理是一个很复杂的过程,首先要说明一下, SurfaceFlinger 只是执行 Windows manager 的指令,由 Windows manager 来决定什么是偶改变大小,位置,设置 透明度,以及如何调整 layer 之间的顺序, SurfaceFlinger 仅仅只是执行它的指令。 PS: Windows Manager 是 java 层的一个服务,提供对全部窗口的管理 功能,这部分的内容我没细看过,以为是未来须要了解的内容。
窗口状态的变化包括位置的移动,窗口大小,透明度, z-order 等等,首先咱们来了解一下 SurfaceComposerClient 是如何和SurfaceFlinger 来交互这些信息的。当应用程序须要改变窗口状态的时候它将全部的状态改变信息打包,而后一块儿发送给 SurfaceFlinger, SurfaceFlinger 改变这些状态信息之后,就会唤醒等待的监听线程,并设置一个标志位告诉监听线程窗口的状态已经改变了,必需要进行处理,在 Android 的实现中,这个打包的过程就是一个 Transaction ,全部对窗口状态 (layer_state_t) 的改变都必须在一个Transaction 中。
到这里应用程序客户端的处理过程已经说完了,基本分为两个部分,一个就是在窗口画图,还一个就是窗口状态改变的处理。
4 、 SurfaceFlinger 的处理过程
了解了 Flinger 和客户端的交互,咱们再来仔细看看 SurfaceFlinger 的处理过程,前面已经说过了 SurfaceFlinger 这个服务在建立的时候会启动一个监听的线程,这个线程负责每次窗口更新时候的处理,下面咱们来仔细看看这个线程的事件的处理,大体就是下面的这个图:
先大体讲一下 Android 组合各个窗口的原理 : Android 其实是经过计算每个窗口的可见区域,就是咱们在屏幕上可见的窗口区域 ( 用 Android 的词汇来讲就是 visibleRegionScreen ) ,而后将各个窗口的可见区域画到一个主 layer 的相应部分,最后就拼接成了一个完整的屏幕,而后将主 layer 输送到 FB 显示。在将各个窗口可见区域画到主 layer 过程当中涉及到一个硬件实现和一个软件实现的问题,若是是软件实现则经过 Opengl 从新画图,其中还包括存在透明度的 alpha 计算;若是实现了 copybit hal 的话,能够直接将窗口的这部分数据 直接拷贝过来,并完成可能的旋转,翻转,以及 alhpa 计算等。
下面来看看 Android 组合各个 layer 并送到 FB 显示的具体过程:
4.1 、 handleConsoleEvent
当接收到 signal 或者 singalEvent 事件之后,线程就中止等待开始对 Client 的请求进行处理,第一个步骤是 handleConsoleEvent,这个步骤我看了下和 /dev/console 这个设备有关,它会取得屏幕或者释放屏幕,只有取得屏幕的时候才可以在屏幕上画图。
4.2 、 handleTransaction
前面提到过,窗口状态的改变只能在一个 Transaction 中进行。由于窗口状态的改变可能形成本窗口和其余窗口的可见区域变化,因此就必须从新来计算窗口的可见区域。在这个处理子过程当中 Android 会根据标志位来对全部 layer 进行遍历,一旦发现哪一个窗口的状态发生了变化就设置标志位以在未来从新计算这个窗口的可见区域。在完成全部子 layer 的遍历之后, Android 还会根据标志位来处理主 layer ,举个例子,好比说传感器感应到手机横过来了,会将窗口横向显示,此时就要从新设置主 layer 的方向。
4.3 、 handlePageFlip
这里会处理每一个窗口 surface buffer 之间的翻转,根据 layer_state_t 的 swapsate 来决定是否要翻转,当 swapsate 的值是eNextFlipPending 是就会翻转。处理完翻转之后它会从新计算每一个 layer 的可见区域,这个从新计算的过程我还没看太明白,但大体是一个这么的过程:
从 Z 值最大的 layer 开始计算,也就是说从最上层的 layer 计算,去掉自己的透明区域和覆盖在它上面的不透明区域,获得的就是这个layer 的可见区域。而后这个 layer 的不透明区域就会累加到不透明覆盖区域,这个 layer 的可见区域会放入到主 layer 的可见区域,而后计算下一个 layer ,直到计算完全部的 layer 的可见区域。这中间的计算是经过定义在 skia 中的一种与或非的图形逻辑运算实现的,相似咱们数学中的与或非逻辑图。
4.4 、 handleRepaint
计算出每一个 layer 的可见区域之后,这一步就是将全部可见区域的内容画到主 layer 的相应部分了,也就是说将各个 surface buffer里面相应的内容拷贝到主 layer 相应的 buffer ,其中可能还涉及到 alpha 运算,像素的翻转,旋转等等操做,这里就像我前面说的能够用硬件来实现也能够用软件来实现。在使用软件的 opengl 作计算的过程当中还会用到 PixFlinger 来作像素的合成,这部份内容我还没时间来细看。
4.5 、 postFrameBuffer
最后的任务就是翻转主 layer 的两个 buffer ,将刚刚写入的内容放入 FB 内显示了。