赞
踩
对于很多Android的显示问题,我们需要使用adb shell dumpsys SurfaceFlinger命令来获取SurfaceFlinger的dump信息,这对于我们分析问题有很大的帮助,因此我们这里来详细讲解下SurfaceFlinger的dump.
SurfaceFlinger的dump信息主要通过dumpAllLocked 函数来获取,因此我们这里就以android 5.0在主屏幕上的一份dump来详细说明下dump的作用.
一般dump的第一行都是这样的:
这说明其实没有打开任何特殊的宏,实际上,如果一下特殊宏打开,第一行log会打印出来:
一般情况下,这些宏一个都不会打开.
第二行一般是这样的:
这行其实打印了目前使用的sync机制,这个值源于这段逻辑:
注意,一二是互斥的,三可以与一二共存.
第三行是打印的是Vsync相关的参数:
这些参数我们还是比较熟悉的,有意思的是打印这些参数时候使用的语法:
PRId64的用法很独特,这是一种跨平台的打印64位整数的做法:
接下来就是很长的一段layer的dump,一般以这样一句话开始:
count的值来源于layersSortedByZ中layer的数量.
接下来就进入各个layer的dump,我们参考代码并以launcher所在的layer为例来解释下各行的意义:
0xb3f92000指向当前layer对象的值,括号中是当前layer的名称,id是创建layer时产生的序列号.
接下来的两段是两个Region的dump,每个region可能包含多个区域,所以这里count也可能不等于1.
前两行的值来源于activeTransparentRegion,表示的是这个layer里面透明区域的大小.
后两行值来源于visibleRegion,表示可见区域的大小.
上面这段dump源自这段代码:
layerStack表示这个layer是保存在哪个layerstack中(不同的display是有不同的layerstack的,这点可以通过一个连接HDMI时的layerstack很容易确认).
z表示Z轴坐标,z值越大,layer越靠上.
pos的值是layer左上角的位置,这个值比较特殊的是ImageWallpaper这个layer的pos值,因为ImageWallpaper的大小大于屏幕大小,所以ImageWallpaper的pos值在屏幕的外面(note4是pos=(-560,0)).
size自然是layer的大小
所有的这些值都可能影响layer的状态,涉及不同模块不同功能,这里不再展开.
接下来的一组tr数据代表屏幕的旋转和缩放程度.大多数的layer实际上是不需要旋转和缩放的,因为他们定义的大小就是跟屏幕一致的,所以他们的这组数据是[1.00, 0.00][0.00, 1.00],实际上如果你使用这组数据来做矩阵变换的话,矩阵是不会发生变化的.
需要旋转的比较典型的场景是照相机.横着拿相机时它的layer的变换矩阵是[-1.00, 0.00][-0.00, -1.00],也就是旋转180°.
这个值的来源是上层调用setMatrix函数设置的.
client含义比较简单,值的来源是创建layer时,对应的SurfaceSession中mNativeClient.这东西也是跟SurfaceSession一一对应的,也就是跟SurfaceFlinger连接时一一对应的.从这个值我们可以判断,client值相同的layer,必然来自同一个进程(因为他们是由同一个连接创建出来的).
首先是数据的format,值的来源是layer创建时赋予的,当然我们如果追溯的话,可以追溯到WindowManagerService创建SurfaceControl的过程,值也是创建时指定的.值的定义如下:
其实只有下面的值是真实可用的,其余值在SurfaceFlinger创建时会被转换:
其实当前常见的format也就是这几种.
0代表未知格式.
常见的layer中,dimlayer一般是0,大多数layer是1,壁纸是2,照相机的预览数据是4,视频播放也是4.
queued-frames的含义是是否有新的帧,如果当前没有新的帧,这个值是0.
一般在画面持续变化时(照相预览,视频播放,窗口滑动,游戏),这个值会是1.表示有新的一帧.
偶尔也可以见到这个值是2(这个值应该最大就是2,因为只有三个缓冲区).
mRefreshPending几乎所有的常见情况下都是0,因为这个参数代表了一个layer执行了Invalidate却没有完成Refresh,除非发生错误这显然不可能.
接下来开始对消费者进行dump,SurfaceFlingerConsumer是GLConsumer子类,所以这里实际上是调用了GLConsumer的dumpLocked函数.
先来看下代码:
它会对应打印出来这一段信息:
mTexName的值来源是在消费者被创建时,我们知道最常见的创建消费者的时候是Layer::onFirstRef时会调用:
创建一个消费者,有两个参数,其中mTextureName是我们目前关注的,如果追溯来源你会发现mTextureName的值来源于glGenTextures,这个函数的实现依赖平台,参考ligagl,它是这样的:
还是继续回来看SurfaceFlingerConsumer的创建:
我们现在可以看出来mTexName的值来源于前面创建的材质名称.
mCurrentTexture的初始值是INVALID_BUFFER_SLOT,也就是-1,后面会在updateAndReleaseLocked时被更改,值的来源是使用的BufferItem的mBuf值,也就是mSlot,这应该是使用的buffer数组的slot值,这个变量的合理取值只有0,1,2三个值(mSlot is the slot index of this buffer ,default INVALID_BUFFER_SLOT).
mCurrentCrop的值来源同样是updateAndReleaseLocked调用时被赋值,值的来源是BufferItem的mCrop值.这个值基本一直都是0,只有在视频播放和照相机时会被设置(值的来源有待更深入的研究, mCrop is the current crop rectangle for this buffer slot).
mCurrentTransform的值和前面我们说过的tr值很类似. (mTransform is the current transform flags for this buffer slot. refer to NATIVE_WINDOW_TRANSFORM_* in ).
它也跟旋转有关,我们来看下window.h中的定义:
子类GLConsumer dump完毕,调用了它的父类的dump函数,基本就是调用了IGraphicBufferConsumer的dump函数.
生产者消费者这套体系我们之前以前讲过,这里我们就不再详细展开,如果不清楚看下Layer::onFirstRef这个函数就明白了,消费者这个值来自于BufferQueue::createBufferQueue的创建,其中创建了新的BufferQueueConsumer做为消费者.
当然BufferQueueConsumer的dump函数啥也没写,就调用了BufferQueueCore的dump函数.
打印出来的信息一般是这样的:
下面我们按照代码顺序详细解释一下:
我们之前在解释queued-frames的含义时已经说过,在画面持续变化时(照相预览,视频播放,窗口滑动,游戏),queued-frames值会是1.表示有新的一帧.
对应的,有新的frames自然需要有在队列中等待的buffer,对应这段代码会把这个队列打印出来:
对应打印出来的dump信息是这样的:
02是mSlot的值,crop是裁剪区域,xform是旋转,这三个我们上面已经讲过,这里不再展开.
time是这个buffer被queue的时间(mTimestamp is the current timestamp for this buffer slot. This gets to set by queueBuffer each time this slot is queued. This value is guaranteed to be monotonically increasing for each newly acquired buffer.).
scale是缩放模式,一般取值如下:
接下来的一段代码会打印BufferQueue的一些基本信息:
一般会打印如下:
mMaxAcquiredBufferCount是允许同时acquire的buffer的数量,解释如下:
基本这个值只能是1,不再深究.
mDequeueBufferCannotBlock几乎总是为0,除非一个应用同时控制了生产者和消费者,这很罕见.
这两个值的来源应该是BufferQueueConsumer::setDefaultBufferSize函数(不是特别确定,因为这段代码写的不好,严重破坏了封装性).
用处是这样的: mDefaultHeight holds the default height of allocated buffers. It is used in dequeueBuffer if a width and height of 0 are specified.
mDefaultBufferFormat很简单,format含义可以参考前面的解释.
mDefaultBufferFormat can be set so it will override the buffer format when it isn't specified in dequeueBuffer.
同样用于旋转.
mTransformHint is the transform probably applied to buffers of this window. this is only a hint, actual transform may differ.
接下来是打印BufferSlot中各个buffer的信息,一般打印如下:
是由下面的代码打印出来的.
ACQUIRED的buffer前面会打印>,表示这是当前在显示的buffer.
state表示buffer的状态,取值包括DEQUEUED,QUEUED,FREE,ACQUIRED.我们知道ACQUIRED是在显示的,DEQUEUED是在绘制的,QUEUED绘制完成还未显示的,free是未使用的.
后面的大小,stride,和format前面都讲过了,这里不再说明.
至此,layer的dump已经说明完毕,我们继续分析Displays的dump.
首先会打印当前display的数量,数量基于mDisplays的大小,这个容器在SurfaceFlinger初始化时会生成数据,后面根据收到不同的消息在handleTransactionLocked函数中也会调整.
正常情况下是1,也就是只有一个display(Built-in Screen),当设备连接了HDMI或者使用了屏幕共享等功能时,会有额外的display加入,比如下面这个:
这个是连接了HDMI后的数据.
首先DisplayDevice是设备的名字,这个可以调用接口设置,但是比较常见的值一般有:Built-in Screen,HDMI Screen,Virtual Screen,wfdservice等等.
type则是一个枚举值:
layerStack是存储layer的容器,我们知道每个display只会有一个layerstack来存储他要显示的layer,但是不同的display可以使用同一个layerStack,也可以使用不同的layerStack.
上面我们贴的这个就是两个display使用了不同的layerstack,因为他们显示的内容不一样(电视播放幻灯片).
后续我们可以研究下什么情况下会导致layerstack切换.
powerMode表示了屏幕当前的状态,它有以下取值:
常见的取值有0和2,代表屏幕熄灭和普通情况.
目前还没看到1和3的情况.
版权声明:本文为博主原创文章,未经博主允许不得转载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。