从systrace看app冷启动过程(二)-首帧的绘制与渲染

原创文章,转载注明出处,多谢合作。

上篇我们分析完了App的启动部分,这篇我们来看看第二个Vsync信号响应阶段:首帧的绘制与渲染

接上篇的systrace图继续往后分析:

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第1张图片
frameworks/base/core/java/android/view/Choreographer.java

   void doFrame(long frameTimeNanos, int frame) {
               ...
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
            mFrameInfo.markInputHandlingStart();
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
                ...
}

Choreographers作为用户层监听Vsync信号的处理者,它统一动画、输入和绘制的处理时机。主要针对3种类型事件:输入、绘制、动画。它主要干两件事情:通过postCallback请求vsync信号收到vsync信号并回调

一旦接收到回调信号,则通过doFrame统一对以上几种事件进行回调。

把图拉大之后能看到doFrame主要处理了Input 、animation和traversal。

这里我们主要来看看traversal阶段,它是执行视图绘制流程。这里视图绘制流程又分软件绘制与硬件加速,4.0之后默认走硬件加速,所以这里跟的是硬件加速流程。

ViewRootImpl.java中按从上往下的调用流程:

setView
|
requestLayout
|
scheduleTraversals
|
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//这里响应vsync回调
|
TraversalRunnable中执行doTraversal
|
performTraversals

而performTraversals主要就是执行performMeasure、performLayout、performDraw, 其中measure和layout在当前vsync信号内完成,draw在下一个vsync信号内完成。

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    if (mView == null) {
        return;
   }
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
   try {
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   }
}

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
       int desiredWindowHeight) {
    ...
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
   try {
        host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
      ...
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   }
 ...
}

private void performDraw() {
  ...
   Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
   try {
        draw(fullRedrawNeeded);
   } finally {
        mIsDrawing = false;
       Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   }
  ...
}

不管是硬件加速还是软件绘制,draw的过程都是在应用层构建DisplayList的数据封装,其中View tree中每个View对应一个RenderNode节点,通过绘制引擎把视图View转化成绘制操作Op,并保存在对应的View的DisplayList中,而子View又会作为一个Op保存到父容器视图的DisplayList中。

详细绘制过程请参考之前的文章:Android9.0 硬件加速(四)-UI Thread绘制过程

与此同时,除了UI Thread外,还有个RenderThread被初始化,开始了setSurface的工作。

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第2张图片

RenderThread初始化流程参考文章:Android9.0 硬件加速(二)-RenderThread线程的启动

流程如下图所示:

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第3张图片

而setSurface部分:参考之前文章:Android9.0 硬件加速(三)-绑定Surface到RenderThread

流程如下图所示:

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第4张图片

这个过程做了一系列初始化,最终创建并设置EGLSurface, 其中EGLSurface最主要任务就是dequeueBuffer/queueBuffer操作.

接下来再看看核心部分:DrawFrame过程。

硬件加速把视图的渲染工作转到了一个新的线程RenderThread中来处理。trace不好展开,这里拆分简单介绍下:

syncFrameState/prepareThree: 将UI thread的DisplayList同步到RenderThread来, 这个同步过程是阻塞UI线程的,可以看到此时UI线程是sleep状态:

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第5张图片

dequeueBuffer:通过Surface申请存放绘制数据的buffer。

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第6张图片

flash commands : DisplayList按层重新组织数据:LayerBuilder ,并转为OpenGL命令,并缓存在本地的GL命令缓冲区中。

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第7张图片

swapbuffers:通过Surface queueBuffer将绘制好的数据放入之前申请好的buffer中,并通知SurfaceFlinger去合成。

从systrace看app冷启动过程(二)-首帧的绘制与渲染_第8张图片

详细渲染过程请参考之前的文章:Android9.0 硬件加速(五) -RenderThread渲染过程

RenderThread setSurface 同步数据以及渲染操作在硬件加速篇都列出了具体标签出处及其流程,可以跟着看一下,这里就不重复贴了。

至此,首帧绘制与渲染过程完成,下一篇分析SurfaceFlinger合成过程。

你可能感兴趣的:(从systrace看app冷启动过程(二)-首帧的绘制与渲染)