Android图形显示流程简介

news2024/11/23 3:00:17

注:本文缩写说明

0a53a9984335dfbd97f28974d07ba4a8.png

本文代码都是基于Android S

一、概述

本文将对从App画出一帧画面到这帧画面是如何到达屏幕并最终被人眼看到的这一过程进行简要分析,并将这其中涉及到的各个流程与其在systrace上的体现对应起来,期望最终能够让读者对Android系统下的画面显示流程有一个宏观的认识。

1e7d9b2e14ec12d6a3c43a0e49884182.png

上图为Android的图形显示系统框架图,首先上层应用通过ViewRoot的scheduleTraversals函数发起绘制任务,并通过HWUI调用OpenGL接口将绘制数据传递给GPU处理;SF会接收所有应用更新的绘制数据,并根据Z-Order、透明度、大小、位置等参数计算出每个应用图层在最终合成图像中的位置;SF完成图层处理后会把所有的应用图层提供给HWC,由HWC来决定这些图层的合成策略并调用屏显驱动做合成;最后屏显驱动会将合成的最终画面送到硬件屏幕显示。

Android系统通过buffer缓冲区来保存图形信息,这个buffer的内存空间是有SF向图形内存分配器Gralloc申请的,而Gralloc是通过ION Driver从kernel中开辟出一块共享内存。在整个图形显示流程中,buffer缓冲区会在App、SF、HWC之间来回流转,本文将通过buffer的数据流向来详细阐述Android的画面显示过程。

二、App到SF

应用界面发生变化也就是view数据发生了变化,会引起ViewRootImpl的requestLayout调用,进而调用scheduleTraversals方法。scheduleTraversals方法内会先向消息队列发送一个同步屏障,然后执行Choreographer回调,注册CALLBACK_TRAVERSAL类型的监听。Choreographer在监听到下一次Vsync信号来了后,会执行mTraversalRunnable的run方法,该方法内会调用doTraversal方法,移除消息队列中的同步屏障,并通过performTraversals方法触发布局绘制流程。

dbe988c6080d5fab9c62798e1b800c79.png

Choreographer和Vsync是在Android 4.1上黄油计划中引入的两个重要元素,最初的Vsync信号是由硬件屏幕根据系统帧率以固定的频率(60/90/120fps)向系统发送的时间脉冲信号,Choreographer和SurfaceFlinger都会监听这个信号来做绘制和合成。后来为了进一步提升界面流畅性体验,Android 4.4上又引入了Vsync虚拟化,通过DispSyncThread把Vsync虚拟化成Vsync-app和Vsync-sf,Vsync-app和Vsync-sf之间有固定的时间偏移,各自分别掌控着App和SurfaceFlinger的工作节奏,他们一前一后保持着绘制任务的流水节奏。

当Choreographer监听到Vsync信号后会回调doFrame方法,该方法主要完成两件事情:确认当前帧执行的时间戳和渲染当前帧数据。渲染数据时会顺序执行输入(Input)、动画(Animation)、绘制(TRAVERSAL)、提交(Commit)这4种类型的回调函数,而在执行TRAVERSAL类型的callback方法时就会调用到上面提到的doTraversal下的performTraversals方法触发布局绘制流程。

89014c0e8a47cae4c6d207d64a87eb08.png

下图的systrace展示了UI数据从App到SurfaceFlinger的处理流程。从systrace上可以看到应用端有两个线程UI Thread和Render Thread用于处理应用想要更新的UI数据,其中UI Thread通过Choreographer配合Vsync信号有节奏的控制应用的绘制任务,并将所有要绘图的信息以绘图指令的形式记录到DisplayList里同步给Render Thread,Render Thread则将UI Thread传递过来的绘图数据送到GPU去做渲染。一旦同步工作完成,UI Thread就可以继续等下一个Vsync-app信号的到来,接着做下一帧的绘制。

Render Thread在做GPU渲染之前还需要申请一块buffer缓冲区用于存储GPU渲染的数据,这个buffer是应用通过Surface接口的dequeueBuffer方法向BufferQueue申请的,拿到buffer之后应用会调用OpenGL接口将绘制指令传递给GPU进行渲染,然后再通过queueBuffer函数将保存有渲染数据的buffer提交到SF作图层处理。

0c3c899099d922a3853a25bbfd8b6fad.png

值得注意的是在Android S以前,buffer状态都是由BufferQueue进行管理,而bufferQueue是在SF中创建的,应用端的dequeue、queue Buffer操作都是通过binder和SF进行交互。但是在Android S上,BufferQueue的创建从SF中移出来,变成BLASTBufferQueue去完成BufferQueue的创建,dequeue、queue、acquire、release Buffer 的操作均由 App 进行。当App绘制完一帧后,会通过BLASTBufferQueue接口执行onFrameAvailable回调,并通过transaction事务将该buffer提交到SF。

三、SF到HWC

当SF监听到Vsync-sf信号就会调用onMessageReceived函数来处理UI数据。

4c0de3e573ca5107287974ba248df1a8.png

onMessageReceived方法主要是用来处理两个Message:

INVALIDATE消息 -- onMessageInvalidate首先会调用handleMessageTransaction方法检查Layer/Display的属性和数量是否有变化;然后调用handleMessageInvalidate方法检查每个Layer是否有新提交的buffer, 如果有则通过handlePageFlip调用latchBuffer方法将BufferQueue中的buffer通过acquireBuffer拿走;最后还会检查HWC是否有repaint请求。上述三种情况只要有一种发生了,refreshNeeded就会被置为true,onMessageRefresh方法就会被调用做图像合成。

4ad67216a176ac0427deac9136efc056.png

REFRESH消息—onMessageRefresh方法则会对所有有buffer更新的Layer进行合成,大部分的合成工作是在present方法里完成的,这里SurfaceFlinger会和HWC进行交互,协同完成画面的合成。基本流程如下:

  1. SF为HWC提供完整的Layer列表并通过chooseCompositionStrategy方法询问合成策略。

  2. HWC根据硬件性能决定是使用硬件图层合成器还是GPU合成,并分别将每个Layer对应标记为overlay或GLES composition来进行响应。

  3. 需要硬件图层合成器合成的Layer直接由HWC处理,需要GPU合成的Layer则需要先由SF负责合成一个Layer后再和其他的Layer一起递交给HWC完成剩余的合成和显示。

当画面合成结束以后,SF还会调用postComposition做一些合成后的处理,其中就包括通过releaseBuffer释放SF在合成上一帧画面时拿到的所有buffer,以便应用在下次dequeueBuffer时能够拿到可用的buffer。

4e2fd52dcfbc2d3747fb09b23a59528d.png

下图的systrace展示了UI数据从SF到HWC的处理流程。当SF监听到Vsync-sf信号后会顺序执行INVALIDATE和REFRESH消息的回调函数,在执行onMessageRefresh方法时,SF和HWC会协同选择合成策略,并由HWC完成最终的画面合成。画面合成完成后,SF会通过transaction事务通知应用释放用于绘制上一帧画面的buffer。

59a4dce3dde60c35514f6816cfb9af36.png

四、HWC到屏幕

systrace上看到的都是软件上的一些操作,无法看到硬件的处理流程。而UI数据从HWC到屏幕的这个阶段只有一小段时间是在软件上进行的,大部分时间都是硬件在处理数据。我们首先来看看该阶段软件上的主要工作,HWC是通过DRM向屏幕输出画面的,DRM是linux内核的一个子系统,用于负责与显卡交互,因此HWC会先通过drmModeAtomicCommit接口向kernel提交Layer数据,drmModeAtomicCommit通过ioctl调用到kernel,然后通知disp thread也就是下图中所示的crtc_commit线程调用complete_commit函数完成剩下的合成工作。

a56a8331df449f014da13cc9363aa2e5.png

crtc_commit线程执行complete_commit方法时几乎一直处于D状态,表明此时DRM内的硬件正在做合成工作。经过一系列合成处理后最终的画面会通过DSI接口送到屏幕显示。至此,UI数据就完成了从应用端到硬件屏幕的旅程。

五、总结

一个buffer从被应用dequeue到最后HWC完成画面合成后由SF release的整个生命周期经历了如下流程:

  1. Vsync-app信号到达后,APP端由Choreographer顺序执行Input、Animation和Traversal的回调,然后通过dequeueBuffer拿到一个可用的buffer开始绘图,再通过queueBuffer将包含绘图数据的buffer提交到SF。

  2. Vsync-sf信号到达后,SF首先通过aquireBuffer获取所有Layer更新的buffer,然后根据Z-Order、透明度、大小、位置等参数对这些Layer进行图层处理,接着将所有的Layer送到HWC做合成。

  3. HWC对多个Layer做合成,合成完成后通过libdrm提供的接口通知DRM模块把图像显示到屏幕。

  4. 最终的画面送到屏幕后,HWC会将用完的buffer还给SF,SF会在下一个Vsync-sf信号到达后release被归还的buffer。

本文以UI数据在显示系统中的数据流向为指引,依次分析了App、SF、HWC和硬件屏幕处理UI数据的基本步骤。Android显示系统十分复杂,涉及模块较多,并且随着时间的推移也在不断更新优化,但是其处理UI数据的基本流向不会变,本文旨在帮助读者对显示系统有一个宏观的认识,其中的一些处理细节还需要读者通过阅读源码慢慢领会。

参考资料:

1.Android源码:https://cs.android.com/android/platform/superproject

2.Android图形系统篇总结:https://www.jianshu.com/p/180e1b6d0dcd

3.Android Systrace 基础知识:https://www.androidperformance.com/2019/05/28/Android-Systrace-About/

65f95cac3a2281d774f3565cb3327216.gif

长按关注内核工匠微信

Linux内核黑科技| 技术文章 | 精选教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Geek Uninstaller:向流氓软件火力全开,超良心的软件彻底卸载工具

写在前面 我们在电脑上安装软件,以及在使用软件的过程中,会产生一些程序文件、注册表项和临时文件等,用来支持软件的正常使用,都是正常现象。 但是,在卸载软件时,很多软件自身的卸载程序很不负责任&#…

内网渗透(十六)之内网信息收集-powershell基础知识

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

chatGPT接入个人微信教程(国内可用)

chatGPT最近突然又大火起来了,而且这次不是一般的火,带有浓浓的商业气息火了。各个互联网大厂都开始进军了,感觉要来一场ChatGPT的军备竞赛一样,看看谁先获取国内的地盘。 作为吃瓜群众,我们也能个人使用ChatGPT&…

PCB设计中的正片和负片设计原理

PCB实际的最终目的 让需要导通的地方铺有铜,让不需要导通的地方没有铜 正片和负片的含义 参考:https://www.sohu.com/a/203224754_100012544,https://blog.csdn.net/weixin_42837669/article/details/110411765 查找资料中常见说法&#x…

力扣HOT100 (1-5)

目录 1.两数之和 2.两数相加 拓展到牛客的TOP101的BM11( 链表相加(二)) 3.无重复的最长子串(牛客BM92) 解法1: 解法2: 4.寻找两个正序数组的中位数 5.最长回文子串 1.两数之和 思路:用Has…

Centos7下安装单节点flink1.13

前置环境配置jdk可以参考博文:Centos7下安装hadoop单节点 。 如下图所示,这里我们将flink-1.13.0-bin-scala_2.12.tgz上传到如下路径: 解压安装文件到/opt/module下面 tar -zxvf flink-1.13.0-bin-scala_2.12.tgz -C /opt/module/将flink…

背包问题求方案数、具体方案

背包问题求方案数、具体方案01背包问题求体积恰好等于V的方案数完全背包问题求体积恰好等于V的方案数01背包问题求最优选法的方案数完全背包问题求最优选法的方案数01背包问题求具体方案01背包问题求体积恰好等于V的方案数 原题链接AcWing278. 数字组合 考虑状态表示&#x…

如何实现LFU缓存(最近最少频率使用)

目录 1.什么是LFU缓存? 2.LFU的使用场景有哪些? 3.LFU缓存的实现方式有哪些? 4.put/get 函数实现具体功能 1.什么是LFU缓存? LFU缓存是一个具有指定大小的缓存,随着添加元素的增加,达到容量的上限&…

为什么我们不再发明编程语言了?

上个世纪,数百种编程语言被发明出来,但是进入21世纪,当我们都进入互联网时代时,只剩那么寥寥几个了。 如果你翻一下TIOBE得编程语言排行榜,就会发现20年来,上蹿下跳的就是那几张老面孔:C , Java…

(片花)原汤话原食:从公共场所不知深浅的熊孩子聊聊边界感这事

点击文末“阅读原文”即可收听本期节目剪辑、音频 / 伊姐 编辑 / SandLiu 卷圈 监制 / 姝琦 文案 / 伊姐 产品统筹 / bobo 录音间 / 声湃轩天津站本期节目完整版请在各大音频平台搜索”原汤话原食“,找到原汤话原食栏目后订阅收听。刚刚过去的春节,许…

靓号管理(2)

表结构: 根据表结构的需求,在models.py中创建类。 主要是创建级别和默认级别 class PrettyNum(models):"""靓号表"""models models.CharField(verbose_name"手机号", max_length32)price models.IntegerFie…

MES系统智能工厂,搭上中国制造2025顺风车

MES在电子制造业中的应用日益广泛,越来越多的厂商已经购置或自行开发了MES,并将其作为“智能化工厂”。国内大大小小、各行各业都有上百个MES系统,还有很多的国外MES系统,怎么才能在MES系统公司中找到适合自己的MES?希…

数据库学习笔记(2)——workbench和SQL语言

1、workbench简介: 登录客户端的两种方法 在cmd中,只能通过sql语句控制数据库;workbench其实就是一种图形化数据库管理工具,在workbench中既可以通过sql语句控制数据库,也可以通过图形化界面控制数据库。通过workbenc…

LeetCode题解 动态规划(四):416 分割等和子集;1049 最后一块石头的重量 II

背包问题 下图将背包问题做了分类 其中之重点,是01背包,即一堆物件选哪样不选哪样放入背包里。难度在于,以前的状态转移,多只用考虑一个变量,比如爬楼梯的阶层,路径点的选择,这也是能用滚动数组…

ChatGPT 的未来挑战和风险

ChatGPT 是 OpenAI 开发的流行语言模型,彻底改变了我们与 AI 交互的方式。然而,随着像 ChatGPT 这样的语言模型的使用越来越广泛,重要的是要考虑它们未来可能面临的潜在风险和挑战。 一、数据质量和公平性 使用 ChatGPT 的主要风险之一是用于…

大数据-------元数据管理

一、什么是元数据 元数据就是描述数据的数据,它为企业的各类数据提供了上下文环境,使企业能够更好地了解、管理和使用数据。 现在数据对于公司的决策十分的重要,随着业务的发展,业务线会慢慢庞大起来,随着开发人员的…

九、STM32定时器讲解 - 通用定时器实战

目录 1.三种定时器的区别 2.通用定时器的特点描述 3.计数器模式 4.通用定时器工作过程 5.计数器时钟计算方法、 5.1定时器的输入时钟频率 - TimeClockFren 5.2计数器时钟计算方法 6.定时器相关寄存器 7.定时器库函数结构体 8.通用定时器函数 9.定时器中断配置过程 1…

图论算法:树上倍增法解决LCA问题

文章目录树上倍增法: LCA问题树上倍增法: LCA问题 树上倍增法用于求解LCA问题是一种非常有效的方法。 倍增是什么? 简单来说,倍增就是 1 2 4 8 16 … 2^k 可以发现倍增是呈 2的指数型递增的一类数据,和二分一样&…

黑马程序员 Linux 教程

目录Linux 简介不同应用领域主流操作系统Linux 系统历史Linux 系统版本Linux 安装安装方式网卡设置安装 SSH 连接工具使用 FinalShell 连接到 LinuxLinux 和 Windows 目录结构对比Linux 目录介绍Linux 常用命令Linux 命令初体验Linux 命令使用技巧Linux 命令格式文件目录操作命…

Python的文件编码,复制,缓冲,删除

能力有限,仅供参考 本篇博文是上一篇博文( Python的文件读取,写入)的后续,也是python文件管理的一部分,废话不多说,现在就开始。 1. 编码 在实际工作学习中,你可以遇到乱码的问题…