系列文章目录Android系统启动 ---- 主要流程类_MrDarly的博客-CSDN博客_android 启动类Android系统启动Zygote关系主要的类https://blog.csdn.net/weixin_68948960/article/details/125310042
Android系统开发 ----- 系统服务开发_MrDarly的博客-CSDN博客_android系统服务开发Android系统开发 系统服务开发https://blog.csdn.net/weixin_68948960/article/details/125427955
前言
日常Android应用开发过程中,没有去了解Android的组件,Activity、Dialog等等可以设置xml布局文件或者可以直接设置控件对象到界面上。哪么真正从设置控件到展示在屏幕上的流程和原理,我们认识多少呢?
当然日常应用开发不用了解这些,作为知识扩展还是可以了解一下:
WindowManagerService(WMS)系统服务做什么?
SurfaceFlinger Native服务做什么?
OpenGL ES 是什么?
FrameBuffer是什么?
等等,一系列的概念和名称我们都可以了解到。
一、记录的是什么
Android屏幕显示整体流程、涉及到了整体框架结构。
从应用层到系统Java FrameWork层,到系统Native FrameWork层,到系统独立服务SurfaceFlinger,到HAL标准设备接口层,到Kernel内核缓冲区层,到设备硬件显示缓冲区,进行图像展示。
由于涉及到了很多层级结构,各个层级又有不同的实现方案、导致整体流程在Android系统中晦涩难懂,代码来回穿插,更影响了逻辑梳理。
梳理了整体流程,细节上做了很多省略,基于AOSP 12 版本的代码逻辑进行梳理。
整体流程见下图:
上层应用端将控件全部都通过setContentView方法传递到了窗口PhoneWindow中。
下面开始介绍控件绘制之前做了哪些事情?开始绘制的时候都要进行哪些处理、这些处理都是如何实现、WindowManagerService、SurfaceFlinger、Surface、以及FrameBuffer有什么关系?通过下面篇章进行工作流程介绍。
整个过程可以配合上面流程图可以更便于理解
二、实现原理这里默认我们只有一个显示屏设备,不用做显示屏设备获取。
1.View显示之前的操作AOSP内部基础Activity中有主要两个方法在View展示前至关重要。
1、setContentView 将界面上的控件全部移交到PhoneWindow中进行处理
2、attach attach中创建PhoneWindow对象,将WindowManager管理类绑定到PhoneWindow对象中。 初始化和Activity相关的信息,比如:显示相关信息。
PhoneWindow中的setContentView功能如下:
1、installDecor,创建DecorView对象和ContentParent DecorView继承FrameLayout,是一个布局控件。根据不同feature创建ContentParent。
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource)这个方法中,将布局id转换成View,然后通过addView将此View添加到DecorView中从,调用findViewById获取到了ContentParent。
2、mLayoutInflater.inflate,通过inflate将我们传递的xml转换成树形结构的View,并把ContentParent作为父节点。
比如我们传递的main_layout.xml,这里会将我们传递的xml进行解析,并将View按照控件层级放到DecorView中
2.应用端和WMS、SurfaceFlinger建立联系WindowManagerGlobal的addView方法
应用程序的生命周期在ActivityThread中被调用,onResume通过handleResumeActivity中的performResumeActivity方法进行调用,onResume调用完成后进入界面渲染流程。 从ActivityClientRecord对象中拿到当前的activity以及拿到绑定的WindowManager服务,拿到DecorView,将DecorView设置到WindowManager中。
每个Activity都对应一个WindowManager对象,对应一个DecorView对象,并且DecorView中持有该WindowManager(其实就是WindowManagerImpl实现类)对象。所以在ActivityThread中可以获取这些对象。最后调用的addView方法。就调用到了WindowManagerImpl实现类里面的WindowManagerGlobal单例对象中的addView方法中。
WindowManagerGlobal是个单例模式,在addView中首次添加会创建ViewRootImp,然后将DecorView添加到ViewRootImpl中。
在ViewRootImpl的setView中,设置信息完成后,调用requestLayout触发绘制流程。我们所熟悉的所有View都会有的回调方法。Measure,layout,draw方法。这一步可以确保View在添加到屏幕之前,已经完成测量和绘制。然后调用mWindowSession的addToDisplayAsUser()通知WindowManagerService添加窗口,这里涉及到跨进程通讯,方法最后,把DecorView的parent设置为ViewRootImp,这样做就是让ViewRootImp能管理整个ViewTree。
ViewRootImpl的setView方法
在ViewRootImpl的setView中分为两步,第一步调用requestLayout,第二步最后进行addWindow,由于内部Handle进行了挡板阻塞。所以可以看做是addWindow之后执行了requestLayout。 插入一个Runnable,保证在所有同步Message之前执行,保证View绘制优先级最高。
TraversalRunnable中包含申请Surface或者重新设置参数、调用测量、调用布局、调用更新window、调用绘制。 relayoutWindow主要是通过mWindowSession.relayout向WMS申请或者更新。WMS调用到了relayoutWindow进行重新布局。
针对应用层申请空白Surface,并回填的说明:
ViewRootImpl中先走了requestLayout(mHandler.getLooper().getQueue().postSyncBarrier()同步屏消息机制。对于异步的消息,Looper遍历队列找到异步消息进行执行,确保刷屏等高级任务及时执行,同步消息得不到处理,这就是同步屏障的原因),然后走了通过Session调用addToDisplayAsUser()方法mWindowSession.addToDisplayAsUser,调用到了WMS的addWindow方法中,进行SurfaceFlinger申请Surface。同步屏障通过Choreographer.postCallbackDelayedInternal方法调用到ViewRootImpl的TraversalRunnable中进行Surface重新设置。
通过IWindowManager,IWindowSession实现应用端和系统服务WindowManagerService进行跨进程通讯
1、WindowManager是一个java接口,实现类为WindowManagerImpl,和WindowManagerGlobal,配合IWindowManager获取主要通讯类。
2、IWindowManager是一个aidl文件, IWindowSession openSession(in IWindowSessionCallback callback),WindowManagerGlobal中调用IWindowManager的openSession获取到IWindowSession对象。
3、IWindowSession是一个aidl文件,是ViewRootImpl和WindowManagerService之间进行跨进程通讯的工具类。
4、aidl是Android Interface Definition Language,Android接口定义语言
ViewRootImpl持有session,WindowManagerService也持有一个内存映射的session,进行跨进程通讯。 之后的流程就需要WindowManagerService和SurfaceFlinger进行配合工作
系统服务WindowManagerService(WMS)
WindowManagerService简称WMS,是一个重要的系统服务,用于窗口管理。从内部实现看,主要包含窗口的增加、删除、启动窗口、窗口动画、控制窗口大小和层级等功能
一个关键概念:Android的视图屏幕是层叠渲染。看到的是一层一层的控件。WMS为所有窗口分配Surface,掌管Surface的显示顺序。
WMS的addWindow方法。
ViewRootImpl通过session调用addToDisplayAsUser方法,WMS通过系统Session对象调用到了addWindow方法中。
该方法中有几个关键点:
A、加锁,不能重复进行一个窗口多次添加。
B、对于子窗口类型的处理。必须有父窗口,父窗口不能是子窗口类型,否则输出错误信息,停止窗口添加。
C、获取WindowToken,是窗口分组令牌,每个窗口有一个分组。
D、新建WindowState,是窗口状态令牌,和每个窗口一一对应。详细记录窗口的参数,控件的层级信息、状态等各种信息,放入到全局的Map中,并附加到对应窗口的分组中。
走到这里,所有的窗口管理以及回调通讯全部打通,应用端向WMS注册窗口的流程完成
系统一个独立至关重要的Native服务SurfaceFlinger
Session的windowAddedLocked方法。
WindowState调用attach向SurfaceFlinger申请Surface, 调用Session中的windowAddedLocked,创建SurfaceSession, SurfaceSession和WindowSession一一对应。SurfaceSession是WMS为应用端向SurfaceFlinger申请的通信通道。
其实SurfaceSession是个外壳,内部持有native对象,就是SurfaceComposerClient,SurfaceComposerClient是由SurfaceFlinger创建出来的。
位置:frameworks/base/core/jni/android_view_SurfaceSession.cpp
通过JNI代码可以看到SurfaceSession所拿到的其实就是SurfaceComposerClient 由上可以获得,APP和SurfaceComposerClient为一一对应关系。
系统一个独立至关重要的Native服务SurfaceFlinger中的关键类
位置: frameworks/native/libs/gui/SurfaceComposerClient.cpp frameworks/native/libs/gui/include/private/gui/ComposerService.h
SurfaceComposerClient是SurfaceFlinger服务通信的代理对象。
ComposerService为单例模式,负责与SurfaceFlinger建立binder链接。 SurfaceFlinger的binder对象就是ComposerService,ComposerService跨进程创建一个ISurfaceComposerClient对象,ISurfaceComposerClient代表了Surface在SurfaceFlinger端的代理。
位置: frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp SurfaceFlinger为SurfaceComposerClient创建了一个Client,是一个Binder对象,这样SurfaceComposerClient可以通过Client来跟SurfaceFlinger进行跨进程通讯。
位置: frameworks/native/services/surfaceflinger/Client.cpp Client提供Surface的创建、销毁功能。 sp
系统一个独立至关重要的Native服务SurfaceFlinger 申请Surface
每个窗口都有一个WindowState,另外每个窗口都有自己的动画。relayoutWindow中初始化了WindowStateAnimator,通过createSurfaceControl方法获取到WindowSurfaceController,在WindowSurfaceController中通过builder对象获取SurfaceControl。
SurfaceControl会调用函数nativeCreate(session, name, w, h, format, flags)创建Surface。 SurfaceControl就是Surface在Java中的表示。 代码位置: frameworks/base/core/jni/android_view_SurfaceControl.cpp
位置: frameworks/native/libs/gui/SurfaceComposerClient.cpp 的createSurfaceChecked中调用createSurface方法
提取到SurfaceSession对象中的SurfaceComposerClient对象,之后调用createSurfaceChecked进一步创建SurfaceControl。
mClient其实是一个BpSurfaceComposerClient对象,是SurfaceFlinger端Client在WMS端的代理,因此创建Surface的代码还是在SurfaceFlinger服务端的Client对象中。 createSurfaceChecked方法中有两个至关重要的变量。
sp
当应用程序的Surface填充了数据,Native层的BufferQueue映射到了该数据,由SurfaceFlinger处理该数据。
注意:IGraphicBufferProducer就是Surface和BufferQueue交流的渠道,是一个Binder对象,Surface通过IGraphicBufferProducer跟BufferQueue申请和填充GraphicBuffer。
位置: frameworks/native/services/surfaceflinger/Client.cpp
Client直接调用SurfaceFlinger的createLayer方法创建一个图层。 SurfaceFlinger会根据不同的窗口参数,创建不同的图层。
可以看到图层最终对应的是BufferQueueLayer,BufferQueueLayer包含Handle和Producer对象信息。Handle是Surface的唯一标识,将来清理时候用。
Producer是BufferQueueProducer对象,关系到共享内存的分配问题。 终于得到了一个图层对象Surface。
BufferQueueLayer建立后,SurfaceFlinger会将图层对象信息传递给WMS,WMS根据图层对象信息,创建一个SurfaceControl对象,利用这个对象创建或更新JNI下的Surface。
位置 frameworks/base/core/java/android/view/Surface.java frameworks/base/core/jni/android_view_Surface.cpp
SurfaceFlinger已经为Surface创建了Layer,但Java中的Surface还是空壳,调用copyFrom对Surface进行完整实例化。
应用端Surface填充数据后会触发内存映射到QueueBuffer中,当QueueBuffer拿到数据时会请求Vsync进行刷新,这里SurfaceFlinger会调用onMessageInvalidate 方法
onMessageInvalidate主要处理的事情
1. 判断当前帧是否丢掉
2. handleMessageTransaction 处理layer或者display事务
3. handleMessageInvalidate 处理应用queue过来的Buffer
4. 帧率切换
5. 触发刷新流程
3.SurfaceFlinger处理数据handleMessageInvalidate 主要作用是执行 latchBuffer 去 acquire 应用queue过来的Buffer,然后拿到queueBuffer时设的Bufferslot一些状态属性给到BufferQueueLayer的mBufferInfo,同时还把这个Buffer做成EGLImage为后面的GPU合成做准备,期间都是数据之间的传递,所以说SurfaceFlinger并未真正触碰Buffer的内容。
对于OpenGL ES来说,SurfaceFlinger只能算是个“应用程序”,正是由于SurfaceFlinger没有真正接触Buffer内容导致如此。
4.进行界面数据展示
这里需要注意:
1、Composer模块也是属于HAL层,Android为场商自定UI合成提供的接口,Composer的直接使用者是SurfaceFlinger中的HWComposer。
2、HWComposer除了管理HAL的Composer模块外,还负责VSync信号的产生和控制(该信号可以由硬件产生,也可以通过软件模拟)
SurfaceFlinger并没有碰触到Buffer的真实数据,是将Buffer的数据通过GPU中的OpenGL ES模块进行绘制整理一个窗口,将绘制出来的Layer通过HAL层接口,将数据移交到Kernel的FrameBuffer中。
设备的显示存储区复制FrameBuffer中的数据。通过电压信号输出到显示区,我们就能看到对应图像。
多屏设备,Gralloc对应的两个模块各自递增。规定:gpu0和fb0是主屏,gpu1...和fb1...都属于副屏。
简单介绍下:OpenGL ES如何通过SurfaceFlinger绘制窗口,生成窗口数据
1:整个Android系统根据GUI设计理念,有两个本地窗口。OpenGL ES服务进程端的本地窗口定义为FramebufferNativeWindow,直接由SurfaceFlinger管理。应用程序进程初中包含多个窗口Surface,每个Surface所需要的图形缓冲区由SurfaceFlinger中的BufferQueue管理。
2:FramebufferNativeWindow的缓冲区直接从FrameBuffer中分配获得。Surface的缓冲区从内存中直接分配。两者的缓冲区都是经过Gralloc进行申请。
3:应用端的Surface通过SurfaceFlinger的GraphicBuffer配合OpenGL ES生成FramebufferNativeWindow,Kernel的FrameBuffer数据拷贝到硬件的缓冲区进行图形输出到屏幕。
总结
应用程序根据Activity或者Dialog等组件,进行系统内存分配,生成Surface本地界面,本地界面通过进程间通讯,将操作的Buffer一直向下传递,通过BufferQueue进行生产消费管理。 在SurfaceFlinger中输出GraphicBuffer到OpenGL ES模块,经OpenGL绘制图层生成FramebufferNativeWindow。 此时图层的缓冲区已经到了FrameBuffer中,在通过VSyncThread的同步机制进行双缓冲区替换。将FrameBuffer的缓冲区数据拷贝到硬件缓冲区,输出到屏幕。 整个流程完成。 注意:VSync同步信号是可以设置,无设置默认屏幕刷新率16.6ms。



