参考文章:
AIDL for HALs实战_hidl会被aidl代替-优快云博客
Android 11 创建自定义AIDL HAL-优快云博客
Native AIDL (与hal通信)_hidl转aidl-优快云博客
1. 定义HAL接口
创建对应的模块目录:/vendor/rockchiip/hardware/interfaces/helloworld/aidl/
创建aidl文件:
/vendor/rockchiip/hardware/interfaces/helloworld/aidl/vendor/rockchip/hardware/testaidl/helloworld/IHelloworld.aidl
package vendor.rockchip.hardware.testaidl.helloworld;
@VintfStability
interface IHelloworld {
void sayHello(in String name);
}
注意: 每个类型定义都必须使用@VintfStability进行注释。
2. 配置Android.bp
创建Android.bp:/vendor/rockchiip/hardware/interfaces/helloworld/aidl/Android.bp
aidl_interface {
name: "vendor.rockchip.hardware.testaidl.helloworld",
vendor_available: true,
srcs: [
"vendor/rockchip/hardware/testaidl/helloworld/*.aidl",
],
stability: "vintf",
owner: "tld",
backend: {
cpp: {
enabled: true,
},
java: {
platform_apis: true,
},
ndk: {
enabled: true,
},
},
versions: [
"1",
],
}
注意: 将owner设置为组织名称。此处正常不用加versions属性,我这个版本编译不加报错,先手动加上并创建相应的目录到1的文件夹,后面需要生成的时候在删除版本属性和目录,在aidl目录下创建如下目录: aidl_api/vendor.rockchip.hardware.testaidl.helloworld/1
backend: 服务的后端,AIDL支持四种后端,分别是C++/JAVA/NDK/RUST, 我们将使用NDK(谷歌推荐),这里都加上会生成相应接口代码,因为后面C++和JAVA要调用。
3. 编译模块
首先前版本没有这个接口,需要更新下API,在项目跟目录下执行:
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
m android.hardware.testaidl.helloworld-update-api
执行成功后会在与1同级目录生出current目录,这时删除1目录和bp文件里的versions属性。
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm vendor.rockchip.hardware.testaidl.helloworld-update-api
再次执行命令,系统会生出1的目录,并在bp文件里的自动versions属性。
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm android.hardware.automotive.helloworld-freeze-api
4. 实现HAL 接口
在aidl目录下添加default目录及实现代码 , 目录结构如下
default
├── Android.bp
├── Helloworld.h
│── Helloworld.cpp
└── service.cpp
└── Helloworld-default.rc
└── Helloworld-default.xml
aidl/default/Helloworld.h
#include <aidl/vendor/rockchip/hardware/testaidl/helloworld/BnHelloworld.h>
#include <android-base/expected.h>
#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
namespace vendor {
namespace rockchip {
namespace hardware {
namespace testaidl {
namespace helloworld {
class Helloworld final : public aidl::vendor::rockchip::hardware::testaidl::helloworld::BnHelloworld {
public:
ndk::ScopedAStatus sayHello(
const std::string& name)
override;
};
} // namespace helloworld
} // namespace testaidl
} // namespace hardware
} // namespace rockchip
} // namespace vendor
aidl/default/Helloworld.cpp
#define ATRACE_TAG ATRACE_TAG_HAL
#define LOG_TAG "voendor.rockchip.hardware.testaidl.Helloworld@1.0-service"
#include <Helloworld.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android/binder_ibinder.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/Trace.h>
#include <android-base/logging.h>
#include <log/log.h>
#include <inttypes.h>
#include <set>
#include <unordered_set>
namespace vendor {
namespace rockchip {
namespace hardware {
namespace testaidl {
namespace helloworld {
namespace {
using ::android::base::Error;
using ::android::base::expected;
using ::android::base::Result;
using ::android::base::StringPrintf;
using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;
} // namespace
ndk::ScopedAStatus Helloworld::sayHello(const std::string& name) {
ALOGD("======sayHello====");
ALOGD("%s: this = %p, name = %s ", __FUNCTION__, this, &name);
return ScopedAStatus::ok();
}
} // namespace helloworld
} // namespace testaidl
} // namespace hardware
} // namespace rockchip
} // namespace vendor
aidl/default/service.cpp
#define LOG_TAG "vendor.rockchip.hardware.testaidl.helloworld@1.0-service"
#include <unistd.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <Helloworld.h>
using ::aidl::vendor::rockchip::hardware::testaidl::helloworld::IHelloworld;
using ::vendor::rockchip::hardware::testaidl::helloworld::Helloworld;
using ::ndk::ScopedAStatus;
using ::ndk::SharedRefBase;
const static char kHelloworldServiceName[] = "default";
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
LOG(INFO) << "Helloworld service is starting";
std::shared_ptr<Helloworld> helloworldHal = SharedRefBase::make<Helloworld>();
const std::string instance =
std::string() + IHelloworld::descriptor + "/" + kHelloworldServiceName;
binder_status_t status =
AServiceManager_addService(helloworldHal->asBinder().get(), instance.c_str());
if (status == STATUS_OK) {
LOG(INFO) << "Service " << kHelloworldServiceName << " is ready";
ABinderProcess_joinThreadPool();
} else {
LOG(ERROR) << "Could not register service " << kHelloworldServiceName
<< ", status: " << status;
}
// In normal operation, we don't expect the thread pool to exit.
LOG(ERROR) << "Helloworld service is shutting down";
return 1;
}
aidl/default/Android.bp
cc_binary {
name: "vendor.rockchip.hardware.testaidl.helloworld@1.0-service",
init_rc: ["Helloworld-default.rc"],
vintf_fragments: ["Helloworld-default.xml"],
relative_install_path: "hw",
vendor: true,
srcs: [
"service.cpp",
"Helloworld.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"libutils",
"liblog",
"libcutils",
"libdl",
"vendor.rockchip.hardware.testaidl.helloworld-ndk_platform",
],
}
到 /vendor/rockchiip/hardware/interfaces/helloworld
下,运行:
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm -j8
或者根目录下执行
mmm /vendor/rockchiip/hardware/interfaces/helloworld -j8
将会在 /out/target/product/trout_arm64/vendor/bin/hw 目录生成如下文件:
vendor.rockchip.hardware.testaidl.helloworld@1.0-service
5. 编写服务启动的rc脚本
aidl/default/Helloworld-default.rc
service vendor.helloworld-1-0 /vendor/bin/hw/vendor.rockchip.hardware.testaidl.helloworld@1.0-service
class hal
user system
group system
6. 声明VINTF AIDL 接口
aidl/default/Helloworld-default.xml
<manifest version="1.0" type="device">
<hal format="aidl">
<name>vendor.rockchip.hardware.testaidl.helloworld</name>
<version>1.0</version>
<fqname>IHelloworld/default</fqname>
</hal>
</manifest>
7. 将模块加入系统中
/device/rockchip/common/device.mk
# test HAL AIDL
PRODUCT_PACKAGES += \
vendor.rockchip.hardware.testaidl.helloworld \
vendor.rockchip.hardware.testaidl.helloworld@1.0-service
8. 将模块添加到兼容性矩阵中
# (选下标最新的那个) hardware/interfaces/compatibility_matrices/compatibility_matrix.5.xml
<hal format="aidl" optional="true">
<name>vendor.rockchip.hardware.testaidl.helloworld</name>
<version>1.0</version>
<interface>
<name>IHelloworld</name>
<instance>default</instance>
</interface>
</hal>
9.解决Selinux权限
hwservice.te
type hal_helloworld_hwservice, hwservice_manager_type, protected_hwservic
hwservice_contexts
vendor.rockchip.hardware.testaidl.helloworld::IHelloworld u:object_r:hal_helloworld_hwservice:s0
file_contexts
/vendor/bin/hw/vendor\.rockchip\.hardware\.testaidl\.helloworld@1\.0-service u:object_r:hal_helloworld_exec:s0
hal_helloworld.te
type hal_helloworld, domain;
type hal_helloworld_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_helloworld)
29.0.ignore.cil 按需求修改忽略文件,增加如下内容
hal_helloworld_hwservice
hal_helloworld_exec
修改的目录为如下图:
10.调用测试
整体进行编译,更设备镜像查看,通过adb shell 查看服务是否启动,有就成功了,执行命令service list 查看服务列表多新增的如下:
vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default: [vendor.rockchip.hardware.testaidl.helloworld.IHelloworld]
查看vendor/bin/hw/目录下会有vendor.rockchip.hardware.testaidl.helloworld@1.0-service
调用是基于framework层的CPP和JAVA调用
JNI的CPP调用需要引入生成的文件,文件地址
frameworks/base/services/core/jni/Android.bp
cc_defaults {
name: "libservices.core-libs",
shared_libs: [
........
"libbinder_ndk",
"vendor.rockchip.hardware.testaidl.helloworld-ndk_platform",
........
],
调用文件frameworks/base/services/core/jni/com_android_server_SystemTestJni.cpp
#define LOG_TAG "SystemTestJniCpp"
#include <cutils/log.h>
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <jni.h>
#include <linux/netlink.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <pthread.h>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <aidl/vendor/rockchip/hardware/testaidl/helloworld/IHelloworld.h>
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <utils/RefBase.h>
#include <android-base/properties.h>
#include <future>
#include <unistd.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::vendor::rockchip::hardware::testaidl::helloworld::IHelloworld;
using ::ndk::ScopedAStatus;
using ::ndk::SharedRefBase;
namespace android {
static JavaVM *g_VM;
static jobject g_obj;
static void nativeSetTestOne(JNIEnv *env, jobject obj, jint flag) {
ALOGD("----run nativeTestOne----flag:%d", flag);
//通过ServiceManager获得aidl服务
ndk::SpAIBinder binder(
AServiceManager_checkService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
if (binder.get() == nullptr) {
ALOGE("---- AIDL is not present---");
} else {
ALOGE("---- AIDL is present---");
std::string mName="def";
IHelloworld::fromBinder(binder)->sayHello(mName);
}
ALOGW("------success to get IHello service-----");
}
JNI的JAVA调用需要引入生成的文件,文件地址
frameworks/base/services/core/Android.bp
static_libs: [
....
"vendor.rockchip.hardware.testaidl.helloworld-java",
.....
],
调用文件frameworks/base/services/core/java/com/android/server/SystemTestJni.java
package com.android.server;
import android.os.ServiceManager;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;
import android.app.SystemTestManager;
import vendor.rockchip.hardware.testaidl.helloworld.IHelloworld;
public class SystemTestJni {
private final String TAG = "SystemTestJni";
private SystemTestManager mManager;
public static native void nativeSetTestOne(int flag);
public SystemTestJni() {
}
public void setTestOne(int flag) throws RemoteException {
try {
Slog.d(TAG, "------setTestOne--------flag:" + String.valueOf(flag));
try {
Slog.d(TAG, "----Trying to get AIDL service----");
///通过ServiceManager获得aidl服务
IHelloworld serviceAidl =
IHelloworld.Stub.asInterface(
ServiceManager.getService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
if (serviceAidl != null) {
Slog.d(TAG, "-----success to get Helloworld AIDL service--111---");
serviceAidl.sayHello("abc");
Slog.d(TAG, "-----success to get Helloworld AIDL service--222---");
}
} catch (Exception eAidl) {
Slog.e(TAG, "-----Failed to get Helloworld AIDL service-----", eAidl);
}
nativeSetTestOne(flag);
} catch (Exception e) {
e.printStackTrace();
}
}
APP 调用
app的libs引入jar包vendor.rockchip.hardware.helloworld-java.jar,导入方式implementaion ,同时引入framework.jar方式compileOnly。
jar位置:out/soong/.intermediates/vendor/rockchip/hardware/interfaces/helloworld/aidl/vendor.rockchip.hardware.helloworld-java/android_common/javac目录下
调用代码同Framework 的JNI 的JAVA调用一致
package xxxxxx;
import android.util.Log;
import android.os.ServiceManager;
import vendor.rockchip.hardware.testaidl.helloworld.IHelloworld;
public class Test{
public void setTestOne() {
try {
Log.d(TAG, "----Trying to get AIDL service----");
///通过ServiceManager获得aidl服务
IHelloworld serviceAidl =
IHelloworld.Stub.asInterface(
ServiceManager.getService("vendor.rockchip.hardware.testaidl.helloworld.IHelloworld/default"));
if (serviceAidl != null) {
Log.d(TAG, "-----success to get Helloworld AIDL service--111---");
serviceAidl.sayHello("abc");
Log.d(TAG, "-----success to get Helloworld AIDL service--222---");
}
} catch (Exception eAidl) {
Log.e(TAG, "-----Failed to get Helloworld AIDL service-----", eAidl);
}
}
再需要补充APP调用权限,修改hal_helloworld.tet添加下面内容即可或者关闭SELinux。
allow hal_helloworld servicemanager:binder { call transfer };
allow { platform_app system_app shell } hal_helloworld_hwservice:hwservice_manager { find };
allow { platform_app system_app shell } hal_helloworld:binder {call};