移动性能测试 Android 的 UI 呈现 (二)

fenfenzhong · 2016年03月18日 · 最后由 fenfenzhong 回复于 2016年08月02日 · 2828 次阅读
本帖已被设为精华帖!

上一篇Android 的 UI 呈现(一)里讲到了视图、帧的一些基本概念,和几种 UI 性能测试方法
这一篇就继续详细的分析下 UI 的构成,谈谈具体的某一帧到底是怎么呈现在我们面前

首先,介绍几个概念:

1.Window ,PhoneWindow

前面说到 Window 才是显示视图(View)的容器,看下图

Android 本来就是一个多窗口堆叠的系统,屏幕上有四种颜色,浅蓝,深蓝,绿色,紫色,就代表了四种窗口(Window)

但是上一篇我们也说到了 Window---PhoneWindow,PhoneWindow 是 Window 的子类,PhoneWindow 对应了是 Activity 中的一个对象 mWindow,是一个不可见的容器,也是一种专门为手机和平板设计的布局方案的体现

那么什么是 Window 呢?可以这么理解,Window 就是一块用来画图的矩形区域

图中虽然有 4 个 window,但最终我们看到的是一幅图,它们的重叠区域都会有序的堆叠,2d 屏幕有X轴Y轴,但事实上还有一个与屏幕垂直相交的Z轴,专业点叫z-order,Window 的摆放顺序就是按照 Z 坐标的大小,至于他们是通过什么组织在一起的,下面会讲到 SurfaceFlinger

说个直白点的例子,dota 里的相位鞋,lol 里的红叉,都有无视碰撞的效果,就是因为我们看到的一张地图,其实不止一张,它们在 Z 维度上的大小不同

2. 双缓冲

双缓冲在图像处理上非常重要,它的工作原理是:先把需要呈现的所有元素都画在一张图上(第一层),再把这张图整个投放到屏幕上去(第二层)

双缓冲的优点如下:

  1. 防止频闪(记得很久以前写 java 坦克大战项目时,如果直接把页面元素投放到屏幕上,会非常的不连贯,造成人眼可识别的卡顿)
  2. 某一具体的帧在投放到屏幕上可见之前,是有一层缓冲的渲染时间,这个时间让 CPU 和 GPU 能更好的协调工作

3. 关于 Surface 的 MVC

前面两点都是铺垫,Surface 才是真正的实现,下面来说说 Surface 里面的 MVC

  • Surface(Model)
    • Handle onto a raw buffer that is being managed by the screen compositor(官方解释)
    • Surface 就是双缓冲技术中的第一层,所有元素都要先在 Surface 上画,每个 window 对应一个 Surface
    • 既然 Surface 是用来画图的,上面就应该有一个 Canvas 对象
  • SurfaceView(听名字就知道是 View 啦)
    • SurfaceView 继承自 View,是显示视图
    • 源码里有一句: mWindow = new MyWindow(this),说明 SurfaceView 里包含一个 window,而 window 对应着 Surface,所以 SurfaceView 里包含一个 Surface
    • SurfaceView 拿到 Surface 里的控件数据,然后画出来
  • SurfaceHolder(Controler)
    • 提供访问和控制 SurfaceView 内嵌的 Surface 相关的方法,以及各种回调
    • 要注意的是,SurfaceView 的绘制过程,要以 surfaceCreated 和 surfaceDestroyed 为边界

4.SurfaceFlinger

主要用途:Android 系统的一个服务,用来生成 Surface,管理帧缓冲区,实际做的事儿就是:把不同 z 坐标的 Window 按顺序排放,将所有的 window 合成一张图,也就是一帧。
我们统计 FPS 是要关注一张完整的图的渲染时间,所以要用到 SurfaceFlinger 这个服务

adb shell dumpsys SurfaceFlinger  --latency + <Component名称>

这条命令,如果指定了正确的 Activity 名,是会有 128 行数据结果的,第一行表示刷新间隔,不同手机可能会有不同的值,接下来的 127 行表示了最近的 127 帧的渲染情况,每行分三列,第二列比较重要,因为它对应的是这一帧渲染时垂直同步脉冲到来的时间

5. VSync

垂直同步:

  1. 让帧的渲染更有规律性,防止掉帧
  2. 如果帧渲染时间太快,可以防止 FPS 比屏幕刷新率高而导致的画面撕裂
  3. 垂直同步的脉冲间隔,应该等于 1000(毫秒)/ 屏幕刷新频率(60)= 16.67 ms,也就是上述 Surface 命令的第一行

这个略复杂,引用几张图来说明

一帧的渲染,我们可以分为以下几个步骤:

  1. CPU 将图像计算成多边形
  2. 交给 GPU 去进行栅格化,这里涉及到矢量图形,位图的转换等等

上图代表没有垂直同步时的渲染情况,从下往上看,数字代表帧的编号,四个 VSync 脉冲把时间轴分为了 5 个部分。

第一部分,先是 CPU 计算,再 GPU 处理,这时正在处理第一帧,Display 的是第 0 帧,这里其实就是双缓冲的体现,当第一个 VSync 脉冲到来前,第 1 帧处理完毕

第二部分,因为第 1 帧已经计算完毕,所以可以 Display,但是可以看出 CPU 和 GPU 的合作工作是非常不自觉的,直到第二部分快结束的时候,才开始第 2 帧的计算

第三部分,第 2 帧的计算还没有完成,所以只能继续显示第一帧,这就相当于你盯着一幅图看了 32 毫秒,这就是掉帧(jank),jank 多了人眼就能识别卡顿

再看看加了 VSync 后的渲染情况,很明显,自觉了很多:

6.缓冲进阶

上面我们讲到双缓冲,但,还有更先进的技术,三缓冲,依然是引用几张图来说明:

这是很理想的状态,A 显示时计算 B,B 显示时计算 A,一切看起来有条不紊,但,世界很残酷

第一张图是因为每一帧都能在 16.67 秒之内计算完,但如果不能呢,就会如上图所示,而且又因为 VSync 的关系,在 B 慢了之后,A 就只能在下下个脉冲开始计算,这样就导致一帧慢,帧帧慢,因此有了 ---- 三缓冲

在 B 慢了之后,A 在下下次脉冲加载之前,趁着这个空闲的时间,去计算一下 C 吧,反正不能让 CPU 闲着,找个合适的机会,这样在脉冲到来时,可能就已经完成了 B 和 C 的计算,她俩都待投放到屏幕,多了个缓冲,解决了一帧慢,帧帧慢的问题

但需要重点说明一下的是:
垂直同步机制是 Android 一直都有的,三缓冲可不是,因为三缓冲会导致某一帧(比如 C)在计算完很久之后才被选中投放到屏幕,即帧延后现象。而且选择 C 去这个过程本身也是一系列计算,所以三缓冲是选择性开启,当双缓冲造成的 jank 现象越来越严重,就开启去调节一下

结语

至于利用 SurfaceFlinger 服务去计算 FPS,可以参照上一篇中的那个库,可视化一下,最后的结果,大致长这样:

Android UI 呈现这部分就写完了,以后会持续更新其他的专项测试

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 13 条回复 时间 点赞

谢谢分享,特别是这种专研的态度

加入我们 atm dota 天团吧

#2 楼 @seveniruby 哈哈,听起来就很支付

dota 里的相位鞋。。。哈哈哈

#4 楼 @neyo 比较直白。。

#5 楼 @fenfenzhong 嗯,一说就理解啦

忽然发现,我看 Testerhome 和看段子一样在笑。

其实看到最后 还是不知道那个库如何使用。。

#8 楼 @zsx10110 你好,这一篇主要不是讲解那个库的使用方法,如果想了解可以见 https://testerhome.com/topics/2232(虽然这篇已经比较久远啦。。),那个库还是有点冗长的,而且代码上有变更,你自己理解它的意思之后,得根据需要做改动,我之后会再贴一篇我现在使用的方法

请问下,如果是自定义的插件,要怎么破?比如 Listview,开发都喜欢自定义封装。。

#10 楼 @lose 你是要解决啥?

LZ,感谢分享,这个问题你解决了吗?是什么原理呢 ?

fenfenzhong · #9 · 19 天前

为什么

如果时间间隔差出现大于刷新周期的情况的话,就是一次 jank,加起来就是 jank_count
按照 Android VSync 机制,既然中间一列代表该帧开始加载时垂直脉冲到来的时间,应该只要【每 2 帧之间的时间间隔】大于 refresh_period 就代表有 jank 啊,为什么还要调用_GetNormalizedDeltas 函数,用【每 2 帧之间的时间间隔差】来计算,这个值有什么意义?

敢问楼主到底是玩 LOL 的,还是 DOTA 选手?求回复,已赞

fenfenzhong [该话题已被删除] 中提及了此贴 07月29日 16:21
fenfenzhong [该话题已被删除] 中提及了此贴 08月02日 15:27
fenfenzhong FPS 计算方法的比较 中提及了此贴 01月19日 11:13
fenfenzhong Android 的 UI 呈现 (一) 中提及了此贴 04月12日 10:04
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册