<span class=“js_title_inner“>60fps背后的秘密:Android图层数据与控制的分离哲学</span>

Android14 SurfaceFlinger-BLASTBufferQueue的创建 分为两步。 阅读详情

点击上方“IT烂笔头”,选择“置顶公众号”

第一时间获取 IT 技术干货!

阅读文本大概需要 15 分钟。

上一文中主要分析了整个Android图形子系统的整体运作流程,本节我们将探索运作流程中的一些关键类创建的时机,从而更好的理解这个过程,以及分析其中的设计逻辑。

①简单类的创建时机

  • DecorView
      • DecorView在Activity.setContentView() 调用时由 PhoneWindow 同步创建,作为承载应用主题框架和用户布局的顶级容器。

    • 此时 DecorView 尚未显示

      :其可见性需等待 Activity.onResume()后通过 WindowManager.addView() 与 ViewRootImpl 绑定完成绘制流程。

    • 主题决定结构:DecorView

       的布局因主题而异(如全屏/带标题栏),由 generateLayout() 动态选择系统资源。

  • PhoneWindow
    • Activity

PhoneWindow 在 Activity.attach() 方法中同步创建,作为 Activity 的窗口代理,负责管理窗口样式、事件回调和视图层级。

    • Dialog

【过期的版本】Android 6.0之前,Dialog通过 PolicyManager.makeNewWindow() 创建 PhoneWindow 对象,具备完整的 DecorView和事件回调能力。

这个在网上很多博客写的还是上面的流程,包括在23、24年的博客,而且用Deepseek等AI去查,结果都是上面的流程,可见AI不是去查最近的源码库,而是基于网上的博客做整理而已。我们去读源码发现,并不是这样,PolicyManager.java早已经被移除了,这个设计因为很少需要扩展被认为是过度抽象设计而增加维护成本,所以从Android 6.0之后,PhoneWindow都是在Dialog和Activity之中直接new来创建,如下:

Dialog 在构造函数中直接创建 PhoneWindow 实例,并在 show() 阶段通过关联 Activity 的 Token 完成窗口注册。

    • Toast

Toast不创建PhoneWindow,仅通过ViewGroup(如 LinearLayout)作为根视图,因此无法直接接收输入事件。

关键步骤:

      1. 通过NMS排队 Toast 请求;
      2. TN收到回调后,在主线程调用WindowManager.addView()添加视图;
      3. 自动触发延时消息,定时移除视图

  • ViewRootImpl
    • ViewRootImpl 在 Activity.onResume() 后通过 WindowManager.addView() 创建,作为连接 DecorView 与 WindowManagerService的核心枢纽,负责驱动 UI 绘制、事件分发及窗口管理。

②Surface相关类

  • Surface
      • 概括:Surface 的创建由窗口状态变更(如首次显示、尺寸调整、层级更新)触发,通过 ViewRootImpl → WMS → SurfaceFlinger 的跨进程协作完成 Layer 注册,最终以句柄形式关联至应用层。

      • 分析:Surface的创建过程中,不得不先分析SurfaceControl和Layer的创建,下图是SurfaceControl的创建过程的简化版(详细的代码细节非常多,不便于大家记忆理解,而且太细节容易让大家脑子更糊涂),其中涉及Binder跨进程调用以及JNI调用等。简单描述下就是wms通过中间一些类的转发最终会调用SurfaceFlinger创建一个Layer(Layer就是在SurfaceFlinger当中对图层的抽象,应用层说的Surface可以理解为在SF这里的Layer)。然后在创建SurfaceControl的时候将Layer关联进去。

*outSurface = sp<SurfaceControl>::make(this, result.handle, result.layerId,                                                   toString(result.layerName), w, h, format,                                                   result.transformHint, flags);

那我们来看看SurfaceControl与Layer是怎么关联的呢?在最终创建SurfaceControl的时候,我们看到构造函数里有result.handle,result.layerId等等,看命名是不是和Layer有什么关系呢?不错确实关系很大,result是CreateSurfaceResult的实例,在Layer创建的时候会将LayerHandle交给CreateSurfaceResult的handle,然后在SurfaceControl构造函数中传入CreateSurfaceResult的handle也就是LayerHandle,那么这个LayerHandle是什么呢?

class LayerHandle : public BBinder {public:  LayerHandle(const sp<android::SurfaceFlinger>& flinger, const sp<android::Layer>& layer);  static sp<android::Layer> getLayer(const sp<IBinder>& handle);  ... }

不用关心上面的代码细节,只需要记住LayerHandle就是一个BBinder。里面有一个接口getLayer可以获取Layer,也就是说拿到这个handle就可以去操作Layer了,那么在SurfaceControl的构造函数里面传入了上面的handle,SurfaceControl间接的持有Layer了:

到这里我们大致了解了SurfaceControl和Layer的创建过程以及直接的关联过程,那么C++层的Surface到底是怎么创建的还没提到。上面的SurfaceControl创建走完,回到WMS类中:

再往上面一直回到ViewRootImpl中,

为了方便理解,以时序图展示C++层Surface创建调用过程:

通过代码和上图可知,最后是通过BLASTBufferQueue去创建Surface,那么BLASTBufferQueue是什么?BLASTBufferQueue代替之前的BufferQueue负责整个缓冲帧的生产者-消费者模型的实现(实现在客户端(new BlastBufferQueue),不在SurfaceFlinger当中,减少IPC),通过BLASTBufferQueue创建的Surface里面会持有这个模型的Producer(生产者),所以Surface可以对缓冲帧(GraphicBuffer)进行申请用来绘制以及绘制完成后入到BLASTBufferQueue中。

Surface创建的时候也会通过SurfaceControl->handle传参到Surface当中,也就是Surface也会持有Layer的句柄,这个是用来传递图层属性(位置,透明度等等),而持有Producer是用来处理图层数据的,为什么要分离?

BLASTBufferQueue传递GraphicBuffer是通过共享内存的方式,可以快速的访问帧的画面数据,

优化设计:

      • 零拷贝(Zero-Copy)
        数据始终位于共享内存中,生产者与消费者通过 同一块物理内存 读写,避免数据复制。
      • 内存映射同步
        通过 lock()/unlock() 控制 CPU 访问权限,并触发 Cache 同步(如 GPU 渲染后需同步 Cache 到内存)。
      • 硬件加速支持
        Gralloc 根据 usage 标志(如 USAGE_HW_TEXTURE)优化内存布局,确保 GPU 可直接访问。

与传统共享内存的差异:

通过Layer的句柄传递的位置和透明度属性是需要IPC,也是通过事务的方式减少Binder调用的次数。

举个例子说明下图层数据与图层属性分开传输:

假设开发一个绘图 App,用户手指滑动时在悬浮窗上绘制红色贝塞尔曲线,同时窗口可拖动(位置变化)。

      • 图形数据:手指轨迹生成的红色曲线像素(通过Path绘制到GraphicBuffer)
      • 控制指令:悬浮窗的位置、透明度、层级(通过 SurfaceControl.Transaction 设置)

实现步骤:

      1. 图形数据生成

当用户手指移动时,系统通过 Path.quadTo() 生成贝塞尔曲线路径,最终渲染到 GraphicBuffer:

      1. 控制指令提交

当用户拖动悬浮窗时,修改窗口位置(不改变曲线内容)

两者协同与分离的意义:

为什么必须分离?

      1. 解耦渲染与合成
        • 应用只需关注绘制内容(如曲线生成),系统服务独立管理合成策略(如叠加顺序、硬件加速)。
      1. 降低 IPC 开销
        • 高频的绘制(60+ fps)与低频的属性变更(如窗口移动)分离,避免每次绘制都触发 IPC。
      1. 动态响应性
        • 控制指令可随时修改(如窗口即时拖动),而图形数据按帧生成(需等待渲染完成)。

此设计是 Android 高帧率流畅交互的基础:图形数据保障内容正确性,控制指令保障交互响应性,两者通过 VSync 信号同步协作。

③小结

       通过上述分析及图像子系统的工作流程可知:首先实例化的是 PhoneWindow 对象。随后,当调用 setContentView 方法时,PhoneWindow 会实例化 DecorView。接着,在 ActivityThread 处理 Activity 的 resume 过程中实例化 ViewRootImpl,此时正式启动画面显示流程。ViewRootImpl 会发起请求,通过窗口管理系统 (WMS) 调用 SurfaceFlinger,由后者实例化 Layer 及 SurfaceControl。最终,ViewRootImpl 会通过 JNI 在 Native 层创建 Surface,该 Surface 后续将用于申请 GraphicBuffer 来存储渲染数据。这就是主要角色类的实例化的顺序过程。

Android 12(S) 图形显示系统 - BufferQueue的工作流程(八) Python微信订餐小程序课程视频 https://edu.youkuaiyun.com/course/detail/36074 Python实战量化交易理财系统 https://edu.youkuaiyun.com/course/detail/35475 题外话 最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从“愚昧之巅”掉到“绝望之谷”了,哈哈哈🐶 邓宁-克鲁格效应 一、前言 前面的文章中已经讲解了如何去创建一个Surface,也讲了一些操作Surface的知识,接下来就是如何利用这个Surface 阅读详情

相关推荐

Android14图形栈升级指南:BLASTBufferQueue特性详解与性能优化

本文深入解析了Android 14图形栈的核心升级——BLASTBufferQueue。它通过解耦渲染与合成时机、优化缓冲区管理,旨在显著降低合成延迟,提升应用渲染性能与帧率稳定性。文章详细剖析了其设计原理、创建流程及性能优化实战,为系统工程师释放设备图形潜力提供关键指导。

blue42的博客 445

BufferQueue研究

了解BufferQueue,有助于分析应用卡顿问题。

lonely_fireworks的专栏 3673

Android SurfaceFlinger——创建缓冲队列(二十二)

BLASTBufferQueue 是 Android 系统中用于图形缓冲区管理的一个重要组件,它是在 Android 12(代号为S)中引入的。在 Android 的图形显示系统中,BufferQueue 被用来协调生产者和消费者之间的缓冲区交换。然而,传统的 BufferQueue 实现涉及到了复杂的跨进程通信(IPC),这可能会成为性能瓶颈,尤其是在高帧率显示和复杂 UI 动画场景下。BLASTBufferQueue 目的是为了减少 IPC 的开销并提高效率。

小旭的专栏 1573

BLASTBufferQueue源码深入理解

updateActiveBuffer方法会对mPreviousReleaseCallbackId这个变量进行赋值,大家注意这里的为啥叫做前一帧的CallbackId,因为下面这个updateActiveBuffer就是赋值是先进行的mPreviousReleaseCallbackId赋值,然后才进行的新buffer的赋值,所以这个mPreviousReleaseCallbackId其实上一个的buffer的Id,不是当前这次的。这里的mPreviousReleaseCallbackId是哪里来的呢?

liaosongmao1的专栏 1833

STM32F103C8T6蓝莓派用HAL库GPIO模拟SPI驱动MAX31865读取PT100温度(附完整代码)

本文详细介绍了如何在STM32F103C8T6蓝莓派开发板上使用HAL库通过GPIO模拟SPI驱动MAX31865读取PT100温度传感器的完整方案。内容包括硬件连接、CubeMX配置、GPIO模拟SPI实现、温度计算算法及常见问题排查,并附有完整代码示例,帮助开发者快速实现高精度温度测量。

weixin_30684743的博客 935

数据中心光模块升级实录:从200G QSFP56到400G QSFP-DD的踩坑指南

本文记录了数据中心从200G QSFP56升级至400G QSFP-DD光模块的完整实战经验。文章深入剖析了升级过程中面临的兼容性、链路预算、布线、散热与功耗管理等核心挑战,并提供了具体的解决方案与排坑指南,为高速网络升级提供了宝贵的实践参考。

butter的博客 479

【转】自上而下解读Android显示流程

假如没有这样一个模块,所有合成任务都将有GPU完成,则会带来性能与功耗的负担,GPU主要用于绘制,参与合成则会造成资源的浪费,特别是在10年前,GPU参与合成,性能会急剧下降——对于如今来说,并没有那么大影响了,基本顺手捎带着就完成了,如今的考虑主要在于功耗,GPU合成的效率太低了。这里的原则也是减小带宽。这是Android发展到2.0之后才出现的概念,算是SF的附属子模块,之前是运行在SF主线程的,如今改成单独的Service,这是Android的设计理念,效率其实是下降了,两个进程的交互是相当频繁的。

fightingup 5299

OneNET物模型实战:如何用NB-IOT模块上传JSON数据并解析

本文详细介绍了如何利用NB-IOT模块将传感器数据上传至中国移动OneNET物联网平台,并利用其物模型功能实现JSON数据的自动解析。文章从理解OneNET物模型与OneJson协议入手,逐步讲解了平台侧物模型创建、设备注册,以及设备端数据构造、HEX编码与NB-IOT模块AT指令上报的全流程,并提供了关键的调试技巧与常见问题排查方法,为物联网开发者提供了完整的实战指南。

sugar的博客 680

Android 14 - 绘制体系 - 概览

从Android 12开始,Android的绘制系统有结构性变化, 在绘制的生产消费者模式中,新增BLASTBufferQueue,客户端进程自行进行queue的生产和消费,随后通过Transation提交到SurfaceFlinger,如此可以使得各进程将缓存提交到SufrfaceFlinger后合并到同一事务后同步提交,在同一帧生效。实际上,从Android12到Android14整个绘制系统在各个环节也都有了或大或小的。

temp7695的博客 2340

FreeFEM++下载安装和使用

最近要利用机器学习求解一些偏微分方程,对于一些复杂的偏微分方程,需要一些精度比较高的参考解,导师推荐了FreeFEM++软件。首次使用,特此记录一下,以备以后查阅。 1、FreeFEM++简介 FreeFEM是开源的有限元模拟系统,有法国利翁斯实验室、埃尔和玛丽居里大学共同开发,在世界范围内广泛使用。 2、FreeFEM++去何处下载? 下载地址:https://freefem.org/ 点击Download,然后会跳转到 https://github.com/FreeFem/FreeFem-source

夜晓岚的博客 1万+

Spring AI RAG 生产级实战:从 0 构建企业智能知识库系统

Spring AI🎯统一的 API 抽象:屏蔽不同 AI 服务商的差异🎯开箱即用的集成:支持主流大模型和向量数据库🎯Spring 生态融合:与 Spring Boot、Spring Data 无缝集成🎯企业级特性:事务管理、监控、安全等RAG 架构:检索 + 增强 + 生成,解决 LLM 局限性Spring AI:统一的 API 抽象,简化 AI 应用开发向量数据库:pgvector 适合中小规模,Milvus 适合大规模文档处理:加载 → 分块 → 向量化 → 存储检索优化。

一起修行,不孤单。这里有编程语言、开发工具、学习方法论和踩坑笔记。用简单的话说复杂的事,陪你从小白到进阶。周更干货,欢迎一起成长! 403

Android图像生产消费模型

之后生产者开始绘制。在生产消费模型中,生产者与消费者在接收到VSync信号时开始生产和消费,但由于生产速率与消费速率不同,因此当下一次VSync信号到来时,生产与消费过程不一定都能完成,这时会通过Fence机制来保障生产消费过程的同步。在Android 12之后,生产消费模型由BLASTBufferQueue进行管理,并且将生产消费模型从SurfaceFlinger服务端移动了客户端。1)减轻了SurfaceFlinger的压力,SurfaceFlinger不再需要管理每个Layer中的生产消费模型。

LeeDuoZuiShuai的博客 1731

【ROS2】Arduino系列之机器人底盘实现

介绍ros中提供的一个已经封装了的模块: ros_arduino_bridge,该模块由下位机驱动和上位机控制两部分组成,通过该模块可以更为快捷、方便的实现自己的机器人平台

guilin 1483

SurfaceFlinger BlastBufferQueue生产者消费者模型(4)

BlastBufferQueue是一个消费者生产者的模型,他们消费生产的对象是GraphicBuffer,GraphicBuffer其实就是一块内存,只不过是一块比较特殊的内存,使用的是dma buffer,相比于一般的内存,它是一块更高效的跨进程共享内存,后面会专门有一篇来介绍它。在Android 12开始,无论是这个模型的消费者还是生产者都在app侧,应用在渲染前,去队列里拿一块buffer,然后进行渲染,后放回队列,并且通知消费者可以取buffer消费,就是让SurfaceFlinger用于合成。

起司锅仔的博客 2079

基于Jetson Nano与YOLOv5s的无人机道路抛洒物实时检测系统【附数据集+代码】

本文详细介绍基于Jetson Nano与YOLOv5s的无人机道路抛洒物实时检测系统,通过硬件选型、数据采集、模型优化等关键步骤,实现高效的道路安全监控。系统结合无人机高空视角和YOLOv5s算法,能精准识别各类抛洒物,实测准确率达98.2%,为交通管理提供智能化解决方案。

weixin_29081163的博客 1453

Cadence 开发合集【总目录】

专栏主要介绍Cadence原理图和PCB信号完整性电源完整性仿真相关的内容,更加注重实操,以帮助大家轻松上手并不断提高;在开始专栏的更新前,博主先列出专栏的大纲,以供大家参考。大家直接点击大纲中的蓝色标题即可轻松传送。 ............

fydar的博客 1万+

SurfaceFlinger BufferQueue(二) BufferQueue初始化

上一篇文章讲到App在ViewRootImpl的draw流程中,而上面提到的surface的mGraphicBufferProducer是ViewRootImpl的relayoutWindow中,创建了BLASTBufferQueue,然后创建surface时传进去的。那么接下来我们开始分析BLASTBufferQueue。

Rainman博的专栏 868

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

BLASTBufferQueue端的GraphicBuffer怎么和SurfaceFlinger端的BufferStateLayer关联上

在跟进hwc_layer是如何产生的,并如何被填充上GraphicBuffer的,怎么也找不到被填充的GraphicBuffer的来源,最终找到了,它的来源是客户端的BLASTBufferQueue传递过来的,我们这里跟进下这个流程。一. BLASTBufferQueue是如何传递GraphicBuffer到SurfaceFlinger端的BufferStateLayer的。我们接着继续往下看,layer->setBuffer会调用子类的setBuffer,子类是BufferStateLayer。

IT先森 2247

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Android 12 BLASTBufferQueue 深度分析

Android 12推出的BLASTBufferQueue重构了传统图形渲染架构,将BufferQueue管理权从SurfaceFlinger(SF)下移到应用进程。这一改进解决了多窗口和高刷新率场景下的三大痛点:减少90%以上的IPC通信开销,降低SF负载,提升应用对缓冲区的自主管理能力。核心设计是应用进程直接管理BufferQueue,SF仅作为轻量级消费者处理合成,同时保持Gralloc模块的实际内存分配机制。该架构使120Hz场景下渲染延迟降低1-3ms,SF负载减少30%,并支持应用根据需求灵活配

weixin_42065195的博客 957

使用MapWinGis ActiveX控件在图层上画点

在上一篇文章中我们学会了如何显示一个地图, 那么接下来我们来实现两个比较简单的功能:描点和画线。 其实这些功能的实现都是在调用MapWin GIS开源库的API函数来实现的, 只要自己仔细的阅读文档就能实现,但是一些外围的博客更有利于初学者 们的进步,所以我想继续写下去。 好了言归正传,下面我们开始啦... 我们要实现描点、画线需要三步走:           1.新建一个图层。

yums467的专栏 2515

图像显示框架十三——BufferQueue的工作流程(基于Android 15源码分析)

指出了是一个“状态更新+条件触发”的过程,其核心是更新中的状态机。​​真正意义上的释放​​ 是指缓冲区​​从ACQUIRED状态成功迁移到FREE状态​​,并被加入到空闲缓冲区集合中。随后通过回调通知生产者,从而完成一个“释放-申请-使用”的完整循环。

龚礼鹏的博客 1192

60fps背后的秘密:Android图层数据与控制的分离哲学

这就是主要角色类的实例化的顺序过程。分析:Surface的创建过程中,不得不先分析SurfaceControl和Layer的创建,下图是SurfaceControl的创建过程的简化版(详细的代码细节非常多,不便于大家记忆理解,而且太细节容易让大家脑子更糊涂),其中涉及Binder跨进程调用以及JNI调用等。这个在网上很多博客写的还是上面的流程,包括在23、24年的博客,而且用Deepseek等AI去查,结果都是上面的流程,可见AI不是去查最近的源码库,而是基于网上的博客做整理而已。

吴延宝 1179

SurfaceFlinger BufferQueue(四) QueueBuffer

在上面的2.2小节我们知道mCore->mQueue的第一个元素BufferItem就是之前从mCore的mSlot拷贝过去的,里面存了被渲染好的buffer,mSlot数据index等信息,这里就把它拿出来,赋值给outBuffer ,outBuffer就是上面一直提到的从BLASTBufferQueue传递进来的BufferItem对象。的代码片段, 剩下的处理就是把ConsumerBase的mSlots[0]的mGraphicBuffer赋值给item的mGraphicBuffer。

Rainman博的专栏 429

Android14 SurfaceFlinger Surface的创建

ViewRootImpl通过WMS创建surfaceControl然后通过surfaceControl创建BLASTBufferQueue让后通过BLASTBufferQueue.createSurface生成一个BBQSurface, 继承与Surface, 也就是创建了Surface, 最后返回给mSurface.BLASTBufferQueue是连接生产者和消费者的纽带。

u012627628的博客 1858

Android T systemTrace 说明

BLASTBufferQueue

wangcheng74520的专栏 2132
上一篇: 60fps背后的秘密:Android图层数据与控制的分离哲学
下一篇: 揭开Android Vulkan渲染封印:帧率暴增的底层指令
IT烂笔头
博客等级 码龄15年 621粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值