Android13 AIDL HAL服务实现Demo
本文基于Android 13平台,详细介绍了如何实现AIDL HAL服务及其与应用程序的交互。
本文基于android13,实现aidl hal服务,以及app如何使用这个aidl和hal交互。
最终实现得hal demo目录层级结构如下:
uluxy181@NJUbuntu18-210:~/workspace1/UIS7870_SAIC/android/vendor/yfe/saic_project/common/hardware/interfaces/demo$ tree
.
└── 1.0
├── aidl
│ └── vendor
│ └── yfe
│ └── hardware
│ └── demo
│ └── IDemo.aidl
├── aidl_api
│ └── vendor.yfe.hardware.demo
│ ├── 1
│ │ └── vendor
│ │ └── yfe
│ │ └── hardware
│ │ └── demo
│ │ └── IDemo.aidl
│ └── current
│ └── vendor
│ └── yfe
│ └── hardware
│ └── demo
│ └── IDemo.aidl
├── Android.bp
└── default
├── Android.bp
├── DemoService.cpp
├── DemoService.h
├── service.cpp
├── vendor.yfe.hardware.demo-service.rc
└── vendor.yfe.hardware.demo-service.xml
19 directories, 10 files
接下来我们一步步实现。
1,实现aidl接口
1.1 实现文件IDemo.aidl:
package vendor.yfe.hardware.demo;
@VintfStability
interface IDemo {
// 简单测试接口:获取字符串
String getHelloString();
// 加法计算
int add(int a, int b);
// 设置/获取值
void setValue(int val);
int getValue();
}
1.2 实现对应得Android.bp文件
我们是实现需要固定接口得量产版aidl接口
package {
// default_visibility: ["//..."],
}
aidl_interface {
name: "vendor.yfe.hardware.demo",
vendor_available: true,
srcs: ["aidl/vendor/yfe/hardware/demo/IDemo.aidl"],
//unstable: true,
owner: "yfe",
stability: "vintf",
visibility: [
"//system/tools/aidl/build",
"//vendor/...",
],
backend: {
cpp: {
enabled: true,
},
java: {
enabled: true,//生成java接口
},
ndk: {
enabled: true, // 关键:生成供 NDK 使用的库
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
],
}
1.3 编译,生成aidl接口
m指令或者make指令编译aidl。
android$ m vendor.yfe.hardware.demo
编译可能会遇到报错
error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:8:9: module "vendor.yfe.hardware.demo_interface": srcs: No sources for a previous version in aidl_api/vendor.yfe.hardware.demo/1. Was a version manually added to .bp file? This is added automatically by <module>-freeze-api.
error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:8:9: module "vendor.yfe.hardware.demo_interface": srcs: No sources provided in aidl_api/vendor.yfe.hardware.demo/1
21:42:26 soong bootstrap failed with: exit status 1
根据报错提醒,执行m vendor.demo.hal-freeze-api ,或者执行m vendor.yfe.hardware.demo-update-api,但是还是会报错,本人放弃了这种方式,采用手动创建aidl_api/vendor.yfe.hardware.demo/1/vendor/yfe/hardware/demo/IDemo.aidl
继续编译,又报新错
error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:5:1: module "vendor.yfe.hardware.demo-api" (created by module "vendor.yfe.hardware.demo_interface"): A frozen aidl_interface must have '.hash' file, but vendor.yfe.hardware.demo-V1 doesn't have it. Use the command below to generate hash.
(croot && system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash)
按照报错指令执行
croot && system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash
然后执行m vendor.demo.hal-freeze-api生成aidl_api/vendor.yfe.hardware.demo/current/vendor/yfe/hardware/demo/IDemo.aidl
android$ m vendor.demo.hal-freeze-api
至此aidl接口编译完成:
└── 1.0
├── aidl
│ └── vendor
│ └── yfe
│ └── hardware
│ └── demo
│ └── IDemo.aidl
├── aidl_api
│ └── vendor.yfe.hardware.demo
│ ├── 1
│ │ └── vendor
│ │ └── yfe
│ │ └── hardware
│ │ └── demo
│ │ └── IDemo.aidl
│ └── current
│ └── vendor
│ └── yfe
│ └── hardware
│ └── demo
│ └── IDemo.aidl
├── Android.bp
2,实现HAL服务功能
实现default目录下创建源文件、rc、xml、bp
default
├── Android.bp
├── DemoService.cpp
├── DemoService.h
├── service.cpp
├── vendor.yfe.hardware.demo-service.rc
└── vendor.yfe.hardware.demo-service.xml
DemoService.h:
#ifndef VENDOR_YFE_HARDWARW_DEMO_SERVICE_H
#define VENDOR_YFE_HARDWARW_DEMO_SERVICE_H
#include <aidl/vendor/yfe/hardware/demo/IDemo.h>
#include <aidl/vendor/yfe/hardware/demo/BnDemo.h>
namespace aidl::vendor::yfe::hardware::demo {
class DemoService : public BnDemo {
public:
DemoService();
ndk::ScopedAStatus getHelloString(std::string* _aidl_return) override;
ndk::ScopedAStatus add(int32_t a, int32_t b, int32_t* _aidl_return) override;
ndk::ScopedAStatus setValue(int32_t val) override;
ndk::ScopedAStatus getValue(int32_t* _aidl_return) override;
private:
int32_t mValue = 0;
};
}
#endif
DemoService.cpp:
#include "DemoService.h"
namespace aidl::vendor::yfe::hardware::demo {
DemoService::DemoService() = default;
ndk::ScopedAStatus DemoService::getHelloString(std::string* _aidl_return) {
*_aidl_return = "Hello from Vendor Demo HAL!";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus DemoService::add(int32_t a, int32_t b, int32_t* _aidl_return) {
*_aidl_return = a + b;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus DemoService::setValue(int32_t val) {
mValue = val;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus DemoService::getValue(int32_t* _aidl_return) {
*_aidl_return = mValue;
return ndk::ScopedAStatus::ok();
}
}
Hal服务入口service.cpp:
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "DemoService.h"
#include <utils/Log.h>
using namespace aidl::vendor::yfe::hardware::demo;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(4);
ABinderProcess_startThreadPool();
std::shared_ptr<IDemo> service = ndk::SharedRefBase::make<DemoService>();
const std::string name = IDemo::descriptor + std::string("/default");//get service name
if (AServiceManager_addService(service->asBinder().get(), name.c_str()) == STATUS_OK) {
ALOGI("vendor demo hal service registered: %s", name.c_str());
} else {
ALOGE("failed to add service");
return -1;
}
ABinderProcess_joinThreadPool();
return 0;
}
vendor.yfe.hardware.demo-service.rc:
service vendor.yfe.hardware.demo /vendor/bin/hw/vendor.yfe.hardware.demo-service
class hal
user root
group root
oneshot
vendor.yfe.hardware.demo-service.xml:
<manifest version="1.0" type="device">
<hal format="aidl">
<name>vendor.yfe.hardware.demo</name>
<version>1</version>
<interface>
<name>IDemo</name>
<instance>default</instance>
</interface>
</hal>
</manifest>
Android.bp:
cc_binary {
name: "vendor.yfe.hardware.demo-service",
soc_specific:true,
init_rc: ["vendor.yfe.hardware.demo-service.rc"],
relative_install_path: "hw",
vintf_fragments: ["vendor.yfe.hardware.demo-service.xml"],
srcs: [
"service.cpp",
"DemoService.cpp",
],
shared_libs: [
"libbinder_ndk",
"libcutils",
"libutils",
"liblog",
//"vendor.demo.hal-ndk",
"vendor.yfe.hardware.demo-V1-ndk",
],
cflags: [
"-Wall",
"-Werror",
],
}
编译:
$ m vendor.yfe.hardware.demo-service
遇到了报错:
[ 92% 207/224] echo "API dump for the current version of AIDL interface vendor.yfe.hardware.demo does not exist." && echo Run "m vendor.yfe.hardware.demo-update-api", or add "unstable: true" to the build
FAILED: out/soong/.intermediates/vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/vendor.yfe.hardware.demo-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface vendor.yfe.hardware.demo does not exist." && echo Run "m vendor.yfe.hardware.demo-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 vendor.yfe.hardware.demo does not exist.
Run m vendor.yfe.hardware.demo-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned
可以重新生成一下.hash
手动删除
android/vendor/yfe/saic_project/common/hardware/interfaces/demo1/vendor/yfe/hardware/demo$ rm -rf .hash
android/vendor/yfe/saic_project/common/hardware/interfaces/demo1/vendor/yfe/hardware/demo$ croot
android$ system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash
如果出现类似下面报错信息
The following HALs in device manifest are not declared in FCM <= level 7:
vendor.yfe.hardware.demo.IDemo/default (@1)
ERROR: files are incompatible: The following instances are in the device manifest but not specified in framework compatibility matrix:
vendor.yfe.hardware.demo.IDemo/default (@1)
Suggested fix:
1. Update deprecated HALs to the latest version.
2. Check for any typos in device manifest or framework compatibility matrices with FCM version >= 7.
3. For new platform HALs, add them to any framework compatibility matrix with FCM version >= 7 where applicable.
4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE.: Success
INCOMPATIBLE
20:07:09 ninja failed with: exit status 1
原因是我得基线原生得product/soc/msoc/qogirn6pro/march/arm64/manifest.xml里写死了
所以我得vendor.yfe.hardware.demo-service.xml里不能带target-level版本号
3,添加manifest.xml
在项目目录android/vendor/yfe/saic_project/common/device/manifest下创建manifest.mk、vendor_framework_compatibility_matrix.xml
android/vendor/yfe/saic_project/common/device/manifest$ cat manifest.mk
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += \
vendor/yfe/saic_project/common/device/manifest/vendor_framework_compatibility_matrix.xml
android/vendor/yfe/saic_project/common/device/manifest$ cat vendor_framework_compatibility_matrix.xml
<compatibility-matrix version="1.0" type="framework">
<hal format="aidl" optional="true">
<name>vendor.yfe.hardware.demo</name>
<version>1</version>
<interface>
<name>IDemo</name>
<instance>default</instance>
</interface>
</hal>
</compatibility-matrix>
然后在项目主mk文件saic_car.mk里include 这个manifest.mk,同时将加入打包vendor.yfe.hardware.demo-service
android/vendor/yfe/saic_project/common/device$ cat saic_car.mk
... ...
-include vendor/yfe/saic_project/common/device/manifest/manifest.mk
PRODUCT_PACKAGES += \
vendor.yfe.hardware.demo-service \
vendor.yfe.hardware.demo-V1-java //这个需要加,不然不生成jar包
至此再整编系统试一下,应该就可以编过了
4,添加selinux相关
vendor/yfe/saic_project/common/device/sepolicy/vendor/目录下创建demo_service.te,file_contexts,hwservice_contexts。如果项目已有file_contexts,hwservice_contexts,则只用添加声明即可。
声明hwservice_contexts:
vendor/yfe/saic_project/common/device/sepolicy$ cat vendor/hwservice_contexts
#add for demo
vendor.yfe.hardware.demo::IDemo/default u:object_r:demo_hwservice_t:s0
声明file_contexts:
... ...
/vendor/bin/hw/vendor.yfe.hardware.demo-service u:object_r:demo_service_t_exec:s0
demo_service.te:
android/vendor/yfe/saic_project/common/device/sepolicy$ cat vendor/demo_service.te
# 基础类型定义(车载Android13 100%兼容)
type demo_service_t, domain;
type demo_service_t_exec, exec_type, file_type, vendor_file_type;
type demo_hwservice_t, hwservice_manager_type;
# 允许init启动服务
init_daemon_domain(demo_service_t)
# Binder基础权限(必须)
binder_use(demo_service_t)
binder_service(demo_service_t)
add_hwservice(demo_service_t, demo_hwservice_t)
# 允许APP访问
# allow platform_app_t demo_hwservice_t:hwservice_manager find;
# allow system_app_t demo_hwservice_t:hwservice_manager find;
# allow untrusted_app_t demo_hwservice_t:hwservice_manager find;
# allow platform_app_t demo_service_t:binder call;
# allow system_app_t demo_service_t:binder call;
# allow untrusted_app_t demo_service_t:binder call;
经过aidl接口声明,HAL服务实现,manifest.xml aidl接口声明,selinux处理等流程后,aidl hal服务基本完成。整编系统,烧录机器。查看服务是否开机启动
5,APP验证接口是否可用
jar包生成物在out目录位置out/target/common/obj/JAVA_LIBRARIES/vendor.yfe.hardware.demo-V1-java_intermediates/classes.jar
5.1,jar引用
Android Studio工程下创建libs目录
取出jar包放在工程源码libs目录
build.gradle文件里添加implementation files(‘libs/classes.jar’)
... ....
dependencies {
//compileOnly files('libs/classes.jar')
implementation files('libs/classes.jar')//添加
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}
... ...
5.2,Aidl接口使用
见下面:
package com.example.aidlhal;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import vendor.yfe.hardware.demo.IDemo;//引用头文件
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button bt_1;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
bt_1 = findViewById(R.id.bt_1);
bt_1.setOnClickListener(this);
Log.d("luyao7870","000000000000");
getService();
try {
Log.d("luyao7870","bt_1 0000000000");
getService().add(1,2);//调用Aidl接口验证功能是否正常
} catch (RemoteException e) {
Log.d("luyao7870","bt_1 111111111111");
throw new RuntimeException(e);
}
}
@Override
public void onClick(View view) {
int id = view.getId();
if(id == R.id.bt_1) {
Log.d("luyao7870","bt_1");
try {
Log.d("luyao7870","bt_1 0000000000");
getService().add(1,2);//调用Aidl接口验证功能是否正常
} catch (RemoteException e) {
Log.d("luyao7870","bt_1 111111111111");
throw new RuntimeException(e);
}
} else {
Log.d("luyao7870","else");
}
}
//获取AIDL服务对象
public static IDemo getService() {
try {
// 反射获取 ServiceManager
Class<?> smClass = Class.forName("android.os.ServiceManager");
java.lang.reflect.Method getService = smClass.getMethod("getService", String.class);
IBinder binder = (IBinder) getService.invoke(null, "vendor.yfe.hardware.demo.IDemo/default");//根据服务名得到binder对象
if (binder == null) {
Log.d("luyao7870","getService null");
return null;
}
Log.d("luyao7870","getService ! null");
return IDemo.Stub.asInterface(binder);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
更多推荐


所有评论(0)