比较常用的SurfaceFlinger 的debug 方式包括下面三种:winscope、dump、sys trace。
winscope:适用用闪黑闪屏动态异常
dump:适用于静态显示异常
sys trace:适用于分析绘制流程或卡顿问题
6.1 winscope
适用于逐帧查看Layer 信息或窗口状态:
官网连接:
source.android.google.cn/docs/core/g…
抓取
- 记录 SurfaceFlinger Layer的跟踪:
adb shell su root service call SurfaceFlinger 1025 i32 1
adb shell su root service call SurfaceFlinger 1025 i32 0
取出trace文件
adb pull /data/misc/wmtrace/layers_trace.pb layers_trace.pb
2. 记录 WindowManager 的跟踪情况:
adb shell cmd window tracing start
adb shell cmd window tracing stop
取出trace文件
adb pull /data/misc/wmtrace/wm_trace.pb wm_trace.pb
或者直接将文件夹pull 出来
adb pull /data/misc/wmtrace
分析
工具在源码路径如下:
android/prebuilts/misc/common/winscope
打开winscope.html,选择pb 文件,下面以layers_trace.pb为例:
6.2 dump
抓取
adb shell dumpsys SurfaceFlinger >sf.txt
当前hwc 合成layer, 顺序为从上到下:
Display 1 HWC layers:
-----------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) [Focused]
-----------------------------------------------------------------------------------------------------------------------------------------------
SurfaceView - com.baidu.naviauto/com.baidu.naviauto.NaviAutoActivity#0
rel -2 | 0 | CLIENT | 0 | 0 0 1440 1920 | 0.0 0.0 1440.0 1920.0 | [*]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
com.baidu.naviauto/com.baidu.naviauto.NaviAutoActivity#0
rel 0 | 1 | CLIENT | 0 | 0 0 1440 1920 | 0.0 0.0 1440.0 1920.0 | [*]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatusBar#0
rel 0 | 2000 | CLIENT | 0 | 0 0 1440 96 | 0.0 0.0 1440.0 96.0 | [ ]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Background for -SurfaceView - dock#0
rel -1 | 0 | CLIENT | 0 | 98 1796 1342 1912 | 0.0 0.0 0.0 0.0 | [ ]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dock#0
rel 0 | 2059 | CLIENT | 0 | 0 1796 1440 1920 | 0.0 0.0 1440.0 124.0 | [ ]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
分析
所有layer 信息,
常用的包括:
- layerStack:可以理解为上层的display id
- z:zOrder ,越大越靠上,最小-2
- pos:位置
- Size:大小
- crop:被裁减大小,会影响layer 大小
- parent:父layer
+ BufferQueueLayer (com.baidu.naviauto/com.baidu.naviauto.NaviAutoActivity#0)
Region TransparentRegion (this=0 count=0)
Region VisibleRegion (this=0 count=1)
[ 0, 0, 1440, 1920]
Region SurfaceDamageRegion (this=0 count=0)
layerStack= 0, z= 0, pos=(0,0), size=(1440,1920), crop=[ 0, 0, 1440, 1920], cornerRadius=0.000000, isProtected=0, isOpaque=0, invalidate=0, dataspace=Default, defaultPixelFormat=RGBA_8888, backgroundBlurRadius=0, color=(0.000,0.000,0.000,1.000), flags=0x00000000, tr=[0.00, 0.00][0.00, 0.00]
parent=c024748 com.baidu.naviauto/com.baidu.naviauto.NaviAutoActivity#0
zOrderRelativeOf=none
activeBuffer=[1440x1920:1472,RGBA_8888], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0, mRefreshPending=0, metadata={windowType:1, ownerUID:10080}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00], shadowRadius=0.000,
flyme extension:
6.3 systrace
抓取
adb shell perfetto -o /data/misc/perfetto-traces/trace_file.perfetto-trace -t 10s sched freq idle am wm gfx view
取出文件:
adb pull /data/misc/perfetto-traces/trace_file.perfetto-trace .
打开以下连接开始分析trace:
分析
- 应用进程:
主线程比较简单,主要是绘制三部曲,这里重点看下渲染线程:
每次硬件加速绘制都会调用Surface.unlockCanvasAndPost,一直到绘制完成queueBuffer 流程如下,标红色背景为sys trace 中会打印的方法:
Surface.unlockCanvasAndPost()
-> HwuiContext::unlockAndPost()
->HardwareRenderer::syncAndDraw()
->RenderProxy.cpp ::syncAndDrawFrame()
-> DrawFrameTask::drawFrame()
-> DrawFrameTask::run() 渲染线程开始执行绘制操作
-> DrawFrameTask::syncFrameState 与主线程同步数据,这个阶段在用AutoMutex加锁,主线程等待
->CanvasContext::prepareTree
-> CanvasContext::draw 通过调用OpenGLPipeline方法开始绘制
->SkSurface::flushAndSubmit() 提交绘制请求到GPU
->SkiaOpenGLPipeline::swapBuffers (CanvasContext::draw()中调用)交换buffer 到SurfaceFlinger
->eglSwapBuffersWithDamageKHR()该方法执行完成后,将回调ANativeWindow::queueBuffer进一步回调到
->Surface::hook_queueBuffer() 到现在应用进程绘制完成
- SurfaceFlinger:
-
onMessageInvalidate
- 遍历所有layer,通过acquireBuffer 获取buffer 更新
-
onMessageRefresh
- 计算可见layer,计算脏区,保存在类Output::mCurrentOutputLayersOrderedByZ中
- prepareFrame 和Hwbinder 通信选择合成策略,需要显示的数据已经送到HWC,且每一层Layer的合成方式已经确定,Buffer也只是将Buffer的handle传给底层的HWC,并没有传Buffer里面的内容,这里创建底层HWCLayer
- finishFrame finishFrame 主要处理需要GPU合成的layer,将Client端的Layer渲染到FBTarget(GPU 作为client dequeueBuffer进行渲染,然后通过queueBuffer到BufferQueue,再acquireBuffer ,将各layer 合成后的数据保存在FBTarget,通过setClientTarget给HWC设置Client端的合成结果,传给底层进行显示)
- postFramebuffer 告诉HWC开始做最后的合成了,包括client和device合成
- postComposition 到此一次合成处理完成,REFRESH处理完成。下一个Vsync到来时,新的一次合成