AIDL Hal 开发笔记5----实现AIDL HAL

目录

  • [一、AIDL 文件编写](#一、AIDL 文件编写)
    • [1.1 生成 current 目录](#1.1 生成 current 目录)
    • [1.2 冻结 API 生成版本 1](#1.2 冻结 API 生成版本 1)
    • [1.3 冻结成功后,更新 Android.bp 并最终编译](#1.3 冻结成功后,更新 Android.bp 并最终编译)
  • 二、服务端
  • 三、客户端
  • 四、Selinux
    • [4.1 `file_contexts`](#4.1 file_contexts)
    • [4.2 `service_contexts`](#4.2 service_contexts)
    • [4.3 `service.te`](#4.3 service.te)
    • [4.3 `hal_hello.te`](#4.3 hal_hello.te)
  • 五、编译执行

|----------------|
| 实现AIDL HAL |

写一个简单的 AIDL HAL 模块

一、AIDL 文件编写

首先,在 hardware/interfaces/ 路径下创建 aidl hal 项目目录:

c 复制代码
cd hardware/interfaces
mkdir hello_aidl_hal
cd hello_aidl_hal
mkdir -p aidl/android/hardware/hello

接着我们在 hardware/interfaces/hello_aidl_hal/aidl/android/hardware/hello 目录下创建 IHello.aidl 文件:

c 复制代码
// hardware/interfaces/hello_aidl_hal/aidl/android/hardware/hello/IHello.aidl
package android.hardware.hello;

@VintfStability 
interface IHello {
    void hello_write(String str);
    String hello_read();
}

接着编写最外层的 Android.bp

c 复制代码
// hardware/interfaces/hello_aidl_hal/aidl/Android.bp
aidl_interface {
    name: "android.hardware.hello", //AIDL包名,和.aidl的package一致
    vendor_available: true, //HAL层接口,开启vendor分区可用
    srcs: ["android/hardware/hello/*.aidl"], //aidl文件路径
    stability: "vintf", //VINTF稳定性校验
    //unstable: true,  // 临时绕过冻结要求
    owner: "henry", //模块归属
    backend: { //按需开启/关闭后端语言
        cpp: {
            enabled: false, // 不需要C++层则关闭
        },
        java: {
            sdk_version: "module_current", //Java层必开
        },
        ndk: {
            vndk: { // 关闭VNDK,编译系统会生成带_platform后缀的库
                enabled: false,
            },
        },
    },
    //versions: ["1"],
}

aidl 会生成
java c++ ndk rust 四种库,一般 java 和 ndk 使用会比较多。这部分内容的细节可以在 backend 中配置。

接着就可以编译了:

c 复制代码
mmm hardware/interfaces/hello_aidl_hal/

报错:

c 复制代码
[ 79% 274/346] echo "API dump for the current version of AIDL interface android.hardware.hello does not exist." && echo Run "m android.hardware.hello-update-api", or add 
FAILED: out/soong/.intermediates/hardware/interfaces/hello_aidl_hal/aidl/android.hardware.hello-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface android.hardware.hello does not exist." && echo Run "m android.hardware.hello-update-api", or add "unstable: true" to the build rule for the interface if it does not need to be versioned && false # hash of input list: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
API dump for the current version of AIDL interface android.hardware.hello does not exist.
Run m android.hardware.hello-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned
16:38:19 ninja failed with: exit status 1

#### failed to build some targets (04:03 (mm:ss)) ####

1.1 生成 current 目录

按提示执行如下命令,更新当前 API dump(生成 current 目录)

c 复制代码
m android.hardware.hello-update-api   

执行完成后,生成的代码结构如下:

c 复制代码
/hardware/interfaces/hello_aidl_hal$ tree
.
└── aidl
    ├── aidl_api
    │   └── android.hardware.hello
    │       └── current
    │           └── android
    │               └── hardware
    │                   └── hello
    │                       └── IHello.aidl
    ├── android
    │   └── hardware
    │       └── hello
    │           └── IHello.aidl
    └── Android.bp

10 directories, 3 files

接着再编译:

c 复制代码
mmm hardware/interfaces/hello_aidl_hal/

执行完成后,就会在 out/soong/.intermediates/hardware/interfaces/hello_aidl_hal/aidl 目录下生成一下的一堆库:

c 复制代码
android.hardware.hello-api        android.hardware.hello-V1-java-source 
android.hardware.hello_interface  android.hardware.hello-V1-ndk
android.hardware.hello-V1-java    android.hardware.hello-V1-ndk-source

1.2 冻结 API 生成版本 1

c 复制代码
m android.hardware.hello-freeze-api

这会自动检测当前 API,并创建 aidl_api/android.hardware.hello/1/ 目录(如果有变化,可能生成版本 2)。如果提示 "no changes detected",它可能会保持当前状态或提示你确认

c 复制代码
......
[100% 262/262] //hardware/interfaces/hello_aidl_hal/aidl:android.hardware.hello-api Making AIDL API of android.hardware.hello as version 1

#### build completed successfully (02:22 (mm:ss)) ####

执行完成后,生成的代码结构如下:

c 复制代码
├── aidl
│   ├── aidl_api
│   │   └── android.hardware.hello
│   │       ├── 1
│   │       │   └── android
│   │       │       └── hardware
│   │       │           └── hello
│   │       │               └── IHello.aidl
│   │       └── current
│   │           └── android
│   │               └── hardware
│   │                   └── hello
│   │                       └── IHello.aidl
│   ├── android
│   │   └── hardware
│   │       └── hello
│   │           └── IHello.aidl
│   ├── Android.bp

1.3 冻结成功后,更新 Android.bp 并最终编译

编辑文件:取消 versions: ["1"], 的注释

移除 owner: "xuejie",(可选,但在 REL 版本下建议保留以避免未来问题)。

我的系统使用完 冻结命令m android.hardware.hello-freeze-api后Android.bp已经自动更新,新增了 versions: ["1"],

为什么这样操作?

REL 版本(PLATFORM_VERSION_CODENAME=REL)要求 AIDL 接口必须冻结(versions 非空)或有 owner。直接加 versions 但路径不存在会报错,所以先用 owner 建起环境,再冻结生成路径,最后加回 versions。

如果没有自动更新Andoid.bp,需要自己手动修改后再编译一下

c 复制代码
mmm hardware/interfaces/hello_aidl_hal/

后面就可以在客户端、服务端使用NDK 绑定库android.hardware.hello-V1-ndk_platform

也可以说是接口库:具体来说,是 AIDL 接口的 NDK 绑定库。它提供了 C++ 头文件(如 BnHello.h、BpHello.h、IHello.h)和实现代码,用于实现 HAL 的客户端(proxy)和服务器端(stub)。 后面的HAL 服务( HelloHalImpl.cpp)会链接这个库来实现 IHello 接口的功能。

客户端侧:BpHello(Binder Proxy)用于上层(如框架或 app)调用 HAL。

服务器侧:BnHello(Binder Native)用于 HAL 实现响应调用。


二、服务端

接下来新建目录 hardware/interfaces/hello_aidl_hal/aidl/default

新建如下文件
hardware/interfaces/hello_aidl_hal/aidl/default/HelloHalImpl.h ,实现如下

c 复制代码
#ifndef ANDROID_HARDWARE_HELLO_H
#define ANDROID_HARDWARE_HELLO_H

#include <aidl/android/hardware/hello/BnHello.h>

namespace aidl::android::hardware::hello {

class HelloHalImpl : public BnHello {
  public:
        ::ndk::ScopedAStatus hello_write(const std::string& in_str) override;

        ::ndk::ScopedAStatus hello_read(std::string* _aidl_return) override;
};

}

#endif

hardware/interfaces/hello_aidl_hal/aidl/default/HelloHalImpl.cpp,实现如下:

c 复制代码
#define LOG_TAG "HelloHalImpl"
#define LOG_NDEBUG 0

#include "HelloHalImpl.h"

#include <log/log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

namespace aidl::android::hardware::hello {


::ndk::ScopedAStatus HelloHalImpl::hello_write(const std::string& in_str) {
    ALOGD("write %s", in_str.c_str());
    int fd;
    int len = in_str.size();
        fd = open("/dev/hello", O_RDWR);
    write(fd, in_str.c_str(), len);
    close(fd);
    return ::ndk::ScopedAStatus::ok();
}

::ndk::ScopedAStatus HelloHalImpl::hello_read(std::string* _aidl_return)  {

    int fd;
    char buf[1024];
        fd = open("/dev/hello", O_RDWR);
    read(fd, buf, 1024);
    *_aidl_return = buf;
    return ::ndk::ScopedAStatus::ok();
}

}

可以看出,这里的 HelloHalImpl 就是 binder 服务端类的具体实现。

接着写一个主程序,来注册这个 binder 服务:

hardware/interfaces/hello_aidl_hal/aidl/default/main.cpp

c 复制代码
#include "HelloHalImpl.h"
#define LOG_TAG "HelloHalImpl"
#define LOG_NDEBUG 0
#include <iostream>

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <stdio.h>
#include <log/log.h>

using aidl::android::hardware::hello::HelloHalImpl;

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    std::shared_ptr<HelloHalImpl> hello = ::ndk::SharedRefBase::make<HelloHalImpl>();

    const std::string instance = std::string() + HelloHalImpl::descriptor + "/default";

    ALOGD("HelloHalImpl instance =%s  sde =%p \n", instance.c_str(), hello->asBinder().get());

    binder_status_t status =
          AServiceManager_addService(hello->asBinder().get(), instance.c_str());

    CHECK_EQ(status, STATUS_OK);
    ALOGD("HelloHalImpl AServiceManager_addService status=%d \n", status);

    fflush(stdout);
    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}

接着还要写一个 hal 的 vintf:

hardware/interfaces/hello_aidl_hal/aidl/default/hellohal-default.xml

c 复制代码
<manifest version="1.0" type="device">
    <hal format="aidl" optional="true">
        <name>android.hardware.hello</name>
        <version>1</version>
        <interface>
        	<name>IHello</name>
        	<instance>default</instance>
    	</interface>
    </hal>
</manifest>

需要开机启动,添加:

hardware/interfaces/hello_aidl_hal/aidl/default/android.hardware.hello.rc

c 复制代码
service vendor_hello_aidl_service  /vendor/bin/hw/android.hardware.hello.example
        class hal
        user system
        group system
        interface aidl android.hardware.hello.IHello/default

接着编写 hardware/interfaces/hello_aidl_hal/aidl/default/Android.bp

c 复制代码
cc_binary {
    name: "android.hardware.hello.example",
    relative_install_path: "hw",
    vendor: true,
    init_rc: ["android.hardware.hello.rc"],
    vintf_fragments: ["hellohal-default.xml"],
    shared_libs: [
        "android.hardware.hello-V1-ndk_platform",
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
        "HelloHalImpl.cpp",
    ],
}

接着还需要将 hal 加入到兼容性矩阵中:
device/softwinner/ceres/BoardConfig.mk

c 复制代码
git diff softwinner/ceres/BoardConfig.mk
diff --git a/device/softwinner/ceres/BoardConfig.mk b/device/softwinner/ceres/BoardConfig.mk
index ae35c96403..3429d7f0d7 100644
--- a/device/softwinner/ceres/BoardConfig.mk
+++ b/device/softwinner/ceres/BoardConfig.mk
@@ -181,6 +181,8 @@ DEVICE_MANIFEST_FILE += $(PRODUCT_PLATFORM_PATH)/common/system/manifest.xml
 DEVICE_MATRIX_FILE := $(PRODUCT_PLATFORM_PATH)/common/system/compatibility_matrix.xml
 
 DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE := $(PRODUCT_PLATFORM_PATH)/common/system/compatibility_matrix_product.xml
+# 新增:指定设备专属的framework兼容性矩阵文件
+DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := $(PRODUCT_PLATFORM_PATH)/common/system/device_framework_matrix.xml
 
xuejie@vt-PowerEdge-R740:~/A11a133a12/device$ 

device/softwinner/ceres/common/system/device_framework_matrix.xml

c 复制代码
<compatibility-matrix version="1.0" type="framework">
    <hal format="aidl" optional="true">
        <name>android.hardware.hello</name>
        <version>1</version>
        <interface>
            <name>IHello</name> 
            <instance>default</instance>
        </interface>
    </hal>
</compatibility-matrix>

三、客户端

hardware/interfaces/hello_aidl_hal 目录下创建目录 test_aidl_hal并新建如下文件:
hardware/interfaces/hello_aidl_hal/test_aidl_hal/main.cpp

c 复制代码
#define LOG_TAG "Test-HAL"
#define LOG_NDEBUG 0
#include <iostream>

#include <log/log.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <aidl/android/hardware/hello/IHello.h>

#include <stdio.h>
using aidl::android::hardware::hello::IHello;

int main() {
    std::shared_ptr<IHello> service = IHello::fromBinder(ndk::SpAIBinder(AServiceManager_getService("android.hardware.hello.IHello/default")));
    ALOGD("get service = %p\n",service.get());

    if (service == nullptr) {
        return -1;
    }
    service->hello_write("hello");
    fflush(stdout);
    return EXIT_FAILURE;  // should not reach
}

hardware/interfaces/hello_aidl_hal/test_aidl_hal/Android.bp

c 复制代码
cc_binary {
    name: "test_aidl_hal",
    vendor: true,
    shared_libs: [
        "android.hardware.hello-V1-ndk_platform",
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
    ],
}

四、Selinux

4.1 file_contexts

device/softwinner/ceres/common/sepolicy/vanstone/non_plat/file_contexts

c 复制代码
/vendor/bin/hw/android.hardware.hello.example       u:object_r:hal_hellohal_default_exec:s0
  • 作用:将 HAL 可执行文件的实际路径(/vendor/bin/hw/...)映射到hal_hellohal_default_exec类型;
  • 核心:当 init 进程执行这个文件时,SELinux 会根据这个映射,将进程域切换为hal_hellohal_default(由init_daemon_domain实现)。

4.2 service_contexts

device/softwinner/ceres/common/sepolicy/vanstone/plat_private/service_contexts

c 复制代码
android.hardware.hello.IHello/default   u:object_r:hal_hellohal_service:s0
  • 作用:将 HAL 的 Binder 服务名(android.hardware.hello.IHello/default)映射到hal_hellohal_service类型;
  • 核心:ServiceManager 会标记该服务为hal_hellohal_service,客户端调用时 SELinux 会检查对这个类型的权限。

4.3 service.te

softwinner/ceres/common/sepolicy/vanstone/plat_public/service.te

c 复制代码
type hal_hellohal_service, service_manager_type, vendor_service;
  • 作用:定义hal_hellohal_service这个服务类型;
  • 关键标记:
    service_manager_type:必须(标记是 ServiceManager 管理的服务);
    vendor_service:标记是厂商自定义服务(/vendor 分区)。

4.3 hal_hello.te

新增文件 hal_hello.te
softwinner/ceres/common/sepolicy/vanstone/non_plat/hal_hello.te

c 复制代码
# 1. 定义HAL专属属性(保留)
hal_attribute(hellohal);

# 2. 定义HAL服务端域
type hal_hellohal_default, domain, mlstrustedsubject;

# 3. 标记为HAL服务端,继承hal_hellohal的基础权限
hal_server_domain(hal_hellohal_default, hal_hellohal);

# 4. 定义二进制文件类型
type hal_hellohal_default_exec, exec_type, vendor_file_type, file_type;

# 5. 允许init启动该服务
init_daemon_domain(hal_hellohal_default);

# 6. 允许HAL服务端添加vendor类型的服务(适配neverallow规则)
add_service(hal_hellohal_default, hal_hellohal_service)

# 7. 允许客户端查找该服务
allow hal_hellohal_client hal_hellohal_service:service_manager find;

# 8. 允许system_server作为客户端调用
hal_client_domain(system_server, hal_hellohal)

# 9. Binder通信规则
binder_call(hal_hellohal_client, hal_hellohal_default)
allow hal_hellohal_default servicemanager:binder { call transfer };
allow {  platform_app shell } hal_hellohal:binder {call};

# 10. 允许访问hello驱动
allow hal_hellohal_default hello_dev_t:chr_file { open read write };
selinux规则 表头
hal_attribute(hellohal); 1. 作用:注册 HAL 属性名称hellohal,是 Android HAL SELinux 框架的约定,用于关联 HAL 的服务端 / 客户端域; 2. 底层:生成隐藏的 SELinux 属性(如hal_hellohal),供后续hal_server_domain/hal_client_domain宏关联;
type hal_hellohal_default, domain, mlstrustedsubject; 1. 定义 HAL 服务进程的安全域(主体 type):hal_hellohal_default;2. domain:标记这是进程域(运行 HAL 服务的进程会被赋予这个身份);3. mlstrustedsubject:标记为 MLS(多级安全)信任的进程,Android 中可信进程的常规标记。
hal_server_domain(hal_hellohal_default, hal_hellohal); 1. 核心 HAL 宏:将hal_hellohal_default域标记为hal_hellohal这个 HAL 的服务端域;2. 底层:自动添加 HAL 服务端属性、关联hal_attribute注册的hellohal,简化服务端基础权限配置;3. 参数:第一个是服务端域,第二个是 HAL 标识(hal_+ 前面的hellohal)。
type hal_hellohal_default_exec, exec_type, vendor_file_type, file_type; 1. 定义 HAL 可执行文件的客体 type:hal_hellohal_default_exec;2. exec_type:必须标记(可执行文件专属属性);3. vendor_file_type:标记文件在 /vendor 分区(厂商自定义分区);4. file_type:所有文件的基础标记。
init_daemon_domain(hal_hellohal_default); 1. init 进程专属宏:允许 init 进程启动hal_hellohal_default域的进程,并完成域切换;2. 核心:Android 进程大多由 init 启动,没有这个宏,init 无法启动你的 HAL 进程(会被 SELinux 拦截)
add_service(hal_hellohal_default, hal_hellohal_service) 1. 允许 HAL 服务进程(hal_hellohal_default)向 ServiceManager注册hal_hellohal_service类型的 Binder 服务;2. 替代手动写:allow hal_hellohal_default servicemanager:service add;。
allow hal_hellohal_client hal_hellohal_service:service_manager find; 1. 允许 HAL 客户端(hal_hellohal_client)在 ServiceManager 中查找hal_hellohal_service类型的服务;2. 核心:客户端要调用 Binder 服务,第一步必须 "找到" 服务,这是基础权限。
hal_client_domain(system_server, hal_hellohal) 1. 核心 HAL 宏:将system_server(Android 系统核心进程)标记为hal_hellohal这个 HAL 的客户端域;2. 底层:自动关联hal_hellohal_client域,简化客户端与服务端的 Binder 通信权限。
binder_call(hal_hellohal_client, hal_hellohal_default) 1. Binder 通信宏:允许 HAL 客户端(hal_hellohal_client)调用HAL 服务端(hal_hellohal_default)的 Binder 服务;2. 替代手动写:allow hal_hellohal_client hal_hellohal_default:binder call;。
allow hal_hellohal_default servicemanager:binder { call transfer }; 1. 允许 HAL 服务端与 ServiceManager 的 Binder 通信:call(调用)、transfer(Binder 对象传递);2. 补充add_service的权限,确保服务注册 / 通信完整。
allow { platform_app shell } hal_hellohal:binder {call}; 1. 扩展客户端权限:允许普通应用(platform_app)和 adb shell(shell)调用 HAL 的 Binder 服务;2. {}:批量指定多个主体类型,简化规则书写。
allow hal_hellohal_default hello_dev_t:chr_file { open read write }; 1. 允许 HAL 服务进程操作硬件设备节点:hello_dev_t是你定义的字符设备(如/dev/hello)的 type;2. chr_file:字符设备文件的客体类型;3. open read write:设备文件的核心操作权限(没有这个,HAL 无法访问硬件)。

五、编译执行

不要忘了将上面的模块统统打包到系统配置里去,我本地是 device/softwinner/ceres/ceres_b7.mk

c 复制代码
xuejie@vt-PowerEdge-R740:~/A11a133a12$ git diff device/softwinner/ceres/ceres_b7.mk
diff --git a/device/softwinner/ceres/ceres_b7.mk b/device/softwinner/ceres/ceres_b7.mk
index 0b1de0d0e5..4546acdc50 100644
--- a/device/softwinner/ceres/ceres_b7.mk
+++ b/device/softwinner/ceres/ceres_b7.mk
@@ -83,6 +83,12 @@ PRODUCT_PACKAGES += \
                                        openssl \
                                        GoogleTTSEngine \
                                        SystemUpdaterSample\
+                                       android.hardware.hello.example\
+                                       test_aidl_hal\         

最后测试,

c 复制代码
vendor/bin # ./test_aidl_hal
1|A11:/vendor/bin #

相关推荐
2501_915106322 小时前
iOS 成品包加固,在只有 IPA 的情况下,能做那些操作
android·ios·小程序·https·uni-app·iphone·webview
LcVong3 小时前
Android 25(API 25)+ JDK 17 环境搭建
android·java·开发语言
AALoveTouch4 小时前
某麦APP抢票技术解析实现
android·ios
stevenzqzq4 小时前
Android 自定义View迁移Compose实战指南
android·compose
似霰6 小时前
AIDL Hal 开发笔记6----添加硬件访问服务
android·framework·hal
诸神黄昏EX7 小时前
Android OTA 之 升级包编译机制
android
2501_915909068 小时前
苹果iOS应用上架详细流程与注意事项解析
android·ios·小程序·https·uni-app·iphone·webview
AC赳赳老秦8 小时前
跨境科技服务的基石:DeepSeek赋能多语言技术文档与合规性说明的深度实践
android·大数据·数据库·人工智能·科技·deepseek·跨境
晚霞的不甘8 小时前
解决 Flutter for OpenHarmony 构建失败:HVigor ERROR 00303168 (SDK component missing)
android·javascript·flutter