目录
一、hidl基本语法
hidl文件后缀为.hal,语法借鉴了C语言和Java语言,相对来说比较简单。
/** */ 表示文档注释。此样式只能应用于类型、方法、字段和枚举值声明。
/* */ 表示多行注释。
// 表示注释一直持续到行尾。除 // 之外,换行符与任何其他空格一样。
文件第一行非注释语句为package 包名@版本;
interface声明接口,不含显式 extends 声明的接口会从 android.hidl.base@1.0::IBase(类似于 Java 中的 java.lang.Object)隐式扩展。隐式导入的 IBase 接口声明了多种不应也不能在用户定义的接口中重新声明或以其他方式使用的预留方法。这些方法包括:
ping
interfaceChain
interfaceDescriptor
notifySyspropsChanged
linkToDeath
unlinkToDeath
setHALInstrumentation
getDebugInfo
debug
getHashChain
import 语句是用于访问其他软件包中的软件包接口和类型的 HIDL 机制。import 语句本身涉及两个实体:
导入实体:可以是软件包或接口;以及被导入实体。
被导入实体:也可以是软件包或接口。
导入语句使用完全限定类型名称语法来提供被导入的软件包或接口的名称和版本:
import android.hardware.nfc@1.0; // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal
详细语法和说明请查看:
接口和软件包 | Android 开源项目 | Android Open Source Project (google.cn)
二、编写hal文件
在hardware/interfaces目录下创建的自己的接口目录和文件,示例如下:
$ mkdir -p helloworld/1.0
$ vim hardware/interfaces/helloworld/1.0/IHelloWorld.hal
package android.hardware.helloworld@1.0;
interface IHelloWorld {
helloworld(string name) generates (int32_t code);
};
三、编译环境设置
第一次执行后面的那些命令需要先执行以下命令编译源码:
source build/envsetup.sh
lunch
make
非初次编译仅执行 source build/envsetup.sh 即可
四、生成Android.bp文件
在hardware/interfaces目录下执行update-makefiles.sh脚本,会在hardware/interfaces/helloworld/1.0目录下自动生成Android.bp文件,示例如下:
$ ./update-makefiles.sh
$ cat hardware/interfaces/helloworld/1.0/Android.bp
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
name: "android.hardware.helloworld@1.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"IHelloWorld.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
gen_java: true,
}
通过命令行执行 hidl-gen -O "" -Landroidbp -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.helloworld@1.0 也可以达到同样的效果
五、生成c++模板代码
1. hidl-gen工具安装
make hidl-gen
2. hidl-gen工具使用
使用方法:hidl-gen -o output-path -Llanguage (-rinterface-root) fqname
示例:
hidl-gen -o hardware/interfaces/helloworld/1.0/default/ -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.helloworld@1.0
参数说明:
-L: 语言类型,包括c++, c++-headers, c++-sources, export-header, c++-impl, java, java-constants, vts, makefile, androidbp, androidbp-impl, hash等。hidl-gen可根据传入的语言类型产生不同的文件。
fqname: 完全限定名称的输入文件。比如本例中android.hardware.helloworld@1.0,要求在源码目录下必须有hardware/interfaces/helloworld/1.0/目录。对于单个文件来说,格式如下:package@version::fileName,比如android.hardware.helloworld@1.0::types.Feature。对于目录来说。格式如下package@version,比如android.hardware.helloworld@1.0。
-r: 格式package:path,可选,对fqname对应的文件来说,用来指定包名和文件所在的目录到Android系统源码根目录的路径。如果没有制定,前缀默认是:android.hardware,目录是Android源码的根目录。
-o:存放hidl-gen产生的中间文件的路径。
3. 模板代码
执行第2步的命令后会在hardware/interfaces/helloworld/1.0/default/生成HelloWorld.h和HelloWorld.cpp两个文件,同时会在out/soong/.intermediates/hardware/interfaces/helloworld/1.0/目录下生成模块代码所依赖的头文件和so库。
$ cat hardware/interfaces/helloworld/1.0/default/HelloWorld.cpp
// FIXME: your file license if you have one
#include "HelloWorld.h"
namespace android::hardware::helloworld::implementation {
// Methods from ::android::hardware::helloworld::V1_0::IHelloWorld follow.
Return<int32_t> HelloWorld::helloworld(const hidl_string& name) {
// TODO implement
return int32_t {};
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
//IHelloWorld* HIDL_FETCH_IHelloWorld(const char* /* name */) {
//return new HelloWorld();
//}
//
} // namespace android::hardware::helloworld::implementation
$ cat hardware/interfaces/helloworld/1.0/default/HelloWorld.h
// FIXME: your file license if you have one
#pragma once
#include <android/hardware/helloworld/1.0/IHelloWorld.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
namespace android::hardware::helloworld::implementation {
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
struct HelloWorld : public V1_0::IHelloWorld {
// Methods from ::android::hardware::helloworld::V1_0::IHelloWorld follow.
Return<int32_t> helloworld(const hidl_string& name) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" IHelloWorld* HIDL_FETCH_IHelloWorld(const char* name);
} // namespace android::hardware::helloworld::implementation
HelloWorld.cpp中的HelloWorld::helloworld(const hidl_string& name)就是我们需要实现的方法。
六、编译
执行命令mm hardware/interfaces/helloworld/1.0/default/就可以编译我们刚才开发的模块了,在out/target/product/<device>/vendor/lib/hw/android::hardware::helloworld@1.0-imp.so
七、添加hidl接口清单
代码开发完成后我们还需要在system/libhidl/vintfdata/manifest.xml中添加我们新增的接口服务,具体做法如下:
$vim system/libhidl/vintfdata/manifest.xml
<hal format="hidl">
<name>android.hardware.helloworld</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IHelloWorld</name>
<instance>default</instance>
</interface>
<fqname>@1.0::IHelloWorld/default</fqname>
</hal>
详情可参考:Android系统之VINTF(1)manifests&compatibility matrices - 君の内存
八、selinux配置
具体selinux配置规则可根据项目需求进行配置,这里说一下需要配置的几条基本规则。
$vim system/sepolicy/private/file_contexts
/vendor/bin/hw/android.hardware.helloworld@1.0-server u:object_r:helloworld_exec:s0
$vim system/sepolicy/public/file.te
type helloworld_data_file, file_type;
typeattribute helloworld_data_file data_file_type, core_data_file_type;
$vim system/sepolicy/private/service_contexts
android.hardware.helloworld::IHelloWorld u:object_r:android.hardware.helloworld_service:s0
$vim system/sepolicy/private/helloworld.te
type helloworld, domain, data_between_core_and_vendor_violators, binder_in_vendor_violators, system_executes_vendor_violators, osproc_domain, osplatform_domain, mlstrustedsubject;
type helloworld_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(helloworld)
type hwhelloworld_service, hwservice_manager_type;
add_hwservice(helloworld, hwhelloworld_service);
allow helloworld hwservicemanager_prop:file read;
allow helloworld hidl_base_hwservice:hwservice_manager add;
allow helloworld hwservicemanager:binder { transfer call};
allow helloworld hwservicemanager_prop:file { getattr map open read };