Android AIDL HAL工程结构示例

📁 顶层目录

复制代码
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::StubBnHello),HelloTest 需要继承它并覆写纯虚函数。

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

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

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

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

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

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

  • 方便扩展 :如果后续要支持多个接口实现(比如一个服务同时实现 IHelloIGoodbye),可以在 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/) 三层。客户端代码引用了不同接口名,属于还没对齐的中间状态,不影响理解整体架构。

相关推荐
赏金术士1 天前
Compose 教学项目
android·kotlin·compose
晓梦林1 天前
ximai靶场学习笔记
android·笔记·学习
十六年开源服务商1 天前
2026服务器配置优化与WordPress运维实战指南
android·运维·服务器
音视频牛哥1 天前
大牛直播SDK(SmartMediaKit)Android平台Unity3D RTSP/RTMP播放器集成实践
android·unity3d·rtsp播放器·rtmp播放器·unity3d rtmp播放器·安卓unity rtsp播放器·安卓unity rtmp播放器
w1wi1 天前
安卓抓包完全指南(一):从入门到 SSL Pinning 绕过
android·网络协议·ssl
aqi001 天前
一文理清 HarmonyOS 6.0.2 涵盖的十个升级点
android·华为·harmonyos·鸿蒙·harmony
赏金术士1 天前
Jetpack Compose 状态提升(State Hoisting)完全指南
android·kotlin·compose
BoomHe1 天前
git Rebase 为任意一笔提交补上 Change-Id
android·git·android studio
TDengine (老段)1 天前
TDengine 超级表/子表/普通表 — 设计理念与内部表示
android·大数据·数据库·物联网·时序数据库·tdengine·涛思数据