android 图像显示框架二——流程分析
一.Android图形组件协作工作
首先先上流程图:
如下是Android12及以后得Android图形组件协作的流程图

上述的图片清晰的展示了Android图形系统最核心的基石——基于BufferQueue的生产者-消费者模式。整个流程是是描述一个图形缓存区(GraphicBuffer)从被绘制到最终被显示出来的完整生命周期。
全景概述:三大角色
整个架构围绕着三大角色展开,对应图中的三个主要部分:
1.图像生产者(Image Producer):负责生产(绘制)图像内容,例如:应用程序、视频解码器。
2.图像消费者(Image Consumer):负责使用(消耗)已生成的图像内容。例如:将图像合成后送到显示屏的SurfaceFlinger。
3.BufferQueue:作为核心中介,连接生产者和消费者,它管理着一组图形缓冲区(GraphicBuffer),是数据交换的通道。
模块详解:
1.图像生产者(右侧)
- 是什么:所有需要将画面绘制到屏幕上的实体。
- 常见生产者:
- OpenGL ES/Vulkan:3D图形渲染库。
- Skia:2D图形绘制库,常用于应用界面绘制。
- Decoder:视频解码器,解码视频帧。
2.图像消费者(左侧)
- 是什么:获取并使用生产者提交的图像数据实体。
- 核心消费者:
- SurfaceFlinger:Android系统的合成器。它接受多个应用(生产者)的缓冲区,将它们最终合成一帧,然后交个HWComposer显示到屏幕上。
- OpenGL ES:在某些情况下(如应用内纹理渲染),它也可以作为消费者。
3.核心枢纽:BufferQueue(中间)
这是整个流程的心脏,它内部包含了三个核心组件,共同管理着缓冲区的一生。
- BufferQueueCore:
- 核心大脑:管理整个队列的状态。
- 资源池:持有固定数量的Buffer Slots(缓冲区槽位)和GraphicBuffer对象。GraphicBuffer是真正存储像素数据的内存块。
- 状态跟踪:跟踪每个缓冲区的状态(空闲、已排队、已获取)
- BufferQueueProducer:
- 面向生产者的接口:生产者只与它交互
- 关键操作:
dequeueBuffer():向生产者分配一个空闲的缓冲区。
queueBuffer():接受生产者已经绘制完成的缓冲区,并将他置于已排队的状态,通知消费者。
- BufferQueueConsumer:
- 面向消费者的接口:消费者只与它打交道
- 关键操作:
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系统保持界面流畅的关键。
