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

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui