对于很多Android的显示问题,我们需要使用adb shell dumpsys SurfaceFlinger命令来获取SurfaceFlinger的dump信息,这对于我们分析问题有很大的帮助,因此我们这里来详细讲解下SurfaceFlinger的dump. SurfaceFlinger的dump信息主要通过dumpAllLocked 函数来获取,因此我们这里就以android 5.0在主屏幕上的一份dump来详细说明下dump的作用. 1 特殊宏的打开一般dump的第一行都是这样的: Build configuration: [sf] [libui] [libgui] 这说明其实没有打开任何特殊的宏,实际上,如果一下特殊宏打开,第一行log会打印出来: FRAMEBUFFER_FORCE_FORMAT,HAS_CONTEXT_PRIORITY,NEVER_DEFAULT_TO_ASYNC_MODE,TARGET_DISABLE_TRIPLE_BUFFERING,DONT_USE_FENCE_SYNC 一般情况下,这些宏一个都不会打开. 2 Sync机制第二行一般是这样的: Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync] 这行其实打印了目前使用的sync机制,这个值源于这段逻辑: if (useNativeFenceSync()) { mString.append(" EGL_ANDROID_native_fence_sync"); } if (useFenceSync()) { mString.append(" EGL_KHR_fence_sync"); } if (useWaitSync()) { mString.append(" EGL_KHR_wait_sync"); } 注意,一二是互斥的,三可以与一二共存. 3 DispSync参数第三行是打印的是Vsync相关的参数: DispSync configuration: app phase 0 ns, sf phase 0 ns, present offset 0 ns (refresh 16666667 ns) 这些参数我们还是比较熟悉的,有意思的是打印这些参数时候使用的语法: result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, " "present offset %d ns (refresh %" PRId64 " ns)", vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); PRId64的用法很独特,这是一种跨平台的打印64位整数的做法: printf("%" PRId64 "\n", value); // 相当于64位的: printf("%" "ld" "\n", value); // 或32位的: printf("%" "lld" "\n", value); 4 layer的dump接下来就是很长的一段layer的dump,一般以这样一句话开始: Visible layers (count = 9)
count的值来源于layersSortedByZ中layer的数量. + Layer 0xb3f92000 (com.sec.android.app.launcher/com.android.launcher2.Launcher) id=87 0xb3f92000指向当前layer对象的值,括号中是当前layer的名称,id是创建layer时产生的序列号. 4.1 区域信息Region transparentRegion (this=0xb3f92164, count=1) [ 0, 0, 0, 0] Region visibleRegion (this=0xb3f92008, count=1) [ 0, 0, 1440, 2560]
接下来的两段是两个Region的dump,每个region可能包含多个区域,所以这里count也可能不等于1. 4.2 基本信息layerStack= 0, z= 21010, pos=(0,0), size=(1440,2560), crop=(0, 0,1440,2560), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00] client=0xb11160c0 上面这段dump源自这段代码: result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" " client=%p\n", s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, s.active.crop.left, s.active.crop.top, s.active.crop.right, s.active.crop.bottom, isOpaque(s), contentDirty, s.alpha, s.flags, s.transform[0][0], s.transform[0][1], s.transform[1][0], s.transform[1][1], client.get());
enum { eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java eLayerOpaque = 0x02, // SURFACE_OPAQUE eLayerTransparent = 0x200, // SURFACE_TRANSPARENT }; enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, eSizeChanged = 0x00000004, eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, eVisibilityChanged = 0x00000040, eLayerStackChanged = 0x00000080, eCropChanged = 0x00000100, /* SRIB : Smg Surface Animator : State that will indicate animation change */ e3DAnimationChanged = 0x00001000, /* SRIB : Smg Surface Animator : Change End*/ eOpacityChanged = 0x00000200, // { SRUK-SFBLUR eTranslucentRegionChanged = 0x00000400, // SRUK-SFBLUR } eTransparencyChanged = 0x80000000, }; enum { // (keep in sync with Surface.java) eHidden = 0x00000004, eDestroyBackbuffer = 0x00000020, eSecure = 0x00000080, eNonPremultiplied = 0x00000100, eOpaque = 0x00000400, eProtectedByApp = 0x00000800, eProtectedByDRM = 0x00001000, eCursorWindow = 0x00002000, /* SISO Changes for Internal_Only - Start */ eFXInternalDisplay = 0x80000000, /* SISO Changes for Internal_Only - End */ eFXSurfaceNormal = 0x00000000, eFXSurfaceDim = 0x00020000, eFXSurfaceMask = 0x000F0000, // begin of app fw : fixed orientation window eFixedOrientation = 0x40000000, // end of app fw // begin of MDM remote control eNoRemoteControl = 0x08000000, // end of MDM remote control }; 所有的这些值都可能影响layer的状态,涉及不同模块不同功能,这里不再展开.
4.3 buffer信息format= 1, activeBuffer=[1440x2560:1664, 1], queued-frames=0, mRefreshPending=0 mTexName=38 mCurrentTexture=2 mCurrentCrop=[0,0,0,0] mCurrentTransform=0 mAbandoned=0 -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1440x2560], default-format=1, transform-hint=00, FIFO(0)={} [00:0xb110e100] state=FREE , 0xb3eb1ec0 [1440x2560:1664, 1] [01:0xb3ec7000] state=FREE , 0xb620d060 [1440x2560:1664, 1] >[02:0xb110e200] state=ACQUIRED, 0xb1111100 [1440x2560:1664, 1] 4.3.1 数据格式首先是数据的format,值的来源是layer创建时赋予的,当然我们如果追溯的话,可以追溯到WindowManagerService创建SurfaceControl的过程,值也是创建时指定的.值的定义如下: enum { // // these constants need to match those // in graphics/PixelFormat.java & pixelflinger/format.h // PIXEL_FORMAT_UNKNOWN = 0, PIXEL_FORMAT_NONE = 0, // logical pixel formats used by the SurfaceFlinger ----------------------- PIXEL_FORMAT_CUSTOM = -4, // Custom pixel-format described by a PixelFormatInfo structure PIXEL_FORMAT_TRANSLUCENT = -3, // System chooses a format that supports translucency (many alpha bits) PIXEL_FORMAT_TRANSPARENT = -2, // System chooses a format that supports transparency // (at least 1 alpha bit) PIXEL_FORMAT_OPAQUE = -1, // System chooses an opaque format (no alpha bits required) // real pixel formats supported for rendering ----------------------------- PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0 PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB PIXEL_FORMAT_sRGB_A_8888 = HAL_PIXEL_FORMAT_sRGB_A_8888, // 4x8-bit sRGB + A PIXEL_FORMAT_sRGB_X_8888 = HAL_PIXEL_FORMAT_sRGB_X_8888, // 4x8-bit sRGB, no A }; 其实只有下面的值是真实可用的,其余值在SurfaceFlinger创建时会被转换: switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: format = PIXEL_FORMAT_RGBX_8888; break; } 其实当前常见的format也就是这几种. HAL_PIXEL_FORMAT_RGBA_8888 = 1, HAL_PIXEL_FORMAT_RGBX_8888 = 2, HAL_PIXEL_FORMAT_RGB_888 = 3, HAL_PIXEL_FORMAT_RGB_565 = 4, HAL_PIXEL_FORMAT_BGRA_8888 = 5,
0代表未知格式. 4.3.2 activeBuffer
4.3.3 queued-frames 新的帧的数量
queued-frames的含义是是否有新的帧,如果当前没有新的帧,这个值是0. 4.3.4 mRefreshPending刷新卡住了吗?mRefreshPending几乎所有的常见情况下都是0,因为这个参数代表了一个layer执行了Invalidate却没有完成Refresh,除非发生错误这显然不可能. 4.4 SurfaceFlingerConsumer的dump
接下来开始对消费者进行dump,SurfaceFlingerConsumer是GLConsumer子类,所以这里实际上是调用了GLConsumer的dumpLocked函数. result.appendFormat( "%smTexName=%d mCurrentTexture=%d\n" "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); 它会对应打印出来这一段信息: mTexName=38 mCurrentTexture=2 mCurrentCrop=[0,0,0,0] mCurrentTransform=0 4.4.1 材质名称mTexName的值来源是在消费者被创建时,我们知道最常见的创建消费者的时候是Layer::onFirstRef时会调用: mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName); 创建一个消费者,有两个参数,其中mTextureName是我们目前关注的,如果追溯来源你会发现mTextureName的值来源于glGenTextures,这个函数的实现依赖平台,参考ligagl,它是这样的: // generate unique (shared) texture names c->surfaceManager->getToken(n, textures); 还是继续回来看SurfaceFlingerConsumer的创建: SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t tex) : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), mTransformToDisplayInverse(false) GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), mCurrentFrameNumber(0), mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), mTexName(tex), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true)
我们现在可以看出来mTexName的值来源于前面创建的材质名称. 4.4.2 mCurrentCrop裁剪区域mCurrentCrop的值来源同样是updateAndReleaseLocked调用时被赋值,值的来源是BufferItem的mCrop值.这个值基本一直都是0,只有在视频播放和照相机时会被设置(值的来源有待更深入的研究, mCrop is the current crop rectangle for this buffer slot). 4.4.3 mCurrentTransform 旋转相关
mCurrentTransform的值和前面我们说过的tr值很类似. (mTransform is the current transform flags for this buffer slot. refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>). /* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */ enum { /* flip source image horizontally */ NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H , /* flip source image vertically */ NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, /*rotate source image 90 degrees clock-wise, is applied after TRANSFORM_FLIP_{H|V} */ NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, /* rotate source image 180 degrees */ NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, /* rotate source image 270 degrees clock-wise */ NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, /* transforms source by the inverse transform of the screen it is displayed onto. This * transform is applied last */ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08 }; enum { /* flip source image horizontally (around the vertical axis) */ HAL_TRANSFORM_FLIP_H = 0x01, /* flip source image vertically (around the horizontal axis)*/ HAL_TRANSFORM_FLIP_V = 0x02, /* rotate source image 90 degrees clockwise */ HAL_TRANSFORM_ROT_90 = 0x04, /* rotate source image 180 degrees */ HAL_TRANSFORM_ROT_180 = 0x03, /* rotate source image 270 degrees clockwise */ HAL_TRANSFORM_ROT_270 = 0x07, /* don't use. see system/window.h */ HAL_TRANSFORM_RESERVED = 0x08, }; 4.5 ConsumerBase(消费者)的dump
子类GLConsumer dump完毕,调用了它的父类的dump函数,基本就是调用了IGraphicBufferConsumer的dump函数. void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, const sp<IGraphicBufferAlloc>& allocator) { sp<BufferQueueCore> core(new BufferQueueCore(allocator)); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core)); sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); *outProducer = producer; *outConsumer = consumer; 当然BufferQueueConsumer的dump函数啥也没写,就调用了BufferQueueCore的dump函数. 打印出来的信息一般是这样的: -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1440x2560], default-format=1, transform-hint=00, FIFO(0)={} [00:0xb110e100] state=FREE , 0xb3eb1ec0 [1440x2560:1664, 1] [01:0xb3ec7000] state=FREE , 0xb620d060 [1440x2560:1664, 1] >[02:0xb110e200] state=ACQUIRED, 0xb1111100 [1440x2560:1664, 1] 下面我们按照代码顺序详细解释一下: 4.5.1 队列中的buffer
我们之前在解释queued-frames的含义时已经说过,在画面持续变化时(照相预览,视频播放,窗口滑动,游戏),queued-frames值会是1.表示有新的一帧. Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", current->mSlot, current->mGraphicBuffer.get(), current->mCrop.left, current->mCrop.top, current->mCrop.right, current->mCrop.bottom, current->mTransform, current->mTimestamp, BufferItem::scalingModeName(current->mScalingMode)); ++current; } 对应打印出来的dump信息是这样的: 02:0xb631e480 crop=[0,0,0,0], xform=0x07, time=0xc4d5da9b1e0, scale=FREEZE
4.5.2 BufferQueue的基本默认信息接下来的一段代码会打印BufferQueue的一些基本信息: result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(), fifo.string()); 一般会打印如下: -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=4, transform-hint=04 4.5.2.1 允许同时acquire的buffer的数量mMaxAcquiredBufferCount是允许同时acquire的buffer的数量,解释如下: // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer // via setMaxAcquiredBufferCount, but this may only be done while no // producer is connected to the BufferQueue. This value is used to derive // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. 基本这个值只能是1,不再深究. 4.5.2.2 dequeueBuffer是否允许被block// mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and // consumer are controlled by the application. bool mDequeueBufferCannotBlock; mDequeueBufferCannotBlock几乎总是为0,除非一个应用同时控制了生产者和消费者,这很罕见. 4.5.2.3 buffer default-size默认buffer大小这两个值的来源应该是BufferQueueConsumer::setDefaultBufferSize函数(不是特别确定,因为这段代码写的不好,严重破坏了封装性). 用处是这样的: mDefaultHeight holds the default height of allocated buffers. It is used in dequeueBuffer if a width and height of 0 are specified. 4.5.2.4 mDefaultBufferFormat默认格式
mDefaultBufferFormat很简单,format含义可以参考前面的解释. 4.5.2.5 mTransformHint
同样用于旋转. 4.5.3 各个Buffer的信息接下来是打印BufferSlot中各个buffer的信息,一般打印如下: [00:0xb651d780] state=QUEUED , 0xb6321240 [1080x1920:1152, 1] [01:0xb1513200] state=FREE , 0xb65189c0 [1080x1920:1152, 1] >[02:0xb651d080] state=ACQUIRED, 0xb6518330 [1080x1920:1152, 1] 是由下面的代码打印出来的. for (int s = 0; s < maxBufferCount; ++s) { const BufferSlot& slot(mSlots[s]); const sp<GraphicBuffer>& buffer(slot.mGraphicBuffer); result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix, (slot.mBufferState == BufferSlot::ACQUIRED) ? ">" : " ", s, buffer.get(), BufferSlot::bufferStateName(slot.mBufferState)); if (buffer != NULL) { result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle, buffer->width, buffer->height, buffer->stride, buffer->format); } result.append("\n"); } }
ACQUIRED的buffer前面会打印>,表示这是当前在显示的buffer. 至此,layer的dump已经说明完毕,我们继续分析Displays的dump. 5 display信息的dump
首先会打印当前display的数量,数量基于mDisplays的大小,这个容器在SurfaceFlinger初始化时会生成数据,后面根据收到不同的消息在handleTransactionLocked函数中也会调整. Displays (2 entries) + DisplayDevice: HDMI Screen type=1, hwcId=1, layerStack=6, (1920x1080), ANativeWindow=0xb4d94d08, orient= 0 (type=00000000), flips=1173, isSecure=1, secureVis=0, powerMode=2, activeConfig=0, numLayers=1 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]] mAbandoned=0 -BufferQueue mMaxAcquiredBufferCount=2, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=1, transform-hint=00, FIFO(0)={} [00:0xb6418c80] state=FREE , 0xb43ed880 [1920x1080:1920, 1] [01:0xb43cb300] state=FREE , 0xb640d970 [1920x1080:1920, 1] >[02:0xb43cb280] state=ACQUIRED, 0xb43ed830 [1920x1080:1920, 1] + DisplayDevice: Built-in Screen type=0, hwcId=0, layerStack=0, (1080x1920), ANativeWindow=0xb4d94608, orient= 0 (type=00000000), flips=3140, isSecure=1, secureVis=0, powerMode=2, activeConfig=0, numLayers=2 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-in Screen,HDMI Screen,Virtual Screen,wfdservice等等. 5.2 设备类型type则是一个枚举值: enum DisplayType { DISPLAY_ID_INVALID = -1, DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL, DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL, NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES, }; enum { HWC_DISPLAY_PRIMARY = 0, HWC_DISPLAY_EXTERNAL = 1, // HDMI, DP, etc. HWC_DISPLAY_VIRTUAL = 2, // wfdservice HWC_NUM_PHYSICAL_DISPLAY_TYPES = 2, HWC_NUM_DISPLAY_TYPES = 3, }; 5.3 layerStack
layerStack是存储layer的容器,我们知道每个display只会有一个layerstack来存储他要显示的layer,但是不同的display可以使用同一个layerStack,也可以使用不同的layerStack. 5.4 屏幕方向
5.4 其他一些参数
7 EventThread的dumpEventThread的dump信息: VSYNC state: disabled soft-vsync: disabled numListeners=33, events-delivered: 18546 8 HWC的dumpHWC的dump从这句话开始: h/w composer state: h/w composer present and enabled 其中present和enable与否由以下参数决定: result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) ? "disabled" : "enabled");
只要init成功,就是present;而是否enable则由众多debug选项决定. 上述四个选项有任意一个打开,就composer的状态就会使disable. 接下来进入HWComposer的dump函数:
接下来就开始打印各个layer的信息,这个也是我们最常见到的layer信息. type | handle | hint | flag | tr | blnd | format | source crop(l,t,r,b) | frame | dirtyRect | name ------------+----------+----------+----------+----+-------+----------+-----------------------------------+---------------------------+------------------- HWC | aed1c650 | 0002 | 0000 | 00 | 0100 | ? 00000011 | 0.0, 0.0, 1920.0, 1080.0 | 0, 0, 960, 540 | [ 0, 0, 1920, 1080] | SurfaceView HWC | aed1c470 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2560.0, 1440.0 | 0, 0, 960, 540 | [ 0, 0, 2560, 1440] | SurfaceView FB TARGET | b3ec5240 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 960.0, 540.0 | 0, 0, 960, 540 | [ 0, 0, 0, 0] | HWC_FRAMEBUFFER_TARGET 逐次来看下:
|