android 图像显示框架二——流程分析

一.Android图形组件协作工作

首先先上流程图:

如下是Android12及以后得Android图形组件协作的流程图

上述的图片清晰的展示了Android图形系统最核心的基石------基于BufferQueue的生产者-消费者模式。整个流程是是描述一个图形缓存区(GraphicBuffer)从被绘制到最终被显示出来的完整生命周期。

全景概述:三大角色

整个架构围绕着三大角色展开,对应图中的三个主要部分:

1.图像生产者(Image Producer) :负责**生产(绘制)**图像内容,例如:应用程序、视频解码器。

2.图像消费者(Image Consumer) :负责**使用(消耗)**已生成的图像内容。例如:将图像合成后送到显示屏的SurfaceFlinger。

3.BufferQueue:作为核心中介 ,连接生产者和消费者,它管理着一组图形缓冲区(GraphicBuffer),是数据交换的通道。

模块详解:

1.图像生产者(右侧)

  • **是什么:**所有需要将画面绘制到屏幕上的实体。
  • 常见生产者:
  1. OpenGL ES/Vulkan:3D图形渲染库。
  2. Skia :2D图形绘制库,常用于应用界面绘制。
  3. Decoder:视频解码器,解码视频帧。

2.图像消费者(左侧)

  • **是什么:**获取并使用生产者提交的图像数据实体。
  • 核心消费者:
  1. SurfaceFlinger:Android系统的合成器。它接受多个应用(生产者)的缓冲区,将它们最终合成一帧,然后交个HWComposer显示到屏幕上。
  2. OpenGL ES:在某些情况下(如应用内纹理渲染),它也可以作为消费者。

3.核心枢纽:BufferQueue(中间)

这是整个流程的心脏,它内部包含了三个核心组件,共同管理着缓冲区的一生。

  • BufferQueueCore:
  1. 核心大脑:管理整个队列的状态。
  2. 资源池:持有固定数量的Buffer Slots(缓冲区槽位)和GraphicBuffer对象。GraphicBuffer是真正存储像素数据的内存块。
  3. 状态跟踪:跟踪每个缓冲区的状态(空闲、已排队、已获取)
  • BufferQueueProducer:
  1. 面向生产者的接口:生产者只与它交互
  2. 关键操作:

dequeueBuffer():向生产者分配一个空闲的缓冲区。

queueBuffer():接受生产者已经绘制完成的缓冲区,并将他置于已排队的状态,通知消费者。

  • BufferQueueConsumer:
  1. 面向消费者的接口:消费者只与它打交道
  2. 关键操作:

acquireBuffer():从队列中获取一个已排队的缓冲区,交个消费者使用

releaseBuffer():消费者使用完毕后,将其释放回空闲状态,可供生产者再次使用

缓冲区生命周期与数据流(重点)

让我们跟随一个GraphicBuffer的旅程,对应流程图中的箭头和文字:

1.dequeue(出队):

  • 生产者(如App)通过Surface------>dequeueBuffer()调用BufferQueueProducer。
  • Producer从BufferQueue的缓冲区槽位(Buffer Slots)中找到一个状态为FREE(空闲)的GraphicBuffer,将其状态改为DEQUEUED,并返回给生产者。

2.生产/渲染:

  • 生产者获取到GraphicBuffer后,使用OpenGL ES或者Skia等库在其上进行绘制,填充图像数据。

3.queue(入队):

  • 绘制完成后,生产者调用Surface------>queueBuffer()。
  • Producer将该GraphicBuffer的状态改成QUEUED(已排队),并将其放入队列中。同时,通过回调通知消费者:"有新的数据可以用了!"

4.acquire(获取):

  • 消费者(如SurfaceFlinger)被唤醒,调用acquireBuffer()。
  • BufferQueueConsumer从队列中取出一个QUEUED状态的缓冲区,将其状态改成ACQUIRED(已获取),然后交给消费者

5.消费(合成/显示):

  • 消费者对获取的缓冲区内容进行处理,对于SurfaceFlinger来说,就是将多个应用的缓冲区合成最终的画面

6.release(释放):

  • 消费者使用完毕后,调用releaseBuffer()。
  • Consumer将该GraphicBuffer的状态重置为FREE(空闲),并将其放会空闲池。
  • 此时,这个缓冲区又可以再次被生产者dequeue,开始新一轮的循环。

关键技术与进阶概念

1.同步机制-Fence(栅栏)

图中箭头旁的acquire和release信号,在实际实现中通常与Fence机制紧密相关。

  • 为什么需要:GPU渲染是异步的。当生产者queueBuffer是,GPU的渲染指令可能还没有真正执行完。直接让消费者读取可能读取不到完整的帧。
  • 如何工作:生产者提交缓冲区时,会附带一个Fence。消费者在acquire缓冲区后,会等待这个Fence发出"信号"(表示GPU渲染完成),才去读取缓冲区内容。这保证了数据同步,避免屏幕撕裂

2.BLASTBufferQueue(Buffer Latency and Synchronization Task)

  • 是什么:Android10/11中引入的现代化BufferQueue。
  • 解决什么问题:传统的Surface和BufferQueue是一对一绑定的。一个窗口(如Activity)通常只有一个Surface,这限制了性能(例如:难以实现无缝转场动画)
  • 优势:BLASTBufferQueue允许一个窗口管理多个缓冲区会话,提供了更加精细、更加灵活的缓冲区控制,显著改善了应用切换、分屏和动画的流畅度。可以看做是BufferQueue的增强版。

总结:

这张图精妙的描绘出Android图形系统解耦和异步处理的核心思想:

  • 解耦:生产者(App)和消费者(SurfaceFlinger)不需要知道对方的存在,也不需要同步工作。它们只与BufferQueue交互,从而可以独立、高效运行。
  • 流水线:通过缓冲区队列,实现了"绘制一帧"和"显示一帧"的并行操作。当消费者正在显示第N帧时,生产者可能已经在绘制第"N+1"帧了。这是Android系统保持界面流畅的关键。
相关推荐
消失的旧时光-19435 小时前
kmp需要技能
android·设计模式·kotlin
帅得不敢出门5 小时前
Linux服务器编译android报no space left on device导致失败的定位解决
android·linux·服务器
雨白6 小时前
协程间的通信管道 —— Kotlin Channel 详解
android·kotlin
TimeFine8 小时前
kotlin协程 容易被忽视的CompletableDeferred
android
czhc11400756639 小时前
Linux1023 mysql 修改密码等
android·mysql·adb
GOATLong10 小时前
MySQL内置函数
android·数据库·c++·vscode·mysql
onthewaying11 小时前
Android SurfaceTexture 深度解析
android·opengl
茄子凉心11 小时前
Android Bluetooth 蓝牙通信
android·蓝牙通信·bluetooth通信
00后程序员张12 小时前
iOS 26 App 运行状况全面解析 多工具协同监控与调试实战指南
android·ios·小程序·https·uni-app·iphone·webview