目录
[1. 缓冲区队列管理(核心机制)](#1. 缓冲区队列管理(核心机制))
[2. 同步机制(Fence系统)](#2. 同步机制(Fence系统))
[3. CPU渲染技术](#3. CPU渲染技术)
[4. 颜色动画逻辑](#4. 颜色动画逻辑)
1.应用demo演示
首先要知道应用层与SurfaceFlinger如何交互,就要知道应用层用哪些api与SurfaceFlinger进行交互的,最快的方式是实现一个应用与SurfaceFlinger交互的演示demo,演示demo详细流程如下:
Android 12(S) 图像显示系统 - 示例应用(二) - 二的次方 - 博客园
2.应用demo代码解析
上述的demo可以实现一秒钟切换一种颜色,demo中源代码有NativeSurfaceWrapper.h、NativeSurfaceWrapper.cpp、main_NativeSFDemo.cpp三个文件,我们进行详细解析:
首先是NativeSurfaceWrapper.h文件:
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Native Surface包装器头文件
* 功能:声明用于创建和管理Android Surface的包装类
* 该类封装了与SurfaceFlinger交互的复杂逻辑,提供简化的接口
*/
#ifndef SURFACE_WRAPPER_H
#define SURFACE_WRAPPER_H
// BLASTBufferQueue - 现代缓冲区队列实现,用于高效的缓冲区管理
#include <gui/BLASTBufferQueue.h>
// IGraphicBufferProducer - 图形缓冲区生产者接口,用于向Surface提交图形数据
#include <gui/IGraphicBufferProducer.h>
// Surface相关头文件
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>
// 系统窗口相关定义
#include <system/window.h>
// RefBase - Android引用计数基类,提供自动内存管理
#include <utils/RefBase.h>
namespace android {
/**
* @brief Native Surface包装器类
*
* 这个类封装了创建和管理Android Surface的复杂逻辑,提供简化的接口用于:
* - 创建全屏Surface
* - 配置显示属性(层级、尺寸、格式等)
* - 管理图形缓冲区队列
* - 与SurfaceFlinger服务交互
*
* 继承自RefBase,支持Android智能指针系统,实现自动内存管理
*/
class NativeSurfaceWrapper : public RefBase {
public:
/**
* @brief 构造函数
* @param name Surface的名称标识,用于调试和日志
* @param layerStack 显示层栈ID,默认为0(主显示器)
* 用于多显示器配置,指定Surface显示在哪个显示器上
*/
NativeSurfaceWrapper(const String8& name, uint32_t layerStack=0);
/**
* @brief 虚析构函数
*
* 声明为虚函数以确保正确的多态销毁
* 使用默认实现,由智能指针系统自动管理资源释放
*/
virtual ~NativeSurfaceWrapper() {}
/**
* @brief 首次引用回调函数
*
* 当对象首次被sp<>智能指针引用时自动调用
* 在此方法中完成实际的Surface创建和配置工作,包括:
* - 连接SurfaceFlinger服务
* - 获取显示器配置信息
* - 创建SurfaceControl对象
* - 初始化BLASTBufferQueue
* - 配置Surface显示属性
*/
virtual void onFirstRef();
/**
* @brief 设置图形缓冲区生产者
* @param producer 输出的生产者接口引用
*
* 获取配置好的IGraphicBufferProducer接口,供外部进行图形渲染:
* - 从BLASTBufferQueue获取生产者接口
* - 配置缓冲区队列参数(如双缓冲设置)
* - 连接生产者到Surface
*/
void setUpProducer(sp<IGraphicBufferProducer>& producer);
/**
* @brief 获取Surface宽度
* @return Surface的像素宽度
*/
int width() { return mWidth; }
/**
* @brief 获取Surface高度
* @return Surface的像素高度
*/
int height() { return mHeight; }
private:
// 禁止拷贝构造和赋值操作,确保单例性
DISALLOW_COPY_AND_ASSIGN(NativeSurfaceWrapper);
/**
* @brief 根据系统限制调整Surface尺寸
* @param width 原始宽度
* @param height 原始高度
* @return 调整后的尺寸,保持宽高比
*
* 检查系统属性中的最大图形尺寸限制,防止创建过大的Surface
* 系统属性:
* - ro.surface_flinger.max_graphics_width
* - ro.surface_flinger.max_graphics_height
*/
ui::Size limitSurfaceSize(int width, int height) const;
// 成员变量
sp<BLASTBufferQueue> mBlastBufferQueue; ///< BLAST缓冲区队列,管理图形缓冲区生命周期
sp<SurfaceControl> mSurfaceControl; ///< Surface控制对象,管理Surface属性和状态
int mWidth; ///< Surface宽度(像素)
int mHeight; ///< Surface高度(像素)
String8 mName; ///< Surface名称,用于调试识别
uint32_t mLayerStack; ///< 显示层栈ID,用于多显示器配置
};
} // namespace android
#endif // SURFACE_WRAPPER_H
然后来看下NativeSurfaceWrapper.cpp文件的详细解析:
cpp
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Native Surface包装器实现文件
* 功能:封装Surface创建、配置和管理的复杂逻辑
*/
#define LOG_TAG "NativeSurfaceWrapper"
#include <android-base/properties.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <utils/Log.h>
#include "NativeSurfaceWrapper.h"
namespace android {
/**
* @brief 构造函数
* @param name Surface名称(用于调试识别)
* @param layerStack 显示层栈ID
*/
NativeSurfaceWrapper::NativeSurfaceWrapper(const String8& name, uint32_t layerStack)
: mName(name), mLayerStack(layerStack) {}
/**
* @brief 首次引用时的初始化回调
*
* 这是Android智能指针系统的标准模式,在对象首次被sp<>引用时自动调用
* 完成Surface创建、显示配置和缓冲区队列初始化等关键操作
*/
void NativeSurfaceWrapper::onFirstRef() {
// 创建SurfaceComposerClient,建立与SurfaceFlinger服务的连接
sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;
status_t err = surfaceComposerClient->initCheck();
if (err != NO_ERROR) {
ALOGD("SurfaceComposerClient::initCheck error: %#x\n", err);
return;
}
// 获取主显示器的标识令牌
sp<IBinder> displayToken = SurfaceComposerClient::getInternalDisplayToken();
if (displayToken == nullptr) {
ALOGE("Failed to get internal display token");
return;
}
// 获取当前显示模式信息(分辨率、刷新率等)
ui::DisplayMode displayMode;
const status_t error = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
if (error != NO_ERROR) {
ALOGE("Failed to get active display mode: %#x", error);
return;
}
// 根据系统限制调整Surface尺寸
ui::Size resolution = displayMode.resolution;
resolution = limitSurfaceSize(resolution.width, resolution.height);
// 创建SurfaceControl对象,管理Surface的生命周期
// eFXSurfaceBufferState表示使用现代BufferState图层类型
sp<SurfaceControl> surfaceControl = surfaceComposerClient->createSurface(
mName, // Surface名称
resolution.getWidth(), // 宽度
resolution.getHeight(), // 高度
PIXEL_FORMAT_RGBA_8888, // 像素格式
ISurfaceComposerClient::eFXSurfaceBufferState, // Surface类型
/*parent*/ nullptr // 父Surface(无)
);
if (surfaceControl == nullptr) {
ALOGE("Failed to create surface control");
return;
}
// 配置Surface的显示属性
SurfaceComposerClient::Transaction{}
.setLayer(surfaceControl, std::numeric_limits<int32_t>::max()) // 设置最高层级(最前面)
.show(surfaceControl) // 显示Surface
.setBackgroundColor(surfaceControl, half3{0, 0, 0}, 1.0f, ui::Dataspace::UNKNOWN) // 黑色背景
.setAlpha(surfaceControl, 1.0f) // 不透明度100%
.setLayerStack(surfaceControl, mLayerStack) // 设置显示层栈
.apply(); // 应用所有配置
// 保存Surface尺寸信息
mWidth = resolution.getWidth();
mHeight = resolution.getHeight();
// 创建BLASTBufferQueue(BufferQueue的现代实现)
// BLAST = Buffer Layout and Surface Control
mBlastBufferQueue = new BLASTBufferQueue(
"DemoBLASTBufferQueue", // 队列名称
surfaceControl, // 关联的SurfaceControl
resolution.getWidth(), // 缓冲区宽度
resolution.getHeight(), // 缓冲区高度
PIXEL_FORMAT_RGBA_8888 // 缓冲区格式
);
mSurfaceControl = surfaceControl; // 保存SurfaceControl引用
}
/**
* @brief 设置并配置图形缓冲区生产者
* @param producer 输出的生产者接口指针
*
* 配置缓冲区队列的生产者端,供应用进行图形渲染
*/
void NativeSurfaceWrapper::setUpProducer(sp<IGraphicBufferProducer>& producer) {
// 获取BLASTBufferQueue的生产者接口
producer = mBlastBufferQueue->getIGraphicBufferProducer();
// 设置最大出队缓冲区数量(双缓冲配置)
producer->setMaxDequeuedBufferCount(2);
// 连接生产者,注册为CPU渲染客户端
IGraphicBufferProducer::QueueBufferOutput qbOutput;
producer->connect(
new StubProducerListener, // 空的监听器(简化实现)
NATIVE_WINDOW_API_CPU, // 使用CPU进行渲染
false, // 不启用生产者受控缓冲
&qbOutput // 输出队列配置信息
);
}
/**
* @brief 根据系统属性限制Surface尺寸
* @param width 原始宽度
* @param height 原始高度
* @return 调整后的尺寸
*
* 防止创建过大的Surface消耗过多系统资源,保持宽高比不变
*/
ui::Size NativeSurfaceWrapper::limitSurfaceSize(int width, int height) const {
ui::Size limited(width, height);
bool wasLimited = false;
const float aspectRatio = float(width) / float(height);
// 从系统属性读取最大允许的图形尺寸
int maxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
int maxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
// 如果宽度超过限制,按比例调整高度
if (maxWidth != 0 && width > maxWidth) {
limited.height = maxWidth / aspectRatio;
limited.width = maxWidth;
wasLimited = true;
}
// 如果调整后的高度仍然超过限制,按比例调整宽度
if (maxHeight != 0 && limited.height > maxHeight) {
limited.height = maxHeight;
limited.width = maxHeight * aspectRatio;
wasLimited = true;
}
// 记录尺寸调整日志(调试用)
SLOGV_IF(wasLimited, "Surface size has been limited to [%dx%d] from [%dx%d]",
limited.width, limited.height, width, height);
return limited;
}
} // namespace android
上面重点的函数是onFirstRef,详细讲解下此函数:
- 创建一个SurfaceComposerClient对象,这个是SurfaceFlinger的Client端,用于和SurfaceFlinger进行跨进程通信的
- 进行主显示器token令牌校验以及当前屏幕显示模式信息(分辨率、刷新率等)校验,都校验通过进行下面的流程
- 获取屏幕参数,SurfaceComposerClient::getActiveDisplayMode获取当前的DisplayMode,其中可以得到resolution信息,并根据当前系统限制调用limitSurfaceSize函数进行resolution的调整
- 创建Surface & SurfaceControl,然后将resolution中获取的宽高信息以及设置像素信息传递给createSurface函数,createSurface函数会进行与SurfaceFlinger进行binder跨进程通信,此时SurfaceFlinger会创建Layer等操作并返回SurfaceControl对象
- setLayer,设置视图在当窗口的z-order,最大值则在最前面,SurfaceFlinger根据当前设置的z-order决定窗口的可见性以及显示区域大小
- show,让当前的视图显示出来
- apply,提交事务,使透过Transaction进行设置的属性生效,一次性调用传递给SurfaceFlinger
然后再来看看main.cpp文件的详细解析:
cpp
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Native SurfaceFlinger 演示程序 - 主程序文件
* 功能:创建一个全屏窗口并循环显示红绿蓝三种颜色
*/
#define LOG_TAG "NativeSFDemo"
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <hardware/gralloc.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
#include "NativeSurfaceWrapper.h"
using namespace android;
// 全局控制变量
bool mQuit = false; // 程序退出标志
int mLayerStack = 0; // 显示层栈(用于多显示器配置)
/**
* @brief 使用指定颜色填充RGBA8888格式的图像缓冲区
* @param img 指向图像数据的指针
* @param width 图像宽度
* @param height 图像高度
* @param stride 图像行跨度(可能包含填充字节)
* @param r 红色分量 (0-255)
* @param g 绿色分量 (0-255)
* @param b 蓝色分量 (0-255)
*
* 该函数通过CPU直接写入像素数据,适用于软件渲染场景
*/
void fillRGBA8Buffer(uint8_t* img, int width, int height, int stride, int r, int g, int b) {
// 遍历每个像素点进行填充
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 计算当前像素位置(每个像素4字节:RGBA)
uint8_t* pixel = img + (4 * (y*stride + x));
pixel[0] = r; // Red
pixel[1] = g; // Green
pixel[2] = b; // Blue
pixel[3] = 0; // Alpha(设置为0表示不透明)
}
}
}
/**
* @brief 主绘制函数,负责图形缓冲区的循环渲染
* @param nativeSurface NativeSurfaceWrapper实例
* @return 错误状态码
*
* 实现典型的图形渲染流水线:
* 1. 出队缓冲区 → 2. CPU渲染 → 3. 入队显示
*/
int drawNativeSurface(sp<NativeSurfaceWrapper> nativeSurface) {
status_t err = NO_ERROR;
int countFrame = 0; // 帧计数器,用于颜色循环
// 获取图形缓冲区生产者接口
sp<IGraphicBufferProducer> igbProducer;
nativeSurface->setUpProducer(igbProducer);
// 主渲染循环:每秒绘制一帧,直到收到退出信号
while(!mQuit) {
int slot; // 缓冲区槽位索引
sp<Fence> fence; // 同步栅栏,确保缓冲区可用
sp<GraphicBuffer> buf; // 图形缓冲区对象
// 步骤1: 从生产者队列中获取一个可用的缓冲区
igbProducer->dequeueBuffer(&slot, &fence, nativeSurface->width(), nativeSurface->height(),
PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
nullptr, nullptr);
// 获取对应槽位的缓冲区对象
igbProducer->requestBuffer(slot, &buf);
// 等待缓冲区就绪(同步操作,避免竞争条件)
int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");
if (waitResult != OK) {
ALOGE("dequeueBuffer_EmptyNative: Fence::wait returned an error: %d", waitResult);
break;
}
// 步骤2: 锁定缓冲区并进行CPU渲染
uint8_t* img = nullptr;
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
if (err != NO_ERROR) {
ALOGE("error: lock failed: %s (%d)", strerror(-err), -err);
break;
}
// 计算当前帧颜色(红绿蓝循环)
countFrame = (countFrame+1)%3;
fillRGBA8Buffer(img, nativeSurface->width(), nativeSurface->height(), buf->getStride(),
countFrame == 0 ? 255 : 0, // 红
countFrame == 1 ? 255 : 0, // 绿
countFrame == 2 ? 255 : 0); // 蓝
// 解锁缓冲区,提交渲染结果
err = buf->unlock();
if (err != NO_ERROR) {
ALOGE("error: unlock failed: %s (%d)", strerror(-err), -err);
break;
}
// 步骤3: 将渲染完成的缓冲区提交到显示队列
IGraphicBufferProducer::QueueBufferOutput qbOutput;
IGraphicBufferProducer::QueueBufferInput input(
systemTime(), // 时间戳
true, // 自动时间戳
HAL_DATASPACE_UNKNOWN, // 数据空间
{}, // 裁剪区域(全屏)
NATIVE_WINDOW_SCALING_MODE_FREEZE, // 缩放模式
0, // 变换
Fence::NO_FENCE // 同步栅栏
);
igbProducer->queueBuffer(slot, input, &qbOutput);
// 控制帧率:每秒一帧
sleep(1);
}
return err;
}
/**
* @brief 信号处理函数,用于优雅退出程序
* @param num 信号编号
*/
void sighandler(int num) {
if(num == SIGINT) {
printf("\nSIGINT: Force to stop !\n");
mQuit = true; // 设置退出标志,终止渲染循环
}
}
/**
* @brief 显示程序使用说明
* @param me 程序名称
*/
static void usage(const char *me)
{
fprintf(stderr, "\nusage: \t%s [options]\n"
"\t--------------------------------------- options ------------------------------------------------\n"
"\t[-h] help\n"
"\t[-d] layer stack(In the case of multi-display, NativeSFDemo shows on the specified displays \n"
"\t in addition to the primary display)\n"
"\t------------------------------------------------------------------------------------------------\n",
me);
exit(1);
}
/**
* @brief 解析命令行参数
* @param argc 参数个数
* @param argv 参数数组
*/
void parseOptions(int argc, char **argv) {
const char *me = argv[0];
int res;
while((res = getopt(argc, argv, "d:")) >= 0) {
switch(res) {
case 'd':
mLayerStack = atoi(optarg); // 设置显示层栈
break;
case 'h':
default:
{
usage(me); // 显示帮助信息
}
}
}
}
/**
* @brief 程序主入口
* @param argc 命令行参数个数
* @param argv 命令行参数数组
* @return 程序退出码
*
* 程序执行流程:
* 1. 解析参数 → 2. 设置信号处理 → 3. 创建Surface → 4. 进入渲染循环
*/
int main(int argc, char ** argv) {
// 初始化阶段
parseOptions(argc, argv); // 解析命令行参数
signal(SIGINT, sighandler); // 注册Ctrl+C信号处理
// 创建Native Surface包装器实例
sp<NativeSurfaceWrapper> nativeSurface(new NativeSurfaceWrapper(String8("NativeSFDemo"), mLayerStack));
// 进入主渲染循环
drawNativeSurface(nativeSurface);
return 0;
}
首先main函数详细解析如下:
- signal函数注册监听SIGINT信号的handler,注册Ctrl+C信号处理,使其可以优雅的退出程序
- 创建NativeSurfaceWrapper对象,并调用drawNativeSurface进行图片的绘制
终端默认的键盘信号映射:
Ctrl+C → SIGINT (中断进程)
Ctrl+Z → SIGTSTP (暂停进程)
Ctrl+\ → SIGQUIT (退出并核心转储)
Ctrl+D → EOF (文件结束)
然后来解析下drawNativeSurface函数中执行的流程以及重点内容
首先主要流程如下:
主循环开始
↓
dequeueBuffer() 获取空闲缓冲区
↓
requestBuffer() 获取缓冲区对象
↓
fence->wait() 等待缓冲区可用
↓
buf->lock() 锁定缓冲区
↓
fillRGBA8Buffer() CPU渲染颜色
↓
buf->unlock() 解锁缓冲区
↓
queueBuffer() 提交显示
↓
sleep(1) 控制帧率
↓
检查mQuit标志 → 继续循环或退出
整体架构图
应用进程 (本程序)
↓ 通过igbProducer (Binder IPC)
SurfaceFlinger进程
↓
显示硬件
具体角色定位
// igbProducer是连接应用和SurfaceFlinger的桥梁
应用层 (Producer) ←→ igbProducer ←→ BufferQueue ←→ SurfaceFlinger (Consumer)
(生产者接口) (缓冲区队列) (消费者)
重点内容提取:
1. 缓冲区队列管理(核心机制)
出队-渲染-入队模式
cpp
// 步骤1:出队缓冲区(获取可用的缓冲区)
igbProducer->dequeueBuffer(&slot, &fence, width, height, format, usage);
// 步骤2:获取缓冲区对象
igbProducer->requestBuffer(slot, &buf);
// 步骤3:渲染内容到缓冲区
// ... 渲染操作 ...
// 步骤4:入队缓冲区(提交显示)
igbProducer->queueBuffer(slot, input, &qbOutput);
关键技术点:
-
双缓冲/三缓冲机制:避免显示撕裂
-
Slot管理:缓冲区槽位复用
-
生产者-消费者模式:解耦渲染和显示
2. 同步机制(Fence系统)
cpp
// 等待缓冲区就绪的同步操作
int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");
// Fence的作用:
// - 确保GPU已完成对缓冲区的操作
// - 防止CPU和GPU访问冲突
// - 实现渲染流水线的正确同步
重要概念:
-
GPU-CPU同步:避免资源竞争
-
流水线控制:保证渲染时序正确
-
超时处理 :
waitForevervswait(带超时)
3. CPU渲染技术
软件渲染实现
cpp
// 等待缓冲区就绪的同步操作
int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");
// Fence的作用:
// - 确保GPU已完成对缓冲区的操作
// - 防止CPU和GPU访问冲突
// - 实现渲染流水线的正确同步
渲染细节:
-
内存布局:RGBA8888格式(每个像素4字节)
-
步长(Stride)处理:可能包含内存对齐的填充字节
-
颜色格式:RGBA颜色空间,Alpha通道未使用
4. 颜色动画逻辑
cpp
// 简单的颜色循环算法
countFrame = (countFrame+1)%3;
fillRGBA8Buffer(...,
countFrame == 0 ? 255 : 0, // 红
countFrame == 1 ? 255 : 0, // 绿
countFrame == 2 ? 255 : 0); // 蓝
动画特性:
-
三色循环:红→绿→蓝→红...
-
帧率控制:每秒1帧(sleep(1))
-
状态保持 :
countFrame维护动画状态
上述就是对demo的解析