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/) 三层。客户端代码引用了不同接口名,属于还没对齐的中间状态,不影响理解整体架构。

相关推荐
y = xⁿ2 小时前
MySQL八股知识合集
android·mysql·adb
andr_gale3 小时前
04_rc文件语法规则
android·framework·aosp
祖国的好青年4 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴4 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭5 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首5 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil6 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙6 小时前
echarts,3d堆叠图
android·3d·echarts