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

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

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

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

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的工作。

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

流程如下图所示:

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

流程如下图所示:

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

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

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

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

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

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

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

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 在乎的人违背了答应自己的事情大概是最令人心碎的事了吧。就好像一次又一次,我爸答应我不喝酒,还是禁不住别人劝或是控制...
    取名字啥的真的好烦阅读 160评论 0 0
  • 我认为应用架构就是整个应用级别的设计模式式!应用架构的思想、设计模式的思想、面向对象的思想等等都是同一思想:高复用...
    科研者阅读 478评论 0 1
  • 用swift的朋友们很多都是从ios8开发了, 其中针对table cell高度自动计算的 UITableView...
    x1911阅读 3,183评论 1 8
  • 考虑到以上情况,我研究出五条武林秘籍供大家参考: 1.体验新鲜事物 2.挑战自己 3.有创造力的思考 4.生活中,...
    一个人的独行阅读 216评论 0 0
  • 22岁的我 从校门踏出 步入社会 对于社会的一切 我如初生婴儿一般 充满着迷茫和丝丝的恐惧 在社会这个大学中 我们...
    9cb7baf3fb48阅读 100评论 0 0