目录
[一、HAL 技术发展史](#一、HAL 技术发展史)
[1.1 传统 HAL(Android 8.0 之前)](#1.1 传统 HAL(Android 8.0 之前))
[1.2 HIDL 时代(Android 8.0 ~ 10)](#1.2 HIDL 时代(Android 8.0 ~ 10))
[1.3 AIDL 时代(Android 11 及以后)](#1.3 AIDL 时代(Android 11 及以后))
[二、HIDL 技术详解](#二、HIDL 技术详解)
[2.1 HIDL 概述](#2.1 HIDL 概述)
[2.2 HIDL 接口定义示例](#2.2 HIDL 接口定义示例)
[2.3 HIDL 的关键特性](#2.3 HIDL 的关键特性)
[2.4 HIDL 的 Android.bp 示例](#2.4 HIDL 的 Android.bp 示例)
[三、AIDL 技术详解](#三、AIDL 技术详解)
[3.1 AIDL 概述](#3.1 AIDL 概述)
[3.2 AIDL 与 HIDL 的核心差异](#3.2 AIDL 与 HIDL 的核心差异)
[3.3 AIDL 接口定义示例](#3.3 AIDL 接口定义示例)
[3.4 AIDL 数据类型](#3.4 AIDL 数据类型)
[3.5 Parcelable 类型定义示例](#3.5 Parcelable 类型定义示例)
[3.6 方向关键字(in / out / inout)](#3.6 方向关键字(in / out / inout))
[3.7 稳定性注解 @VintfStability](#3.7 稳定性注解 @VintfStability)
[3.8 AIDL 的 Android.bp 定义](#3.8 AIDL 的 Android.bp 定义)
[四、基于 AIDL 的 HAL 服务开发完整流程](#四、基于 AIDL 的 HAL 服务开发完整流程)
[4.1 整体目录结构](#4.1 整体目录结构)
[4.2 第一步:定义 AIDL 接口](#4.2 第一步:定义 AIDL 接口)
[4.3 第二步:编写 aidl_interface 编译脚本](#4.3 第二步:编写 aidl_interface 编译脚本)
[4.4 第三步:实现 HAL 服务](#4.4 第三步:实现 HAL 服务)
[4.5 第四步:编写服务入口 main.cpp](#4.5 第四步:编写服务入口 main.cpp)
[4.6 第五步:编写服务编译脚本 default/Android.bp](#4.6 第五步:编写服务编译脚本 default/Android.bp)
[4.7 第六步:编写 init 启动脚本(.rc)](#4.7 第六步:编写 init 启动脚本(.rc))
[4.8 第七步:编写 VINTF 清单(.xml)](#4.8 第七步:编写 VINTF 清单(.xml))
[4.9 第八步:编译与部署](#4.9 第八步:编译与部署)
[4.10 客户端调用示例](#4.10 客户端调用示例)
[五、为已有 AIDL HAL 增加新接口的注意事项](#五、为已有 AIDL HAL 增加新接口的注意事项)
[5.1 判断接口是否已冻结](#5.1 判断接口是否已冻结)
[5.2 增加新接口的两种方式](#5.2 增加新接口的两种方式)
[5.3 增加新接口时的完整检查清单](#5.3 增加新接口时的完整检查清单)
[5.4 编译注意事项](#5.4 编译注意事项)
[5.5 常见错误与排查](#5.5 常见错误与排查)
[六、HIDL 与 AIDL 对比总结](#六、HIDL 与 AIDL 对比总结)
一、HAL 技术发展史
HAL(Hardware Abstraction Layer,硬件抽象层)是 Android 系统中位于 Linux 内核驱动与上层 Framework 之间的一层抽象,其核心目的是:将硬件厂商的具体实现与 Android 系统框架解耦,使得上层应用和系统服务无需关心底层硬件的具体差异,同时保护厂商的私有实现。
1.1 传统 HAL(Android 8.0 之前)
在 Android 8.0 之前,HAL 采用 libhardware 方式实现。厂商通过实现 hw_module_t 和 hw_device_t 结构体,并导出 HAL_MODULE_INFO_SYM 符号,向系统提供硬件能力。上层通过 hw_get_module() 动态加载 .so 库并调用其中的函数指针。
// 传统 HAL 模块结构(libhardware/include/hardware/hardware.h)
typedef struct hw_module_t {
uint32_t tag; // 固定为 HARDWARE_MODULE_TAG
uint16_t module_api_version;
uint16_t hal_api_version;
const char *id; // 模块 ID,如 "vibrator"
const char *name;
const char *author;
struct hw_module_methods_t *methods; // 打开设备的方法
void *dso;
...
} hw_module_t;
typedef struct hw_device_t {
uint32_t tag;
uint32_t version;
struct hw_module_t *module;
int (*close)(struct hw_device_t *device);
...
} hw_device_t;
这种方式的缺点非常明显:HAL 与 Framework 运行在同一个进程(system_server)中,HAL 一旦崩溃会导致整个系统重启;同时 HAL 与 Framework 之间没有稳定的接口契约,接口变更难以管理,安全性也较差。
1.2 HIDL 时代(Android 8.0 ~ 10)
从 Android 8.0 开始,Google 引入了 HIDL(HAL Interface Definition Language,HAL 接口定义语言) 。HIDL 将 HAL 从 Framework 进程中彻底分离,HAL 运行在独立的进程(vendor 进程)中,通过 Binder IPC 与 Framework 通信。HIDL 接口使用 .hal 文件定义,编译时生成 C++/Java 的客户端与服务端代码。
HIDL 的引入解决了传统 HAL 的稳定性问题,但 HIDL 本身也存在不足:它是一套全新的、与 Android 传统 Binder/AIDL 并行的机制,学习成本高,且与 Java 层的 AIDL 生态不统一。
1.3 AIDL 时代(Android 11 及以后)
从 Android 11 开始,Google 逐步推动 HAL 从 HIDL 迁移到 AIDL(Android Interface Definition Language) 。AIDL 是 Android 自诞生以来就存在的、成熟的 IPC 机制,被广泛用于应用层与系统服务之间的通信。将 HAL 迁移到 AIDL 后,实现了统一:HAL 与 Framework 使用同一套 IPC 语言和工具链,降低了维护成本。
到 Android 13/14,绝大多数 HAL 接口已经或正在迁移到 AIDL,HIDL 处于冻结状态(不再新增功能,仅维护)。新开发的 HAL 接口应优先使用 AIDL。
发展脉络总结: 传统 libhardware(进程内,无契约)→ HIDL(独立进程,.hal 契约)→ AIDL(独立进程,.aidl 契约,统一生态)。
二、HIDL 技术详解
2.1 HIDL 概述
HIDL 是专为 HAL 设计的接口定义语言,接口文件以 .hal 为后缀,使用 hidl-gen 工具生成 C++/Java 代码。HIDL 接口采用包名 + 版本号的命名方式,例如 android.hardware.thermal@2.0。
2.2 HIDL 接口定义示例
以下是一个 HIDL 接口定义示例(参考 hardware/interfaces/thermal/2.0/IThermal.hal):
// IThermal.hal
package android.hardware.thermal@2.0;
import android.hardware.thermal@1.0::IThermal;
import android.hardware.thermal@1.0::ThermalStatus;
import IThermalChangedCallback;
interface IThermal extends @1.0::IThermal {
// 获取当前温度
getCurrentTemperatures(bool filterType, TemperatureType type)
generates (ThermalStatus status, vec<Temperature> temperatures);
// 注册温度变化回调
registerThermalChangedCallback(IThermalChangedCallback callback)
generates (ThermalStatus status);
};
2.3 HIDL 的关键特性
- 版本化 :接口通过 @1.0、@2.0 等版本号管理,支持接口继承与演进。
- 独立进程 :HAL 服务运行在 vendor 进程,通过 Binder 与 Framework 通信。
- 返回状态 :HIDL 方法通过 generates 返回 status 和返回值,错误处理相对繁琐。
- 类型系统 :使用 vec、struct、enum 等 HIDL 特有类型。
- 编译工具 :使用 hidl-gen 生成代码,Android.bp 中使用 hidl_interface 模块。
2.4 HIDL 的 Android.bp 示例
// Android.bp
hidl_interface {
name: "android.hardware.thermal@2.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"IThermal.hal",
"types.hal",
],
interfaces: [
"android.hardware.thermal@1.0",
],
gen_java: true,
gen_java_constants: true,
}
三、AIDL 技术详解
3.1 AIDL 概述
AIDL(Android Interface Definition Language)是 Android 的标准 IPC 接口定义语言,自 Android 诞生起就存在,被广泛用于应用进程与系统服务之间的通信。从 Android 11 起,AIDL 被扩展用于定义 HAL 接口,成为 HAL 接口定义的主流方式。
AIDL 接口文件以 .aidl 为后缀,使用 aidl 编译器生成 C++/Java/Rust 代码。AIDL 支持三种后端(backend):NDK(C++) 、Java 和 Rust。
3.2 AIDL 与 HIDL 的核心差异
|----------------|--------------------------|------------------------------------------|
| 对比项 | HIDL | AIDL |
| 接口文件后缀 | .hal | .aidl |
| 包名/版本 | android.hardware.xxx@1.0 | android.hardware.xxx(版本在 Android.bp 中管理) |
| 生成工具 | hidl-gen | aidl 编译器 |
| 后端语言 | C++ / Java | C++(NDK) / Java / Rust |
| 返回方式 | generates (status, ret) | 直接返回,异常通过 ScopedAStatus 抛出 |
| 类型系统 | vec, struct, enum | List, Parcelable, enum, union |
| 稳定性 | @1.0 版本化 | @VintfStability 注解 + versions_with_info |
| 与 Framework 统一 | 否(独立体系) | 是(与系统服务同一套) |
3.3 AIDL 接口定义示例
以下是一个 AIDL HAL 接口定义示例(参考 hardware/interfaces/thermal/aidl/android/hardware/thermal/IThermal.aidl):
// IThermal.aidl
package android.hardware.thermal;
import android.hardware.thermal.CoolingDevice;
import android.hardware.thermal.CoolingType;
import android.hardware.thermal.IThermalChangedCallback;
import android.hardware.thermal.Temperature;
import android.hardware.thermal.TemperatureType;
/* @hide */
@VintfStability
interface IThermal {
// 获取冷却设备信息
CoolingDevice[] getCoolingDevices();
// 获取指定类型的冷却设备
CoolingDevice[] getCoolingDevicesWithType(in CoolingType type);
// 获取温度列表
Temperature[] getTemperatures();
// 注册温度变化回调
void registerThermalChangedCallback(
in IThermalChangedCallback callback);
};
3.4 AIDL 数据类型
AIDL 支持以下数据类型:
- 基本类型 :boolean、byte、char、int、long、float、double、String。
- 集合类型 :List、Map、数组 T[]。
- Parcelable :自定义可序列化类型,用 parcelable 关键字定义。
- enum :枚举类型。
- union :联合类型(AIDL 特有)。
- 接口类型 :其他 AIDL 接口(用于回调)。
3.5 Parcelable 类型定义示例
// Temperature.aidl
package android.hardware.thermal;
import android.hardware.thermal.TemperatureType;
import android.hardware.thermal.ThrottlingSeverity;
/* @hide */
@VintfStability
@JavaDerive(toString=true)
parcelable Temperature {
TemperatureType type; // 温度类型
String name; // 温度名称,如 cpu0
float value; // 温度值(摄氏度)
ThrottlingSeverity throttlingStatus; // 节流等级
}
3.6 方向关键字(in / out / inout)
AIDL 方法参数支持方向关键字,用于指示数据传递方向:
-
in:客户端传入服务端(默认,可省略)。
-
out:服务端返回给客户端。
-
inout:双向传递。
// 示例:in 参数 + 返回值
Temperature[] getTemperaturesWithType(in TemperatureType type);// 示例:out 参数(通过指针返回)
void getVersion(out int major, out int minor);
3.7 稳定性注解 @VintfStability
用于 HAL 的 AIDL 接口必须添加 @VintfStability 注解,表示该接口是 VINTF 稳定接口,其定义被冻结,不能随意修改。这是 AIDL HAL 与普通 AIDL 接口的重要区别。
/* @hide */
@VintfStability
interface IThermal {
...
}
3.8 AIDL 的 Android.bp 定义
AIDL HAL 接口使用 aidl_interface 模块定义(参考 interfaces/thermal/aidl/Android.bp):
// Android.bp
aidl_interface {
name: "android.hardware.thermal",
vendor_available: true,
srcs: [
"android/hardware/thermal/*.aidl",
],
stability: "vintf",
backend: {
cpp: {
enabled: true,
},
java: {
platform_apis: true,
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
],
frozen: true,
}
关键字段说明:
- name:接口模块名,即包名。
- vendor_available:是否对 vendor 可用(HAL 必须为 true)。
- stability: "vintf":声明为 VINTF 稳定接口。
- backend:启用哪些后端(cpp/java/rust)。
- versions_with_info:接口版本信息。
- frozen: true:接口已冻结,禁止修改。
四、基于 AIDL 的 HAL 服务开发完整流程
本章以一个简化的示例说明如何从零开发一个基于 AIDL 的 HAL 服务。我们以 android.hardware.led(LED 灯控制)为例,接口只包含一个 setBrightness 方法,重点展示完整流程而非复杂接口。
4.1 整体目录结构
一个完整的 AIDL HAL 服务通常包含以下目录结构:
hardware/interfaces/led/aidl/
├── Android.bp # aidl_interface 定义
├── android/hardware/led/
│ ├── ILed.aidl # 接口定义
│ └── LedBrightness.aidl # Parcelable 类型定义
├── aidl_api/
│ └── android.hardware.led/
│ ├── current/ # 当前接口快照(冻结后生成)
│ └── 1/ # 版本 1 快照
└── default/ # 服务实现
├── Android.bp # 服务编译脚本
├── main.cpp # 服务入口
├── Led.cpp # 接口实现
├── Led.h
├── android.hardware.led-service.rc # init 启动脚本
└── android.hardware.led-service.xml # VINTF 清单
4.2 第一步:定义 AIDL 接口
创建接口文件 android/hardware/led/ILed.aidl:
// ILed.aidl
package android.hardware.led;
import android.hardware.led.LedBrightness;
/* @hide */
@VintfStability
interface ILed {
// 设置 LED 亮度,返回是否成功
boolean setBrightness(in LedBrightness brightness);
// 获取当前亮度
LedBrightness getBrightness();
};
创建 Parcelable 类型 android/hardware/led/LedBrightness.aidl:
// LedBrightness.aidl
package android.hardware.led;
/* @hide */
@VintfStability
parcelable LedBrightness {
int level; // 亮度等级 0~255
String color; // 颜色,如 "red"
}
4.3 第二步:编写 aidl_interface 编译脚本
创建 Android.bp(位于 hardware/interfaces/led/aidl/):
// Android.bp
package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
aidl_interface {
name: "android.hardware.led",
vendor_available: true,
srcs: [
"android/hardware/led/*.aidl",
],
stability: "vintf",
backend: {
cpp: {
enabled: true,
},
java: {
platform_apis: true,
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
],
}
说明: 首次开发时不要设置 frozen: true。当接口稳定后,通过 make -freeze 冻结接口,系统会自动生成 aidl_api/ 目录下的快照,并自动将 frozen 置为 true。
4.4 第三步:实现 HAL 服务
创建服务实现类 default/Led.h:
// Led.h
#pragma once
#include <aidl/android/hardware/led/BnLed.h>
namespace aidl::android::hardware::led::impl {
class Led : public BnLed {
public:
ndk::ScopedAStatus setBrightness(const LedBrightness& in_brightness,
bool* _aidl_return) override;
ndk::ScopedAStatus getBrightness(LedBrightness* _aidl_return) override;
};
} // namespace aidl::android::hardware::led::impl
创建实现文件 default/Led.cpp:
// Led.cpp
#define LOG_TAG "led_service"
#include "Led.h"
#include <android-base/logging.h>
namespace aidl::android::hardware::led::impl {
using ndk::ScopedAStatus;
ScopedAStatus Led::setBrightness(const LedBrightness& in_brightness,
bool* _aidl_return) {
LOG(INFO) << "setBrightness level=" << in_brightness.level
<< " color=" << in_brightness.color;
// TODO: 在此调用底层驱动接口(如 /sys/class/leds/...)
*_aidl_return = true;
return ScopedAStatus::ok();
}
ScopedAStatus Led::getBrightness(LedBrightness* _aidl_return) {
LedBrightness b;
b.level = 128;
b.color = "red";
*_aidl_return = b;
return ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::led::impl
4.5 第四步:编写服务入口 main.cpp
创建 default/main.cpp,负责创建服务实例并注册到 ServiceManager:
// main.cpp
#define LOG_TAG "led_service"
#include "Led.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::android::hardware::led::impl::Led;
int main() {
// 设置线程池最大线程数为 0(表示由 Binder 驱动决定)
ABinderProcess_setThreadPoolMaxThreadCount(0);
// 创建服务实例
std::shared_ptr<Led> led = ndk::SharedRefBase::make<Led>();
// 注册服务,instance 为 "default"
const std::string instance = std::string() + Led::descriptor + "/default";
binder_status_t status =
AServiceManager_addService(led->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
// 进入 Binder 线程池,等待客户端调用
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // 不应到达
}
4.6 第五步:编写服务编译脚本 default/Android.bp
// default/Android.bp
package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_binary {
name: "android.hardware.led-service",
relative_install_path: "hw",
init_rc: [":android.hardware.led-service.rc"],
vintf_fragments: [":android.hardware.led-service.xml"],
vendor: true,
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.led-V1-ndk",
],
srcs: [
"main.cpp",
"Led.cpp",
],
}
filegroup {
name: "android.hardware.led-service.xml",
srcs: ["android.hardware.led-service.xml"],
}
filegroup {
name: "android.hardware.led-service.rc",
srcs: ["android.hardware.led-service.rc"],
}
关键点:
- relative_install_path: "hw":服务安装到 /vendor/bin/hw/ 目录。
- vendor: true:编译为 vendor 模块。
- shared_libs 中的 android.hardware.led-V1-ndk:由 aidl_interface 自动生成的 NDK 后端库。
- init_rc 和 vintf_fragments:分别关联 rc 脚本和 VINTF 清单。
4.7 第六步:编写 init 启动脚本(.rc)
创建 default/android.hardware.led-service.rc:
// android.hardware.led-service.rc
service vendor.led /vendor/bin/hw/android.hardware.led-service
class hal
user system
group system
字段说明:
- service vendor.led:服务名,vendor. 前缀表示 vendor 服务。
- /vendor/bin/hw/android.hardware.led-service:可执行文件路径。
- class hal:服务属于 hal 类,由 init 统一管理。
- user/group:服务运行的用户和组。
4.8 第七步:编写 VINTF 清单(.xml)
创建 default/android.hardware.led-service.xml:
<!-- android.hardware.led-service.xml -->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.led</name>
<version>1</version>
<fqname>ILed/default</fqname>
</hal>
</manifest>
VINTF(Vendor Interface)清单用于声明设备提供的 HAL 服务,供系统在启动时校验。关键点:
- format="aidl":声明为 AIDL 格式的 HAL。
- name:HAL 包名。
- version:HAL 版本号。
- fqname:完全限定名,格式为 接口名/实例名。
4.9 第八步:编译与部署
在 Android 源码根目录执行编译:
# 编译接口库
make android.hardware.led-V1-ndk
# 编译服务
make android.hardware.led-service
# 或直接编译整个镜像
make systemimage vendorimage
编译产物:
- 接口库:android.hardware.led-V1-ndk.so(供客户端和服务端链接)。
- 服务可执行文件:/vendor/bin/hw/android.hardware.led-service。
4.10 客户端调用示例
Framework 或应用侧通过 AServiceManager_getService 获取服务并调用:
// 客户端示例(C++ NDK)
#include <android/binder_manager.h>
#include <aidl/android/hardware/led/ILed.h>
using aidl::android::hardware::led::ILed;
using aidl::android::hardware::led::LedBrightness;
// 获取服务
const std::string instance = std::string() + ILed::descriptor + "/default";
std::shared_ptr<ILed> led;
binder_status_t status = AServiceManager_getService(instance.c_str(), &led);
CHECK(status == STATUS_OK);
// 调用接口
LedBrightness b;
b.level = 200;
b.color = "blue";
bool ok = false;
led->setBrightness(b, &ok);
五、为已有 AIDL HAL 增加新接口的注意事项
当需要为已有的 AIDL HAL 增加新接口(方法)时,必须遵循 AIDL HAL 的版本化与冻结规则。由于 AIDL HAL 接口是 @VintfStability 稳定接口,一旦冻结(frozen)就不能直接修改,必须通过新增版本的方式演进。
5.1 判断接口是否已冻结
查看 Android.bp 中 aidl_interface 模块是否设置了 frozen: true,以及 aidl_api/ 目录下是否存在版本快照。若已冻结,则不能直接修改 .aidl 文件。
5.2 增加新接口的两种方式
方式一:接口未冻结(开发阶段)
如果接口尚未冻结(frozen 未设置或为 false),可以直接修改 .aidl 文件增加方法:
// ILed.aidl(直接增加方法)
@VintfStability
interface ILed {
boolean setBrightness(in LedBrightness brightness);
LedBrightness getBrightness();
// 新增方法
void setBlink(in int frequencyMs);
};
修改后需要同步更新服务实现 Led.cpp,增加对应方法的实现,然后重新编译。
方式二:接口已冻结(正式发布后)
如果接口已冻结,必须新增一个版本。步骤如下:
步骤 1: 在 Android.bp 的 versions_with_info 中增加新版本,并移除 frozen 或更新:
aidl_interface {
name: "android.hardware.led",
vendor_available: true,
srcs: [
"android/hardware/led/*.aidl",
],
stability: "vintf",
backend: {
cpp: { enabled: true },
java: { platform_apis: true },
},
versions_with_info: [
{ version: "1", imports: [] },
{ version: "2", imports: [] }, // 新增版本 2
],
}
步骤 2: 在 .aidl 文件中增加新方法(新方法属于最新版本):
// ILed.aidl
@VintfStability
interface ILed {
boolean setBrightness(in LedBrightness brightness);
LedBrightness getBrightness();
// 版本 2 新增
void setBlink(in int frequencyMs);
};
步骤 3: 重新冻结接口,生成新版本快照:
# 在源码根目录执行
make android.hardware.led-freeze
该命令会生成 aidl_api/android.hardware.led/2/ 目录,并将 frozen 置为 true。
步骤 4: 更新服务实现,实现新方法:
// Led.cpp
ScopedAStatus Led::setBlink(int32_t in_frequencyMs) {
LOG(INFO) << "setBlink frequency=" << in_frequencyMs;
// TODO: 实现闪烁逻辑
return ScopedAStatus::ok();
}
步骤 5: 更新 VINTF 清单中的版本号:
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.led</name>
<version>2</version> <!-- 更新为 2 -->
<fqname>ILed/default</fqname>
</hal>
</manifest>
5.3 增加新接口时的完整检查清单
|--------|----------------------------|----------------------------------|
| 序号 | 需要修改/增加的内容 | 说明 |
| 1 | .aidl 接口文件 | 增加新方法定义,注意方向关键字和 @VintfStability |
| 2 | Android.bp(aidl_interface) | 若已冻结,增加新版本到 versions_with_info |
| 3 | 服务实现类(.h/.cpp) | 继承 BnLed,实现新方法 |
| 4 | VINTF 清单(.xml) | 更新 version 号 |
| 5 | aidl_api 快照 | 执行 make xxx-freeze 生成新版本快照 |
| 6 | 客户端代码 | 若客户端需要调用新方法,需链接新版本库 |
| 7 | VTS 测试 | 若接口有 VTS 测试,需同步更新 |
5.4 编译注意事项
重要编译注意事项:
- 接口冻结后禁止修改 :一旦 frozen: true,修改 .aidl 会导致编译报错(hash 校验失败)。必须通过新增版本演进。
- 版本号必须递增 :新增版本号必须大于现有最大版本号,且不能跳过(如从 1 直接到 3 不允许)。
- 新方法不能修改已有方法签名 :已发布的方法签名(参数、返回值)不能改变,只能新增方法。
- Parcelable 字段不能删除或改类型 :已发布的 Parcelable 字段只能新增,不能删除或修改类型,否则破坏兼容性。
- 编译顺序 :先编译接口库(make android.hardware.led-V1-ndk),再编译服务。
- 清理缓存 :修改接口后,若编译异常,可尝试 make clean 或删除 out/ 下相关产物。
- VINTF 校验 :服务启动时系统会校验 VINTF 清单,若清单与接口不匹配,服务可能无法注册成功。
5.5 常见错误与排查
|----------------|---------------|------------------------------|
| 错误现象 | 可能原因 | 解决方法 |
| 编译报 hash 校验失败 | 接口已冻结但被修改 | 新增版本而非修改冻结接口 |
| 服务无法注册 | VINTF 清单版本不匹配 | 更新 .xml 中的 version |
| 客户端找不到服务 | 服务未启动或实例名错误 | 检查 rc 脚本和 fqname |
| 链接错误:找不到 BnLed | 未链接 NDK 后端库 | 在 shared_libs 中加入 xxx-V1-ndk |
| 方法未实现编译错误 | 新增方法未在实现类中实现 | 在 .cpp 中实现所有纯虚方法 |
六、HIDL 与 AIDL 对比总结
|----------------|------------------------|--------------------|
| 维度 | HIDL | AIDL |
| 引入版本 | Android 8.0 | Android 11(用于 HAL) |
| 当前状态 | 冻结,仅维护 | 主流,新功能首选 |
| 接口文件 | .hal | .aidl |
| 版本管理 | 包名@版本号 | versions_with_info |
| 后端 | C++/Java | C++(NDK)/Java/Rust |
| 错误处理 | generates(status, ret) | ScopedAStatus 异常 |
| 与 Framework 统一 | 否 | 是 |
| 学习成本 | 高(独立体系) | 低(复用 AIDL) |
| 推荐度 | 不推荐新开发 | 强烈推荐 |
总结建议: 对于 Android 11 及以上的新项目,HAL 接口应一律使用 AIDL。AIDL 与 Framework 使用同一套 IPC 机制,工具链成熟、生态统一、维护成本低。开发时务必遵循 @VintfStability 稳定接口规范,通过版本化机制管理接口演进,避免破坏兼容性。