📁 顶层目录

testtld/
├── aidl/              ← ① AIDL 接口定义 + 服务端实现
└── test_aidl_hal/     ← ② 客户端测试程序

① aidl/ — 接口定义 + 服务端

这是最核心的部分,Android HAL 的 "三层结构" 都在这里:

第 1 层:AIDL 接口定义

aidl/
├── Android.bp                              ← 构建配置:定义 aidl_interface
└── android/hardware/testtld/
    └── IHelloTest.aidl                     ← ★ 接口定义文件

IHelloTest.aidl 定义了服务接口:

@VintfStability
interface IHelloTest {
    int getTestOne(int event, String name);
}

关键点:@VintfStability 表示这是稳定的 Vendor 接口,Android 框架会对其做版本冻结管理。

aidl/Android.bp 把这个接口注册为 android.hardware.testtld,并声明它支持 VINTF、生成 C++/NDK/Java 三种后端代码。frozen: true 表示版本 1 已冻结。

第 1.5 层:API 快照(版本控制)

aidl/aidl_api/
├── android.hardware.testtld/1/...     ← 版本 1 的 frozen API 副本
└── android.hardware.testtld/current/... ← 当前开发中的最新版本

Android 的 aidl_interface 编译时自动生成,用来做接口兼容性检查。你改了 .aidl 文件之后,编译系统会对比 current/ 和已冻结版本,防止破坏兼容性。

第 2 层:服务端实现(default/

aidl/default/
├── Android.bp              ← 构建配置:编译成 cc_binary 服务程序
├── HelloTest.h             ← IHelloTest 的实现类声明
├── HelloTest.cpp           ← IHelloTest 的实现类代码
├── service.cpp             ← ★ 服务入口:main(),注册服务到 vndbinder
├── HelloTest-default.rc    ← init.rc 脚本(开机自启)
└── HelloTest-default.xml   ← VINTF manifest 片段(声明设备有这个 HAL)

各文件的作用:

HelloTest.h/cpp 继承 BnHelloTest,实现 getTestOne() 方法。当前实现就打了个 log,返回 2。
service.cpp 服务进程入口。用 initWithDriver("/dev/vndbinder") 注册到 vendor binder,然后 AServiceManager_addService() 把服务暴露出去,最后 joinThreadPool() 等待请求。
HelloTest-default.rc Android init 脚本,告诉系统开机时启动这个服务(class hal
HelloTest-default.xml VINTF manifest,声明本设备实现了 android.hardware.testtld HAL v1,FQName 是 IHelloTest/default,没有它,系统就不知道 testtld-service 是合法的 HAL
Android.bp 把 service.cpp + HelloTest.cpp 编译成 android.hardware.testtld-service,依赖 android.hardware.testtld-V1-ndk(由上层 aidl_interface 生成的 NDK 绑定库)

为什么要有HelloTest.h/cpp还要有service.cpp:

1. service.cpp —— 服务进程的入口

它是整个 HAL 服务的启动器和注册器,负责把一个可执行程序变成系统服务。

  • 启动 Binder 线程池:通过 ABinderProcess_setThreadPoolMaxThreadCount() 和 ABinderProcess_startThreadPool() 初始化 Binder 通信环境。

  • 创建服务实例:使用 HelloTest 类(或其他实现类)实例化一个服务对象(通常 ndk::SharedRefBase::make<HelloTest>())。

  • 注册到 ServiceManager:调用 AServiceManager_addService(),把实例和一个服务名(如 "vendor.hello.test.IHello/default")绑定,让客户端能通过名字找到它。

  • 进入循环等待:调用 ABinderProcess_joinThreadPool() 阻塞等待请求。

没有 service.cpp,服务只是一堆代码,无法独立运行,也无法被系统识别和调用。

2. HelloTest.h/cpp —— 接口的具体实现

这是业务逻辑的核心,实现了 AIDL 接口定义的方法。

  • 继承生成的 Stub 类:AIDL 工具会根据 .aidl 文件生成一个抽象类(如 IHello::Stub 或 BnHello),HelloTest 需要继承它并覆写纯虚函数。

  • 编写实际功能:比如 sayHello() 方法里返回一段字符串,或者操作硬件设备。

  • 与 service.cpp 解耦service.cpp 不关心具体怎么实现,只创建 HelloTest 对象并注册;将来如果想替换实现,只需修改 HelloTest.cpp 而无需动服务入口代码。

3. 为什么不能合成一个文件?

当然可以写成单文件,但分开的好处是:

  • 符合单一职责原则:服务注册(进程管理)和业务实现分离,代码更清晰。

  • 便于测试:可以对 HelloTest 类单独做单元测试,而不需要启动完整的服务进程。

  • 方便扩展:如果后续要支持多个接口实现(比如一个服务同时实现 IHello 和 IGoodbye),可以在 service.cpp 里注册多个实例,而实现分散在不同文件中。

  • 框架推荐:Android 官方 HAL 模板(如 hardware/interfaces 下的参考实现)基本都是这种结构。

② test_aidl_hal/ — 客户端测试

test_aidl_hal/
├── Android.bp    ← 构建 cc_binary: test_aidl_hal
└── main.cpp      ← 客户端代码

main.cpp 是服务的消费者,流程:

  1. 通过 AServiceManager_getService() 查找已注册的服务
  2. 拿到 IHelloHal 的 binder 代理
  3. 调用 service->hello_write("hello")

🔗 整体调用链路

┌─────────────────────────────────────────────────┐
│  客户端程序 (test_aidl_hal)                       │
│  main.cpp → AServiceManager_getService()         │
│           → IHelloTest::fromBinder()             │
│           → getTestOne()                          │
└────────────────────┬────────────────────────────┘
                     │ vendor binder (/dev/vndbinder)
                     ▼
┌─────────────────────────────────────────────────┐
│  服务程序 (android.hardware.testtld-service)     │
│  service.cpp → AServiceManager_addService()      │
│              → ABinderProcess_joinThreadPool()   │
│  HelloTest.cpp → getTestOne() 具体处理            │
└─────────────────────────────────────────────────┘

一句话总结

这是一个 Android HAL 的 Hello World,展示了:

  1. 用 AIDL 定义一个带 @VintfStability 的硬件接口
  2. 用 C++ 实现服务端,注册到 vendor binder
  3. 写 init.rc + VINTF manifest 让系统自动拉起服务
  4. 写客户端通过 binder 远程调用

结构本身很标准,就是 接口定义(Android.bp + .aidl) → 服务实现(default/) → 客户端(test_aidl_hal/) 三层。客户端代码引用了不同接口名,属于还没对齐的中间状态,不影响理解整体架构。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐