本文已参与「新人创造礼」活动,一起敞开创造之路。

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 definitions
ITEM =
    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 EXTENDS
EXTENDS = <empty> | extends import_name  // must be interface, not package
GENERATES = 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<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]
FIELD =
   TYPE identifier
UFIELD =
   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
     constexpr
ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION
ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)
ANNO_ENTRY =
     identifier=VALUE
VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations
ENUM_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文件

参照如下,能够根据自己的需求恰当的增删
在leeservice目录创立自己的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/types.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/impl
PKG=vendor.lee.lee@1.0
hidl-gen  -Landroidbp  -rvendor.lee.lee:vendor/lee/interfaces/leeservice $PKG
hidl-gen -o $LOC -Lc++-impl  -rvendor.lee.lee:vendor/lee/interfaces/leeservice $PKG
hidl-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.bp
3 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 <LeeManager.h>
#include <android/log.h>
#include <hidl/HidlTransportSupport.h>
using namespace android;
using namespace vendor::lee::lee::V1_0::implementation;
int main(int /* argc */, char* /* argv */[]) {
    android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
    sp<LeeManager> mLeeManager = new LeeManager();
    status_t status = mLeeManager->registerAsService();
    if (status != OK) {
        ALOGE("Unable to register lee 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 system
on 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.lee</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>ILeeManager</name>
            <instance>default</instance>
        </interface>
    </hal>

并在vendor_framework_compatibility_matrix.xml增加如下代码

    <hal format="hidl" optional="true">
        <name>vendor.lee.lee</name>
        <version>1.0</version>
        <interface>
            <name>ILeeManager</name>
             <instance>default</instance>
        </interface>
    </hal>

至此hidl service部分已经悉数完成
剩余的便是根据需求装备selinux的权限了