📌一、分析

Android HAL(Hardware Abstraction Layer)是连接 Framework底层驱动 的桥梁。
根据 Android 版本:

HAL类型 对应Android版本 接口定义方式 特点
Legacy HAL (C接口) Android 7 及以前 .so + .h 传统方式
HIDL HAL Android 8~10 .hal 接口文件 编译生成 binder 服务
AIDL HAL Android 11+ .aidl 文件 新标准,更统一
Google 在Android 11引入了AIDL for HALs,旨在代替HIDL原先的作用。在之后的Android版本推荐使用AIDL 实现Hal层的访问。
注意
在HAL 层使用AIDL必须使用`Stable AIDL`, 和我们在应用层或者框架层稍微不同,因为和vendor的接口设计要兼顾稳定性,system和vendor的更新速率不一样。

📌二、实现

1. 定义aidl接口

1.1. 新建模块目录:
$PROJECT_TOP/hardware/interfaces/hello/aidl/Android.bp
1.2. 新建aidl文件:
$PROJECT_TOP/hardware/interfaces/hello/aidl/android/hardware/hello/IHello.aidl

package android.hardware.hello;

@VintfStability
interface IHello {
    String getName();
    
    void setName(in String msg);
}

2. 配置Android.bp

新建顶层Android.bp
$PROJECT_TOPhardware/interfaces/hello/aidl/Android.bp

aidl_interface {
   name: "android.hardware.hello",
   vendor_available: true,
   srcs: ["android/hardware/hello/*.aidl"],
   stability: "vintf",
   owner: "lucius",
   backend: {
       cpp: {
           enabled: false,
       },
       java: {
       	   enabled: false,
       },
   },
}

3. 编译模块

mmm hardware/interfaces/hello/aidl/
会报错

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 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

原因是当前版本没有这个接口,需要更新下API,根据提示执行
m android.hardware.hello-update-api
然后再重新编译模块:
mmm hardware/interfaces/hello/aidl/
会在当前目录下生成

❯ tree
.
└── aidl
    ├── aidl_api
    │   └── android.hardware.hello
    │       └── current
    │           └── android
    │               └── hardware
    │                   └── hello
    │                       └── IHello.aidl
    ├── android
    │   └── hardware
    │       └── hello
    │           └── IHello.aidl
    └── Android.bp

10 directories, 3 files

❯ cat aidl/aidl_api/android.hardware.hello/current/android/hardware/hello/IHello.aidl 
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
///////////////////////////////////////////////////////////////////////////////

// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.

package android.hardware.hello;
@VintfStability
interface IHello {
  String getName();
  void setName(in String msg);
}

以及生成
$PROJECT_TOP/out/soong/.intermediates/hardware/interfaces/hello/aidl/

4. 实现HAL接口

 ❯ find android/out/soong/.intermediates/hardware/interfaces/hello/aidl/ -name "*.h"
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk-source/gen/include/aidl/android/hardware/hello/BpHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk-source/gen/include/aidl/android/hardware/hello/IHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk-source/gen/include/aidl/android/hardware/hello/BnHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-cpp-source/gen/include/android/hardware/hello/BpHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-cpp-source/gen/include/android/hardware/hello/IHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-cpp-source/gen/include/android/hardware/hello/BnHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk_platform-source/gen/include/aidl/android/hardware/hello/BpHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk_platform-source/gen/include/aidl/android/hardware/hello/IHello.h
android/out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-ndk_platform-source/gen/include/aidl/android/hardware/hello/BnHello.h

在IHello.h中找到要实现的接口:

  virtual ::ndk::ScopedAStatus getName(std::string* _aidl_return) = 0;
  virtual ::ndk::ScopedAStatus setName(const std::string& in_msg) = 0;

新建:
$PROJECT_TOP/hardware/interfaces/hello/aidl/default/Hello.h

#pragma once

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

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

class Hello : public BnHello {
  public:
    // String getName();
    ndk::ScopedAStatus getName(std::string* _aidl_return);

    // void setName(in String msg);
    ndk::ScopedAStatus setName(const std::string& in_msg);

  private:
    std::string name = "";
};

}  // namespace hello
}  // namespace hardware
}  // namespace android
}  // namespace aidl

新建:
$PROJECT_TOP/hardware/interfaces/hello/aidl/default/Hello.cpp

#define LOG_TAG "Hello-AIDL"

#include "Hello.h"
#include <utils/Log.h>
#include <iostream>

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

ndk::ScopedAStatus Hello::getName(std::string* _aidl_return) {
    *_aidl_return = name;

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Hello::setName(const std::string& in_msg) {
    name = in_msg;

    return ndk::ScopedAStatus::ok();
}

}  // namespace hello
}  // namespace hardware
}  // namespace android
}  // namespace aidl

5. 实现服务

新建:
$PROJECT_TOP/hardware/interfaces/hello/aidl/default/main.cpp

#define LOG_TAG "Hello-AIDL"

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "Hello.h"

using aidl::android::hardware::hello::Hello;
using std::string_literals::operator""s;

int main() {
    // Enable vndbinder to allow vendor-to-venfor binder call
    android::ProcessState::initWithDriver("/dev/vndbinder");  // 使用vnbinder的配置

    ABinderProcess_setThreadPoolMaxThreadCount(0);  // vnbinder的线程池独立,需要单独配置
    ABinderProcess_startThreadPool();

    std::shared_ptr<Hello> hello = ndk::SharedRefBase::make<Hello>();
    const std::string desc = Hello::descriptor + "/default"s;

    if (hello != nullptr) {
        if (AServiceManager_addService(hello->asBinder().get(), desc.c_str()) != STATUS_OK) {
            ALOGE("Failed to register IHello service");
            return -1;
        }
    } else {
        ALOGE("Failed to get IHello instance");
        return -1;
    }

    ALOGD("IHello service starts to join service pool");
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;  // should not reached
}

6. 编写服务开机启动脚本

$PROJECT_TOP/hardware/interfaces/hello/aidl/default/android.hardware.hello-service.rc

service android.hardware.hello-service /vendor/bin/hw/android.hardware.hello-service
        interface aidl android.hardware.hello.IHello/default
        class hal
        user system
        group system

7. 声明VINTF AIDL接口

$PROJECT_TOP/hardware/interfaces/hello/aidl/default/android.hardware.hello-service.xml

<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>android.hardware.hello</name>
        <fqname>IHello/default</fqname>
    </hal>
</manifest>

8. 编写服务构建脚本

$PROJECT_TOP/hardware/interfaces/hello/aidl/default/Android.bp

cc_binary {
    name: "android.hardware.hello-service",
    vendor: true,
    relative_install_path: "hw",
    init_rc: ["android.hardware.hello-service.rc"],
    vintf_fragments: ["android.hardware.hello-service.xml"],

    srcs: [
        "Hello.cpp",
        "main.cpp",
    ],

    cflags: [
        "-Wall",
        "-Werror",
    ],

    shared_libs: [
        "libbase",
        "liblog",
        "libhardware",
        "libbinder_ndk",
        "libbinder",
        "libutils",
        "android.hardware.hello-ndk_platform",
    ],
}

9. 将模块加入系统

$PROJECT_TOP/build/make/target/product/base_vendor.mk

 PRODUCT_PACKAGES += \
     android.hardware.cas@1.2-service \
+    android.hardware.hello \
+    android.hardware.hello-service \
     android.hardware.media.omx@1.0-service \
     boringssl_self_test_vendor \
     dumpsys_vendor \

10. 将模块添加到兼容性矩阵

$PROJECT_TOP/hardware/interfaces/compatibility_matrices/compatibility_matrix.5.xml

@@ -563,4 +563,12 @@
             <instance>default</instance>
         </interface>
     </hal>
+        <hal format="aidl" optional="true">
+        <name>android.hardware.hello</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHello</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
 </compatibility-matrix>

11. 配置Selinux权限

  1. 添加$PROJECT_TOP/system/sepolicy/vendor/hal_hello.te
hal_attribute(hellohal);
type hal_hellohal_default, domain, mlstrustedsubject;
hal_server_domain(hal_hellohal_default, hal_hellohal);
type hal_hellohal_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_hellohal_default);

binder_call(hal_hellohal_client, hal_hellohal_default)

type hal_hellohal_service, service_manager_type;
add_service(hal_hellohal_default, hal_hellohal_service)
allow hal_hellohal_client hal_hellohal_service:service_manager find;
hal_client_domain(system_server, hal_hellohal)

allow hal_hellohal_default servicemanager:binder { call transfer };
allow {  platform_app shell } hal_hellohal:binder {call};

allow hal_hellohal_default hello_dev_t:chr_file { open read write }; 


📌三、测试

1. SDK

  1. 新建模块目录
    $PROJECT_TOP/hardware/interfaces/hello/test_aidl_hal/
  2. 新建$PROJECT_TOP/hardware/interfaces/hello/test_aidl_hal/main.cpp
#define LOG_TAG "Test-HAL"
#define LOG_NDEBUG 0
#include <iostream>

#include <aidl/android/hardware/hello/IHello.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <log/log.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;
    }
    std::string res;
    service->setName("hello");
    service->getName(&res);
    ALOGD("Client: getName returned = %s", res.c_str());
    fflush(stdout);
    return EXIT_FAILURE;  // should not reach
}

  1. 新建$PROJECT_TOP/hardware/interfaces/hello/test_aidl_hal/Android.bp
cc_binary {
    name: "test_aidl_hal",
    vendor: true,
    shared_libs: [
        "android.hardware.hello-ndk_platform", 
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
    ],
}

  1. 编译
    mmm hardware/interfaces/hello/test_aidl_hal生成out/target/product/rk3566_r/vendor/bin/test_aidl_hal

2. APP

  1. 取出out/soong/.intermediates/hardware/interfaces/hello/aidl/android.hardware.hello-java/android_common/turbine/android.hardware.hello-java.jar放入安卓工程中,添加编译
@@ -30,6 +30,8 @@ android {

 dependencies {

+    compileOnly files('libs/android.hardware.hello-java.jar')
+//    implementation fileTree(dir: 'libs', include: ['*.jar'])
     implementation 'androidx.appcompat:appcompat:1.4.1'
     implementation 'com.google.android.material:material:1.5.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

  1. 由于android.os.ServiceManager是个隐藏类,所以使用反射
    src/main/java/com/example/myapp/MainActivity.java
package com.example.myapp;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.hardware.hello.IHello;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "Test-HAL_APP";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testHelloHal();
    }

    private void testHelloHal() {
        new Thread(() -> {
            try {
                /* 1. 通过反射获取 ServiceManager.getService() */
                Class<?> smClass = Class.forName("android.os.ServiceManager");
                Method getService = smClass.getMethod("getService", String.class);
                IBinder binder = (IBinder) getService.invoke(null, "android.hardware.hello.IHello/default");
                if (binder == null) {
                    Log.e(TAG, "Hello HAL service not found!");
                    return;
                }
                /* 2. 转为 AIDL 接口 */
                IHello helloService = IHello.Stub.asInterface(binder);
                /* 3. 调用服务端方法 */
                helloService.setName("Hello from App (reflection)");
                String name = helloService.getName();
                Log.d(TAG, "HAL getName() = " + name);
            } catch (Exception e) {
                Log.e(TAG, "调用 HAL 失败", e);
            }
        }).start();
    }
}


📁四、附言

参考文章

  1. AIDL for HALs实战_hidl会被aidl代替-CSDN博客
  2. android 12 的 aidl for HAL 开发示例 - 技术栈
  3. AIDL Hal 开发指南7 —— 实现一个简单的 AIDL HAL接下来我们仿造振动器写一个简单的 AIDL HAL - 掘金
  4. Android12 AIDL native层实现_android native aidl-CSDN博客

代码

https://git.luciusxu.cn/lucius/25Oct23-Test-AIDL_Hello.git