您的位置:首页 > 移动开发 > Android开发

Android L SurfaceFlinger dump信息全解(1)

2016-01-13 11:20 489 查看

AndroidLSurfaceFlingerdump信息全解(1)

2015年01月22日⁄

Android⁄共19446字⁄字号小中大⁄

暂无评论

SurfaceFlinger的dump信息详解

对于很多Android的显示问题,我们需要使用adbshelldumpsysSurfaceFlinger命令来获取SurfaceFlinger的dump信息,这对于我们分析问题有很大的帮助,因此我们这里来详细讲解下SurfaceFlinger的dump.

SurfaceFlinger的dump信息主要通过dumpAllLocked函数来获取,因此我们这里就以android5.0在主屏幕上的一份dump来详细说明下dump的作用.

1特殊宏的打开

一般dump的第一行都是这样的:

1
Buildconfiguration:[sf][libui][libgui]
这说明其实没有打开任何特殊的宏,实际上,如果一下特殊宏打开,第一行log会打印出来:

1
FRAMEBUFFER_FORCE_FORMAT,HAS_CONTEXT_PRIORITY,NEVER_DEFAULT_TO_ASYNC_MODE,TARGET_DISABLE_TRIPLE_BUFFERING,DONT_USE_FENCE_SYNC
一般情况下,这些宏一个都不会打开.

2Sync机制

第二行一般是这样的:

1
Syncconfiguration:[
using
:EGL_ANDROID_native_fence_syncEGL_KHR_wait_sync]
这行其实打印了目前使用的sync机制,这个值源于这段逻辑:

1
if

(useNativeFenceSync()){
2
mString.append(
"EGL_ANDROID_native_fence_sync"
);
3
}
4
if

(useFenceSync()){
5
mString.append(
"EGL_KHR_fence_sync"
);
6
}
7
if

(useWaitSync()){
8
mString.append(
"EGL_KHR_wait_sync"
);
9
}
注意,一二是互斥的,三可以与一二共存.

3DispSync参数

第三行是打印的是Vsync相关的参数:

1
DispSyncconfiguration:appphase0ns,sfphase0ns,presentoffset0ns(refresh16666667ns)
这些参数我们还是比较熟悉的,有意思的是打印这些参数时候使用的语法:

1
result.appendFormat(
"appphase%"

PRId64
"ns,sfphase%"

PRId64
"ns,"
2
"presentoffset%dns(refresh%"

PRId64
"ns)"
,
3
vsyncPhaseOffsetNs,sfVsyncPhaseOffsetNs,PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
4
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
PRId64的用法很独特,这是一种跨平台的打印64位整数的做法:

1
printf
(
"%"

PRId64
"\n"
,value);
2
//相当于64位的:
3
printf
(
"%"

"ld"
"\n"
,value);
4
//或32位的:
5
printf
(
"%"

"lld"
"\n"
,value);

4layer的dump

接下来就是很长的一段layer的dump,一般以这样一句话开始:

1
Visiblelayers(count=9)
count的值来源于layersSortedByZ中layer的数量.

接下来就进入各个layer的dump,我们参考代码并以launcher所在的layer为例来解释下各行的意义:

1
+Layer0xb3f92000(com.sec.android.app.launcher/com.android.launcher2.Launcher)id=87
0xb3f92000指向当前layer对象的值,括号中是当前layer的名称,id是创建layer时产生的序列号.

4.1区域信息

1
RegiontransparentRegion(
this
=0xb3f92164,count=1)
2
[0,0,0,0]
3
RegionvisibleRegion(
this
=0xb3f92008,count=1)
4
[0,0,1440,2560]
接下来的两段是两个Region的dump,每个region可能包含多个区域,所以这里count也可能不等于1.

前两行的值来源于activeTransparentRegion,表示的是这个layer里面透明区域的大小.

后两行值来源于visibleRegion,表示可见区域的大小.

4.2基本信息

1
layerStack=0,z=21010,pos=(0,0),size=(1440,2560),crop=(0,0,1440,2560),isOpaque=0,
2
invalidate=0,alpha=0xff,flags=0x00000000,tr=[1.00,0.00][0.00,1.00]
3
client=0xb11160c0
上面这段dump源自这段代码:

01
result.appendFormat(

""
02
"layerStack=%4d,z=%9d,pos=(%g,%g),size=(%4d,%4d),crop=(%4d,%4d,%4d,%4d),"
03
"isOpaque=%1d,invalidate=%1d,"
04
"alpha=0x%02x,flags=0x%08x,tr=[%.2f,%.2f][%.2f,%.2f]\n"
05
"client=%p\n"
,
06
s.layerStack,s.z,s.transform.tx(),s.transform.ty(),s.active.w,s.active.h,
07
s.active.crop.left,s.active.crop.top,
08
s.active.crop.right,s.active.crop.bottom,
09
isOpaque(s),contentDirty,
10
s.alpha,s.flags,
11
s.transform[0][0],s.transform[0][1],
12
s.transform[1][0],s.transform[1][1],
13
client.get());
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的大小

crop代表裁剪区域,这点依然是对于壁纸很明显,因为壁纸layer大小大于屏幕,必须涉及到需要裁剪一部分显示在屏幕上,因此它的裁剪区域是crop=(560,0,2000,2560).
isOpaque代表是否是不透明的,只有完全不透明的layer这个值才是1,比如壁纸,像状态栏和launcher他们都是0,代表不是完全不透明的
invalidate表示这个layer的数据是失效的,这个值绝大多数情况下都是0.因为我们看到的一般都是绘制好的有效的数据.一种情况下这值特别频繁的多见为1,就是刚刚锁屏(解锁)时.因为突然锁屏,会导致绘制的内容和要显示的内容完全不同,导致layer的各种数据要重新计算,所以将layer置为失效.
alpha表示了这张layer的透明度,这个值跟isOpaque是有区别的.isOpaque表示了这个layer可以是透明的,也就是没有显示数据的地方,可以透明;而alpha表示透明度,也即是有数据的地方也可以因为透明度而收到影响产生透明的效果.
flag值含义丰富,它是众多flag或出来的结果,影响它值的包括:

01
enum
{
02
eLayerHidden=0x01,
//SURFACE_HIDDENinSurfaceControl.java
03
eLayerOpaque=0x02,
//SURFACE_OPAQUE
04
eLayerTransparent=0x200,
//SURFACE_TRANSPARENT
05
};
06
07
enum
{
08
ePositionChanged=0x00000001,
09
eLayerChanged=0x00000002,
10
eSizeChanged=0x00000004,
11
eAlphaChanged=0x00000008,
12
eMatrixChanged=0x00000010,
13
eTransparentRegionChanged=0x00000020,
14
eVisibilityChanged=0x00000040,
15
eLayerStackChanged=0x00000080,
16
eCropChanged=0x00000100,
17
/*SRIB:SmgSurfaceAnimator:Statethatwillindicateanimationchange*/
18
e3DAnimationChanged=0x00001000,
19
/*SRIB:SmgSurfaceAnimator:ChangeEnd*/
20
eOpacityChanged=0x00000200,
21
//{SRUK-SFBLUR
22
eTranslucentRegionChanged=0x00000400,
23
//SRUK-SFBLUR}
24
eTransparencyChanged=0x80000000,
25
};
26
enum
{
//(keepinsyncwithSurface.java)
27
eHidden=0x00000004,
28
eDestroyBackbuffer=0x00000020,
29
eSecure=0x00000080,
30
eNonPremultiplied=0x00000100,
31
eOpaque=0x00000400,
32
eProtectedByApp=0x00000800,
33
eProtectedByDRM=0x00001000,
34
eCursorWindow=0x00002000,
35
/*SISOChangesforInternal_Only-Start*/
36
eFXInternalDisplay=0x80000000,
37
/*SISOChangesforInternal_Only-End*/
38
eFXSurfaceNormal=0x00000000,
39
eFXSurfaceDim=0x00020000,
40
eFXSurfaceMask=0x000F0000,
41
//beginofappfw:fixedorientationwindow
42
eFixedOrientation=0x40000000,
43
//endofappfw
44
//beginofMDMremotecontrol
45
eNoRemoteControl=0x08000000,
46
//endofMDMremotecontrol
47
};
所有的这些值都可能影响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,必然来自同一个进程(因为他们是由同一个连接创建出来的).

4.3buffer信息

1
format=1,activeBuffer=[1440x2560:1664,1],queued-frames=0,mRefreshPending=0
2
mTexName=38mCurrentTexture=2
3
mCurrentCrop=[0,0,0,0]mCurrentTransform=0
4
mAbandoned=0
5
-BufferQueuemMaxAcquiredBufferCount=1,mDequeueBufferCannotBlock=0,
6
default
-size=[1440x2560],
default
-format=1,transform-hint=00,FIFO(0)={}
7
[00:0xb110e100]state=FREE,0xb3eb1ec0[1440x2560:1664,1]
8
[01:0xb3ec7000]state=FREE,0xb620d060[1440x2560:1664,1]
9
>[02:0xb110e200]state=ACQUIRED,0xb1111100[1440x2560:1664,1]

4.3.1数据格式

首先是数据的format,值的来源是layer创建时赋予的,当然我们如果追溯的话,可以追溯到WindowManagerService创建SurfaceControl的过程,值也是创建时指定的.值的定义如下:

01
enum
{
02
//
03
//theseconstantsneedtomatchthose
04
//ingraphics/PixelFormat.java&pixelflinger/format.h
05
//
06
PIXEL_FORMAT_UNKNOWN=0,
07
PIXEL_FORMAT_NONE=0,
08
//logicalpixelformatsusedbytheSurfaceFlinger-----------------------
09
PIXEL_FORMAT_CUSTOM=-4,
10
//Custompixel-formatdescribedbyaPixelFormatInfostructure
11
PIXEL_FORMAT_TRANSLUCENT=-3,
12
//Systemchoosesaformatthatsupportstranslucency(manyalphabits)
13
PIXEL_FORMAT_TRANSPARENT=-2,
14
//Systemchoosesaformatthatsupportstransparency
15
//(atleast1alphabit)
16
PIXEL_FORMAT_OPAQUE=-1,
17
//Systemchoosesanopaqueformat(noalphabitsrequired)
18
//realpixelformatssupportedforrendering-----------------------------
19
PIXEL_FORMAT_RGBA_8888=HAL_PIXEL_FORMAT_RGBA_8888,
//4x8-bitRGBA
20
PIXEL_FORMAT_RGBX_8888=HAL_PIXEL_FORMAT_RGBX_8888,
//4x8-bitRGB0
21
PIXEL_FORMAT_RGB_888=HAL_PIXEL_FORMAT_RGB_888,
//3x8-bitRGB
22
PIXEL_FORMAT_RGB_565=HAL_PIXEL_FORMAT_RGB_565,
//16-bitRGB
23
PIXEL_FORMAT_BGRA_8888=HAL_PIXEL_FORMAT_BGRA_8888,
//4x8-bitBGRA
24
PIXEL_FORMAT_RGBA_5551=6,
//16-bitARGB
25
PIXEL_FORMAT_RGBA_4444=7,
//16-bitARGB
26
PIXEL_FORMAT_sRGB_A_8888=HAL_PIXEL_FORMAT_sRGB_A_8888,
//4x8-bitsRGB+A
27
PIXEL_FORMAT_sRGB_X_8888=HAL_PIXEL_FORMAT_sRGB_X_8888,
//4x8-bitsRGB,noA
28
};
其实只有下面的值是真实可用的,其余值在SurfaceFlinger创建时会被转换:

1
switch

(format){
2
case
PIXEL_FORMAT_TRANSPARENT:
3
case
PIXEL_FORMAT_TRANSLUCENT:
4
format=PIXEL_FORMAT_RGBA_8888;
5
break
;
6
case
PIXEL_FORMAT_OPAQUE:
7
format=PIXEL_FORMAT_RGBX_8888;
8
break
;
9
}
其实当前常见的format也就是这几种.

1
HAL_PIXEL_FORMAT_RGBA_8888=1,
2
HAL_PIXEL_FORMAT_RGBX_8888=2,
3
HAL_PIXEL_FORMAT_RGB_888=3,
4
HAL_PIXEL_FORMAT_RGB_565=4,
5
HAL_PIXEL_FORMAT_BGRA_8888=5,
0代表未知格式.

常见的layer中,dimlayer一般是0,大多数layer是1,壁纸是2,照相机的预览数据是4,视频播放也是4.

4.3.2activeBuffer

activeBuffer的前两项表示了当前正在显示的buffer的宽和高.
第三项表示Stride.这个值很有意思,我们发现他有时候是等于宽的,有时候是大于宽的,我们先来看下这个值的解释.

Thenumberofpixelsthatalineinthebuffertakesinmemory.Thismaybe>=width.

我们知道内存申请使用是需要成块对齐的,也就是说不是说使我们申请多大的内存,就会给我们多大的内存,因为涉及到对齐,所以很可能这个内存实际上是大于我们的需要的.(暂时没有仔细研究,有待确认)像有些marvell型号,内存是按照64位对齐的,那么我们申请一个100宽的buffer,系统就会给我们留出128的buffer大小供我们使用.
第四项并没有什么特殊,表示format,跟前面的format应该是一致的.

4.3.3queued-frames新的帧的数量

queued-frames的含义是是否有新的帧,如果当前没有新的帧,这个值是0.

一般在画面持续变化时(照相预览,视频播放,窗口滑动,游戏),这个值会是1.表示有新的一帧.

偶尔也可以见到这个值是2(这个值应该最大就是2,因为只有三个缓冲区).

4.3.4mRefreshPending刷新卡住了吗?

mRefreshPending几乎所有的常见情况下都是0,因为这个参数代表了一个layer执行了Invalidate却没有完成Refresh,除非发生错误这显然不可能.

4.4SurfaceFlingerConsumer的dump

接下来开始对消费者进行dump,SurfaceFlingerConsumer是GLConsumer子类,所以这里实际上是调用了GLConsumer的dumpLocked函数.

先来看下代码:

1
result.appendFormat(
2
"%smTexName=%dmCurrentTexture=%d\n"
3
"%smCurrentCrop=[%d,%d,%d,%d]mCurrentTransform=%#x\n"
,
4
prefix,mTexName,mCurrentTexture,prefix,mCurrentCrop.left,
5
mCurrentCrop.top,mCurrentCrop.right,mCurrentCrop.bottom,
6
mCurrentTransform);
它会对应打印出来这一段信息:

1
mTexName=38mCurrentTexture=2
2
mCurrentCrop=[0,0,0,0]mCurrentTransform=0

4.4.1材质名称

mTexName的值来源是在消费者被创建时,我们知道最常见的创建消费者的时候是Layer::onFirstRef时会调用:

1
mSurfaceFlingerConsumer=
new

SurfaceFlingerConsumer(consumer,mTextureName);
创建一个消费者,有两个参数,其中mTextureName是我们目前关注的,如果追溯来源你会发现mTextureName的值来源于glGenTextures,这个函数的实现依赖平台,参考ligagl,它是这样的:

1
//generateunique(shared)texturenames
2
c->surfaceManager->getToken(n,textures);
还是继续回来看SurfaceFlingerConsumer的创建:

01
SurfaceFlingerConsumer(
const

sp<IGraphicBufferConsumer>&consumer,
02
uint32_ttex)
03
:GLConsumer(consumer,tex,GLConsumer::TEXTURE_EXTERNAL,
false
,

false
),
04
mTransformToDisplayInverse(
false
)
05
06
GLConsumer::GLConsumer(
const

sp<IGraphicBufferConsumer>&bq,uint32_ttex,
07
uint32_ttexTarget,
bool
useFenceSync,
bool
isControlledByApp):
08
ConsumerBase(bq,isControlledByApp),
09
mCurrentTransform(0),
10
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
11
mCurrentFence(Fence::NO_FENCE),
12
mCurrentTimestamp(0),
13
mCurrentFrameNumber(0),
14
mDefaultWidth(1),
15
mDefaultHeight(1),
16
mFilteringEnabled(
true
),
17
mTexName(tex),
18
mUseFenceSync(useFenceSync),
19
mTexTarget(texTarget),
20
mEglDisplay(EGL_NO_DISPLAY),
21
mEglContext(EGL_NO_CONTEXT),
22
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
23
mAttached(
true
)
我们现在可以看出来mTexName的值来源于前面创建的材质名称.

mCurrentTexture的初始值是INVALID_BUFFER_SLOT,也就是-1,后面会在updateAndReleaseLocked时被更改,值的来源是使用的BufferItem的mBuf值,也就是mSlot,这应该是使用的buffer数组的slot值,这个变量的合理取值只有0,1,2三个值(mSlotistheslotindexofthisbuffer,defaultINVALID_BUFFER_SLOT).

4.4.2mCurrentCrop裁剪区域

mCurrentCrop的值来源同样是updateAndReleaseLocked调用时被赋值,值的来源是BufferItem的mCrop值.这个值基本一直都是0,只有在视频播放和照相机时会被设置(值的来源有待更深入的研究,mCropisthecurrentcroprectangleforthisbufferslot).

4.4.3mCurrentTransform旋转相关

mCurrentTransform的值和前面我们说过的tr值很类似.(mTransformisthecurrenttransformflagsforthisbufferslot.refertoNATIVE_WINDOW_TRANSFORM_*in).

它也跟旋转有关,我们来看下window.h中的定义:

01
/*parameterforNATIVE_WINDOW_SET_BUFFERS_TRANSFORM*/
02
enum
{
03
/*flipsourceimagehorizontally*/
04
NATIVE_WINDOW_TRANSFORM_FLIP_H=HAL_TRANSFORM_FLIP_H,
05
/*flipsourceimagevertically*/
06
NATIVE_WINDOW_TRANSFORM_FLIP_V=HAL_TRANSFORM_FLIP_V,
07
/*rotatesourceimage90degreesclock-wise,isappliedafterTRANSFORM_FLIP_{H|V}*/
08
NATIVE_WINDOW_TRANSFORM_ROT_90=HAL_TRANSFORM_ROT_90,
09
/*rotatesourceimage180degrees*/
10
NATIVE_WINDOW_TRANSFORM_ROT_180=HAL_TRANSFORM_ROT_180,
11
/*rotatesourceimage270degreesclock-wise*/
12
NATIVE_WINDOW_TRANSFORM_ROT_270=HAL_TRANSFORM_ROT_270,
13
/*transformssourcebytheinversetransformofthescreenitisdisplayedonto.This
14
*transformisappliedlast*/
15
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY=0x08
16
};
17
18
enum
{
19
/*flipsourceimagehorizontally(aroundtheverticalaxis)*/
20
HAL_TRANSFORM_FLIP_H=0x01,
21
/*flipsourceimagevertically(aroundthehorizontalaxis)*/
22
HAL_TRANSFORM_FLIP_V=0x02,
23
/*rotatesourceimage90degreesclockwise*/
24
HAL_TRANSFORM_ROT_90=0x04,
25
/*rotatesourceimage180degrees*/
26
HAL_TRANSFORM_ROT_180=0x03,
27
/*rotatesourceimage270degreesclockwise*/
28
HAL_TRANSFORM_ROT_270=0x07,
29
/*don'tuse.seesystem/window.h*/
30
HAL_TRANSFORM_RESERVED=0x08,
31
};

4.5ConsumerBase(消费者)的dump

子类GLConsumerdump完毕,调用了它的父类的dump函数,基本就是调用了IGraphicBufferConsumer的dump函数.

生产者消费者这套体系我们之前以前讲过,这里我们就不再详细展开,如果不清楚看下Layer::onFirstRef这个函数就明白了,消费者这个值来自于BufferQueue::createBufferQueue的创建,其中创建了新的BufferQueueConsumer做为消费者.

1
void

BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>*outProducer,
2
sp<IGraphicBufferConsumer>*outConsumer,
3
const

sp<IGraphicBufferAlloc>&allocator){
4
sp<BufferQueueCore>core(
new

BufferQueueCore(allocator));
5
sp<IGraphicBufferProducer>producer(
new

BufferQueueProducer(core));
6
sp<IGraphicBufferConsumer>consumer(
new

BufferQueueConsumer(core));
7
*outProducer=producer;
8
*outConsumer=consumer;
当然BufferQueueConsumer的dump函数啥也没写,就调用了BufferQueueCore的dump函数.

打印出来的信息一般是这样的:

1
-BufferQueuemMaxAcquiredBufferCount=1,mDequeueBufferCannotBlock=0,
2
default
-size=[1440x2560],
default
-format=1,transform-hint=00,FIFO(0)={}
3
[00:0xb110e100]state=FREE,0xb3eb1ec0[1440x2560:1664,1]
4
[01:0xb3ec7000]state=FREE,0xb620d060[1440x2560:1664,1]
5
>[02:0xb110e200]state=ACQUIRED,0xb1111100[1440x2560:1664,1]
下面我们按照代码顺序详细解释一下:

4.5.1队列中的buffer

我们之前在解释queued-frames的含义时已经说过,在画面持续变化时(照相预览,视频播放,窗口滑动,游戏),queued-frames值会是1.表示有新的一帧.

对应的,有新的frames自然需要有在队列中等待的buffer,对应这段代码会把这个队列打印出来:

01
Fifo::const_iteratorcurrent(mQueue.begin());
02
while

(current!=mQueue.end()){
03
fifo.appendFormat(
"%02d:%pcrop=[%d,%d,%d,%d],"
04
"xform=0x%02x,time=%#"

PRIx64
",scale=%s\n"
,
05
current->mSlot,current->mGraphicBuffer.get(),
06
current->mCrop.left,current->mCrop.top,current->mCrop.right,
07
current->mCrop.bottom,current->mTransform,current->mTimestamp,
08
BufferItem::scalingModeName(current->mScalingMode));
09
++current;
10
}
对应打印出来的dump信息是这样的:

1
02:0xb631e480crop=[0,0,0,0],xform=0x07,
time
=0xc4d5da9b1e0,scale=FREEZE
02是mSlot的值,crop是裁剪区域,xform是旋转,这三个我们上面已经讲过,这里不再展开.

time是这个buffer被queue的时间(mTimestampisthecurrenttimestampforthisbufferslot.ThisgetstosetbyqueueBuffereachtimethisslotisqueued.Thisvalueisguaranteedtobemonotonicallyincreasingforeachnewlyacquiredbuffer.).

scale是缩放模式,一般取值如下:

01
enum
{
02
/*thewindowcontentisnotupdated(frozen)untilabufferof
03
*thewindowsizeisreceived(enqueued)
04
*/
05
NATIVE_WINDOW_SCALING_MODE_FREEZE=0,
06
/*thebufferisscaledinbothdimensionstomatchthewindowsize*/
07
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW=1,
08
/*thebufferisscaleduniformlysuchthatthesmallerdimension
09
*ofthebuffermatchesthewindowsize(croppingintheprocess)
10
*/
11
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP=2,
12
/*thewindowisclippedtothesizeofthebuffer'scroprectangle;pixels
13
*outsidethecroprectanglearetreatedasiftheyarecompletely
14
*transparent.
15
*/
16
NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP=3,
17
};

4.5.2BufferQueue的基本默认信息

接下来的一段代码会打印BufferQueue的一些基本信息:

1
result.appendFormat(
"%s-BufferQueuemMaxAcquiredBufferCount=%d,"
2
"mDequeueBufferCannotBlock=%d,default-size=[%dx%d],"
3
"default-format=%d,transform-hint=%02x,FIFO(%zu)={%s}\n"
,
4
prefix,mMaxAcquiredBufferCount,mDequeueBufferCannotBlock,
5
mDefaultWidth,mDefaultHeight,mDefaultBufferFormat,mTransformHint,
6
mQueue.size(),fifo.string());
一般会打印如下:

1
-BufferQueuemMaxAcquiredBufferCount=1,mDequeueBufferCannotBlock=0,
default
-size=[1920x1080],
2
default
-format=4,transform-hint=04

4.5.2.1允许同时acquire的buffer的数量

mMaxAcquiredBufferCount是允许同时acquire的buffer的数量,解释如下:

1
//mMaxAcquiredBufferCountisthenumberofbuffersthattheconsumermay
2
//acquireatonetime.Itdefaultsto1,andcanbechangedbytheconsumer
3
//viasetMaxAcquiredBufferCount,butthismayonlybedonewhileno
4
//producerisconnectedtotheBufferQueue.Thisvalueisusedtoderive
5
//thevaluereturnedfortheMIN_UNDEQUEUED_BUFFERSquerytotheproducer.
基本这个值只能是1,不再深究.

4.5.2.2dequeueBuffer是否允许被block

1
//mDequeueBufferCannotBlockindicateswhetherdequeueBufferisallowedto
2
//block.Thisflagissetduringconnectwhenboththeproducerand
3
//consumerarecontrolledbytheapplication.
4
bool
mDequeueBufferCannotBlock;
mDequeueBufferCannotBlock几乎总是为0,除非一个应用同时控制了生产者和消费者,这很罕见.

4.5.2.3bufferdefault-size默认buffer大小

这两个值的来源应该是BufferQueueConsumer::setDefaultBufferSize函数(不是特别确定,因为这段代码写的不好,严重破坏了封装性).

用处是这样的:mDefaultHeightholdsthedefaultheightofallocatedbuffers.ItisusedindequeueBufferifawidthandheightof0arespecified.

4.5.2.4mDefaultBufferFormat默认格式

mDefaultBufferFormat很简单,format含义可以参考前面的解释.

mDefaultBufferFormatcanbesetsoitwilloverridethebufferformatwhenitisn'tspecifiedindequeueBuffer.

4.5.2.5mTransformHint

同样用于旋转.

mTransformHintisthetransformprobablyappliedtobuffersofthiswindow.thisisonlyahint,actualtransformmaydiffer.

4.5.3各个Buffer的信息

接下来是打印BufferSlot中各个buffer的信息,一般打印如下:

1
[00:0xb651d780]state=QUEUED,0xb6321240[1080x1920:1152,1]
2
[01:0xb1513200]state=FREE,0xb65189c0[1080x1920:1152,1]
3
>[02:0xb651d080]state=ACQUIRED,0xb6518330[1080x1920:1152,1]
是由下面的代码打印出来的.

01
for

(
int

s=0;s<maxBufferCount;++s){
02
const

BufferSlot&slot(mSlots[s]);
03
const

sp<GraphicBuffer>&buffer(slot.mGraphicBuffer);
04
result.appendFormat(
"%s%s[%02d:%p]state=%-8s"
,prefix,
05
(slot.mBufferState==BufferSlot::ACQUIRED)?
">"
:
""
,
06
s,buffer.get(),
07
BufferSlot::bufferStateName(slot.mBufferState));
08
if

(buffer!=NULL){
09
result.appendFormat(
",%p[%4ux%4u:%4u,%3X]"
,buffer->handle,
10
buffer->width,buffer->height,buffer->stride,
11
buffer->format);
12
}
13
result.append(
"\n"
);
14
}
15
}
ACQUIRED的buffer前面会打印>,表示这是当前在显示的buffer.

state表示buffer的状态,取值包括DEQUEUED,QUEUED,FREE,ACQUIRED.我们知道ACQUIRED是在显示的,DEQUEUED是在绘制的,QUEUED绘制完成还未显示的,free是未使用的.

后面的大小,stride,和format前面都讲过了,这里不再说明.

至此,layer的dump已经说明完毕,我们继续分析Displays的dump.

5display信息的dump

首先会打印当前display的数量,数量基于mDisplays的大小,这个容器在SurfaceFlinger初始化时会生成数据,后面根据收到不同的消息在handleTransactionLocked函数中也会调整.

正常情况下是1,也就是只有一个display(Built-inScreen),当设备连接了HDMI或者使用了屏幕共享等功能时,会有额外的display加入,比如下面这个:

01
Displays(2entries)
02
+DisplayDevice:HDMIScreen
03
type=1,hwcId=1,layerStack=6,(1920x1080),ANativeWindow=0xb4d94d08,orient=0(type=00000000),flips=1173,isSecure=1,
04
secureVis=0,powerMode=2,activeConfig=0,numLayers=1
05
v:[0,0,1920,1080],f:[0,0,1920,1080],s:[0,0,1920,1080],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]]
06
mAbandoned=0
07
-BufferQueuemMaxAcquiredBufferCount=2,mDequeueBufferCannotBlock=0,
default
-size=[1920x1080],
default
-format=1,transform-hint=00,
08
FIFO(0)={}
09
[00:0xb6418c80]state=FREE,0xb43ed880[1920x1080:1920,1]
10
[01:0xb43cb300]state=FREE,0xb640d970[1920x1080:1920,1]
11
>[02:0xb43cb280]state=ACQUIRED,0xb43ed830[1920x1080:1920,1]
12
+DisplayDevice:Built-inScreen
13
type=0,hwcId=0,layerStack=0,(1080x1920),ANativeWindow=0xb4d94608,orient=0(type=00000000),flips=3140,isSecure=1,
14
secureVis=0,powerMode=2,activeConfig=0,numLayers=2
15
v:[0,0,1080,1920],f:[0,0,1080,1920],s:[0,0,1080,1920],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]]
这个是连接了HDMI后的数据.

5.1设备名称

首先DisplayDevice是设备的名字,这个可以调用接口设置,但是比较常见的值一般有:Built-inScreen,HDMIScreen,VirtualScreen,wfdservice等等.

5.2设备类型

type则是一个枚举值:

01
enum

DisplayType{
02
DISPLAY_ID_INVALID=-1,
03
DISPLAY_PRIMARY=HWC_DISPLAY_PRIMARY,
04
DISPLAY_EXTERNAL=HWC_DISPLAY_EXTERNAL,
05
DISPLAY_VIRTUAL=HWC_DISPLAY_VIRTUAL,
06
NUM_BUILTIN_DISPLAY_TYPES=HWC_NUM_PHYSICAL_DISPLAY_TYPES,
07
};
08
09
enum
{
10
HWC_DISPLAY_PRIMARY=0,
11
HWC_DISPLAY_EXTERNAL=1,
//HDMI,DP,etc.
12
HWC_DISPLAY_VIRTUAL=2,
//wfdservice
13
HWC_NUM_PHYSICAL_DISPLAY_TYPES=2,
14
HWC_NUM_DISPLAY_TYPES=3,
15
};

5.3layerStack

layerStack是存储layer的容器,我们知道每个display只会有一个layerstack来存储他要显示的layer,但是不同的display可以使用同一个layerStack,也可以使用不同的layerStack.

上面我们贴的这个就是两个display使用了不同的layerstack,因为他们显示的内容不一样(电视播放幻灯片).

后续我们可以研究下什么情况下会导致layerstack切换.

5.4屏幕方向

orient表示屏幕方向
后面括号里面的type,是和我们上面说的设备类型完全不同的东西,这个值是由Transform::type算出来的.

基本是下面这些值与或非出来的:

1
enum

type_mask{
2
IDENTITY=0,
3
TRANSLATE=0x1,
4
ROTATE=0x2,
5
SCALE=0x4,
6
UNKNOWN=0x8
7
};

5.5powerMode

powerMode表示了屏幕当前的状态,它有以下取值:

01
enum
{
02
/*Thedisplayisturnedoff(blanked).*/
03
HWC_POWER_MODE_OFF=0,
04
/*Thedisplayisturnedonandconfiguredinalowpowerstate
05
*thatissuitableforpresentingambientinformationtotheuser,
06
*possiblywithlowerfidelitythannormalbutgreaterefficiency.*/
07
HWC_POWER_MODE_DOZE=1,
08
/*Thedisplayisturnedonnormally.*/
09
HWC_POWER_MODE_NORMAL=2,
10
/*ThedisplayisconfiguredasinHWC_POWER_MODE_DOZEbutmay
11
*stopapplyingframebufferupdatesfromthegraphicssubsystem.
12
*Thispowermodeiseffectivelyahintfromthedozedreamto
13
*tellthehardwarethatitisdonedrawingtothedisplayforthe
14
*timebeingandthatthedisplayshouldremainoninalowpower
15
*stateandcontinueshowingitscurrentcontentsindefinitely
16
*untilthemodechanges.
17
*
18
*Thismodemayalsobeusedasasignaltoenablehardware-baseddoze
19
*functionality.Inthiscase,thedozedreamiseffectively
20
*indicatingthatthehardwareisfreetotakeoverthedisplay
21
*andmanageitautonomouslytoimplementlowpoweralways-ondisplay
22
*functionality.*/
23
HWC_POWER_MODE_DOZE_SUSPEND=3,
24
};
常见的取值有0和2,代表屏幕熄灭和普通情况.

目前还没看到1和3的情况.

5.4其他一些参数

设备大小由eglQuerySurface得来,不展开.
ANativeWindow代表要渲染的本地窗口,这个不同的display之间应该肯定不同.
flips代表屏幕翻页的次数,其实也就是SurfaceFlinger调用doComposition的次数,也就是屏幕画面更新的次数
hwcId需要注意的是,如果一个设备不是HWC合成的,这个值会是负数.需要指出的是,这个值不受开关overlay的影响,也就是说如果这个设备是支持HWC的,应该就不会是负数.目前来看,只有开发者选项模拟二级显示出现的display这个会是负数.
mIsSecure是屏幕自身的属性,mSecureLayerVisible应该会跟播放DRM之类的场景相关
activeConfig目前看到的总是0,还不清楚作用
numLayers是这个display上可见的layer的数量
v,f,s分别代表三个大小:Viewport,Frame,Scissor.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: