AIDL/HIDL与HAL层通信实战:从接口定义到服务实现

0 阅读15分钟

引言

在前两篇文章中,我们深入分析了Binder驱动机制和ServiceManager服务注册。但在真实的Android系统开发中,很少有人直接操作Binder驱动——大家使用的都是更高层的抽象:AIDL(Android Interface Definition Language)和HIDL(HAL Interface Definition Language)。

想象一下这个场景:Framework层的BatteryService想要获取电池电量,它需要和HAL层的Health服务通信。怎么做?

Framework (Java)  ←→  Native Service (C++)  ←→  HAL Service (C++)  ←→  硬件
    ↓                      ↓                         ↓
 AIDL接口             AIDL/HIDL桥接           AIDL HAL接口

这就是本文要解决的问题:如何通过AIDL/HIDL定义接口,并实现跨进程的HAL层通信?

📖 系列前置阅读:建议先阅读第9篇(Binder驱动)和第10篇(ServiceManager),理解Binder IPC的底层机制。


AIDL与HIDL:两代接口定义语言

为什么需要接口定义语言?

直接操作Binder需要手工编写大量模板代码:

// 手工Binder代码示例(已简化)
class BpMyService : public BpInterface<IMyService> {
    virtual int getValue() {
        Parcel data, reply;
        data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
        remote()->transact(TRANSACTION_getValue, data, &reply);
        return reply.readInt32();
    }
};

这种方式容易出错、维护困难、版本管理混乱

AIDL和HIDL的诞生就是为了自动生成这些模板代码,让开发者专注于业务逻辑。

AIDL vs HIDL:历史演进

特性AIDL (传统)HIDLAIDL (Stable/现代)
引入版本Android 1.0Android 8.0Android 11
主要用途Framework内部Framework-HALFramework-HAL
语言支持Java + C++C++Java + C++ + Rust
版本管理❌ 无✅ 强制语义化版本✅ Stable接口
向后兼容❌ 不保证✅ 保证✅ 保证
当前状态维护中❌ 不推荐新项目推荐

Android 15的策略:

  • 新HAL服务:使用Stable AIDL
  • 遗留HAL:HIDL继续支持,但不再新增
  • Framework内部:传统AIDL和Stable AIDL混用

🎯 关键洞察:Google在Android 11后推动"HIDL退役,AIDL统一天下"的策略。Stable AIDL结合了AIDL的灵活性和HIDL的版本管理优势。

11-01-aidl-hidl-hal-architecture.png

图:从Framework Java层到内核驱动的完整调用链,通过AIDL接口实现跨进程HAL通信


AIDL基础:从语法到生成代码

AIDL文件结构

一个典型的AIDL接口定义:

// IHealth.aidl (简化版)
package android.hardware.health;

import android.hardware.health.HealthInfo;
import android.hardware.health.IHealthInfoCallback;

@VintfStability  // ← Android 15: VINTF声明标记
interface IHealth {
    // 常量定义
    const int STATUS_UNKNOWN = 2;
    const int STATUS_CALLBACK_DIED = 4;

    // 方法声明
    void registerCallback(in IHealthInfoCallback callback);
    void unregisterCallback(in IHealthInfoCallback callback);
    void update();

    // 返回值可以是基本类型或Parcelable
    int getChargeCounterUah();
    int getCurrentNowMicroamps();
    HealthInfo getHealthInfo();
}

语法要点:

  1. 包名:package声明命名空间
  2. 导入:import其他AIDL类型
  3. 注解:@VintfStability表示接口稳定性(Android 15强制要求)
  4. 方向标记:in(输入)/out(输出)/inout(双向)
  5. 支持类型:基本类型、String、List、Map、Parcelable、其他AIDL接口

AIDL编译流程

IHealth.aidl[AIDL Compiler]  →  生成代码
                                     ├── IHealth.h/cpp (C++ Native Backend)
                                     ├── IHealth.java (Java Backend)
                                     └── IHealth.rs (Rust Backend)

生成的C++代码(Android 15,简化版):

// 自动生成的 IHealth.h (片段)
#include <android/binder_ibinder.h>

namespace aidl::android::hardware::health {

class IHealth : public ::ndk::ICInterface {
public:
    static const char* descriptor;  // "android.hardware.health.IHealth"

    // 纯虚函数,由实现类覆盖
    virtual ::ndk::ScopedAStatus registerCallback(
        const std::shared_ptr<IHealthInfoCallback>& in_callback) = 0;

    virtual ::ndk::ScopedAStatus getChargeCounterUah(int32_t* _aidl_return) = 0;

    // Binder通信相关
    static std::shared_ptr<IHealth> fromBinder(const ::ndk::SpAIBinder& binder);
};

// Bn = Binder Native (服务端基类)
class BnHealth : public ::ndk::BnCInterface<IHealth> {
public:
    ::ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) final;
protected:
    ::ndk::SpAIBinder createBinder() override;
};

// Bp = Binder Proxy (客户端代理)
class BpHealth : public ::ndk::BpCInterface<IHealth> {
public:
    explicit BpHealth(const ::ndk::SpAIBinder& binder);

    // 实现所有虚函数,内部调用transact()
    ::ndk::ScopedAStatus registerCallback(
        const std::shared_ptr<IHealthInfoCallback>& in_callback) override {
        // 序列化参数 → transact() → 反序列化返回值
        // ...
    }
};

}  // namespace aidl::android::hardware::health

关键类的职责:

  • IHealth(接口类):定义API契约
  • BnHealth(Binder Native):服务端基类,处理transact()
  • BpHealth(Binder Proxy):客户端代理,封装IPC细节

Stable AIDL:版本管理的救星

传统AIDL的痛点

在Android 10之前,AIDL接口变更是噩梦:

// Version 1
interface IFoo {
    void methodA();
}

// Version 2 (破坏性变更!)
interface IFoo {
    void methodA();
    void methodB();  // ← 新增方法,老版本无法识别!
}

问题:

  • 无法在新旧版本间兼容
  • HAL升级强制要求Framework同步升级
  • OTA更新可能导致系统崩溃

Stable AIDL的解决方案

核心机制:冻结旧版本接口 + 通过新方法扩展。

# Stable AIDL的目录结构
hardware/interfaces/health/aidl/
├── android/hardware/health/
│   ├── IHealth.aidl              # 当前开发版本
│   ├── HealthInfo.aidl
│   └── ...
└── aidl_api/android.hardware.health/
    ├── 1/                         # 冻结的版本1
    │   └── android/hardware/health/IHealth.aidl
    ├── 2/                         # 冻结的版本2
    │   └── android/hardware/health/IHealth.aidl
    └── current/                   # 当前版本符号链接

版本演进示例(Android 15 Health HAL):

// Version 1 (冻结,不可修改)
package android.hardware.health;
interface IHealth {
    void registerCallback(in IHealthInfoCallback callback);
    int getCapacity();
}

// Version 2 (冻结,不可修改)
package android.hardware.health;
interface IHealth {
    void registerCallback(in IHealthInfoCallback callback);
    int getCapacity();
    // 新增方法(向后兼容!)
    void setChargingPolicy(BatteryChargingPolicy in_value);
    BatteryChargingPolicy getChargingPolicy();
}

// Current (开发中)
package android.hardware.health;
interface IHealth {
    // ... 继承所有旧方法
    // 新增Android 15特性
    BatteryHealthData getBatteryHealthData();
}

版本检查代码(客户端):

// 客户端检查HAL服务版本
std::shared_ptr<IHealth> health = IHealth::fromBinder(binder);

int32_t version = 0;
health->getInterfaceVersion(&version);

if (version >= 2) {
    // 使用Version 2的特性
    BatteryChargingPolicy policy;
    health->getChargingPolicy(&policy);
} else {
    // 降级处理
    LOG(WARNING) << "Health HAL version " << version << " does not support charging policy";
}

Stable AIDL的优势:

  1. 向后兼容:新Framework可以使用老HAL
  2. 向前兼容:老Framework不会因新HAL崩溃(忽略未知方法)
  3. 独立升级:HAL和Framework可以各自OTA

HIDL简介:HAL的前辈

虽然HIDL正在被Stable AIDL取代,但Android 15中仍有大量遗留HAL使用HIDL。

HIDL语法特点

// IUsb.hal (HIDL 1.0)
package android.hardware.usb@1.0;

import IUsbCallback;

interface IUsb {
    /**
     * oneway = 异步调用,不等待返回
     */
    oneway switchRole(string portName, PortRole role);

    oneway setCallback(IUsbCallback callback);

    oneway queryPortStatus();
};

HIDL vs AIDL对比:

特性HIDLAIDL
文件后缀.hal.aidl
版本标记@1.0 (包名中)aidl_api/版本号/ (目录)
异步语法oneway 关键字oneway 关键字
数据传输hidl_vec/hidl_stringstd::vector/std::string

HIDL遗留问题

  1. 复杂的版本号管理:@1.0@1.1@2.0 需要手动维护
  2. 工具链老旧:hidl-gen已停止维护
  3. 无Rust支持:限制了现代化改造

HAL服务实现:以Health HAL为例

Health HAL架构

┌─────────────────────────────────────────────────────────┐
│             Framework (Java)                            │
│  frameworks/base/services/core/java/...BatteryService   │
└─────────────┬───────────────────────────────────────────┘
              │ JNI
              ↓
┌─────────────────────────────────────────────────────────┐
│         Native Service (C++)                            │
│  frameworks/native/services/batteryservice              │
└─────────────┬───────────────────────────────────────────┘
              │ Binder IPC (AIDL)
              ↓
┌─────────────────────────────────────────────────────────┐
│           HAL Service (C++)                             │
│  hardware/interfaces/health/aidl/default/Health.cpp     │
│                                                          │
│  ┌────────────────────────────────────────────┐         │
│  │  class Health : public BnHealth {          │         │
│  │    BatteryMonitor battery_monitor_;        │         │
│  │    ndk::ScopedAStatus getCapacity(...) {   │         │
│  │      // 读取 /sys/class/power_supply/...  │         │
│  │    }                                        │         │
│  │  }                                          │         │
│  └────────────────────────────────────────────┘         │
└─────────────┬───────────────────────────────────────────┘
              │ sysfs
              ↓
┌─────────────────────────────────────────────────────────┐
│              Kernel Driver                              │
│  drivers/power/supply/xxx_battery.c                     │
└─────────────────────────────────────────────────────────┘

服务端实现(Android 15源码分析)

Health.cpp(截取核心逻辑):

// hardware/interfaces/health/aidl/default/Health.cpp (Android 15)
namespace aidl::android::hardware::health {

// Health服务构造函数
Health::Health(std::string_view instance_name,
               std::unique_ptr<struct healthd_config>&& config)
    : instance_name_(instance_name),
      healthd_config_(std::move(config)),
      death_recipient_(AIBinder_DeathRecipient_new(&OnCallbackDiedWrapped)) {

    // 注册死亡通知回调(类似ServiceManager的linkToDeath)
    AIBinder_DeathRecipient_setOnUnlinked(death_recipient_.get(), onCallbackUnlinked);

    // 初始化电池监控器(底层读取sysfs)
    battery_monitor_.init(healthd_config_.get());
}

// ========== AIDL接口实现:获取电池电量 ==========
ndk::ScopedAStatus Health::getCapacity(int32_t* out) {
    // 调用BatteryMonitor读取 /sys/class/power_supply/battery/capacity
    return GetProperty<int32_t>(&battery_monitor_,
                                 ::android::BATTERY_PROP_CAPACITY,
                                 0,  // 默认值
                                 out);
}

// ========== AIDL接口实现:获取充电状态 ==========
ndk::ScopedAStatus Health::getChargeStatus(BatteryStatus* out) {
    return GetProperty(&battery_monitor_,
                       ::android::BATTERY_PROP_BATTERY_STATUS,
                       BatteryStatus::UNKNOWN,
                       out);
}

// ========== AIDL接口实现:设置充电策略 (Android 15新增) ==========
ndk::ScopedAStatus Health::setChargingPolicy(BatteryChargingPolicy in_value) {
    ::android::status_t err = battery_monitor_.setChargingPolicy(static_cast<int>(in_value));

    switch (err) {
        case ::android::OK:
            return ndk::ScopedAStatus::ok();
        case ::android::NAME_NOT_FOUND:
            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
        case ::android::BAD_VALUE:
            return ndk::ScopedAStatus::fromStatus(::android::INVALID_OPERATION);
        default:
            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
    }
}

// ========== 回调管理:注册健康信息监听器 ==========
ndk::ScopedAStatus Health::registerCallback(
    const std::shared_ptr<IHealthInfoCallback>& callback) {

    if (callback == nullptr) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }

    {
        std::lock_guard<std::mutex> lock(callbacks_lock_);
        callbacks_.push_back(callback);

        // 为callback注册死亡通知(防止客户端崩溃后内存泄漏)
        auto linked = std::make_unique<LinkedCallback>(weak_from_this(), callback);
        auto binder = callback->asBinder();
        auto status = AIBinder_linkToDeath(binder.get(),
                                           death_recipient_.get(),
                                           linked.get());
        if (status == STATUS_OK) {
            linked.release();  // 交给Binder管理生命周期
        } else {
            LOG(WARNING) << "Cannot link to death: " << status;
        }
    }

    return ndk::ScopedAStatus::ok();
}

// ========== 主动通知所有回调 ==========
ndk::ScopedAStatus Health::update() {
    battery_monitor_.updateValues();
    HealthInfo health_info = battery_monitor_.getHealthInfo();

    std::lock_guard<std::mutex> lock(callbacks_lock_);
    for (auto& callback : callbacks_) {
        // 异步通知(oneway),避免阻塞
        auto status = callback->healthInfoChanged(health_info);
        if (!status.isOk()) {
            LOG(WARNING) << "Callback failed: " << status.getDescription();
        }
    }

    return ndk::ScopedAStatus::ok();
}

}  // namespace aidl::android::hardware::health

关键设计:

  1. 错误处理:统一转换::android::status_t到AIDL的ScopedAStatus
  2. 死亡通知:防止客户端崩溃导致服务端泄漏回调
  3. 线程安全:使用std::mutex保护共享数据(callbacks_)
  4. 异步通知:回调使用oneway,避免阻塞HAL服务

服务注册与启动

main.cpp(Health HAL服务入口):

// hardware/interfaces/health/aidl/default/main.cpp
int main() {
    // 创建Health服务实例
    auto config = std::make_unique<healthd_config>();
    ::android::hardware::health::InitHealthdConfig(config.get());
    auto health = ndk::SharedRefBase::make<Health>("default", std::move(config));

    // 注册到ServiceManager
    const std::string instance = std::string(Health::descriptor) + "/default";
    auto status = AServiceManager_addService(health->asBinder().get(), instance.c_str());
    if (status != STATUS_OK) {
        LOG(FATAL) << "Failed to register Health HAL: " << status;
    }

    // 启动Binder线程池
    ABinderProcess_setThreadPoolMaxThreadCount(0);  // 0 = 自动管理
    ABinderProcess_startThreadPool();
    ABinderProcess_joinThreadPool();  // 阻塞等待

    return EXIT_FAILURE;  // 永不返回,除非异常
}

注册流程解析:

Health HAL服务启动
    ↓
1. 创建Health实例 (new Health(...))
    ↓
2. 生成服务名称 ("android.hardware.health.IHealth/default")
    ↓
3. 调用 AServiceManager_addService()
    ├→ 内部调用 Binder transact(ADD_SERVICE)
    └→ ServiceManager记录到 mNameToService
    ↓
4. 启动Binder线程池 (等待客户端调用)
    ↓
5. joinThreadPool() (阻塞主线程)

客户端调用

Native客户端代码:

// frameworks/native/services/batteryservice/HealthHalCallbackHidl.cpp (简化)
#include <android/hardware/health/IHealth.h>
#include <android/binder_manager.h>

using aidl::android::hardware::health::IHealth;
using aidl::android::hardware::health::HealthInfo;

// 获取Health HAL服务
std::shared_ptr<IHealth> getHealthService() {
    const std::string instance = std::string(IHealth::descriptor) + "/default";

    // 通过ServiceManager查询服务
    ndk::SpAIBinder binder(AServiceManager_waitForService(instance.c_str()));
    if (binder.get() == nullptr) {
        LOG(ERROR) << "Failed to get Health HAL service";
        return nullptr;
    }

    // 将Binder转换为IHealth接口
    return IHealth::fromBinder(binder);
}

// 使用Health HAL获取电池信息
void getBatteryInfo() {
    auto health = getHealthService();
    if (!health) return;

    // 调用AIDL接口
    HealthInfo info;
    auto status = health->getHealthInfo(&info);
    if (!status.isOk()) {
        LOG(ERROR) << "getHealthInfo failed: " << status.getDescription();
        return;
    }

    LOG(INFO) << "Battery level: " << info.batteryLevel << "%";
    LOG(INFO) << "Charging status: " << toString(info.batteryStatus);
}

实战技巧:AIDL/HIDL开发最佳实践

1. 选择AIDL还是HIDL?

决策树:

新项目?
├─ Yes  使用 Stable AIDL
└─ No  已有HAL使用HIDL?
       ├─ Yes  继续维护HIDL (除非有重大重构)
       └─ No  迁移到 Stable AIDL

2. Stable AIDL版本升级流程

# 1. 修改当前开发版本的AIDL文件
vim hardware/interfaces/health/aidl/android/hardware/health/IHealth.aidl

# 2. 冻结当前版本(假设从version 2升级到3)
m android.hardware.health-freeze-api

# 3. 自动生成 aidl_api/android.hardware.health/3/ 目录

# 4. 更新实现代码以支持新接口

# 5. 构建验证
m android.hardware.health-impl

3. 错误处理规范

// ❌ 错误示例:直接返回空指针
ndk::ScopedAStatus getService(...) {
    if (error) return nullptr;  // 编译错误!
}

// ✅ 正确示例:使用ScopedAStatus
ndk::ScopedAStatus getService(...) {
    if (not_found) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    if (unknown_error) {
        return ndk::ScopedAStatus::fromServiceSpecificError(
            IHealth::STATUS_UNKNOWN, "Detailed error message");
    }
    return ndk::ScopedAStatus::ok();
}

4. 性能优化:减少Binder往返

❌ 低效写法(每次调用都跨进程):

int level = health->getCapacity();       // Binder调用1
int current = health->getCurrentNow();   // Binder调用2
int voltage = health->getVoltage();      // Binder调用3

✅ 高效写法(一次调用获取所有数据):

HealthInfo info;
health->getHealthInfo(&info);  // 单次Binder调用,包含所有数据

int level = info.batteryLevel;
int current = info.batteryCurrentMicroamps;
int voltage = info.batteryVoltage;

性能对比:

  • 方案1:3次Binder transact,约 300-900μs
  • 方案2:1次Binder transact,约 100-300μs
  • 提升: 60%-70%

5. 死亡通知最佳实践

class MyCallback : public BnHealthInfoCallback {
private:
    // 使用weak_ptr避免循环引用
    std::weak_ptr<MyService> service_;

public:
    explicit MyCallback(std::shared_ptr<MyService> service)
        : service_(service) {}

    ndk::ScopedAStatus healthInfoChanged(const HealthInfo& info) override {
        // 检查service是否还存活
        if (auto svc = service_.lock()) {
            svc->onHealthInfoUpdate(info);
        }
        return ndk::ScopedAStatus::ok();
    }

    // 死亡通知回调
    void binderDied() {
        LOG(WARNING) << "Health HAL服务崩溃,尝试重连...";
        if (auto svc = service_.lock()) {
            svc->reconnectHealthHAL();
        }
    }
};

6. 调试技巧

查看已注册的AIDL服务:

# 列出所有AIDL HAL服务
adb shell dumpsys -l | grep android.hardware

# 查看Health HAL服务详情
adb shell dumpsys android.hardware.health.IHealth/default

# 输出示例:
# Battery Health:
#   batteryLevel: 85
#   batteryStatus: CHARGING
#   batteryHealth: GOOD
#   batteryChargeCounter: 2850000 µAh

Binder通信追踪:

# 启用Binder日志
adb shell setprop log.tag.binder VERBOSE

# 实时查看AIDL调用
adb logcat -s binder:V | grep "IHealth"

# 输出示例:
# binder: 1234:1234 BC_TRANSACTION thr 1234 -> 5678 node 12345 handle 0x3 code 0x1 (IHealth::getCapacity)

常见问题与解答

Q1: Stable AIDL的版本号如何管理?

A: 版本号存储在aidl_api/目录下,每次freeze-api自动递增:

aidl_api/android.hardware.health/
├── 1/      # 第一次freeze
├── 2/      # 第二次freeze
├── 3/      # 最新freeze
└── current -> 3/  # 符号链接指向最新版本

客户端代码可以通过getInterfaceVersion()查询服务版本:

int32_t version = 0;
health->getInterfaceVersion(&version);
LOG(INFO) << "Health HAL version: " << version;

Q2: AIDL接口可以修改已冻结的版本吗?

A: 绝对不行! 这会破坏向后兼容性。

# ❌ 错误操作:修改冻结版本
vim aidl_api/android.hardware.health/2/android/hardware/health/IHealth.aidl

# ✅ 正确做法:修改当前开发版本,然后freeze
vim android/hardware/health/IHealth.aidl
m android.hardware.health-freeze-api

Q3: HIDL如何调用AIDL服务(或反向)?

A: 需要编写适配层(Adapter):

// HIDL → AIDL适配器示例
class HidlToAidlAdapter : public IHidlInterface {
    std::shared_ptr<IAidlInterface> aidl_service_;

    Return<void> hidlMethod(...) override {
        // 转换HIDL类型到AIDL类型
        AidlType aidl_param = convertHidlToAidl(hidl_param);

        // 调用AIDL服务
        auto status = aidl_service_->aidlMethod(aidl_param);

        // 转换返回值
        return convertAidlToHidl(status);
    }
};

Android 15的部分遗留HAL仍在使用此模式。

Q4: 如何处理HAL服务崩溃?

A: 使用死亡通知(DeathRecipient)自动重连:

class HealthServiceManager {
    std::shared_ptr<IHealth> health_;
    ndk::ScopedAIBinder_DeathRecipient death_recipient_;

    void connectService() {
        health_ = getHealthService();
        if (!health_) {
            LOG(ERROR) << "Failed to get Health HAL";
            return;
        }

        // 注册死亡通知
        auto binder = health_->asBinder();
        AIBinder_linkToDeath(binder.get(), death_recipient_.get(), this);
    }

    static void onServiceDied(void* cookie) {
        auto* manager = static_cast<HealthServiceManager*>(cookie);
        LOG(WARNING) << "Health HAL died, reconnecting...";

        // 等待100ms后重连
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        manager->connectService();
    }
};

Q5: AIDL的性能与直接Binder调用相比如何?

A: 性能差异在5%以内(主要是代码生成的轻微开销):

方式延迟(中位数)吞吐量
直接Binder100μs10k ops/s
AIDL (C++)105μs9.5k ops/s
AIDL (Java)120μs8.3k ops/s

结论:AIDL的抽象带来的开销可以忽略,应优先使用AIDL以获得更好的维护性。


Android 15新特性:AIDL生态的升级

1. Rust Backend支持

Android 15的AIDL编译器新增Rust语言支持:

# 生成Rust绑定
aidl_interface {
    name: "android.hardware.health",
    backend: {
        rust: {
            enabled: true,
        },
    },
}

生成的Rust代码(简化):

// 自动生成的 IHealth.rs
pub trait IHealth: binder::Interface {
    fn get_capacity(&self) -> binder::Result<i32>;
    fn get_health_info(&self) -> binder::Result<HealthInfo>;
}

impl IHealth for BpHealth {
    fn get_capacity(&self) -> binder::Result<i32> {
        let mut reply = self.binder.transact(TRANSACTION_getCapacity, 0)?;
        reply.read()
    }
}

2. VINTF强制验证

Android 15要求所有Stable AIDL HAL声明VINTF稳定性:

@VintfStability  // ← 必须添加
interface IHealth {
    // ...
}

同时需要在vintf目录添加清单文件:

<!-- hardware/interfaces/health/aidl/vintf/android.hardware.health-service.xml -->
<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>android.hardware.health</name>
        <version>2</version>
        <interface>
            <name>IHealth</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>

3. Lazy HAL支持

按需启动HAL服务,节省内存:

// main.cpp (Lazy启动)
int main() {
    auto health = ndk::SharedRefBase::make<Health>("default", ...);

    // 使用LazyServiceRegistrar代替直接注册
    auto registrar = ndk::LazyServiceRegistrar::getInstance();
    registrar.registerService(health->asBinder().get(),
                               instance.c_str());

    // 当无客户端连接时,服务会自动退出
    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;
}

优势:

  • 待机状态下,未使用的HAL不占用内存
  • 首次调用时自动启动(100ms延迟)
  • 适用于低频使用的HAL(如NFC、IR)

实战案例:创建自定义AIDL HAL

假设我们要为智能座舱系统添加一个"氛围灯控制"HAL。

1. 定义AIDL接口

// hardware/interfaces/ambientlight/aidl/android/hardware/ambientlight/IAmbientLight.aidl
package android.hardware.ambientlight;

import android.hardware.ambientlight.LightZone;
import android.hardware.ambientlight.RgbColor;

@VintfStability
interface IAmbientLight {
    /**
     * 设置指定区域的颜色
     * @param zone 灯光区域(前排/后排/氛围带)
     * @param color RGB颜色值
     */
    void setColor(in LightZone zone, in RgbColor color);

    /**
     * 设置亮度(0-100)
     */
    void setBrightness(int brightness);

    /**
     * 启用/禁用呼吸灯效果
     */
    void setBreathingMode(boolean enabled);
}
// RgbColor.aidl
package android.hardware.ambientlight;

parcelable RgbColor {
    int red;    // 0-255
    int green;  // 0-255
    int blue;   // 0-255
}
// LightZone.aidl
package android.hardware.ambientlight;

@Backing(type="int")
enum LightZone {
    FRONT_DASHBOARD = 0,
    REAR_SEATS = 1,
    DOOR_AMBIENT = 2,
}

2. 添加构建配置

# hardware/interfaces/ambientlight/aidl/Android.bp
aidl_interface {
    name: "android.hardware.ambientlight",
    vendor_available: true,
    srcs: ["android/hardware/ambientlight/*.aidl"],
    stability: "vintf",
    backend: {
        java: {
            sdk_version: "module_current",
        },
        cpp: {
            enabled: true,
        },
        rust: {
            enabled: true,
        },
    },
    versions_with_info: [
        {
            version: "1",
            imports: [],
        },
    ],
}

3. 实现HAL服务

// hardware/interfaces/ambientlight/aidl/default/AmbientLight.h
#pragma once

#include <aidl/android/hardware/ambientlight/BnAmbientLight.h>

namespace aidl::android::hardware::ambientlight {

class AmbientLight : public BnAmbientLight {
public:
    ndk::ScopedAStatus setColor(LightZone zone, const RgbColor& color) override;
    ndk::ScopedAStatus setBrightness(int32_t brightness) override;
    ndk::ScopedAStatus setBreathingMode(bool enabled) override;

private:
    void writeToHardware(LightZone zone, const RgbColor& color, int brightness);
};

}  // namespace
// AmbientLight.cpp
ndk::ScopedAStatus AmbientLight::setColor(LightZone zone, const RgbColor& color) {
    if (color.red < 0 || color.red > 255) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }

    // 写入硬件寄存器或通过CAN总线发送
    writeToHardware(zone, color, current_brightness_);

    return ndk::ScopedAStatus::ok();
}

void AmbientLight::writeToHardware(LightZone zone, const RgbColor& color, int brightness) {
    // 伪代码:实际应通过SPI/I2C/CAN与硬件通信
    int led_controller_fd = open("/dev/led_controller", O_RDWR);

    struct led_command {
        uint8_t zone;
        uint8_t r, g, b;
        uint8_t brightness;
    } cmd = {
        .zone = static_cast<uint8_t>(zone),
        .r = static_cast<uint8_t>(color.red),
        .g = static_cast<uint8_t>(color.green),
        .b = static_cast<uint8_t>(color.blue),
        .brightness = static_cast<uint8_t>(brightness),
    };

    write(led_controller_fd, &cmd, sizeof(cmd));
    close(led_controller_fd);
}

4. 注册服务

// main.cpp
int main() {
    auto ambient_light = ndk::SharedRefBase::make<AmbientLight>();

    const std::string instance = std::string(IAmbientLight::descriptor) + "/default";
    auto status = AServiceManager_addService(ambient_light->asBinder().get(),
                                             instance.c_str());
    CHECK(status == STATUS_OK) << "Failed to register AmbientLight HAL";

    ABinderProcess_setThreadPoolMaxThreadCount(4);
    ABinderProcess_startThreadPool();
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;
}

5. 客户端调用

Native客户端:

#include <android/hardware/ambientlight/IAmbientLight.h>

using aidl::android::hardware::ambientlight::IAmbientLight;
using aidl::android::hardware::ambientlight::RgbColor;
using aidl::android::hardware::ambientlight::LightZone;

void setAmbientLightColor() {
    // 获取HAL服务
    const std::string instance = std::string(IAmbientLight::descriptor) + "/default";
    auto binder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
    auto light = IAmbientLight::fromBinder(binder);

    if (!light) {
        LOG(ERROR) << "Failed to get AmbientLight HAL";
        return;
    }

    // 设置前排仪表台为蓝色
    RgbColor blue{.red = 0, .green = 0, .blue = 255};
    auto status = light->setColor(LightZone::FRONT_DASHBOARD, blue);

    if (!status.isOk()) {
        LOG(ERROR) << "setColor failed: " << status.getDescription();
    }
}

Java客户端(Framework层):

import android.hardware.ambientlight.IAmbientLight;
import android.hardware.ambientlight.RgbColor;
import android.hardware.ambientlight.LightZone;
import android.os.ServiceManager;

public class AmbientLightManager {
    private IAmbientLight mService;

    public AmbientLightManager() {
        try {
            mService = IAmbientLight.Stub.asInterface(
                ServiceManager.waitForService("android.hardware.ambientlight.IAmbientLight/default")
            );
        } catch (Exception e) {
            Log.e(TAG, "Failed to get AmbientLight service", e);
        }
    }

    public void setFrontColor(int r, int g, int b) {
        RgbColor color = new RgbColor();
        color.red = r;
        color.green = g;
        color.blue = b;

        try {
            mService.setColor(LightZone.FRONT_DASHBOARD, color);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to set color", e);
        }
    }
}

总结

本文深入分析了AIDL和HIDL在Android 15中的应用,涵盖了从接口定义到HAL服务实现的完整流程。

核心要点回顾:

  1. AIDL vs HIDL:

    • HIDL正在退役,新项目使用Stable AIDL
    • Stable AIDL通过版本冻结实现向后兼容
    • Android 15全面支持Rust AIDL Backend
  2. HAL服务开发:

    • 继承BnXXX实现服务端
    • 通过AServiceManager_addService()注册
    • 使用fromBinder()获取客户端代理
  3. 性能优化:

    • 批量获取数据减少Binder往返
    • 使用oneway实现异步回调
    • 考虑Lazy HAL减少内存占用
  4. 最佳实践:

    • 注册死亡通知防止泄漏
    • 统一错误处理(ScopedAStatus)
    • VINTF清单声明确保兼容性

通过Health HAL和自定义AmbientLight HAL的实战案例,你已经具备了开发AIDL HAL服务的完整能力!


参考资料


系列文章


欢迎来我中的个人主页找到更多有用的知识和有趣的产品