栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android系统开发 ----- 屏幕展示图像原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android系统开发 ----- 屏幕展示图像原理

系列文章目录

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 getLayerUser(const sp& handle) const;方法中可以看出Client内部保存对应的Layer。Layer是Surface在SurfaceFlinger中的标识,代表一个现实层,每个Client可以有多个Surface,有多个Layer。

 系统一个独立至关重要的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 handle, sp handle,图层标识,需要SurfaceFlinger进行填充数据。 sp gbp,创建GraphicBuffer,需要SurfaceFlinger进行填充数据。 两个变量的类型都是IBinder类。 应用程序需要绘制到Surface窗口中,绘制UI内容都需要一个GraphicBuffer存储,而GraphicBuffer需要Surface去申请和绘制,由SurfaceFlinger进行消费,合成图层,这套生成消费机制就是BufferQueue机制,平衡协调SurfaceFlinger和Surface。

当应用程序的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。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1027876.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号