📌一、分析
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权限
- 添加
$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
- 新建模块目录
$PROJECT_TOP/hardware/interfaces/hello/test_aidl_hal/ - 新建
$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
}
- 新建
$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",
],
}
- 编译
mmm hardware/interfaces/hello/test_aidl_hal生成out/target/product/rk3566_r/vendor/bin/test_aidl_hal
2. APP
- 取出
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'
- 由于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();
}
}
📁四、附言
参考文章
- AIDL for HALs实战_hidl会被aidl代替-CSDN博客
- android 12 的 aidl for HAL 开发示例 - 技术栈
- AIDL Hal 开发指南7 —— 实现一个简单的 AIDL HAL接下来我们仿造振动器写一个简单的 AIDL HAL - 掘金
- Android12 AIDL native层实现_android native aidl-CSDN博客