3. Display 设备枚举与热插拔监听
任务说明
本案例实现 Display HAL 模块的 close 函数,用于释放 open 时分配的资源并正确关闭显示设备。该函数是 hw_module_methods_t 中定义的设备关闭入口,由 SurfaceFlinger 在不再需要显示设备时调用。
核心实现
// display_hal.cpp
#include <hardware/hardware.h>
#include <hardware/display.h>
#include <cutils/log.h>
#include <cstdlib>
// 自定义显示设备上下文结构
struct display_device_context {
int fd; // 设备文件描述符
void* mapped_mem; // mmap 映射的显存地址
size_t mem_size; // 映射大小
bool initialized; // 初始化标志
};
// 设备关闭函数
static int display_device_close(struct hw_device_t* dev) {
if (dev == nullptr) {
ALOGE("display_device_close: null device pointer");
return -EINVAL;
}
display_device_context* ctx = reinterpret_cast<display_device_context*>(dev);
// 1. 释放 mmap 映射
if (ctx->mapped_mem != nullptr && ctx->mem_size > 0) {
munmap(ctx->mapped_mem, ctx->mem_size);
ctx->mapped_mem = nullptr;
ctx->mem_size = 0;
ALOGI("display close: munmap done");
}
// 2. 关闭设备文件描述符
if (ctx->fd >= 0) {
close(ctx->fd);
ctx->fd = -1;
ALOGI("display close: fd closed");
}
// 3. 释放上下文结构
ctx->initialized = false;
free(ctx);
ALOGI("display close: context freed");
return 0;
}
// open 函数中注册 close 回调(供参考)
int display_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device) {
display_device_context* ctx =
(display_device_context*)calloc(1, sizeof(display_device_context));
if (ctx == nullptr) return -ENOMEM;
ctx->fd = open("/dev/fb0", O_RDWR);
if (ctx->fd < 0) {
free(ctx);
return -errno;
}
// 实际项目中在此处进行 mmap 等操作
ctx->initialized = true;
// 注册 close 回调
ctx->common.tag = HARDWARE_DEVICE_TAG;
ctx->common.version = HARDWARE_DEVICE_API_VERSION(1, 0);
ctx->common.module = const_cast<hw_module_t*>(module);
ctx->common.close = display_device_close;
*device = &ctx->common;
return 0;
}
关键设计说明
上述实现中,display_device_close 接收 hw_device_t* 指针,通过 reinterpret_cast 将其还原为自定义的 display_device_context 结构。关闭流程按逆序执行:先解除显存映射,再关闭文件描述符,最后释放上下文内存。每个步骤都进行了空指针和有效性检查,避免重复关闭或释放野指针。
SVG:close 调用时序与资源释放流程
编译与验证
// Android.bp 或 Android.mk 中编译
cc_library_shared {
name: "display.default",
srcs: ["display_hal.cpp"],
shared_libs: ["libhardware", "liblog", "libcutils"],
}
// 验证命令
adb shell dmesg | grep "display close"
// 预期输出(示例):
// display close: munmap done
// display close: fd closed
// display close: context freed
判定标准
通过以下条件判定实现正确:
- 调用
close()后返回 0,无段错误或 double-free - dmesg 中依次出现 munmap、fd closed、context freed 三条日志
- 关闭后再次调用
open()能成功,说明资源已完全释放 - 使用
valgrind或AddressSanitizer检查无内存泄漏