写一个自己的 Android(安卓)Hidl Service
HIDL
HAL 接口定义语言(简称 HIDL,发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。HIDL 允许指定类型和方法调用(会汇集到接口和软件包中)。从更广泛的意义上来说,HIDL 是用于在可以独立编译的代码库之间进行通信的系统。
HIDL 旨在用于进程间通信 (IPC)。进程之间的通信采用 Binder 机制。对于必须与进程相关联的代码库,还可以使用直通模式(在 Java 中不受支持)。
HIDL 可指定数据结构和方法签名,这些内容会整理归类到接口(与类相似)中,而接口会汇集到软件包中。尽管 HIDL 具有一系列不同的关键字,但 C++ 和 Java 程序员对 HIDL 的语法并不陌生。此外,HIDL 还使用 Java 样式的注释。
HIDL 设计
HIDL 的目标是,可以在无需重新构建 HAL 的情况下替换框架。HAL 将由供应商或 SOC 制造商构建,并放置在设备的 /vendor 分区中,这样一来,就可以在框架自己的分区中通过 OTA 替换框架,而无需重新编译 HAL。
HIDL 设计在以下方面之间保持了平衡:
- 互操作性。 在可以使用各种架构、工具链和编译配置来编译的进程之间创建可互操作的可靠接口。HIDL 接口是分版本的,发布后不得再进行更改。
-效率。 HIDL 会尝试尽可能减少复制操作的次数。HIDL 定义的数据以 C++ 标准布局数据结构传递至 C++ 代码,无需解压,可直接使用。此外,HIDL 还提供共享内存接口;由于 RPC 本身有点慢,因此 HIDL 支持两种无需使用 RPC 调用的数据传输方法:共享内存和快速消息队列 (FMQ)。
-直观。 通过仅针对 RPC 使用 in 参数,HIDL 避开了内存所有权这一棘手问题(请参阅 Android 接口定义语言 (AIDL));无法通过相应方法高效返回的值将通过回调函数返回。无论是将数据传递到 HIDL 中以进行传输,还是从 HIDL 接收数据,都不会改变数据的所有权,也就是说,数据所有权始终属于调用函数。数据仅需要在函数被调用期间保留,可在被调用的函数返回数据后立即清除。
HIDL 语法
根据设计,HIDL 语言与 C 语言类似(但前者不使用 C 预处理器)。下面未描述的所有标点符号(用途明显的 = 和 | 除外)都是语法的一部分。
注意:如需详细了解 HIDL 代码样式,请参阅代码样式指南。
- /** */ 表示文档注释。此样式只能应用于类型、方法、字段和枚举值声明。
- /* */ 表示多行注释。
- // 表示注释一直持续到行尾。除 // 之外,换行符与任何其他空格一样。
- 在以下示例语法中,从 // 到行尾的文本不是语法的一部分,而是对语法的注释。
- [empty] 表示该字词可能为空。
- ? 跟在文本或字词后,表示它是可选的。
- … 表示包含零个或多个项、使用指定的分隔符号分隔的序列。HIDL 中不含可变参数。
- 逗号用于分隔序列元素。
- 分号用于终止各个元素,包括最后的元素。
- 大写字母是非终止符。
- italics 是一个令牌系列,如 integer 或 identifier(标准 C 解析规则)。
- constexpr 是 C 样式的常量表达式(例如 1 + 1 和 1L << 3)。
- import_name 是软件包或接口名称,按 HIDL 版本编号中所述的方式加以限定。
- 小写 words 是文本令牌。
例如
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitionsITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier;VERSION = integer.integer;PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;PREAMBLE = interface identifier EXTENDSEXTENDS = | extends import_name // must be interface, not packageGENERATES = generates (FIELD, FIELD ...)// allows the Binder interface to be used as a type// (similar to typedef'ing the final identifier)IMPORTS = [empty] | IMPORTS import import_name;TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string| identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file| memory| pointer| vec| bitfield // TYPE is user-defined enum| fmq_sync| fmq_unsync| TYPE[SIZE]FIELD = TYPE identifierUFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier;SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier;SIZE = // Must be greater than zero constexprANNOTATIONS = [empty] | ANNOTATIONS ANNOTATIONANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...)ANNO_ENTRY = identifier=VALUEVALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotationsENUM_ENTRY = identifier | identifier = constexpr
以上摘自Google 官网
写自己的Hidl service
创建自己的代码工作目录
创建自己的service目录
例如 vendor/lee/interfaces/leeservice
mkdir -p vendor/lee/interfaces/leeservice
创建service版本1.0目录可以根据需要创建1.1/1.2或者2.0版本
mkdir -p vendor/lee/interfaces/leeservice/1.0
创建默认service实现目录
mkdir -p vendor/lee/interfaces/leeservice/1.0/default/impl
指定package-root
在vendor/lee/interfaces/leeservice创建Android.bp 然后写入
subdirs = [ "1.0","1.0/default",]hidl_package_root { name: "vendor.lee.lee", path: "vendor/lee/interfaces/leeservice",}
创建自己的Hal文件
参照如下,可以根据自己的需要适当的增删
在logservice目录创建自己的hal文件
- 接口hal文件
vendor/lee/interfaces/leeservice/1.0/ILeeManager.hal - callback的hal文件
vendor/lee/interfaces/leeservice/1.0/ILeeCallback.hal - 类型定义文件
vendor/lee/interfaces/leeservice/1.0/typers.hal
在接口hal文件中创建自己的接口
例如
package vendor.lee.lee@1.0;import ILeeCallback;interface ILeeManager { setLevel(int32_t level); getLevel() generates(int32_t level); requestString(string s); registerCallback(ILeeCallback callback); unregisterCallback(ILeeCallback callback);};
在callback的hal文件创建回调函数
例如
package vendor.lee.lee@1.0;interface ILeeCallback { OnLeeEvent(LeeEvent event, LeeExtra extra);};
在类型定义的hal中添加自己的定义
例如
package vendor.lee.lee@1.0;enum LeeEvent : uint32_t{ LEE_ADD = 0, LEE_DEL = 1,};struct LeeExtra { uint32_t extraSize; string extraPath;};
生成CPP文件和bp文件
在vendor/lee/interfaces/leeservice/目录执行
LOC=1.0/default/implPKG=vendor.lee.lee@1.0hidl-gen -Landroidbp -rvendor.lee.lee:vendor/lee/interfaces/leeservice $PKGhidl-gen -o $LOC -Lc++-impl -rvendor.lee.lee:vendor/lee/interfaces/leeservice $PKGhidl-gen -o $LOC -Landroidbp-impl -rvendor.lee.lee:vendor/lee/interfaces/leeservice $PKG
然后你就发现在impl目录生成了cpp文件及bp文件,这是自动生成发的空实现
现在文件树形结构如下
vendor/lee/interfaces/leeservice/|-- 1.0| |-- Android.bp| |-- ILeeCallback.hal| |-- ILeeManager.hal| |-- default| | `-- impl| | |-- Android.bp| | |-- LeeCallback.cpp| | |-- LeeCallback.h| | |-- LeeManager.cpp| | `-- LeeManager.h| `-- types.hal`-- Android.bp3 directories, 10 files
注释掉vendor/lee/interfaces/leeservice/1.0/default/impl/Android.bp中
// relative_install_path: “hw”,
并添加如下两句
local_include_dirs: [ ".", ], export_include_dirs: [ ".", ],
然后你就可以在LeeManager.cpp及其他文件中添加自己的实现了
添加service及rc
在vendor/lee/interfaces/leeservice/1.0/default添加service.cpp
添加如下代码
#include #include #include using namespace android;using namespace vendor::lee::lee::V1_0::implementation;int main(int /* argc */, char* /* argv */[]) { android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */); sp mLeeManager = new LeeManager(); status_t status = mLeeManager->registerAsService(); if (status != OK) { ALOGE("Unable to register log service (%d)", status); return 1; } android::hardware::joinRpcThreadpool(); return 1;}
在vendor/lee/interfaces/leeservice/1.0/default创建vendor.lee.lee@1.0-service.rc并添加如下代码
service lee-hal-1.0 /vendor/bin/hw/vendor.lee.lee@1.0-service class hal user system group systemon post-fs-data start lee-hal-1.0
自此hidlservice就创建完成了
但是此时上层应用是拿不到service的
需要注册service
注册halservice
修改自己board目录的manifest.xml
例如
device/google/wahoo/manifest.xml
添加如下代码
<hal format="hidl" optional="true"> <name>vendor.lee.leename> <transport>hwbindertransport> <version>1.0version> <interface> <name>ILeeManagername> <instance>defaultinstance> interface> hal>
并在vendor_framework_compatibility_matrix.xml添加如下代码
<hal format="hidl" optional="true"> <name>vendor.lee.leename> <version>1.0version> <interface> <name>ILeeManagername> <instance>defaultinstance> interface> hal>
至此hidl service部分已经全部完成
剩下的就是根据需要配置selinux的权限了
更多相关文章
- Android应用资源的使用方法(数组、颜色、尺寸、字符串、布尔、整
- 「Android」 APK瘦身探索
- Android学习笔记(4)---模拟手机拨号器
- Android中AS创建点9图片与使用
- RSA公钥、私钥的生成详解,包含Java、PHP、Android、iOS端
- Android布局类型资源(二)---XML、drawable、layout
- 【安卓笔记】res/raw与assets区别
- Android真机测试,Find Explorer无法打开data文件夹解决办法
- Android(安卓)studio文件编码格式怎么快速切换?