UI绘制过程解析

一、目的:主要核心是探究UI如何进行具体绘制

1.UI从数据加载到具体展现的过程:

UI绘制过程解析

2.进程间的启动协作:

UI绘制过程解析

二、如何加载到数据

1.应用从启动到onCreate的过程:

UI绘制过程解析

2.Activity生产过程详解:

        1) AMS启动流程:

        [21版本]

        UI绘制过程解析

        [28版本]

UI绘制过程解析

        2)核心对象:

UI绘制过程解析

        3)Activity具体生产流程:

                1.zygote进程fork后,系统启动ActivityThread;

                2.ActivityThread准备一个ApplicationThread用于和AMS通信;

                3.ActivityThread发起一个对于AMS.attachApplication的Binder调用;

                4.在AMS中验证ActivityThread的调用过程,忽略其他不看,关于流程重点在bindApplication上,在bindApplication中发现数据组装后的Handler调用,sendMessage转入handlerMessage中(BIND_APPLICATION),最终调用到handleBindApplication;

                5.handleBindApplication中,mInstrumentation用于管理构建对象的生命周期,Application的反射构建和最后的调用create函数;

                【上述过程完成了Application的创建调用管理过程,接着是Activity的相关管理】

                6.回到AMS中,继续thread的观察,mStackSupervisor.attachApplicatoinLocked完成对Activity的管理;

                7.验证是否是Main入口被Launcher;

                8.进入realStartActivityLocked中去启动Activity创建,ClientTransactionActivity启动事务管理,首先会封装事务数据,然后进行相关事务提交,事务提交的目的是让人去进行调度,ClientTransaction进行回调后调用的是ApplicationThread中的scheduleTransaction,发送消息EXECUTE_TRANSACTION;

                9.消息发送接收到后执行mTransactionExecutor.execute,此时执行到回调内部发现executeCallbacks内部取回了一个callback进行执行,而之前在ActivityStackSupervisor中添加到是LaunchActivityItem,之后调用item.execute,内部能够看到调用了client.handleLaunchActivity,最后调用performLaunchActivity进行处理;

                10.在performLaunchActivity反射构建了Activity,之后进行activity.attach初始化PhoneWindow对象,再调用了Activity生命周期函数callActivityOnCreate(acitivty.performCreate);

        总结:

                a.Lunch进程会将清单文件中相关信息数据传入AMS;

                b.AMS负责管理配置信息;

                c.Activity启动后生产一个ApplicationThread通信类与AMS进行通信;

                d.AMS接收到attach调用后,筛选相关配置信息打包后交由事务管理进行回调,事务管理会回调ApplicationThread中相关schedule函数进行通信;

                e.所有的具体数据构建的反射构建由Instrumentation完成;

        4)setContentView加载数据的核心概念

                目的是xml信息的加载和管理:1.加载基础布局的数据;2.加载用户布局数据。

                UI绘制过程解析

                1.Activity.setContentView,这里实际上调用的是Window.setContentView,在attach中实际上生产的对象是PhoneWindow,所以这里对应的是PhoneWindow.setContentView;

                2.PhoneWindow.setContentView中,由installDecor完成基础布局数据加载,由mLayoutInflater.inflate完成用户布局数据加载;

                总结:

                        a.加载基础布局xml生产对应数据,形成DecorView;

                        b.将用户布局要挂载的位置提取出来,即mContentParent;

                        c.逐层加载用户布局文件生产对应的VIew,挂载到mContentParent下,至此所有View数据加载完毕。

三、数据交给谁管理,如何管理View

1.handleResumeActivity被触发的时机;    

        1)通过launcher进程出发AMS.startActivity,LauncherAcitivty.onListItemClick-->Activity.startActivityForResult-->Instrumentation.execStartActviity;

        2)由ActivityManager.startActivity触发ATMS的startActivity-->startActivityAsUser(ActivityStarter.execute);

        3)在ActivityStarter.execute中调用startActivityMayWait-->startActivityUncheched-->ActivityStackSupervisor.resumeFocusedStackTopActivityLocked-->ActivityStack.resumeFocusedStackTopAcivityLocked-->ActivityStackSupervisor.startSpecificActivityLocked-->在realStartActivityLocked看到事务调用处理,注意andResume状态;

        4)在当前位置进行对生命周期状态的设置,而到ActivityThread中执行是TransactionExecutor中会在执行完callback后调用生命周期的执行。

        总结:从launcher中发起调用,然后调用到AMS中,在AMS中会对当前状态进行设置,而处理launcherItem的callback之后会处理生命周期,那么只需要在每一个生命周期调用时去进行下一个生命周期的设置就能完成生命周期调用链条的产生,如下图:

UI绘制过程解析

UI绘制过程解析

2.将View添加到Window的时机

        1)上面分析结果已经能够确认handleResumeActivity的调用;

        2)在handleResumeActivity中调用perfromResumeActivity;

        3)在之前的Activity.attach中,已经完成对WindowManager的创建,在handleResumeActivity后续调用中有wm.addView将Decor添加到WindowManager进行管理;

        4)深入发现addView被转嫁到WindowManagerGlobal.addView,这个类负责与WMS进行通信,通过addView生产一个ViewRootImpl对象对VIew进行管理;

        5)VIewRootImpl.setView中requestLayout调用;

        6)requestLayout中调用scheduleTraversals;

        7)此处注意在scheduleTraversals中有一个mChoreographer属性,这是一个非常核心的关键对象,Choreographer的引入,主要是配合Vsyns,给上层App的渲染提供一个稳定的绘制处理时机,也就是Vsync到来的时候,Choreographer可以接收Vsync信号,统一管理应用的输入、动画、绘制等任务的实际执行。

四、绘制管理节奏

1.Choreography管理节奏

        总体流程示意:

UI绘制过程解析

        1)继续上述将view交给Window后,在ViewRootImpl.scheduleTraverals中,Choreographer发起postCallback;

        2)进入消息队列发送,在Choreographer创建阶段我们可以看到绘制节奏固定时16.63每帧,帧率存储在框架层面的系统属性文件中;

        3)进入Choreographer从postCallback进行分析,首先需要注意的是传入一个mTraversalRunnable对象,该对象是一个线程接口的实现;

        4)进入postCallback后发现该线程接口对象,进入一个队列以数组+列表形成存储,然后进行一组消息发送;

        UI绘制过程解析

        5)mHandler(内部类FrameHandler对象)对象分析,当前FrameHandler对象主要是管理整个绘制过程的调用以及控制绘制节奏,MSG_DO_SCHEDULE_CALLBACK:回调(函数控制)、MSG_DO_SCHEDULE_VSYNC:底层请求垂直同步信号、MSG_DO_FRAME:帧绘制;

        6)三个消息处理函数分析,doScheduleCallback:这里不做任何处理,只验证是否存在延迟、doScheduleVsync:这里被触发只有一种状况就是在子线程中调用的绘制、doFrame:绘制帧;

        7) 调用DisplayEventReceiver的scheduleVsync到native层请求同步信号,在dispatchVsync(Called from native code.)回调,最后会回到FrameHandler对象中执行run函数,最终在doCallbacks中通过CALLBACK_TRAVERSALViewRootImpl执行到doTraversal-->performTraversals为最终的绘制者。

2.Surfaceflinger简述

        1)Surfaceflinger概述

                SurfaceFlinger作为androids中真正的绘制者,他在最底层调用OpenGL进行硬件层面的绘制。本身是一个独立的服务,是framebuffer合成的服务,将各个应用程序及应用程序中的逻辑窗口图像数据(surface)合成到一个物理窗口中显示(framebuffer)的服务程序。init进程是linux系统中用户空间的第一个进程,进程号为1,当bootloader启动后,启动kernel后,在用户空间启动init进程,再通过init进程来读取init.rc中的相关配置,从而启动其他相关进程以及其他操作,而Surfaceflinger就是由init进程启动的。处理过程如下:

UI绘制过程解析

                 核心问题:Surface是面向android系统中所有UI应用程序的,即它承担着应用进程中的UI显示需求。需要面向上传实现(主要是Java层)提供绘制图像的画板。Surfaceflinger需要收集系统中所有应用程序绘制的图像数据,然后集中显示到物理屏幕上。Surface需要扮演相应角色,本质上还是由Surfaceflinger服务统一管理,涉及到很多跨进程的通信细节。

        2)帧缓冲区(Frame Buffer)

                帧缓冲(framebuffer)是linux为显示提供的一个接口,把显存抽象后的一种设计,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

        3)Surfaceflinger的三个核心线程

                a)UI渲染进程

                        Surfaceflinger服务的UI渲染线程有一个消息队列,当队列为空时,Surfaceflinger服务的UI渲染线程就会进入休眠等待状态。一旦SurfaceFlinger服务的Binder线程接收到其他进程发送过来的渲染UI的请求时,它就会往UI渲染线程的消息队列发送一个消息,唤醒线程执行渲染操作。同样,一旦Surfaceflinger服务的控制台事件监控线程发现硬件帧缓冲区即将进入睡眠或者唤醒状态时,它就会往UI渲染线程的消息队列中发送一个消息,以便UI渲染线程可以执行冻结或者解冻显示屏的操作。

                b)Binder线程:跨进程通信;

                c)事件处理线程:Vsync信号。

五、具体绘制过程

1.WMS与绘制的关系

        1)WMS对象解析

                WindowManager:桥接的管理对象,而非AMS;

                WindowManagerGlobal:AMS通信类;

                WindowSession:AMS具体通信对象;

                WIndowToken:鉴别Token,实际上是一个IWindow的Binder;

                WindowState:窗口实体,即窗口所有的属性;

                WindowHashMap:所有窗口的容器(IWindow,WindowState)。

        2)WMS的功能与作用

                1.主要负责测算View的显示尺寸、位置、层级等;

                2.负责与Surfaceflinger进行具体的绘制;

                WMS扮演的是数据管理者和与SurfaceFlinger的通信协调者。

2.performTraversals【定位来自上述:四,1,7)】

        1)关于Surface

                在ViewRootImpl中我们可以看到surface(包含一个画布)的创建,因为最终的绘制图形数据是由底层的Surfaceflinger完成的,所以这里我们认为当前的Surface仅有我们的用户数据对象,需要在native层与系统的surface(由native创建)合并后才最终提供绘制。

        2)relayoutWindow

                做了三件事情:保存信息到WMS、判定是否有需要重新计算相关坐标等数据,可见性、去native层申请一个Surface  返回地址回来。

        3)performMeasure、performLayout、performDraw

3.图像生成过程

UI绘制过程解析 六、总结

1.由Launcher发起调用;

2.AMS管理配置信息数据;

3.具体的对象创建过程在ActivityThread中完成;

4.由AMS的startActivity触发resume生命周期,在resume中对于View数据进行推送至WindowManager进行管理,同时生成一个ViewRootImpl对象对所有View数据进行绘制管理;

5.ViewRootImpl中依赖于编舞者工具对绘制进行控制,一般情况为60FPS;

6.具体绘制由ViewRootImpl中的performTraversals进行具体绘制操作;

7.每一个View都是一个Surface;

8.由WMS统一协调各个VIew的层级、尺寸、布局等;

9.最终交由Surfaceflinger进行帧合成,完成整体界面输出;

10.底层由OpenGL完成;

上一篇:浏览器兼容性问题:典例


下一篇:深入Android系统(十二)Android图形显示系统-2-SurfaceFlinger与图像输出