从零搭建 Android AIDL NDK HAL:完整实战与常见构建坑全解析
本文详细介绍了在Android 14中开发AIDL HAL的完整流程。AIDL HAL作为Android硬件抽象层的新标准,相比传统HIDL具有性能更好、API更简洁等优势。文章从创建AIDL接口文件开始,逐步讲解了目录结构规范、接口定义、C++实现类编写、服务注册等关键步骤,并提供了完整的代码示例。重点内容包括:AIDL HAL架构的关键组件、@VintfStability注解的重要性、ndk:
前言
在 Android 系统架构中,硬件抽象层(Hardware Abstraction Layer,HAL)扮演着至关重要的角色。它作为 Android 框架与设备硬件之间的桥梁,使得应用开发者能够通过统一的 API 访问硬件功能,而无需关心底层硬件的具体实现。
随着 Android 版本的演进,Google 不断改进 HAL 的架构。在 Android 11 之后,AIDL(Android Interface Definition Language)HAL 成为 Google 首推的开发方式。相比传统的 HIDL(Hardware Interface Definition Language),AIDL HAL 具有以下优势:
- 更好的性能表现
- 更简洁的 API 设计
- 与 Android 框架更好的集成
- 支持更多编程语言
本文基于 Android 14 源码,通过一个实际的 Cloud HAL 示例,详细讲解 AIDL HAL 的开发流程。
AIDL HAL 架构概述

关键组件
- AIDL 接口文件(.aidl):定义 HAL 的接口规范
- HAL 实现(C++/Java):具体实现硬件功能
- 服务注册:将 HAL 服务注册到系统
- VINTF 清单:描述 HAL 的版本和接口信息
- Init RC 文件:配置服务的启动和权限
AIDL 接口定义
AIDL HAL 完整文件清单
| 文件路径 | 用途 |
|---|---|
| hardware/interfaces/cloud/aidl/Android.bp | 接口构建配置 |
| hardware/interfaces/cloud/aidl/android/hardware/cloud/cloud.aidl | AIDL 接口定义 |
| hardware/interfaces/cloud/aidl/default/Android.bp | 实现构建配置 |
| hardware/interfaces/cloud/aidl/default/cloud.h | C++ 头文件 |
| hardware/interfaces/cloud/aidl/default/cloud.cpp | C++ 实现 |
| hardware/interfaces/cloud/aidl/default/main.cpp | 服务入口 |
| hardware/interfaces/cloud/aidl/default/cloud-default.rc | init 脚本 |
| hardware/interfaces/cloud/aidl/default/cloud-default.xml | VINTF 片段 |
创建目录结构
在 Android 源码树中,AIDL HAL 遵循严格的目录结构规范。根据 Google 官方推荐,我们在 hardware/interfaces/ 下创建相应的目录:
# 创建 AIDL HAL 基础目录结构
mkdir -p hardware/interfaces/cloud/aidl/android/hardware/cloud
mkdir -p hardware/interfaces/cloud/aidl/default
目录结构说明
hardware/interfaces/cloud/
├── aidl/ # AIDL HAL主目录
│ ├── Android.bp # AIDL接口构建文件
│ ├── android/ # AIDL包名路径(映射到Java包名)
│ │ └── hardware/
│ │ └── cloud/
│ │ ├── ICloud.aidl # 主接口定义
│ │ ├── ICloudCallback.aidl # 回调接口
│ │ └── types.aidl # 数据类型定义
│ ├── default/ # HAL默认实现
│ │ ├── Android.bp # 服务构建文件
│ │ ├── Cloud.h # HAL头文件
│ │ ├── Cloud.cpp # HAL实现文件
│ │ ├── main.cpp # 服务入口点
│ │ ├── android.hardware.cloud-service.rc # init rc文件
│ │ └── android.hardware.cloud-service.xml # VINTF清单
│ └── tests/ # 测试代码,这里我们一般用不到
│ └── ... # 单元测试
创建 ICloud.aidl 接口文件
简单提供一个日志打印方法
路径: hardware/interfaces/cloud/aidl/android/hardware/cloud/ICloud.aidl
// package 名称必须与目录结构完全匹配
/**
*
* @VintfStability 是关键注解!它表示这是一个 VINTF(Vendor Interface)稳定接口
* 用于 Framework 和 Vendor 之间的通信
* 标记了这个注解的接口会在设备 manifest 中声明
*/
package android.hardware.cloud;
@VintfStability
interface ICloud {
/**
*
* 简单打印个日志
*/
boolean log(String tag, String msg);
}
创建接口的 Android.bp
主要作用是:创建、编译、版本管理、生成产物、稳定性要求等一系列关于这个 AIDL 接口的规则和约束
路径: hardware/interfaces/cloud/aidl/Android.bp
aidl_interface {
name: "android.hardware.cloud", // 接口名称
stability: "vintf", // 声明为 VINTF 稳定接口
vendor_available: true, // 允许 vendor 模块使用
srcs: [
"android/hardware/cloud/*.aidl", // AIDL 文件路径
],
backend: {
java: {
// 生成 Java 绑定,供 Framework 调用
sdk_version: "system_current",
},
cpp: {
// 也生成 C++ 绑定(可选)
enabled: true,
},
ndk: {
// NDK 绑定用于 vendor C++ 实现
enabled: true,
},
},
}
创建 HAL 默认实现
创建 C++ 头文件 Cloud.h
路径: hardware/interfaces/cloud/aidl/default/Cloud.h
#pragma once
// 引入 AIDL 自动生成的 Bn (Binder Native) 基类
// BnCalculator 是服务端基类,实现了 ICalculator 接口
// 路径格式:aidl/android/hardware/<module>/Bn<Interface>.h
#include <aidl/android/hardware/cloud/BnCloud.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cloud {
/**
* Cloud HAL 实现类
*
* 继承 BnCloud(由 AIDL 编译器自动生成)
* Bn = Binder Native,表示这是服务端(native 端)实现
*
* 对应的客户端代理类是 BpCloud(Binder Proxy)
*/
class Cloud : public BnCloud {
public:
/**
* 实现 log 方法
*
* 返回类型 ndk::ScopedAStatus 用于传递调用状态
* - 成功时返回 ndk::ScopedAStatus::ok()
* - 失败时返回错误码
*
* 实际返回值通过 _aidl_return 指针参数传出
*/
ndk::ScopedAStatus log(const std::string& tag, const std::string& msg, bool* _aidl_return) override;
};
} // namespace cloud
} // namespace hardware
} // namespace android
} // namespace aidl
创建 C++ 实现文件 Cloud.cpp
路径: hardware/interfaces/cloud/aidl/default/Cloud.cpp
#include "Cloud.h"
#include <android/binder_status.h>
#include <android-base/logging.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cloud {
/**
* log 实现
*
* 参数说明:
* - tag, msg: 输入参数(从客户端传入)
* - _aidl_return: 输出参数指针,用于返回结果给客户端
*
* 返回值 ndk::ScopedAStatus 表示调用状态,不是计算结果
*/
ndk::ScopedAStatus Cloud::log(const std::string& tag, const std::string& msg, bool* _aidl_return) {
if (tag.empty() || msg.empty()) { // 如果 tag 或 msg 为空
*_aidl_return = false;
LOG(ERROR) << "tag or msg is empty";
return ndk::ScopedAStatus::fromServiceSpecificError(-EFAULT);
}
// 打印日志
// 实际 HAL 中这里可能调用驱动或读取硬件
LOG(INFO) << "Cloud::log: " << tag << ": " << msg;
*_aidl_return = true;
// 返回成功状态
return ndk::ScopedAStatus::ok();
}
} // namespace cloud
} // namespace hardware
} // namespace android
} // namespace aidl
创建服务入口 main.cpp
#include "Cloud.h"
#include <android/binder_manager.h> // AServiceManager_*
#include <android/binder_process.h> // ABinderProcess_*, ABinderProcess_joinThreadPool
#include <android-base/logging.h>
using aidl::android::hardware::cloud::Cloud;
int main() {
// 设置线程池大小为 0,表示只使用主线程处理请求
// 对于简单 HAL 足够了,复杂 HAL 可以增加线程数
ABinderProcess_setThreadPoolMaxThreadCount(0);
// 创建 Cloud 实例
// 使用 ndk::SharedRefBase::make 来创建,确保引用计数正确
std::shared_ptr<Cloud> cloud = ndk::SharedRefBase::make<Cloud>();
// 构建服务名称
// 格式:<接口描述符>/default
// descriptor 是 AIDL 自动生成的,格式如 "android.hardware.cloud.ICloud"
const std::string instance = std::string(Cloud::descriptor) + "/default";
LOG(INFO) << "Cloud Registering HAL Service: " << instance;
// 将服务注册到 ServiceManager
// 注意:AIDL HAL 使用统一的 ServiceManager(不是 HwServiceManager)
binder_status_t status = AServiceManager_addService(
cloud->asBinder().get(), // 获取底层 Binder 对象
instance.c_str()); // 服务名称
// 检查注册是否成功
if (status != STATUS_OK) {
LOG(ERROR) << "Failed to register: " << status;
return 1;
}
LOG(INFO) << "Cloud HAL Service registered successfully";
// 进入线程池循环,处理来自客户端的请求
// 这个调用会阻塞,直到进程被终止
ABinderProcess_joinThreadPool();
// 正常情况下不会执行到这里
return EXIT_FAILURE;
}
创建实现的 Android.bp
与 AIDL 的 bp文件类似,一些规则和约束
路径: hardware/interfaces/cloud/aidl/default/Android.bp
cc_binary {
name: "android.hardware.cloud-service",
vendor: true, // 标记为 vendor 代码
relative_install_path: "hw", // 安装到 /vendor/bin/hw/
init_rc: ["cloud-default.rc"], // 服务启动脚本
vintf_fragments: ["cloud-default.xml"], // VINTF 声明
srcs: [
"Cloud.cpp",
"main.cpp",
],
shared_libs: [
"libbase", // Android 基础库(日志等)
"android.hardware.cloud-V1-ndk", // AIDL 生成的 NDK 库(版本1)
"libbinder_ndk", // NDK Binder 库
],
}
创建 init 脚本
告诉 Android 的 init 进程在系统启动时自动启动我们创建的 HAL 服务可执行文件。
路径: hardware/interfaces/cloud/aidl/default/cloud-default.rc
# vendor.cloud 服务的名字(自定义,但要唯一
# /vendor/bin/hw/android.hardware.cloud-service )要执行的可执行文件的完整路径
service vendor.cloud /vendor/bin/hw/android.hardware.cloud-service )
class hal # 声明一个要由 init 启动的服务(进程)指定这个服务属于哪个启动类(class)
user system # 服务以 system 用户 身份运行(uid=1000)
group system # 服务所属的 system 组(gid=1000)
# rc 文件在整个流程中的位置
设备开机
↓
init 进程启动
↓
读取 /vendor/etc/init/ 目录下的所有 .rc 文件
↓
看到 class hal 的服务
↓
在 HAL 启动阶段 fork + exec /vendor/bin/hw/android.hardware.calculator-service
↓
服务进程运行 main() → 注册 binder 服务(AServiceManager_addService)
↓
服务进入 ABinderProcess_joinThreadPool() 等待请求
↓
Framework 层可以通过 ServiceManager 找到并调用这个服务
创建 VINTF 片段
vendor 声明
type="device"表示vendor 侧的声明,告诉系统这个设备实现了 android.hardware.cloud@1 接口,并且提供了 ICloud/default 实例
路径: hardware/interfaces/cloud/aidl/default/cloud-default.xml
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.calculator</name>
<version>1</version>
<fqname>ICalculator/default</fqname>
</hal>
</manifest>
Framework 声明
type=“framework” 表示 framework 层要求或支持 android.hardware.calculator@1 接口,接口名为 ICalculator,默认实例是 default,同时optional=“true” 表示这个 HAL 是可选的,没有实现也不会导致兼容性失败(设备可以不提供这个 HAL)
<compatibility-matrix version="1.0" type="framework"> #
<hal format="aidl" optional="true">
<name>android.hardware.cloud</name>
<version>1</version>
<interface>
<name>ICloud</name>
<instance>default</instance>
</interface>
</hal>
</compatibility-matrix>
配置 HAL
在 device.mk 中添加
# 添加 Calculator HAL
PRODUCT_PACKAGES += \
android.hardware.cloud-service
配置SELinux
要想 HAL 模块运行起来,SELinux 是必不可少的,否则Permissive mode 与 Enforcing mode都存在被拒绝的风险。
SELinux 配置清单
| 文件 | 用途 |
|---|---|
| hal_cloud.te | 定义 HAL 进程域 |
| service.te | 定义服务类型 |
| service_contexts | 绑定 AIDL 服务名 |
| file_contexts | 绑定可执行文件 |
| system_server | 允许 system_server 查找和调用 |
创建 hal_cloud.te
为当前 HAL 模块自定义一个 SELinux 域,主要作用如下:
- 定义一个 hal_cloud_default 进程域
- 运行被 init 启动
- 使用 binder 与 system_server
- 向 servicemanager 注册 HAL 服务
完整内容:
# 定义 Calculator HAL 进程域
type hal_cloud_default, domain;
# 定义可执行文件类型
type hal_cloud_default_exec, exec_type, vendor_file_type, file_type;
# 允许 init 启动此域,注意:可执行文件最好以*_exe结尾,init_daemon_domain宏是根据命名规则自动推导 *_exec 的
init_daemon_domain(hal_cloud_default)
# AIDL HAL 使用普通 binder
binder_use(hal_cloud_default)
# 允许向 servicemanager 注册服务
add_service(hal_cloud_default, hal_cloud_service)
# 允许被 system_server 调用
binder_call(hal_cloud_default, system_server)
修改 service.te
添加服务类型定义,对应hal_cloud.te 中 add_service(hal_cloud_default, hal_cloud_service) 表示允许hal_cloud_default向ServiceManager注册类型为hal_calculator_service的服务
# Cloud HAL 服务类型
type hal_cloud_service, service_manager_type;
修改 service_contexts
将service.te 定义的类型与 AIDL 服务名绑定起来
android.hardware.cloud.ICloud/default u:object_r:hal_cloud_service:s0
修改 file_contexts
这里作用比较简单就是为 HAL 的文件打 SELinux 标签
/(vendor|system/vendor)/bin/hw/android\.hardware\.cloud-service u:object_r:hal_cloud_default_exec:s0
system_server
当我们在 framework 获取当前服务时就需要配置规则否则会被拒,下面规则意思是允许 system_server 向 servicemanager 查询(find)名为 Cloud HAL 的服务
# 允许 system_server 查找和调用 Cloud HAL
allow system_server hal_cloud_service:service_manager find;
binder_call(system_server, hal_cloud_default)
编译HAL模块
第一次我们需要完整从零构建,需要执行以下命令生成对应的文件后才可编译完成 AOSP 进行测试
# 步骤 1:清理旧状态(防止干扰)
rm -rf hardware/interfaces/cloud/aidl/android/hardware/cloud/aidl_api/
# 步骤 2:第一次生成版本 1(冻结接口)
m android.hardware.cloud-freeze-api
# 步骤 3:如果后续修改接口,再更新 current
m android.hardware.cloud-update-api
# 步骤 4:构建 AIDL 接口模块
m android.hardware.cloud
# 步骤 5:构建 HAL 服务可执行文件
m android.hardware.cloud-service
测试
选择云手机常修改的TelephonyManager的getNetworkOperatorName方法作为测试锚点,然后定义initCloudHal和testCloudHal分别用于获取服务和调用方法打印日志。
路径:frameworks/base/telephony/java/android/telephony/TelephonyManager.java
更新 Android.bp
由于我们是在framework 层调用 HAL,需要将相应的模块加入 libs 中否则会报错提示找不到相关文件
以 Server 的 bp为例:frameworks/base/services/core/Android.bp,先说明系统模块名称怎么生成,再说怎么配置模块。
AIDL Java 库命名规则
命名格式为:
<aidl_interface的name字段>-V<版本号>-<后端类型>
以我们的 AIDL bp文件为例:
| Android.bp 中的定义 | 生成的库名称 |
|---|---|
| name: “android.hardware.cloud” | 基础名 |
| versions_with_info: [{version: “1”}] | 版本号 V1 |
组合后按不同后端生成:
| 后端 | 库名称 | 用途 |
|---|---|---|
| Java | android.hardware.cloud-V1-java | Framework Java 层调用 |
| C++ | android.hardware.cloud-V1-cpp | Framework C++ 层调用 |
| NDK | android.hardware.cloud-V1-ndk | Vendor C++ 实现 |
| 如果不想生成 cpp后端,可以在 AIDL 的 bp中将 enabled 设置成 false 即可 |
backend: {
java: {
sdk_version: "system_current",
},
cpp: {
enabled: false,// 修改这里即可
},
ndk: {
enabled: true,
},
},
配置 Cloud Java 模块
libs: [
"android.hardware.cloud-V1-java",
]
static_libs: [
"android.hardware.cloud-V1-java",
]
TelephonyManager.java 加入以下代码:
// 导入 HAL 模块在 Java 层的路径
import android.hardware.cloud.ICloud;
// 常量化服务名称,方便获取服务
private static final String CLOUD_HAL_SERVICE = "android.hardware.cloud.ICloud/default";
// HAL 的 本地Binder 代理
private ICloud mCloud;
private void initCloudHal() {
try {
// 通过 ServiceManager 获取 HAL 服务
// waitForService 会阻塞等待服务可用
IBinder binder = ServiceManager.waitForService(CLOUD_HAL_SERVICE);
if (binder != null) {
// 将 IBinder 转换为 ICalculator 接口
// Stub.asInterface 会返回本地或远程代理
mCloud = ICloud.Stub.asInterface(binder);
Log.i(TAG, "Cloud HAL 初始化成功!");
} else {
Log.e(TAG, "Cloud HAL 服务不可用");
}
} catch (Exception e) {
Log.e(TAG, "获取 Cloud HAL 时发生异常", e);
}
}
private void testCloudHal() {
if (mCloud == null) {
Log.e(TAG, "Cloud HAL 未初始化");
return;
}
try {
// 调用 HAL 的 add 方法
// 调用会通过 Binder 传递到 vendor 进程中的 HAL 服务
boolean result = mCloud.log("cloud_hal", "test cloud hal");
Log.i(TAG, "HAL log测试: " + result);
} catch (RemoteException e) {
Log.e(TAG, "调用 Cloud HAL 失败", e);
}
}
结果
framework 层调用 HAL 成功!
参考资料
硬件抽象层(HAL)
稳定型 AIDL
Makefile Google 官方教程
Android SELinux权限概念和配置说明
SElinux 官方资料
更多推荐


所有评论(0)