2、HIDL基础回顾:HIDL接口定义语言(IDL)语法、包名规则、数据类型映射、服务端与客户端模型
在深入Camera HAL层初始化工程之前,必须牢固掌握HIDL(HAL Interface Definition Language)的核心基础。HIDL是Android Treble架构的基石,它定义了Framework与HAL之间的契约。本节将系统回顾HIDL的接口定义语言语法、包名规则、数据类型映射以及服务端与客户端模型,为后续分析Camera HAL初始化流程奠定理论基础。
2.1 HIDL接口定义语言(IDL)语法
HIDL使用类似于C++和Java的语法来描述接口。一个典型的HIDL接口文件(.hal)包含包声明、导入语句、接口定义和方法声明。
核心语法要素:
- 包声明:使用
package关键字定义接口所属的包路径。 - 导入:使用
import关键字引入其他HIDL类型或接口。 - 接口定义:使用
interface关键字声明接口名称,可继承自其他接口。 - 方法声明:定义接口方法,包含返回值类型、方法名和参数列表。
- 类型定义:支持
enum、struct、union等复合类型。
以下是一个Camera HAL中常见的HIDL接口定义示例:
// ICameraDevice.hal
package android.hardware.camera.device@3.4;
import android.hardware.camera.common@1.0::Status;
import android.hardware.camera.common@1.0::CameraMetadata;
interface ICameraDevice extends @3.2::ICameraDevice {
/**
* 初始化相机设备并返回状态。
* @param cameraId 相机ID
* @return Status 初始化结果
*/
open(string cameraId) generates (Status status);
/**
* 配置相机数据流。
* @param streams 数据流配置列表
* @return Status 配置结果
*/
configureStreams(vec<Stream> streams) generates (Status status);
/**
* 捕获请求。
* @param request 捕获请求参数
* @return Status 捕获状态
*/
processCaptureRequest(CaptureRequest request) generates (Status status);
};
语法要点:HIDL方法使用
generates 关键字分隔输入参数和返回值,这与AIDL的 out 参数不同。所有HIDL方法调用都是同步的,但可以通过回调接口实现异步通知。
2.2 包名规则
HIDL的包名规则严格遵循Android的命名空间体系,确保接口的唯一性和版本管理。包名由三部分组成:包前缀、包路径和版本号。
| 组成部分 | 格式 | 示例 | 说明 |
|---|---|---|---|
| 包前缀 | android.hardware |
android.hardware |
固定前缀,表示硬件抽象层接口 |
| 包路径 | 模块名.子模块 |
camera.device |
使用点号分隔的模块层级路径 |
| 版本号 | @主版本.次版本 |
@3.4 |
主版本号不兼容时需升级,次版本号向后兼容 |
完整的包名示例:android.hardware.camera.device@3.4
版本管理规则:
- 主版本号(Major)变更:接口不向后兼容,所有实现必须更新。
- 次版本号(Minor)变更:只能添加新方法或类型,不能修改或删除已有接口。
- 同一主版本下的不同次版本可以共存,客户端可以选择支持的最高次版本。
2.3 数据类型映射
HIDL定义了一套独立于语言的数据类型系统,并提供了到C++和Java的映射规则。理解这些映射对于编写正确的HAL实现至关重要。
| HIDL类型 | C++映射 | Java映射 | 说明 |
|---|---|---|---|
int8_t |
int8_t |
byte |
8位有符号整数 |
uint8_t |
uint8_t |
short |
8位无符号整数 |
int32_t |
int32_t |
int |
32位有符号整数 |
uint32_t |
uint32_t |
long |
32位无符号整数 |
int64_t |
int64_t |
long |
64位有符号整数 |
float |
float |
float |
32位浮点数 |
double |
double |
double |
64位浮点数 |
string |
std::string |
String |
UTF-8编码字符串 |
vec<T> |
std::vector<T> |
ArrayList<T> |
可变长度数组 |
hidl_array<T, N> |
std::array<T, N> |
T[] |
固定长度数组 |
hidl_handle |
native_handle_t* |
NativeHandle |
文件描述符等原生句柄 |
MemoryBlock |
hidl_memory |
MemoryBlock |
共享内存块 |
Camera HAL中常用类型:
CameraMetadata:相机元数据,使用hidl_vec<uint8_t>序列化传输。Stream:数据流配置结构体,包含分辨率、格式、使用场景等字段。CaptureRequest:捕获请求,包含输出缓冲区、元数据、物理相机ID等。BufferStatus:缓冲区状态枚举,如OK、ERROR、DROPPED。
2.4 服务端与客户端模型
HIDL采用经典的C/S(客户端/服务端)架构。服务端(HAL实现)注册服务并等待客户端(Framework)连接;客户端通过服务名获取代理,然后调用接口方法。整个通信过程由HIDL的Binder化机制(hwbinder)驱动。
服务端与客户端交互步骤:
- 服务注册:HAL实现进程启动后,通过
hwservicemanager注册服务,例如ICameraDevice注册为"android.hardware.camera.device@3.4::ICameraDevice/default"。 - 服务发现:客户端(如CameraService)通过
ICameraDevice::getService()获取服务代理。 - 接口调用:客户端通过代理调用接口方法,参数通过
hwbinder序列化传输到服务端。 - 回调机制:服务端可以通过回调接口(如
ICameraDeviceCallback)异步通知客户端事件。
2.5 服务端与客户端代码骨架
以下展示Camera HAL中服务端和客户端的基本代码结构,帮助理解HIDL接口的实际使用方式。
服务端实现(HAL侧):
// CameraDevice.cpp
#include <android/hardware/camera/device/3.4/ICameraDevice.h>
using namespace android::hardware::camera::device::V3_4;
class CameraDevice : public ICameraDevice {
public:
// 实现接口方法
Return<Status> open(const hidl_string& cameraId) override {
// 实际硬件初始化逻辑
ALOGI("Opening camera: %s", cameraId.c_str());
return Status::OK;
}
Return<Status> configureStreams(const hidl_vec<Stream>& streams) override {
// 配置数据流
return Status::OK;
}
Return<Status> processCaptureRequest(const CaptureRequest& request) override {
// 处理捕获请求
return Status::OK;
}
};
// 注册服务
int main() {
android::sp<ICameraDevice> service = new CameraDevice();
android::status_t ret = service->registerAsService("default");
if (ret != android::OK) {
ALOGE("Failed to register camera device service");
return -1;
}
// 进入服务循环
android::hardware::joinRpcThreadpool();
return 0;
}
客户端调用(Framework侧):
// CameraService.cpp
#include <android/hardware/camera/device/3.4/ICameraDevice.h>
using namespace android::hardware::camera::device::V3_4;
// 获取服务代理
android::sp<ICameraDevice> cameraDevice = ICameraDevice::getService("default");
if (cameraDevice == nullptr) {
ALOGE("Failed to get camera device service");
return;
}
// 调用接口方法
Status status;
Return<Status> ret = cameraDevice->open("0", [&](Status s) {
status = s;
});
if (!ret.isOk()) {
ALOGE("Failed to call open: %s", ret.description().c_str());
}
// 配置数据流
hidl_vec<Stream> streams;
// ... 填充streams ...
ret = cameraDevice->configureStreams(streams, [&](Status s) {
status = s;
});
关键注意事项:
- 服务端必须调用
joinRpcThreadpool()进入线程池循环,否则无法处理客户端请求。 - 客户端调用
getService()时,如果服务尚未注册,会阻塞等待直到超时(默认5秒)。 - 所有HIDL方法调用都是同步的,但可以通过回调接口实现异步通知,避免阻塞客户端。
- 在Camera HAL中,
processCaptureRequest等高频方法需要特别注意性能,避免在Binder传输中产生过多拷贝。
2.6 小结
本节回顾了HIDL的核心基础:
- IDL语法:使用
package、import、interface关键字定义接口,方法使用generates分隔参数和返回值。 - 包名规则:遵循
android.hardware.模块名@版本号格式,版本管理严格区分主次版本。 - 数据类型映射:HIDL类型到C++/Java有明确的映射关系,Camera HAL中常用
hidl_vec、CameraMetadata、Stream等类型。 - C/S模型:服务端注册服务,客户端通过
hwservicemanager发现并获取代理,通过hwbinder进行跨进程通信。