前言

在 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 架构概述

在这里插入图片描述

关键组件

  1. AIDL 接口文件(.aidl):定义 HAL 的接口规范
  2. HAL 实现(C++/Java):具体实现硬件功能
  3. 服务注册:将 HAL 服务注册到系统
  4. VINTF 清单:描述 HAL 的版本和接口信息
  5. 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.teadd_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

测试

选择云手机常修改的TelephonyManagergetNetworkOperatorName方法作为测试锚点,然后定义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 官方资料

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐