2. HIDL 基础回顾:接口定义语言、服务端与客户端模型
在深入 Camera HAL3 的通信链路性能调优之前,必须牢固掌握 HIDL(HAL Interface Definition Language)的核心机制。HIDL 是 Android 系统用于定义 HAL 与 Framework 之间进程间通信(IPC)接口的规范语言。本章将系统回顾 HIDL 的接口定义语法、服务端与客户端的生命周期模型,以及它们在 Camera HAL3 中的具体映射关系。
2.1 HIDL 接口定义语言(IDL)核心语法
HIDL 使用 .hal 文件描述接口。与 AIDL 不同,HIDL 接口是面向服务的,每个接口必须继承自 IBase。Camera HAL3 的核心接口定义在 android.hardware.camera.provider 和 android.hardware.camera.device 包中。
2.1.1 接口定义结构
以下是一个简化的 Camera HAL3 设备接口定义示例,展示了 HIDL 的核心语法元素:
// types.hal
package android.hardware.camera.device@3.5;
enum CameraDeviceStatus : int32_t {
NOT_PRESENT = 0,
PRESENT = 1,
ENUMERATING = 2,
};
struct CameraMetadata {
vec<uint8_t> metadata;
};
// ICameraDevice.hal
package android.hardware.camera.device@3.5;
interface ICameraDevice extends IBase {
// 同步方法:获取相机信息
getCameraInfo() generates (CameraMetadata info);
// 单向回调(oneway):异步通知框架
oneway notify(CameraDeviceStatus status);
// 异步方法:配置流,返回结果通过回调
configureStreams(StreamConfiguration config)
generates (Status status, StreamConfiguration outConfig);
};
| 语法元素 | 说明 | Camera HAL3 典型用途 |
|---|---|---|
package ...@x.y; |
定义包名和版本号 | @3.4、@3.5、@3.6 |
interface ... extends IBase |
声明接口,必须继承 IBase | ICameraDevice、ICameraProvider |
generates |
定义同步返回值类型 | 返回 Status、CameraMetadata |
oneway |
声明单向异步调用,不阻塞 | 帧回调、错误通知 |
vec<T> |
可变长度向量 | 元数据缓冲区、流配置列表 |
2.1.2 数据类型映射与性能影响
HIDL 数据类型与 C++ 类型的映射直接影响内存拷贝次数和 IPC 传输效率。Camera HAL3 中高频使用的数据类型及其性能特征如下:
| HIDL 类型 | C++ 映射类型 | 传输方式 | 性能注意事项 |
|---|---|---|---|
vec<uint8_t> |
hidl_vec<uint8_t> |
共享内存 / Binder 直传 | 大块元数据(>4KB)建议使用 hidl_memory 避免拷贝 |
fmq_sync<T> |
MQDescriptorSync<T> |
快速消息队列(无锁) | 用于帧时间戳、统计信息,延迟 < 1μs |
handle |
native_handle_t* |
文件描述符传递 | 用于 GraphicBuffer 共享,零拷贝 |
MemoryBlock |
hidl_memory |
ashmem / mmap 共享 | 用于大块元数据,避免序列化开销 |
vec<uint8_t> 用于传递相机元数据(CameraMetadata)。当元数据大小超过 4KB 时,应切换为 hidl_memory 或 fmq,否则每次 IPC 调用都会触发完整的内存拷贝,导致帧处理延迟增加 200-500μs。
2.2 服务端与客户端模型
HIDL 采用经典的 C/S(客户端-服务端)架构。在 Camera HAL3 中,HAL 实现端是服务端,Framework 的 CameraService 是客户端。理解两者的生命周期和通信模型是性能调优的基础。
CameraProvider、CameraDevice)注册为 HIDL 服务,等待 Framework 连接并调用其方法。服务端负责实际的硬件操作,客户端负责策略调度。
2.2.1 服务端生命周期
服务端(HAL 实现)遵循以下生命周期:
- 注册服务:HAL 进程启动后,通过
registerAsService()将接口实例注册到 hwservicemanager。 - 等待连接:服务端进入事件循环,等待客户端(CameraService)通过 hwservicemanager 获取代理。
- 处理请求:接收客户端 IPC 调用,执行硬件操作(如打开相机、配置流、捕获帧)。
- 发送回调:通过
oneway接口或回调对象异步通知客户端事件(如帧到达、错误)。 - 注销服务:进程退出时自动注销。
2.2.2 客户端模型
客户端(CameraService)通过 hwservicemanager 发现并绑定服务:
// CameraService 获取 CameraProvider 服务
sp<ICameraProvider> provider = ICameraProvider::getService();
if (provider == nullptr) {
// 服务未就绪,等待或重试
ALOGE("Failed to get CameraProvider service");
return;
}
// 通过 provider 获取 camera device
sp<ICameraDevice> device;
Status status = provider->getCameraDeviceInterface(
"device@3.5/cameraId0",
[&](Status s, sp<ICameraDevice> d) {
status = s;
device = d;
});
getService() 是阻塞调用,默认超时 5 秒。在 Camera 启动流程中,如果 hwservicemanager 响应慢或 HAL 进程未就绪,会导致 ANR。调优时建议将服务注册放在 init.rc 的 early 阶段,并设置 getService() 超时时间为 1 秒。
2.3 HIDL 通信链路架构
以下 SVG 图展示了 Camera HAL3 中 HIDL 服务端与客户端的完整通信链路,包括服务注册、代理获取、IPC 调用和回调路径。
2.4 服务端线程模型与性能影响
HIDL 服务端默认使用 Binder 线程池处理客户端请求。线程池的配置直接影响 Camera HAL3 的并发处理能力。
| 配置参数 | 默认值 | Camera HAL3 推荐值 | 说明 |
|---|---|---|---|
maxThreads |
4 | 8-16 | 高分辨率多路并发时需要更多线程 |
maxIdleTime |
60s | 10s | 减少空闲线程占用,降低内存压力 |
maxStackSize |
1MB | 256KB | Camera 回调栈深度较浅,可减小栈大小 |
// 在 HAL 服务端初始化时配置线程池
// CameraProvider.cpp
int main() {
// 配置 Binder 线程池
ProcessState::self()->setThreadPoolConfiguration(
8, // maxThreads
10, // maxIdleTime (秒)
256 * 1024 // maxStackSize (字节)
);
// 注册服务
sp<ICameraProvider> provider = new CameraProvider();
status_t status = provider->registerAsService("legacy/0");
if (status != OK) {
ALOGE("Failed to register CameraProvider: %d", status);
return -1;
}
// 启动线程池
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
maxThreads 设置为 2 * (相机数量 + 1)。例如,三摄系统推荐 8 个线程。过少的线程会导致 IPC 调用排队,增加帧延迟;过多的线程则增加上下文切换开销。
2.5 本章小结
- HIDL 接口定义:使用
.hal文件声明接口,支持同步、异步和单向调用。Camera HAL3 的核心接口是ICameraProvider和ICameraDevice。 - 服务端模型:HAL 实现通过
registerAsService()注册到 hwservicemanager,等待客户端连接。服务端负责硬件操作和回调发送。 - 客户端模型:CameraService 通过
getService()发现服务,获取代理后发起 IPC 调用。客户端负责策略调度和数据处理。 - 性能关键点:服务注册延迟、服务发现延迟、IPC 调用延迟、数据拷贝开销和线程池配置是影响 Camera HAL3 通信性能的核心因素。