1.背景
在上一篇中提到了许多陌生的类,比如Surface/SurfaceControl/ANativeWindow/ANativeWindowBuffer,这些类有什么作用,以及有什么关系,以及他们和BufferQueue之间是什么关系?我们带着这些疑问来开始讲解这篇内容
ANativeWindow
Surface
SurfaceControl
ANativeWindowBuffer
2.介绍
ANativeWindow
ANativeWindow结构是本地窗口的抽象描述
代码位置:framework/native/libs/nativewindow/include/system/window.h
struct ANativeWindow
{
#ifdef __cplusplus
// 构造函数:初始化 magic number、版本号及各类窗口属性默认值
ANativeWindow()
: flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
{
common.magic = ANDROID_NATIVE_WINDOW_MAGIC; // 魔术字,用于类型验证
common.version = sizeof(ANativeWindow); // 结构体版本
memset(common.reserved, 0, sizeof(common.reserved)); // 保留字段置零
}
// 以下两个函数实现了引用计数功能,使 ANativeWindow 可由 sp<> (强指针) 自动管理生命周期
void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
// 基础结构体,核心作用是提供引用计数机制 (incRef/decRef) 和类型识别信息 [5](@ref)
struct android_native_base_t common;
const uint32_t flags; // 描述窗口或其更新器的属性标志
const int minSwapInterval; // 该窗口支持的最小缓冲区交换间隔
const int maxSwapInterval; // 该窗口支持的最大缓冲区交换间隔
const float xdpi; // 屏幕水平方向的物理DPI (每英寸像素数)
const float ydpi; // 屏幕垂直方向的物理DPI
intptr_t oem[4]; // 为OEM厂商驱动保留的存储空间
// --- 关键函数指针表 (操作接口) ---
// 设置缓冲区交换的间隔,用于控制帧率同步(如垂直同步)
int (*setSwapInterval)(struct ANativeWindow* window, int interval);
// 查询窗口信息,如宽度、高度、像素格式等 [1](@ref)
int (*query)(const struct ANativeWindow* window, int what, int* value);
// 一个通用操作入口,用于执行各种无法用简单函数表示的窗口操作 [1,2](@ref)
int (*perform)(struct ANativeWindow* window, int operation, ...);
// ===================== 已弃用的缓冲区操作接口 (无Fence机制) =====================
// 旧版:从窗口的缓冲区队列中申请一个可用的缓冲区(可能阻塞)
int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer** buffer);
// 旧版:锁定缓冲区,准备写入数据(在现代图形架构中已无实际作用)
int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
// 旧版:将填充好的缓冲区重新加入队列,并提交给消费者(如SurfaceFlinger)进行合成与显示
int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
// 旧版:取消一个已出列的缓冲区,将其归还给队列
int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer);
// ===================== 现代的缓冲区操作接口 (支持Fence同步机制) =====================
/*
* 现代:出列一个缓冲区。
* @param buffer 输出参数,指向获取到的缓冲区指针。
* @param fenceFd 输出参数,指向一个同步Fence的文件描述符。
* 应用必须等待此Fence发出信号后,才能向缓冲区写入数据。
* 如果值为-1,表示可立即写入。
*/
int (*dequeueBuffer)(struct ANativeWindow* window,
struct ANativeWindowBuffer** buffer, int* fenceFd);
/*
* 现代:将缓冲区入队。
* @param fenceFd 输入参数,一个同步Fence的文件描述符。
* 图形系统会等待此Fence信号,才读取缓冲区内容。
* 如果无需等待,应传入-1。
*/
int (*queueBuffer)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer, int fenceFd);
/*
* 现代:取消一个已出列的缓冲区。
* @param fenceFd 应传入从 dequeueBuffer 获取的fenceFd,以确保数据安全。
*/
int (*cancelBuffer)(struct ANativeWindow* window,
struct ANativeWindowBuffer* buffer, int fenceFd);
};
window.h这个头文件还有许多enum常量,如下:
用于query()函数检索信息的常量
/* 可通过 query() 函数查询的窗口属性常量 */
enum {
NATIVE_WINDOW_WIDTH = 0, // 查询窗口缓冲区的当前宽度(像素)
NATIVE_WINDOW_HEIGHT = 1, // 查询窗口缓冲区的当前高度(像素)
NATIVE_WINDOW_FORMAT = 2, // 查询窗口缓冲区的像素格式(如RGB_565、RGBA_8888)
/* 参见 vndk/window.h 中的 ANativeWindowQuery 定义 */
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS, // 查询需要维护的最小未加入队列的缓冲区数量(用于避免缓冲区枯竭)
/* 检查对此ANativeWindow的queueBuffer操作是否会将缓冲区发送到窗口合成器。
* 如果ANativeWindow将已排队的缓冲区直接发送到窗口合成器,则查询将返回的'value'参数设为1,
* 如果缓冲区不直接进入窗口合成器,则设为0。
* 这可用于判断是否应将受保护的缓冲区内容发送到ANativeWindow。
*/
NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4,
/* 获取ANativeWindow的具体类型。参见下方可能的返回值列表。
* 此查询不应在Android框架之外使用,并可能在近期移除。
*/
NATIVE_WINDOW_CONCRETE_TYPE = 5,
/* 查询ANativeWindow缓冲区的默认宽度和高度。这些是缓冲区的基础尺寸,
* 不受NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS调用影响,通常与原生窗口大小匹配,
* 除非被NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS覆盖。
*/
NATIVE_WINDOW_DEFAULT_WIDTH = ANATIVEWINDOW_QUERY_DEFAULT_WIDTH, // 缓冲区的默认宽度
NATIVE_WINDOW_DEFAULT_HEIGHT = ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT, // 缓冲区的默认高度
/* 参见 vndk/window.h 中的 ANativeWindowQuery 定义 */
NATIVE_WINDOW_TRANSFORM_HINT = ANATIVEWINDOW_QUERY_TRANSFORM_HINT, // 查询合成器建议应用于缓冲区的事先变换(如旋转),以优化合成性能
/* 布尔值,指示消费者是否比生产者落后超过一个缓冲区(即是否运行缓慢) */
NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
/* 消费者当前设置的gralloc使用位。值定义在hardware/libhardware/include/gralloc.h中。(已弃用) */
NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, // 已弃用
/* 将由hwcomposer应用于缓冲区的变换。生产者端点不得设置或检查此值,
* 并且它将禁用SurfaceFlinger中设置的变换提示(参见NATIVE_WINDOW_TRANSFORM_HINT)。
* 用途:临时性,请勿使用。仅供相机LEGACY模式使用。
*/
NATIVE_WINDOW_STICKY_TRANSFORM = 11, // 设置粘性变换,通常由消费者端(如SurfaceFlinger)为特定用例(如相机预览)设置
/* 缓冲区默认的数据空间(DataSpace),用于定义颜色编码、范围、转换函数等。值定义在graphics.h中。 */
NATIVE_WINDOW_DEFAULT_DATASPACE = 12, // 查询缓冲区关联的默认数据空间(如色彩空间)
/* 参见 vndk/window.h 中的 ANativeWindowQuery 定义 */
NATIVE_WINDOW_BUFFER_AGE = ANATIVEWINDOW_QUERY_BUFFER_AGE, // 查询当前缓冲区相对于队列中最新缓冲区的"年龄"(即经历了多少帧),用于增量渲染优化
/* 返回上一次dequeueBuffer调用的持续时间(微秒)。已弃用:请改用perform()中的NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION(支持纳秒精度)。 */
NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14, // 上一次dequeueBuffer操作耗时(微秒),已弃用
/* 返回上一次queueBuffer调用的持续时间(微秒)。已弃用:请改用perform()中的NATIVE_WINDOW_GET_LAST_QUEUE_DURATION(支持纳秒精度)。 */
NATIVE_WINDOW_LAST_QUEUE_DURATION = 15, // 上一次queueBuffer操作耗时(微秒),已弃用
/* 返回ANativeWindow缓冲区包含的图像层数。默认为1,除非显式分配了包含多层的缓冲区。 */
NATIVE_WINDOW_LAYER_COUNT = 16, // 缓冲区包含的图像层数(例如用于立体3D等多层渲染)
/* 如果原生窗口有效(即调用其任何方法都是安全的,不会发生崩溃)则返回1,否则返回0。 */
NATIVE_WINDOW_IS_VALID = 17, // 检查ANativeWindow对象是否有效(可安全操作)
/* 如果NATIVE_WINDOW_GET_FRAME_TIMESTAMPS将返回显示呈现(present)信息,则返回1,否则返回0。 */
NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18, // 查询是否支持获取帧时间戳中的显示呈现时间
/* 消费者端能够处理受保护的缓冲区(即具有GRALLOC_USAGE_PROTECTED使用位的缓冲区)。 */
NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19, // 查询消费者是否支持受保护内容(用于DRM等内容保护)
/* 返回缓冲区的数据空间(DataSpace)。 */
NATIVE_WINDOW_DATASPACE = 20, // 查询缓冲区实际使用的数据空间
/* 返回由BufferQueueConsumer设置的最大缓冲区数量。 */
NATIVE_WINDOW_MAX_BUFFER_COUNT = 21, // 查询此窗口允许的最大缓冲区数量(用于缓冲区队列管理)
};
用于(*perform)()的标识各种操作的常量
这个枚举定义了 ANativeWindow的 perform()方法支持的所有操作指令,用于控制窗口缓冲区的各种行为。以下是每个操作的中文注释,按功能分类说明:
🎛️ 缓冲区配置与属性设置
NATIVE_WINDOW_SET_USAGE = 0, // 设置生产者使用标志(已弃用,请使用 SET_USAGE64)
NATIVE_WINDOW_SET_BUFFER_COUNT = 4, // 设置缓冲区队列的缓冲区数量
NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, // 同时设置缓冲区的宽度、高度和格式(已弃用)
NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, // 设置缓冲区的宽度和高度(像素)
NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, // 设置缓冲区的像素格式(如 RGB_565、RGBA_8888)
NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, // 设置用户空间的缓冲区尺寸(内部使用)
NATIVE_WINDOW_SET_USAGE64 = 30, // 设置64位生产者使用标志(替代 SET_USAGE)
NATIVE_WINDOW_SET_BUFFERS_ADDITIONAL_OPTIONS = 50, // 设置缓冲区的附加选项
🔄 连接与生命周期管理
NATIVE_WINDOW_CONNECT = 1, // 连接生产者到窗口(已弃用)
NATIVE_WINDOW_DISCONNECT = 2, // 断开生产者连接(已弃用)
NATIVE_WINDOW_API_CONNECT = 13, // 以指定API类型连接生产者(内部使用)
NATIVE_WINDOW_API_DISCONNECT = 14, // 断开指定API类型的生产者(内部使用)
🖼️ 图像变换与显示控制
NATIVE_WINDOW_SET_CROP = 3, // 设置缓冲区裁剪区域(内部使用)
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, // 设置缓冲区显示变换(如旋转、镜像)
NATIVE_WINDOW_SET_SCALING_MODE = 10, // 设置缓冲区缩放模式(内部使用)
NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, // 设置粘性变换(内部使用,通常由消费者设置)
NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, // 设置自动预旋转(根据显示方向调整缓冲区)
NATIVE_WINDOW_SET_FRAME_RATE = 40, // 设置期望的帧率
📊 元数据与色彩管理
NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, // 设置缓冲区时间戳
NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, // 设置缓冲区数据空间(色彩空间等)
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, // 设置HDR SMPTE ST 2086元数据
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, // 设置HDR CTA-861.3元数据
NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, // 设置HDR10+元数据
⏱️ 性能监控与时序控制
NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, // 获取显示刷新周期持续时间
NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, // 获取下一个要排队的帧ID
NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, // 启用帧时间戳报告
NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, // 获取合成器时间信息
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, // 获取特定帧的详细时间戳
NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, // 获取上一次dequeueBuffer开始时间(内部使用)
NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, // 设置dequeueBuffer超时时间(内部使用)
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, // 获取上一次dequeueBuffer耗时(内部使用)
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, // 获取上一次queueBuffer耗时(内部使用)
🔧 高级控制与调试
NATIVE_WINDOW_LOCK = 11, // 锁定窗口用于CPU绘制(内部使用)
NATIVE_WINDOW_UNLOCK_AND_POST = 12, // 解锁并提交缓冲区(内部使用)
NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, // 设置后变换裁剪(已弃用,未实现)
NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, // 设置侧通道流(用于非图形数据同步传输)
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, // 设置表面损伤区域(内部使用)
NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, // 设置共享缓冲区模式(用于静止内容优化)
NATIVE_WINDOW_SET_AUTO_REFRESH = 22, // 设置自动刷新模式
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, // 获取消费者的64位使用标志
🛡️ 拦截器与缓冲区管理
NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR = 41, // 设置cancelBuffer拦截器(内部使用)
NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR = 42, // 设置dequeueBuffer拦截器(内部使用)
NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, // 设置perform操作拦截器(内部使用)
NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, // 设置queueBuffer拦截器(内部使用)
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, // 预分配缓冲区(内部使用)
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, // 获取最后一个入队的缓冲区(内部使用)
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, // 设置query操作拦截器(内部使用)
NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, // 设置帧时间线信息(内部使用)
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 49, // 获取最后一个入队的缓冲区(扩展版本,内部使用)
生产者类型的枚举
/* 参数用于 NATIVE_WINDOW_[API_][DIS]CONNECT 操作 */
enum {
/* 缓冲区由 EGL 通过 eglSwapBuffers 进行排队,在此之前缓冲区已使用 OpenGL ES 进行填充。
* 典型应用:OpenGL ES 或 Vulkan 图形渲染。
*/
NATIVE_WINDOW_API_EGL = 1,
/* 缓冲区在使用 CPU 填充后进行排队。
* 典型应用:Canvas 绘图、软件渲染(如 Bitmap 操作)。
*/
NATIVE_WINDOW_API_CPU = 2,
/* 缓冲区由视频解码器(软件或硬件解码器)填充后,由 Stagefright 进行排队。
* 典型应用:视频播放(如 MediaCodec、MediaPlayer)。
*/
NATIVE_WINDOW_API_MEDIA = 3,
/* 缓冲区由相机硬件抽象层(HAL)进行排队。
* 典型应用:相机预览。
*/
NATIVE_WINDOW_API_CAMERA = 4,
};
参数使用方法详解
这些 NATIVE_WINDOW_API_*常量用于标识生产者(Producer)的类型 ,核心作用是在生产者(如 Camera、MediaCodec、OpenGL)与 Surface(其背后是 BufferQueue)建立连接时,明确指定以何种身份和规则进行交互 。
核心使用流程
下面的表格概括了关键的使用步骤和函数:
| 步骤 | 关键函数 | 说明 |
|---|---|---|
| 1. 连接生产者 | native_window_api_connect(ANativeWindow*, int api) |
将生产者与 ANativeWindow连接,并声明其 API 类型。 |
| 2. 配置缓冲区 | native_window_set_usage(), native_window_set_buffers_dimensions() |
设置缓冲区的使用标志、尺寸、格式等属性。 |
| 3. 缓冲区操作 | dequeueBuffer(), queueBuffer(), cancelBuffer() |
执行具体的图形数据生产和消费。 |
| 4. 断开连接 | native_window_api_disconnect(ANativeWindow*, int api) |
生产结束时,断开与 ANativeWindow的连接。 |
用于几何变换
如下是枚举常量代码
/* 参数用于 NATIVE_WINDOW_SET_BUFFERS_TRANSFORM 操作 */
enum {
/* 将源图像水平翻转(镜像效果) */
NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
/* 将源图像垂直翻转 */
NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
/* 将源图像顺时针旋转90度,此变换在 TRANSFORM_FLIP_H 或 TRANSFORM_FLIP_V 之后应用 */
NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
/* 将源图像旋转180度 */
NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
/* 将源图像顺时针旋转270度 */
NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
/* 根据显示屏幕自身的逆变换来变换源图像。此变换最后应用。
* 通常用于补偿显示设备的固有旋转或镜像,确保最终显示方向正确。 */
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
};
枚举的核心作用
这些枚举常量定义了图形缓冲区(Buffer) 在提交给 ANativeWindow后,直到最终显示在屏幕上之前,可以施加的各种几何变换 。它们本质上是生产者(例如你的应用、相机、视频解码器)向消费者(通常是 SurfaceFlinger,即合成器)传递的指令,告诉合成器:"请在显示这个缓冲区的内容之前,先对它进行如下旋转或翻转"。
其核心作用是在不修改缓冲区实际像素数据的前提下,高效地调整图像的显示方向。这对于适配设备旋转、实现镜像效果、校正传感器方向与显示方向不一致等问题至关重要。
使用方法
使用这些变换主要通过 native_window_set_buffers_transform这个辅助函数来完成,该函数内部会调用 ANativeWindow的 perform方法并传入 NATIVE_WINDOW_SET_BUFFERS_TRANSFORM操作码
源码如下
/*
* native_window_set_buffers_transform - 设置后续入队缓冲区的显示变换。
* 此调用之后提交的所有缓冲区,在显示时都会按照指定的变换参数进行几何变换(如旋转、翻转)。
*
* @param window: 指向 ANativeWindow 结构体的指针,代表目标原生窗口。
* @param transform: 需要应用的变换类型,使用 NATIVE_WINDOW_TRANSFORM_* 系列常量。
* @return: 成功返回0,失败返回错误码。
*/
static inline int native_window_set_buffers_transform(
struct ANativeWindow* window,
int transform)
{
// 通过 ANativeWindow 的 perform 函数指针,发送 SET_BUFFERS_TRANSFORM 命令。
// 这是一个内联封装函数,简化了直接调用 perform 的复杂性。
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, transform);
}
如何缩放以适应窗口显示
枚举类型如下:
/* 参数用于 NATIVE_WINDOW_SET_SCALING_MODE 操作
* 与 frameworks/base 中的 Surface.java 保持同步
*/
enum {
/* 冻结模式:在接收到与窗口尺寸相匹配的缓冲区之前,不更新窗口内容。
* 适用于内容尺寸与窗口尺寸必须精确匹配的场景,可避免中间状态的拉伸变形。
*/
NATIVE_WINDOW_SCALING_MODE_FREEZE = 0,
/* 缩放至窗口:缓冲区的宽度和高度两个维度都进行缩放,以完全填充窗口。
* 可能导致图像宽高比失真,但能确保内容完全可见且充满整个窗口。
*/
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1,
/* 缩放并裁剪:缓冲区按统一比例缩放,使缓冲区的较小边与窗口对应边匹配。
* 会裁剪掉缓冲区较大边超出的部分以保持宽高比,画面内容可能不完整但不变形。
*/
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2,
/* 不缩放,仅裁剪:窗口内容被严格限制在缓冲区的裁剪矩形内。
* 裁剪矩形之外的像素被视为完全透明。适用于需要精确控制显示区域的特殊应用。
*/
NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3,
};
核心作用与模式对比
此枚举通过 NATIVE_WINDOW_SET_SCALING_MODE操作,控制着图形缓冲区(GraphicBuffer) 中的图像数据在显示到屏幕上的 Surface (可理解为窗口)时,如何适应可能存在的尺寸差异。其核心是在 画面完整性 、比例正确性 和 填充度 之间做出权衡 。
下表对比了四种模式的特点和典型应用场景:
| 模式 | 核心行为 | 是否保持宽高比 | 画面是否完整 | 典型应用场景 |
|---|---|---|---|---|
**FREEZE** |
等待尺寸匹配的缓冲区,否则不更新 | - | - | 界面预览、精确匹配需求 |
**SCALE_TO_WINDOW** |
拉伸图像以完全填充窗口 | ❌ 失真 | ✅ 完整 | 视频播放、壁纸 |
**SCALE_CROP** |
按比例缩放,裁剪溢出部分 | ✅ 保持 | ❌ 可能裁剪 | 相机预览、全屏游戏 |
**NO_SCALE_CROP** |
不缩放,按缓冲区原区域显示 | ✅ 保持 | ❌ 严格裁剪 | UI控件、精准显示 |
使用方法
使用方法源码如下:
/*
* native_window_set_scaling_mode - 设置原生窗口的缓冲区缩放模式
* 此调用之后提交到该窗口的所有缓冲区,都将按照指定的缩放模式进行显示适配。
*
* 缩放模式决定了当缓冲区的尺寸与目标窗口的显示区域尺寸不一致时,系统如何调整缓冲区内容以适应窗口。
*
* @param window: 指向目标 ANativeWindow 结构体的指针,代表要设置缩放模式的窗口。
* @param mode: 需要设置的缩放模式,使用 NATIVE_WINDOW_SCALING_MODE_* 系列常量。
* @return: 成功返回0,失败返回相应的错误码。
*/
static inline int native_window_set_scaling_mode(
struct ANativeWindow* window,
int mode)
{
// 通过 ANativeWindow 的 perform 函数指针,发送 SET_SCALING_MODE 命令。
// 这是一个内联的辅助函数,封装了对通用 perform 操作的调用,简化了使用。
return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE, mode);
}
Surface
Surface继承了ANativeWindow,并对其中的功能做了具体实现。 ANativeWindow这个结构体中定义了大量的函数指针,这些函数指针指向了哪里?或函数功能在哪里?答案就在Surface中。
Surface的定义位于:/frameworks/native/libs/gui/include/gui/Surface.h
先看看类的声明

然后再看下它的父类ANativeObjectBase
template <typename NATIVE_TYPE, typename TYPE, typename REF,
typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{
...
}
这里可以明显看出来其实Surface就是继承了ANativeWindow类
然后再看下Surface中定义的很多接口函数和私有成员
hook_xxx的函数
我们看下Surface中的构造函数中hook_xxx函数初始化位置,如下:
代码位置:/frameworks/native/libs/gui/Surface.cpp
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
const sp<IBinder>& surfaceControlHandle)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
mBufferAge(0),
mGenerationNumber(0),
mSharedBufferMode(false),
mAutoRefresh(false),
mAutoPrerotation(false),
mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
mSharedBufferHasBeenQueued(false),
mQueriedSupportedTimestamps(false),
mFrameTimestampsSupportsPresent(false),
mEnableFrameTimestamps(false),
mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
...
}
上述可以看出来这些函数其实和ANativeWindow函数关联起来了,实际调用的其实是Surface中的hook_xxx函数,例如,调用的ANativeWindow中的query函数实际调用的是Surface的hook_query函数
dispatch_xxx函数
dispatch函数有47个,前面我们有讲到perform函数对应的各种操作,都是会走到对应的dispatch函数中。
看一下具体代码位置:
/**
* Surface::perform - 处理原生窗口操作的统一入口函数
*
* 这是 ANativeWindow 接口中最重要的函数之一,它是一个"万能"的调度中心。
* 所有通过 native_window_set_* 等辅助函数发起的、无法用简单专用函数表示的操作请求,
* 最终都会通过这个函数路由到具体的实现方法。
*
* @param operation 操作类型,由 NATIVE_WINDOW_* 常量定义,指定要执行的具体动作。
* @param args 可变参数列表,包含执行操作所需的具体参数。
* @return 成功返回 NO_ERROR (0),失败返回错误码。
*/
int Surface::perform(int operation, va_list args)
{
int res = NO_ERROR; // 默认返回成功
switch (operation) {
// 已弃用的连接/断开连接操作,为保持兼容性而保留,直接返回成功。
case NATIVE_WINDOW_CONNECT:
// 已弃用。必须返回 NO_ERROR。
break;
case NATIVE_WINDOW_DISCONNECT:
// 已弃用。必须返回 NO_ERROR。
break;
// === 缓冲区属性配置操作 ===
case NATIVE_WINDOW_SET_USAGE: // 设置缓冲区的使用标志(如 CPU 读/写、GPU 纹理)
res = dispatchSetUsage(args);
break;
case NATIVE_WINDOW_SET_CROP: // 设置缓冲区的裁剪区域
res = dispatchSetCrop(args);
break;
case NATIVE_WINDOW_SET_BUFFER_COUNT: // 设置缓冲区队列的缓冲区数量(如双缓冲/三缓冲)
res = dispatchSetBufferCount(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: // 同时设置缓冲区的宽度、高度和像素格式
res = dispatchSetBuffersGeometry(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: // 设置缓冲区的显示变换(如旋转、镜像)
res = dispatchSetBuffersTransform(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM: // 设置粘性变换(通常由消费者如SurfaceFlinger设置)
res = dispatchSetBuffersStickyTransform(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: // 设置缓冲区的宽度和高度
res = dispatchSetBuffersDimensions(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: // 设置用户空间的缓冲区尺寸
res = dispatchSetBuffersUserDimensions(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_FORMAT: // 设置缓冲区的像素格式(如 RGBA_8888)
res = dispatchSetBuffersFormat(args);
break;
case NATIVE_WINDOW_SET_SCALING_MODE: // 设置缓冲区内容的缩放模式(如拉伸、裁剪)
res = dispatchSetScalingMode(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: // 设置缓冲区关联的数据空间(色彩空间)
res = dispatchSetBuffersDataSpace(args);
break;
case NATIVE_WINDOW_SET_SURFACE_DAMAGE: // 设置表面损伤区域(提示哪些区域内容已变化)
res = dispatchSetSurfaceDamage(args);
break;
case NATIVE_WINDOW_SET_USAGE64: // 设置64位的缓冲区使用标志(替代 SET_USAGE)
res = dispatchSetUsage64(args);
break;
// === 生产者连接管理 ===
case NATIVE_WINDOW_API_CONNECT: // 以指定的 API 类型(如 CPU, EGL, MEDIA)连接生产者
res = dispatchConnect(args);
break;
case NATIVE_WINDOW_API_DISCONNECT: // 断开指定 API 类型的生产者连接
res = dispatchDisconnect(args);
break;
// === 高级元数据与 HDR 支持 ===
case NATIVE_WINDOW_SET_SIDEBAND_STREAM: // 设置侧通道流(用于非图形数据的传输)
res = dispatchSetSidebandStream(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA: // 设置 HDR10 静态元数据
res = dispatchSetBuffersSmpte2086Metadata(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA: // 设置 HDR10 动态元数据
res = dispatchSetBuffersCta8613Metadata(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA: // 设置 HDR10+ 动态元数据
res = dispatchSetBuffersHdr10PlusMetadata(args);
break;
// === 运行模式与控制 ===
case NATIVE_WINDOW_SET_SHARED_BUFFER_MODE: // 设置共享缓冲区模式(用于静止内容优化)
res = dispatchSetSharedBufferMode(args);
break;
case NATIVE_WINDOW_SET_AUTO_REFRESH: // 设置自动刷新模式(适用于无内容更新时也刷新)
res = dispatchSetAutoRefresh(args);
break;
case NATIVE_WINDOW_SET_AUTO_PREROTATION: // 设置自动预旋转(根据显示方向调整缓冲区)
res = dispatchSetAutoPrerotation(args);
break;
case NATIVE_WINDOW_SET_FRAME_RATE: // 设置期望的帧率
res = dispatchSetFrameRate(args);
break;
case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: // 设置 dequeueBuffer 操作的超时时间
res = dispatchSetDequeueTimeout(args);
break;
// === 性能监控与调试 ===
case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION: // 获取显示的刷新周期持续时间
res = dispatchGetDisplayRefreshCycleDuration(args);
break;
case NATIVE_WINDOW_GET_NEXT_FRAME_ID: // 获取下一个要排队的帧的 ID
res = dispatchGetNextFrameId(args);
break;
case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS: // 启用帧时间戳报告
res = dispatchEnableFrameTimestamps(args);
break;
case NATIVE_WINDOW_GET_COMPOSITOR_TIMING: // 获取合成器的时序信息
res = dispatchGetCompositorTiming(args);
break;
case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS: // 获取特定帧的详细时间戳
res = dispatchGetFrameTimestamps(args);
break;
case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: // 获取上一次 dequeueBuffer 的开始时间
res = dispatchGetLastDequeueStartTime(args);
break;
case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION: // 获取上一次 dequeueBuffer 的耗时
res = dispatchGetLastDequeueDuration(args);
break;
case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION: // 获取上一次 queueBuffer 的耗时
res = dispatchGetLastQueueDuration(args);
break;
case NATIVE_WINDOW_GET_CONSUMER_USAGE64: // 获取消费者的 64 位使用标志
res = dispatchGetConsumerUsage64(args);
break;
// === 拦截器(用于调试和监控)===
case NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR: // 设置 cancelBuffer 操作的拦截器
res = dispatchAddCancelInterceptor(args);
break;
case NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR: // 设置 dequeueBuffer 操作的拦截器
res = dispatchAddDequeueInterceptor(args);
break;
case NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR: // 设置 perform 操作本身的拦截器
res = dispatchAddPerformInterceptor(args);
break;
case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR: // 设置 queueBuffer 操作的拦截器
res = dispatchAddQueueInterceptor(args);
break;
case NATIVE_WINDOW_SET_QUERY_INTERCEPTOR: // 设置 query 操作的拦截器
res = dispatchAddQueryInterceptor(args);
break;
// === 缓冲区管理 ===
case NATIVE_WINDOW_ALLOCATE_BUFFERS: // 预分配所有缓冲区
allocateBuffers(); // 此函数无返回值
res = NO_ERROR;
break;
case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: // 获取最后一个入队的缓冲区信息
res = dispatchGetLastQueuedBuffer(args);
break;
case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2: // 获取最后一个入队的缓冲区信息(扩展版本)
res = dispatchGetLastQueuedBuffer2(args);
break;
case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: // 设置帧时间线信息
res = dispatchSetFrameTimelineInfo(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_ADDITIONAL_OPTIONS: // 设置缓冲区的附加选项
res = dispatchSetAdditionalOptions(args);
break;
// 已弃用的锁定/解锁操作(旧版 CPU 渲染路径)
case NATIVE_WINDOW_LOCK: // 锁定缓冲区以供 CPU 写入(已弃用)
res = dispatchLock(args);
break;
case NATIVE_WINDOW_UNLOCK_AND_POST: // 解锁并提交缓冲区(已弃用)
res = dispatchUnlockAndPost(args);
break;
// 未识别的操作码,返回找不到的错误
default:
res = NAME_NOT_FOUND;
break;
}
return res;
}
可以看出来dispatch_xxx相关函数是通过perform函数调用的,然后我们来点不一样的,按照倒序的方式梳理下是哪里调用的,我们看下perform函数是哪里调用的
如下代码
int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
Surface* c = getSelf(window);
int result;
// Don't acquire shared ownership of the interceptor mutex if we're going to
// do interceptor registration, as otherwise we'll deadlock on acquiring
// exclusive ownership.
if (!isInterceptorRegistrationOp(operation)) {
std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
if (c->mPerformInterceptor != nullptr) {
result = c->mPerformInterceptor(window, Surface::performInternal,
c->mPerformInterceptorData, operation, args);
va_end(args);
return result;
}
}
result = c->perform(operation, args);
va_end(args);
return result;
}
可以看出来是hook_perform进行调用的,这个和前面的hook_xxx函数关联起来了,就是在ANativeWindow中进行调用的,然后再看下window.h头文件,是对外的接口
位置:framework/native/libs/nativewindow/include/system/window.h
static inline int native_window_set_buffers_format(
struct ANativeWindow* window,
int format)
{
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
}
在往前看其实就是之前写的demo调用的代码,如下:

这样其实就串联起来了,然后在回到Surface.cpp中
int Surface::dispatchSetBuffersFormat(va_list args) {
PixelFormat format = va_arg(args, PixelFormat);
return setBuffersFormat(format);
}
可以看出来最终实现在私有方法Surface::setBuffersFormat 中
上述就梳理完成从应用层调用到Surface.cpp的dispatchxxx相关流程,流程图如下:

SurfaceControl
SurfaceControl 其实就是Surface的控制类,如何实现控制的,我们在看看之前写的demo
之前写的demo中有创建surface的代码,如下
// 创建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(无)
);
可以看出来返回的就是SurfaceControl对象,然后我们继续看这个创建Surface过程
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
PixelFormat format, int32_t flags,
const sp<IBinder>& parentHandle,
LayerMetadata metadata,
uint32_t* outTransformHint) {
sp<SurfaceControl> s;
createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata),
outTransformHint);
return s;
}
在继续看createSurfaceChecked函数
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
PixelFormat format,
sp<SurfaceControl>* outSurface, int32_t flags,
const sp<IBinder>& parentHandle,
LayerMetadata metadata,
uint32_t* outTransformHint) {
status_t err = mStatus;
if (mStatus == NO_ERROR) {
gui::CreateSurfaceResult result;
binder::Status status = mClient->createSurface(std::string(name.c_str()), flags,
parentHandle, std::move(metadata), &result);
err = statusTFromBinderStatus(status);
if (outTransformHint) {
*outTransformHint = result.transformHint;
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
*outSurface = new SurfaceControl(this, result.handle, result.layerId,
toString(result.layerName), w, h, format,
result.transformHint, flags);
}
}
return err;
}
这里我们就看到了,其实是新建了一个SurfaceControl对象,在前面两篇文章中也有详细介绍
我们再重新贴一下
源码位置:framework/native/libs/gui/include/gui/SurfaceControl.h
/**
* SurfaceControl 是对屏幕上一个"层(Layer)"的句柄。
* 它允许应用控制该层的属性(如位置、缩放、透明度等),这些操作通常通过 SurfaceComposerClient 的 Transaction 提交。
*/
class SurfaceControl : public RefBase
{
...
// --- 成员变量 ---
sp<SurfaceComposerClient> mClient; // 负责与 SurfaceFlinger 通信的连接
sp<IBinder> mHandle; // 在 SurfaceFlinger 中的唯一标识 Token
mutable Mutex mLock; // 线程锁
mutable sp<Surface> mSurfaceData; // 缓存生成的 Surface 对象
// BLAST (Buffer-Like-As-Surface-Transactions) 机制相关
// Android 11+ 引入,旨在将 Buffer 更新同步到 SurfaceFlinger 事务中
mutable sp<BLASTBufferQueue> mBbq; // BLASTBufferQueue对象实例
mutable sp<SurfaceControl> mBbqChild; // child layer,它会和mBbq相关联
...
}
根据前面的梳理以及当下的梳理SurfaceControl中各种类的关系如下

ANativeWindowBuffer
我们应该还注意到一个struct ANativeWindowBuffer,它和GraphicBuffer是紧密相关的
代码位置:/frameworks/native/libs/nativebase/include/nativebase/nativebase.h
看定义:这个struct中主要是定义了有关buffer的宽、高、格式等信息
// ANativeWindowBuffer 是 Android 系统中描述图形缓冲区的核心结构体
// 它封装了缓冲区的元数据(如尺寸、格式)和底层的 native_handle(如 DMA-BUF 文件描述符)
// 主要用于在图形生产者(如应用)和消费者(如 SurfaceFlinger)之间传递缓冲区信息[1,7](@ref)
typedef struct ANativeWindowBuffer
{
#ifdef __cplusplus
// 构造函数:初始化魔术字和版本号,用于类型识别和版本控制
ANativeWindowBuffer() {
common.magic = ANDROID_NATIVE_BUFFER_MAGIC; // 魔术字,用于验证类型安全性
common.version = sizeof(ANativeWindowBuffer); // 结构体版本
memset(common.reserved, 0, sizeof(common.reserved));
}
// 实现智能指针所需的方法,使 ANativeWindowBuffer 支持自动引用计数
void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
// 基础结构体,提供引用计数机制和类型识别[4](@ref)
// 包含 incRef/decRef 函数指针,用于管理对象生命周期
struct android_native_base_t common;
// === 缓冲区描述属性 ===
int width; // 缓冲区的有效宽度(以像素为单位)
int height; // 缓冲区的有效高度(以像素为单位)
int stride; // 缓冲区中每行像素在内存中的跨度(可能大于宽度,用于内存对齐)
int format; // 像素格式(如 RGBA_8888、RGB_565 等)
int usage_deprecated; // 已弃用的使用标志字段,用于向后兼容
uintptr_t layerCount; // 缓冲区包含的图层数量(用于立体渲染等场景)
void* reserved[1]; // 保留字段,供未来扩展使用
// === 关键句柄 ===
// 指向底层缓冲区内存的句柄,通常是 native_handle_t 或 private_handle_t[1,4](@ref)
// 包含实际的文件描述符(fd)等信息,使得缓冲区可以跨进程共享
const native_handle_t* handle;
// === 现代使用标志 ===
// 64位使用标志,定义缓冲区的用途(如 GPU 纹理、CPU 读写等)
// 替代旧的 usage_deprecated 字段
uint64_t usage;
// 保留字段,用于存储64位使用标志的额外空间
// 具体使用哪些保留槽位取决于架构要求
void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
} ANativeWindowBuffer_t;
关键作用解析
-
图形缓冲区的统一描述符 :
ANativeWindowBuffer是 Android 图形系统中对一块图形缓冲区内存的标准化描述 。它并不直接管理内存,而是通过handle字段引用底层实际分配的缓冲区(如 Gralloc 分配的 DMA-BUF)。 -
跨进程传递的基石 :其核心设计目标是支持跨进程共享 。图形缓冲区通常由专门的服务(如 Gralloc)分配,但需要被多个进程(如应用进程、SurfaceFlinger 进程)访问。
ANativeWindowBuffer本身可以通过 Binder 传递,而其handle字段(通常是native_handle_t)封装了文件描述符(fd),使得不同进程可以映射并访问同一块物理内存。 -
继承关系中的基类 :在实际使用中,最重要的实现是
GraphicBuffer类,它继承自ANativeWindowBuffer 。这意味着一个GraphicBuffer*指针可以直接转换为ANativeWindowBuffer*指针使用。这种设计允许 Android 图形框架在需要通用缓冲区描述时使用ANativeWindowBuffer接口,而在需要更复杂功能时使用GraphicBuffer的完整实现。 -
与 ANativeWindow 的协作 :
ANativeWindow(或其实现类Surface)作为生产者 接口,其核心函数如dequeueBuffer和queueBuffer操作的对象正是ANativeWindowBuffer。生产者通过dequeueBuffer获取一个ANativeWindowBuffer来填充内容,完成后通过queueBuffer将其送回队列等待消费者(如 SurfaceFlinger)使用。
GraphicBuffer继承了ANativeWindowBuffer,和之前的ANativeWindow与Surface类似,如下:
/frameworks/native/libs/ui/include/ui/GraphicBuffer.h
class GraphicBuffer
: public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
public Flattenable<GraphicBuffer>
{
}
总结
如下是ai生成的时序图,仅供参考,后续待验证

架构图
