参考文章:
AIDL for HALs实战_hidl会被aidl代替-优快云博客
Android 11 创建自定义AIDL HAL-优快云博客
Native AIDL (与hal通信)_hidl转aidl-优快云博客
1. 定义HAL接口
创建对应的模块目录:/hardware/interfaces/testtld/aidl/
创建aidl文件:
hardware/interfaces/testtld/aidl/android/hardware/testtld/IHelloTest.aidl
package android.hardware.testtld;
@VintfStability
interface IHelloTest {
int getTestOne(in int event, in String name);
}
注意: 每个类型定义都必须使用@VintfStability进行注释。
2. 配置Android.bp
创建Android.bp:/hardware/interfaces/testtld/aidl/Android.bp
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
aidl_interface {
name: "android.hardware.testtld",
vendor_available: true,
srcs: ["android/hardware/testtld/*.aidl"],
stability: "vintf",
owner: "tld",
backend: {
cpp: {
enabled: true,
},
java: {
sdk_version: "module_current",
},
ndk: {
enabled: true,
},
},
frozen: false,
}
注意: 将owner设置为组织名称,此处不用加versions_with_info属性,后面编译完会自动生成,frozen会自动变成true 。vendor_available属性一定不能改成vendor,不然so文件不会在system文件下生成,只是在vendor下就引用不到了。
backend: 服务的后端,AIDL支持四种后端,分别是C++/JAVA/NDK/RUST, 我们将使用NDK(谷歌推荐),这里都加上会生成相应接口代码,因为后面C++和JAVA要调用。
3. 编译模块
首先前版本没有这个接口,需要更新下API,在项目跟目录下执行:
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
m android.hardware.testtld-update-api
执行成功后会生出current目录。
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mmm hardware/interfaces/testtld
再次执行命令,系统会生出1的目录,并在bp文件里的自动添加版本属性frozen变成true。
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm android.hardware.testtld-freeze-api
4. 实现HAL 接口
在aidl目录下添加default目录及实现代码 , 目录结构如下
default
├── Android.bp
├── HelloTest.h
│── HelloTest.cpp
└── service.cpp
└── HelloTest-default.rc
└── HelloTest-default.xml
aidl/default/HelloTest.h
#include <aidl/android/hardware/testtld/BnHelloTest.h>
namespace aidl {
namespace android {
namespace hardware {
namespace testtld {
class HelloTest : public BnHelloTest {
public:
ndk::ScopedAStatus getTestOne(int32_t in_event, const std::string& in_name, int32_t* _aidl_return);
};
} // namespace testtld
} // namespace hardware
} // namespace android
} // namespace aild
aidl/default/HelloTest.cpp
#define LOG_TAG "android.hardware.testtld-service"
#include <utils/Log.h>
#include <log/log.h>
#include <iostream>
#include <HelloTest.h>
namespace aidl {
namespace android {
namespace hardware {
namespace testtld {
ndk::ScopedAStatus HelloTest::getTestOne(int32_t in_event, const std::string& in_name, int32_t* _aidl_return) {
ALOGD("======getTestOne====1");
std::int32_t ret = in_event;
std::string name = in_name;
*_aidl_return = 2;
ALOGD("======getTestOne====2===in_event:%d",ret);
ALOGD("%s: this = %p, name = %s ", __FUNCTION__, this, name.c_str());
return ndk::ScopedAStatus::ok();
}
} // namespace testtld
} // namespace hardware
} // namespace android
} // namespace aidl
aidl/default/service.cpp
#define LOG_TAG "android.hardware.testtld-service"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "HelloTest.h"
using aidl::android::hardware::testtld::HelloTest;
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<HelloTest> helloTest = ndk::SharedRefBase::make<HelloTest>();
const std::string desc = HelloTest::descriptor + "/default"s;
if (helloTest != nullptr) {
if(AServiceManager_addService(helloTest->asBinder().get(), desc.c_str()) != STATUS_OK) {
ALOGE("Failed to register IHelloTest service");
return -1;
}
} else {
ALOGE("Failed to get IHelloTest instance");
return -1;
}
ALOGD("IHelloTest service starts to join service pool");
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reached
}
aidl/default/Android.bp
cc_binary {
name: "android.hardware.testtld-service",
init_rc: ["HelloTest-default.rc"],
vintf_fragments: ["HelloTest-default.xml"],
relative_install_path: "hw",
vendor: true,
srcs: [
"service.cpp",
"HelloTest.cpp",
],
shared_libs: [
"libbase",
"libbinder",
"libbinder_ndk",
"libutils",
"liblog",
"libcutils",
"libutils",
"libdl",
"android.hardware.testtld-V1-ndk",
],
cflags: [
"-Wall",
"-Werror",
],
}
到 /hardware/interfaces/testtld/
下,运行:
source build/envsetup.sh
lunch your target ##需要根据自己的实际情况进行选择
mm -j8
或者根目录下执行
mmm /hardware/interfaces/testtld -j8
将会在 /out/target/product/rk3576_u/vendor/bin/hw 目录生成如下文件:
android.hardware.testtld-service
5. 编写服务启动的rc脚本
aidl/default/HelloTest-default.rc
service android.hardware.testtld-service /vendor/bin/hw/android.hardware.testtld-service
class hal
user system
group system
6. 声明VINTF AIDL 接口
aidl/default/HelloTest-default.xml
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.testtld</name>
<version>1</version>
<fqname>IHelloTest/default</fqname>
</hal>
</manifest>
7. 将模块加入系统中
/device/rockchip/common/device.mk
# test AIDL
PRODUCT_PACKAGES += \
android.hardware.testtld \
android.hardware.testtld-service
8. 将模块添加到兼容性矩阵中
# 查看对应的API级别文件对应的兼容矩阵文件 # device/rockchip/common/manifests/compatibility_matrix_level_34.xml # device/rockchip/common/manifests/manifest_level_34.xml hardware/interfaces/compatibility_matrices/compatibility_matrix.8.xml
<hal format="aidl" optional="true">
<name>android.hardware.testtld</name>
<version>1</version>
<interface>
<name>IHelloTest</name>
<instance>default</instance>
</interface>
</hal>
9.解决Selinux权限
hwservice.te
type hal_hellotest_hwservice, hwservice_manager_type, protected_hwservice;
hwservice_contexts
android.hardware.testtld::IHelloTest u:object_r:hal_hellotest_hwservice:s0
file_contexts
/vendor/bin/hw/android\.hardware\.testtld-service u:object_r:hal_hellotest_exec:s0
hal_hellotest.te
type hal_hellotest, domain;
type hal_hellotest_exec, vendor_file_type, exec_type, file_type;
init_daemon_domain(hal_hellotest)
29.0.ignore.cil 按需求修改忽略文件,增加如下内容
hal_hellotest_exec
hal_hellotest_hwservice
修改的目录为如下:
system/sepolicy/prebuilts/api/34.0/private/compat/29.0/29.0.ignore.cil
system/sepolicy/prebuilts/api/34.0/private/compat/30.0/30.0.ignore.cil
system/sepolicy/prebuilts/api/34.0/private/compat/30.0/30.0.ignore.cil
system/sepolicy/prebuilts/api/34.0/private/compat/32.0/32.0.ignore.cil
system/sepolicy/prebuilts/api/34.0/private/compat/33.0/33.0.ignore.cil
system/sepolicy/prebuilts/api/34.0/private/file_contexts
system/sepolicy/prebuilts/api/34.0/private/hal_hellotest.te
system/sepolicy/prebuilts/api/34.0/private/hal_hellotest.te
system/sepolicy/prebuilts/api/34.0/private/hwservice.te
system/sepolicy/prebuilts/api/34.0/private/hwservice_contexts
system/sepolicy/private/compat/29.0/29.0.ignore.cil
system/sepolicy/private/compat/30.0/30.0.ignore.cil
system/sepolicy/private/compat/31.0/31.0.ignore.cil
system/sepolicy/private/compat/32.0/32.0.ignore.cil
system/sepolicy/private/compat/33.0/33.0.ignore.cil
system/sepolicy/private/file_contexts
system/sepolicy/private/hal_hellotest.te
system/sepolicy/private/hwservice.te
system/sepolicy/private/hwservice_contexts
10.调用测试
整体进行编译,更设备镜像查看,通过adb shell 查看服务是否启动,有就成功了,执行命令service list 查看服务列表多新增的如下:
android.hardware.testtld.IHelloTest/default: [android.hardware.testtld.IHelloTest]
查看vendor/bin/hw/目录下会有android.hardware.testtld-service
so 库文件目录
/system/lib64/android.hardware.testtld-V1-ndk.so
调用是基于framework层的CPP和JAVA调用
JNI的CPP调用需要引入生成的文件,文件地址
frameworks/base/services/core/jni/Android.bp
cc_defaults {
name: "libservices.core-libs",
shared_libs: [
........
"libbinder_ndk",
"android.hardware.testtld-V1-ndk",
........
],
调用文件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/android/hardware/testtld/IHelloTest.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::android::hardware::testtld::IHelloTest;
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("android.hardware.testtld.IHelloTest/default"));
if (binder.get() == nullptr) {
ALOGE("---- AIDL is not present---");
} else {
ALOGE("---- AIDL is present---");
std::string mName="def";
std::int32_t in_event =456 ;
int32_t* aidl_return = new int32_t;
IHelloTest::fromBinder(binder)->getTestOne(in_event,mName,aidl_return);
ALOGD("------success to get IHelloTest service----aidl_return:%d", static_cast<int>(*aidl_return));
}
}
JNI的JAVA调用需要引入生成的文件,文件地址
frameworks/base/services/core/Android.bp
static_libs: [
....
"android.hardware.testtld-V1-java", // AIDL
.....
],
调用文件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 android.hardware.testtld.IHelloTest;
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));
nativeSetTestOne(flag);
try {
Slog.d(TAG, "----Trying to get AIDL service----");
///通过ServiceManager获得aidl服务
IHelloTest serviceAidl =
IHelloTest.Stub.asInterface(
ServiceManager.getService("android.hardware.testtld.IHelloTest/default"));
if (serviceAidl != null) {
Slog.d(TAG, "-----success to get IHelloTest AIDL service--111---");
int result = serviceAidl.getTestOne(123,"abc");
Slog.d(TAG, "-----success to get IHelloTest AIDL service-result:" + result);
}
} catch (Exception eAidl) {
Slog.e(TAG, "-----Failed to get IHelloTest AIDL service-----", eAidl);
}
} catch (Exception e) {
e.printStackTrace();
}
}
APP 调用
app的libs引入jar包android.hardware.testtld-V1-java.jar,导入方式implementaion ,同时引入framework.jar方式compileOnly。
jar位置:out/soong/.intermediates/hardware/interfaces/testtld/aidl/vandroid.hardware.testtld-V1-java/android_common/javac目录下
调用代码同Framework 的JNI 的JAVA调用一致
package xxxxxx;
import android.util.Log;
import android.os.ServiceManager;
import android.hardware.testtld.IHelloTest;
public class Test{
public void setTestOne() {
try {
Log.d(TAG, "------setTestOne--------flag:" + String.valueOf(flag));
nativeSetTestOne(flag);
try {
Log.d(TAG, "----Trying to get AIDL service----");
///通过ServiceManager获得aidl服务
IHelloTest serviceAidl =
IHelloTest.Stub.asInterface(
ServiceManager.getService("android.hardware.testtld.IHelloTest/default"));
if (serviceAidl != null) {
Log.d(TAG, "-----success to get IHelloTest AIDL service--111---");
int result = serviceAidl.getTestOne(123,"abc");
Log.d(TAG, "-----success to get IHelloTest AIDL service-result:" + result);
}
} catch (Exception eAidl) {
Log.e(TAG, "-----Failed to get IHelloTest AIDL service-----", eAidl);
}
} catch (Exception e) {
e.printStackTrace();
}
}
再需要补充APP调用权限,修改hellotest.tet添加下面内容即可或者关闭SELinux。
allow hal_hellotest servicemanager:binder { call transfer };
allow { platform_app system_app shell } hal_hellotest_hwservice:hwservice_manager { find };
allow { platform_app system_app untrusted_app_29 shell } hal_hellotest:binder {call};