安卓HAL接口技术之HIDL&AIDL

目录

[一、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++)JavaRust

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 稳定接口规范,通过版本化机制管理接口演进,避免破坏兼容性。

相关推荐
YF02111 小时前
Android 系统自带机制的卸载更新都哪些实现方案
android
事圆则缓1 小时前
MVC、MVP、MVVM、MVI 的区别与实现原理
android·kotlin·mvc
事圆则缓2 小时前
Android组件化指南
android·kotlin
binbin_522 小时前
HarmonyOS 应用功耗优化实战:定位耗电、收口任务与验证回归
android·回归·harmonyos
AFinalStone3 小时前
Android 7系统无障碍服务(七)手势分发与 KeyEvent 处理
android·无障碍服务
事圆则缓4 小时前
Jetpack Compose Effect 完全指南
android·kotlin
平头哥技术团队13 小时前
Day 10 | 工欲善其事:VS Code 配置与项目归档
android·开发语言·前端·javascript·html·交互
冬木家居14 小时前
40㎡客厅变形记,小家住出大自由[特殊字符]
android·经验分享·笔记·智能家居·微信公众平台
AFinalStone14 小时前
Android 7系统无障碍服务(六)输入事件拦截与 TouchExplorer
android·无障碍服务