Android SurfaceFlinger——概述(一)

一、基础介绍

        SurfaceFlinger 是 Android 系统中的一个关键组件,负责管理屏幕显示的合成和渲染。

  • 服务角色:SurfaceFlinger 作为一个系统服务独立运行,它不依赖于任何应用程序进程,而是由系统启动并持续运行。
  • 窗口管理:它管理着系统中所有窗口的层次结构,包括应用程序窗口、状态栏、导航栏等,并根据ZOrder(深度顺序)决定哪些窗口应该在前面显示。
  • 合成操作:SurfaceFlinger 接收各个窗口的 Surface(图形缓冲区),这些 Surface 可能来自不同的应用程序或系统服务。根据每个 Surface 的透明度、大小、位置等属性,SurfaceFlinger 计算它们在最终显示图像中的位置和效果。
  • 硬件加速:SurfaceFlinger 利用硬件加速功能,如 GPU,来高效地执行合成操作。它可以与 HWComposer(硬件作曲家)协同工作,优化显示性能和功耗。
  • 帧缓冲区操作:合成后的图像被写入到帧缓冲区,然后由显示硬件读取并呈现到屏幕上。
  • 多显示器支持:SurfaceFlinger 还支持多显示器配置,能够将内容正确地输出到连接到设备的多个显示设备上。
  • 低延迟渲染:为了实现流畅的用户体验,SurfaceFlinger 致力于减少帧之间的延迟,确保以 60Hz 或其他刷新率连续显示内容。
  • 与其他组件的交互:与 WMS(Window Manager Service)协作,处理窗口的布局和可见性。与 Content Providers、View System 等其他 Android 组件进行通信,获取和更新显示内容。
  • 权限控制:SurfaceFlinger 还负责权限控制,确保只有授权的进程可以访问和修改显示内容。

        通过上述功能,SurfaceFlinger 在 Android 系统中扮演着至关重要的角色,确保了用户界面的正确显示和高效的渲染。

二、系统渲染流程

1、SurfaceFlinger

        SurfaceFlinger 是整个 Android 系统渲染的核心进程。所有应用的渲染逻辑最终都会来到 SurfaceFlinger 中进行处理,最终会把处理后的图像数据交给 CPU 或者 GPU 进行绘制。

        在这个过程中 SurfaceFlinger 并非担当渲染的角色,而是作为图元抛射机一样,把所有应用进程传递过来的图元数据加工处理后,交给 CPU 和 GPU 做真正的绘制。

2、Surface

        在每一个应用中都以 Surface 作为一个图元传递单元,向 SurfaceFlinger 这个服务端传递图元数据。

        Surface 与 SurfaceFlinger 交互流程如下图所示:

3、设计思想

        SurfaceFlinger 是以生产者以及消费者为核心设计思想,把每一个应用进程作为生产者生产图元保存到 SurfaceFlinger 的图元队列中,SurfaceFlinger 则作为消费者依照一定的规则把生产者存放到 SurfaceFlinger 中的队列一一处理。

        SurfaceFlinger 处理 Surface 流程如下:

4、共享内存

        为了能够跨进程的传输大容量的图元数据,使用了匿名共享内存内存作为工具把图元数据都输送到 SurfaceFlinger 中处理。

        我们要知道从应用进程把图元数据传输到 SurfaceFlinger 进程中处理,就需要跨进程通信,这里我们能想到的就是 socket通信、Binder 通信以及共享内存了。对于 Ashmem 匿名共享内存的选择,后面我们详细讲解。

5、时间钟

        SurfaceFlinger 底层有一个时间钟在不断的循环,或从硬件中断发出,或从软件模拟发出计时唤起,每隔一段时间都会获取 SurfaceFlinger 中的图元队列通过 CPU/GPU 绘制在屏幕。

        这个时间钟很符合 Android 系统的设计情况,除了需要 Android 应用有办法通知 SurfaceFlinger 需要渲染的模式,也需要 SurfaceFlinger 在不断的处理图元数据并绘制到屏幕的同时回调信息给自身。

        其中 EventThread 扮演一个极其重要的角色,在 SurfaceFlinger 中设计大致如下:

三、缓冲原理

        在了解缓冲原理前,我们先来开一个比较重要的概念——垂直同步信号(VSync)。

1、垂直同步信号

        在 SurfaceFlinger 中,垂直同步信号(Vertical Synchronization, VSync)起着核心作用,确保图形渲染和屏幕显示的同步,避免画面撕裂现象并提高视觉流畅性。

  • 作用原理:VSync 是一种同步机制,与显示器的刷新周期对齐,指示何时开始新的一帧渲染最合适。每当显示器完成一次刷新周期,硬件会产生一个 VSync 信号,通知系统现在可以安全地开始绘制下一帧图像。
  • 硬件与软件的结合:虽然早期的 SurfaceFlinger 可能依赖于软件模拟 VSync,现代 Android 系统通常利用硬件提供的精确 VSync 信号,以减少误差和提升效率。
  • 分发与接收:SurfaceFlinger 负责接收硬件产生的 VSync 信号,并将其分发给系统中的渲染器,包括 App 的 UI 线程和 SurfaceFlinger 自身。onVSyncReceived 方法会在接收到 VSync 信号时被调用,该方法内部会触发一系列的渲染调度操作。
  • 同步渲染:应用程序通过 Choreographer(编舞者)类监听 VSync 信号,确保 UI 绘制与屏幕刷新同步。这使得 AppUI 和 SurfaceFlinger 都能按照硬件 VSync 的节奏进行工作,从而保证动画和滚动等操作的平滑性。
  • 减少延迟与提高效率:通过精确的 VSync 同步,可以减少由于无序渲染导致的额外缓冲需求,降低输入到显示的延迟。VSync 还帮助优化 CPU 和 GPU 的利用率,避免过度渲染或空闲等待,进而节省电池。
  • 可调节性:在某些场景下,开发者可以通过调整 Choreographer 的行为来适应特定的渲染需求,比如三重缓冲策略的调整。
  • 异常处理与校准:SurfaceFlinger 还涉及处理 VSync 信号的异常情况,比如信号丢失或频率不匹配,以维持系统的稳定性和显示质量。

        综上所述,VSync 在 SurfaceFlinger 中是确保图形显示流畅和高效的基石,通过精确的时间控制,协调系统资源,提供最佳的用户体验。

2、双缓冲

        在 SurfaceFlinger 中,双缓冲是一种优化显示性能的技术,用于减少屏幕闪烁并提高动画的平滑性。

  • 缓冲区管理:双缓冲涉及到两个独立的帧缓冲区(front buffer 和 back buffer)。前缓冲区是当前显示在屏幕上的图像,而后缓冲区则用于绘制新的内容。
  • 绘制过程:应用程序在后台缓冲区完成绘制操作,不会影响到正在显示的图像。当绘制完成后,SurfaceFlinger 会收到 VSync 信号,此时可以安全地交换前后缓冲区。
  • 缓冲区交换:在 VSync 时刻,SurfaceFlinger 将后缓冲区的内容复制到前缓冲区,这个过程称为"翻页"或"PageFlip"。这个操作通常是原子性的,确保在屏幕刷新时看到的是完整的一帧,而不是部分更新的内容。
  • 减少闪烁:因为用户看到的始终是已经完成绘制的图像,而不是正在绘制的过程,所以避免了因多次绘制导致的闪烁现象。
  • 提高效率:应用程序可以同时在后缓冲区进行下一帧的绘制,而前一帧的显示不会受到影响,这提高了渲染效率。

        简单来说,双缓冲就是渲染第一帧的同时已经在绘制第二帧的内容,等到第二帧绘制完毕后就显示出来。这么做的好处很明显,如果一帧画完,才开始画下一帧,势必有一个计算的过程导致 ui 交互迟缓。 

        双缓冲是 SurfaceFlinger 在处理多个窗口和动画时的关键技术,它确保了 Android 系统的视觉流畅性和稳定性。通过与 VSync 信号的配合,双缓冲有效地减少了画面撕裂和不连续的视觉效果,提升了用户体验。 

        通过这种方式显示前一帧的时候提前绘制好下一帧图元,放在背后等待时机交换,这样就能从感官上流畅不少。

        这么做的效果十分显示,但是怎么找到一个合适的时机进行交换前后两帧这是一个问题,如果按照屏幕刷新频率来,一般按照通用屏幕刷新 60fps 也就是约 16ms 刷新一次即可。但是我们深入思考一下,其实这个过程中有两个变量,一个是绘图速度,一个是显示速度。就算是绘图速度中也有分 CPU 和 GPU 的绘制速度。

        这里我看一下当年 google 在“黄油计划”示意图。

无缓冲流程

        理想中的情况就是上图,在显示第 0 帧的时候,CPU/GPU 合成绘制完成第 1 帧在 16ms 内,当 vsync 信号来了,就把第 1 帧交换到显示屏显示。

        但是很可能出现下面这种情况,CPU 因为繁忙来不及,显示完第一帧的时候,还没空渲染第二帧,就算 SurfaceFlinger 接受到了 Vsync 的信号,也只能拿出已经渲染好的第一帧显示在屏幕上。这样就重复显示了第一帧,Google 开发团队称这种为 jank。

        能看到显示第一帧因为第二帧没准备好,只能重复显示第一帧了。再来看看双缓冲的工作原理流程。

双缓冲流程

        可以看到此时就不是简单的第一第二帧,而是分为 A 缓冲,B 缓冲。能看到在正常情况下,先显示 A 缓冲的内容,同时准备B缓冲,当一切正常的时候,B 缓冲应该在下一个 vsync 来之前准备好,一旦 vsync 到来则显示 B 缓冲,A 缓冲回到后台继续绘制。

        那么这种方式一旦遇到 jank 会是什么样的一个情况。

        如果是双缓冲好像没有问题,但是一旦出现 jank 了之后,之后显示屏就会不断的出现 jank。如果缓冲 A 在显示,而 B 准备的时间超过 16ms,就会导致 A 缓冲区重复显示,而当 B 显示的时候,A 也很可能准备时间不足 16ms 导致无法绘制完成,只能重复显示 B 缓冲的内容。

        这种方式更加的危险,为了解决这个问题,Google 引入三重缓冲。

3、三重缓冲

        在 SurfaceFlinger 中,三重缓冲(Triple Buffering)是双缓冲的一个扩展,旨在进一步减少画面撕裂和提高渲染性能,特别是在高帧率和垂直同步(V-Sync)启用时。

  • 缓冲区数量:与双缓冲的两个缓冲区不同,三重缓冲使用三个独立的帧缓冲区。当前显示的前缓冲区、一个用于绘制的新缓冲区(后缓冲区)以及一个额外的中间缓冲区。
  • 渲染流程:应用程序在中间缓冲区完成新帧的渲染,同时前缓冲区正在屏幕上显示。当前帧绘制完成后,SurfaceFlinger 等待下一个 VSync 信号,然后将中间缓冲区的内容移动到后缓冲区。
  • 缓冲区交换:在下一个 VSync 到来时,SurfaceFlinger 将后缓冲区的内容复制到前缓冲区,同时释放中间缓冲区供应用程序绘制下一帧。
  • 这样,应用程序可以在前一帧显示的同时开始绘制下一帧,而不是等待前一帧完全呈现后再开始。
  • 减少延迟:三重缓冲减少了等待 VSync 信号的空闲时间,因为总有一个缓冲区可供应用程序使用,从而降低了帧间延迟。
  • 性能提升:在某些情况下,尤其是在高帧率下,三重缓冲可以减少因等待 VSync 而引起的帧率下降,从而提供更稳定的帧率表现。
  • 权衡:尽管三重缓冲可以提高性能,但它也增加了内存占用,因为需要存储额外的缓冲区。此外,对于某些设备或应用场景,双缓冲可能已经足够,而且更节省资源。
  • 适用场景:三重缓冲通常在需要高性能图形渲染、高刷新率显示器或者需要减少 V-Sync 带来的延迟时采用。

        三重缓冲是 SurfaceFlinger 为了优化高动态场景和减少延迟而采用的一种策略,它在现代游戏和高性能应用中尤其有用,能够提供更加流畅的视觉体验。

        三重缓冲处理 jank 的原理流程图:

        可以看到为了避免后面连锁式的错误,引入三重缓冲就为了让空闲出来的等待时间,能够做更多的事情。就如同双缓冲遇到 jank 之后,一旦 B 缓冲 CPU+GPU 的时间超过了下一个 vsync 的时间,能够发现其实 CPU 和 GPU 有一段时间都没有事情做,光等待下一次 Vsync 的到来,才会导致整个系统后面的绘制出现连锁式的出现 jank。

        而三缓冲的出现,在重复显示 A 缓冲区的时候,CPU 不会光等待而是会准备 C 缓冲区的图元,之后就能把 C 缓冲区接上。这就是 Google 所说的三重缓冲区的来源,不过绝大多数情况下的缓冲策略都是由 SurfaceFlinger 系统自己决定的。实际上这种方式也可以用到音视频的编写优化,里面常用的缓冲区设计和这里也有异曲同工之处。

        有了缓冲原理的介绍,这里我们再来回顾一下上面的时间钟。其实每一次 Vsync 从硬件/软件过来的时候,Dispsync 都会尝试着通知 SurfaceFlinger 和APP,这是完全没有问题,而后面那个 Phase 相位又有什么作用?这就是系统的设计的巧妙,我们如果同时把信号通知同时告诉 APP 和 SurfaceFlinger 会导致什么结果?

        如果此时 APP 后返回了图元,但是 SurfaceFlinger 已经执行了刷新合成绘制行为(很有可能,因为 APP 到 SurfaceFlinger 传输图元速度必定比 SurfaceFlinger 自己通知自己慢),此时就会导致类似 jank 的问题,导致下一个 vsync 还是显示当前帧数,因此需要如下一个时间差,先通知 APP 后通知 SurfaceFlinger,如下图:

        加上这个理解就能明白上面 Phase 相位处理的初衷了。

总结

        对于系统渲染流程的理解是指导 SurfaceFlinger 设计的核心思想,从 Android 4.1 一直到 Android 9.0 都没有太大的变化。只要抓住这五个核心思想,我们阅读 SurfaceFlinger 的难度就会下降不少。

        下面看一下 SurfaceFlinger 的体系和 Skia 以及 View的绘制流程的关系。

  • framework 面向开发者所有的 View 是便于开发的控件,里面仅仅只是提供了当前 View 各种属性以及功能。
  • 而 Android 底层的 Skia 是 Android 对于屏幕上的画笔,经过 View 绘制流程的 onDraw 方法回调,把需要绘制的东西通过 Skia 绘制成像素图元保存起来
  • SurfaceFlinger 则是最后接受 Skia 的绘制结果,最后绘制到屏幕上。

        所以说,Skia 是 Android 渲染核心,但是最终还是需要 Skia 和系统所提供起来,才是一个 Android 完整渲染体系。经过这一层层的屏蔽,让开发者不需要对 Android 底层的渲染体系有任何理解,也能绘制出不错的效果。

        最后会把绘制结果传输到屏幕中。

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

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

相关文章

为什么有人认为Linux不如macOS?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!首先要明确你说的是哪个Lin…

快速自定义表单开发受欢迎的几个优势

为了满足业务需求,低代码技术平台带着更理想的优势特点,广泛用于各中大型企业中,是助力企业实现提质增效、提升开发效率的有力武器。那么,您知道快速自定义表单开发的优势体现在哪里吗?为了帮助大家了解这些详情&#…

路由框架 ARouter 原理及源码解析

文章目录 前言一、ARouter 简介二、ARouter 使用1.添加依赖和配置2.添加注解3.初始化SDK4.发起路由操作 三、ARouter 成员1. PostCard 明信片2. Interceptor 拦截器3. Warehouse 路由仓库4. ARouter 注解处理 四、ARouter 原理五、ARouter 源码分析1. ARouter 初始化1.1 ARoute…

基于SSM的足球联赛管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式 🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 &…

分布式系列之限流组件

概述 在高并发场景下,请求量瞬间到达,后端服务器即使有缓存、集群主备、分库分表、容错降级等措施,也有可能扛不住这请求量,因此可考虑引入限流组件。限流的目的:防止恶意请求流量或流量超出系统承载。 应用场景&…

计算机毕业设计师hadoop+spark+hive知识图谱医生推荐系统 医生数据分析可视化大屏 医生爬虫 医疗可视化 医生大数据 机器学习 大数据毕业设计

流程: 1.Python爬虫采集中华健康网约10万医生数据,最终存入mysql数据库; 2.使用pandasnumpy/hadoopmapreduce对mysql中的医生数据进行数据分析,使用高德地图解析地理位置,并将结果转入.csv文件同时上传到hdfs文件系统&…

百度文心智能体平台(想象即现实):轻松上手,开启智能新时代!创建属于自己的智能体应用。

目录 1.1、文心智能体平台 1.2、创建智能体 1.3、智能体报名入口 1.4、古诗词小助手 1.5、访问我的智能体 我的智能体访问地址:https://mbd.baidu.com/ma/s/7u8kBFYA。 在这个全新的时代里,人工智能技术正以前所未有的速度发展,渗透到我…

LinkedHashMap详解

目录 LinkedHashMap详解1、LinkedHashMap的继承体系2、LinkedHashMap的特性介绍和代码示例①、特性②、适用场景使用LinkedHashMap 实现最简单的 LRU缓存 3、LinkedHashMap的构造函数4、LinkedHashMap是如何存储元素的,底层数据结构是什么?LinkedHashMap…

用LoRA微调 Llama 2:定制大型语言模型进行问答

Fine-tune Llama 2 with LoRA: Customizing a large language model for question-answering — ROCm Blogs (amd.com) 在这篇博客中,我们将展示如何在AMD GPU上使用ROCm对Llama 2进行微调。我们采用了低秩适配大型语言模型(LoRA)来克服内存和计算限制,…

SAP赋能食品行业,确保安全与品质的双重飞跃

品安全与品质是消费者最关心的问题,也是食品企业的生命线。随着科技的发展和消费者需求的日益多样化,食品行业正面临着前所未有的挑战和机遇。SAP作为全球领先的企业资源规划(ERP)系统,为食品行业提供了全面的解决方案…

RealityCheck™电机监测和预测性维护模型

RealityCheck™电机 一个附加的软件工具箱,可实现条件监测和预测性维护功能,而无需依赖额外的传感器。相反,它使用来自电机控制过程的电子信息作为振动和其他传感器的代理。凭借其先进的信号处理和机器学习(ML)模型,RealityCheck …

惠普8596E频谱分析仪

8590E系列频谱分析仪具有各种各样的性能、功能,其价格亦是为适应用户的承受能力而确定的。用户可以从价格低廉、具有基本性能的分析仪直至高性能分析仪中进行挑选,无论选择哪种分析仪,都会感受到8590系列频谱分析仪便于使用且高度可靠。这些仪…

Palo Alto GlobalProtect App 6.3 (macOS, Linux, Windows, Andriod) - 端点网络安全客户端

Palo Alto GlobalProtect App 6.3 (macOS, Linux, Windows, Andriod) - 端点网络安全客户端 Palo Alto Networks 远程访问 VPN 客户端软件 请访问原文链接:https://sysin.org/blog/globalprotect-6/,查看最新版。原创作品,转载请保留出处。…

从0开始C++(三):构造函数与析构函数详解

目录 构造函数 构造函数的基本使用 构造函数也支持函数重载 构造函数也支持函数参数默认值 构造初始化列表 拷贝构造函数 浅拷贝和深拷贝 析构函数 总结 练习一下ヽ( ̄▽ ̄)ノ 构造函数 构造函数的基本使用 构造函数是一种特殊的成…

腾讯地图撒点并默认显示点位信息

实现步骤如下: 1、注册腾讯位置服务账号并获取 Key 2、需要创建一个地图容器,并使用腾讯地图的 API 初始化地图。通常涉及到设置地图的中心点、缩放级别和地图样式。 map new TMap.Map(document.getElementById(‘container’), { center: center, zo…

Vue56-组件的自定义事件

一、什么是自定义事件 二、子组件—【传值】—>父组件 2-1、prop属性 2-2、自定义事件 v-on在谁身上,就给谁绑定事件! 给谁绑定的事件,想触发就找谁! 2-3、prop属性VS自定义属性 2-4、简写形式 2-5、ref属性实现 加了ref属性…

软件监控发展简史

软件监控简史,从 00 年代开始。发生了什么变化?为什么事情变得如此神秘? 终端设备上日益重要的用户体验通过边缘计算和分布式计算不断得到改善。然而,服务质量的测量仍然使用基于服务器的原语进行。 我们的 2000 年软件监控是这样…

程序员兼职接单有哪些渠道?一篇文章带你了解!

2024年,程序员兼职接单别只盯着朋友圈啦!这些兼职接单渠道你一个都不容错过!想要通过兼职接单获取收入的程序员,一定不能错过这篇文章! 程序员兼职接单的渠道可以简单的分类为兼职平台和程序员论坛和自身人脉拓展三个…

【SD3辅助工具推荐】InstantX发布了三种SD3专属的ControlNet模式——Pose、Canny和Tile

InstantX 是一家专注于人工智能内容生成的独立研究机构。此前,曾开源著名的InstantID和论文《InstantID : Zero-shot Identity-Preserving Generation in Seconds》。随着本月12号,Stability AI正式开源了其产品 Stable Diffusion 3,这家机构…

高效设计必选!5款好用的UI动效工具

UI 动态设计是应用程序设计的重要组成部分。随着技术的积累,UI设计中的动态效果遍地开花,UI动态效果可以使我们的页面更时尚、更有趣、更人性化。5G网络的快速发展也使美丽的动态效果几乎无缝地嵌入到UI界面中。今天,毫不夸张地说&#xff0c…