android HIDL HAL控制LED demo(一)之C++作客户端

目录

    • 基本环境
    • 演示场景
    • 一、 HIDL 代码
    • 二、纯 Binder 化 HAL
    • 三、HAL 纯绑定式服务器
    • 四、C++实现 HAL 客户端
    • 五、JAVA实现用户界面APP
    • 六、系统配置
    • 七、测试和总结
    • 参考文献

基本环境

  • 开发板:hikey960 (4G+32G版本)
  • 代码:aosp,Android R(master分支)
  • 开发环境:64bit ubuntu 16.04

演示场景

   Android 8.0 或更高版本的设备必须使用 HIDL 语言编写 HAL1。HIDL HAL类型分为Binderized HALs(绑定式HAL)和Passthrough HALs(直通式HAL);拜读 AOSP对两种HAL的规定,总结:除了[email protected][email protected] 两个被强制规定采用直通式HAL外,其它的HAL采用绑定式HAL必然不会有 VTS 问题,绑定式HAL是google aosp主推方式;故本文仅介绍使用纯绑定式 HAL实现以下场景:
   通过APP控制,最终在HAL中通过文件操作函数open()、close()、write()访问LED的设备节点,控制LED的亮灭。
  本文涉及到的关键源码我已释放到github上面:https://github.com/LuciferZhu/android_drviver_demo,使用方法如下。

$ cd aosp/
$ git clone [email protected]:LuciferZhu/android_drviver_demo.git
$ mv android_drviver_demo my_demo

一、 HIDL 代码

   已发布的 HIDL 软件包的根目录为 hardware/interfacesvendor/vendorName(例如,对于 Pixel 设备,根目录为 vendor/google),但为了熟悉HIDL软件包从零到一的流程,我们把demo代码部署在全新的根目录my_demo/interfaces/上面,执行命令:

$ croot                                       # 这个命令在对源码进行source和lunch后才有
$ mkdir -p my_demo/interfaces/led/1.0/default
$ touch my_demo/interfaces/led/1.0/ILed.hal

   上面创建的ILed.hal是HAL接口描述文件,要在其中定义开放给上层的接口,内容如下。其中参数的数据类型的表示需参考HIDL基元与C++的数据类型对应关系表。

package my_demo.hardware.led@1.0;   /* 整个HAL的软件包名称,包名前缀“my_demo.hardware”由后面要定义的my_demo/interfaces/Android.bp决定 */

interface ILed {
   control(uint32_t enable) generates (int32_t retval);   /* 调用接口会返回一个 int32_t 型数*/
};

二、纯 Binder 化 HAL

① 使用aosp提供的hidl-gen工具,通过ILed.hal生成HAL的必要文件。

$ touch my_demo/interfaces/led/1.0/hidl-generate.sh
$ make hidl-gen -j6                   # 手动生成 hidl-gen 工具,编译aosp时并没有默认生成

   脚本hidl-generate.sh内容如下所示。

#!/bin/bash
set -e

if [ ! -d $ANDROID_BUILD_TOP/my_demo/interfaces ] ; then
 echo "Where is my_demo/interfaces?";
 exit 1;
fi

if [ ! -d $ANDROID_BUILD_TOP/system/libhidl/transport ] ; then
 echo "Where is system/libhidl/transport?";
 exit 1;
fi

PACKAGE=[email protected]
LOC=$ANDROID_BUILD_TOP/my_demo/interfaces/led/1.0/default/
options="-rmy_demo.hardware:my_demo/interfaces \
       -randroid.hidl:system/libhidl/transport"

#make hidl-gen -j6

hidl-gen -o $LOC -Lc++-impl $options $PACKAGE

hidl-gen -o $LOC -Landroidbp-impl $options $PACKAGE

echo done!

   如下所示执行脚本hidl-generate.sh并查看my_demo/interfaces/led目录的结构;可见my_demo/interfaces/led/1.0/default/下新生成了三个文件。

$ chmod +x my_demo/interfaces/led/1.0/hidl-generate.sh
$ ./my_demo/interfaces/led/1.0/hidl-generate.sh
$ tree my_demo/interfaces/led/
my_demo/interfaces/led/
└── 1.0
    ├── default
    │   ├── Android.bp
    │   ├── Led.cpp
    │   └── Led.h
    ├── hidl-generate.sh
    └── ILed.hal

2 directories, 5 files

② 借助system/tools/hidl/update-makefiles-helper.sh中的do_makefiles_update函数生成HAL的必要make-files,具体操作如下:

$ touch my_demo/interfaces/update-makefiles.sh
$ chmod +x my_demo/interfaces/update-makefiles.sh

  编辑my_demo/interfaces/update-makefiles.sh内容如下所示。其中第14行指定了以目录my_demo/interfaces为软件包my_demo.hardware根目录,进行更新或生成该软件包下子包的makefiles文件。

#!/bin/bash
# Script to update Android make-files for HAL and VTS modules.

set -e

if [ -z "$ANDROID_BUILD_TOP" ]; then
    echo "Missing ANDROID_BUILD_TOP env variable. Run 'lunch' first."
    exit 1
fi

source $ANDROID_BUILD_TOP/system/tools/hidl/update-makefiles-helper.sh

do_makefiles_update \
  "my_demo.hardware:my_demo/interfaces" \
  "android.hidl:system/libhidl/transport"

  函数do_makefiles_update要求在Android源码根目录执行脚本update-makefiles.sh,执行该脚本如下所示。可知新生成了my_demo/interfaces/led/1.0/Android.bp,它将会控制编译生成HIDL接口[email protected],该软件包还会导出一些必要的中间件,具体参考《Google aosp > 设计 > 架构 > HIDL(C++) > 软件包 > 生成的文件》。

$ ./my_demo/interfaces/update-makefiles.sh 
Updating makefiles for my_demo.hardware in /home/lucifer/samba_share/android_code/hikey960/aosp/my_demo/interfaces.
Updating [email protected]
$ tree my_demo/interfaces/
my_demo/interfaces/
├── led
│   └── 1.0
│       ├── Android.bp
│       ├── default
│       │   ├── Android.bp
│       │   ├── Led.cpp
│       │   └── Led.h
│       ├── hidl-generate.sh
│       └── ILed.hal
└── update-makefiles.sh

3 directories, 7 files

③ 指定目录my_demo/interfaces作为HIDL软件包my_demo.hardware的根目录。具体操作如下:

$ touch my_demo/interfaces/Android.bp

  编辑my_demo/interfaces/Android.bp内容如下:

hidl_package_root {
    name: "my_demo.hardware",
    path: "my_demo/interfaces",
}

④ 实现控制LED的纯绑定式hal代码。如下图所示my_demo/interfaces/led/1.0/default/Led.cpp是前面通过aosp自带工具hidl-gen生成的HAL核心代码。
android HIDL HAL控制LED demo(一)之C++作客户端_第1张图片
  我们在这个基础框架上填充我们的实现代码后如下所示。

// FIXME: your file license if you have one

#define LOG_TAG "[email protected]"
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "Led.h"

namespace my_demo {
namespace hardware {
namespace led {
namespace V1_0 {
namespace implementation {

static const char THE_DEVICE[] = "/sys/devices/platform/leds/leds/user_led3/brightness";

// Methods from ::my_demo::hardware::led::V1_0::ILed follow.
Led::Led() {
    ALOGD("%s() ++++++++", __func__);
}

Led::~Led() {
    ALOGD("%s() ++++++++", __func__);
}

Return<int32_t> Led::control(uint32_t enable) {
    char ctrl_str[4];
    int ret = 0;
    ALOGD("%s() ++++++++ enable=%d", __func__, enable);

    int fd = open(THE_DEVICE, O_RDWR);
    if (fd < 0) {
        ALOGE("open: %s", strerror(errno));
        ret = -1; 
        goto err_open;
    }   

    memset(ctrl_str, '\0', sizeof(ctrl_str));
    if (enable)
        strcpy(ctrl_str, "255");
    else
        strcpy(ctrl_str, "0");

    ALOGD("ctrl_str='%s'", ctrl_str);
    ret = write(fd, ctrl_str, strlen(ctrl_str)+1);
    if (ret < 0) {
        ALOGE("write: %s", strerror(errno));
        ret = -1; 
        goto err_write;
    }

    close(fd);
    return 0;
err_write:
    close(fd);
err_open:
    return int32_t {ret};
}
// Methods from ::android::hidl::base::V1_0::IBase follow.

}  // namespace implementation
}  // namespace V1_0
}  // namespace led
}  // namespace hardware
}  // namespace my_demo

  上面可看到我添加了Led结构体的构造函数Led::Led()和析构函数Led::~Led(),因此还要修改my_demo/interfaces/led/1.0/default/Led.h成如下所示,其中第25、26行是新添加的函数声明。

// FIXME: your file license if you have one

#pragma once

#include 
#include 
#include 

namespace my_demo {
namespace hardware {
namespace led {
namespace V1_0 {
namespace 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 Led : public ILed {
    // Methods from ::my_demo::hardware::led::V1_0::ILed follow.
    Led();
    ~Led();
    Return<int32_t> control(uint32_t enable) override;
    // Methods from ::android::hidl::base::V1_0::IBase follow.
};

}  // namespace implementation
}  // namespace V1_0
}  // namespace led
}  // namespace hardware
}  // namespace my_demo

三、HAL 纯绑定式服务器

  对于纯绑定式HAL,HAL的调用者将会通过HwBinder RPC通信进行间接调用HAL接口,所以我们要构建一个守护进程用于处理这些HwBinder通信请求。

① 创建并编写服务器代码my_demo/interfaces/led/1.0/default/service.cpp内容如下所示。第16行调用configureRpcThreadpool()设置当前进程用于hwbinder通信的最大线程数;第20行的registerAsService()方法是Led结构体继承于自动生成的my_demo/hardware/led/1.0/ILed.h中的ILed结构体,它会向 hwservicemanager注册HAL接口实现;第29行执行joinRpcThreadpool()会将当前的通信加入HwBinder的线程池进行循环。

#define LOG_TAG "[email protected]"
#include 
#include 
#include 
#include 
#include "Led.h"

using my_demo::hardware::led::V1_0::implementation::Led;
using android::sp;
using android::status_t;

int main(int /* argc */, char* /* argv */ []) {
    // This function must be called before you join to ensure the proper
    // number of threads are created. The threadpool will never exceed
    // size one because of this call.
    ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);

    ALOGD("prepare for [email protected]");
    sp<ILed> led = new Led();
    const status_t status = led->registerAsService();
    if (status != ::android::OK) {
        ALOGE("Can't register service of Led");
        return 1; // or handle error
    }

    // Adds this thread to the threadpool, resulting in one total
    // thread in the threadpool. We could also do other things, but
    // would have to specify 'false' to willJoin in configureRpcThreadpool.
    ::android::hardware::joinRpcThreadpool();
    return 1; // joinRpcThreadpool should never return
}

② 创建并编辑my_demo/interfaces/led/1.0/default/[email protected],用于实现开机自启动上述守护进程。

service my_demo.led-1-0 /vendor/bin/hw/my_demo.hardware.led@1.0-service
    class hal
    user system
    group system

③ 前面hidl-gen自动生成的my_demo/interfaces/led/1.0/default/Android.bp只适用于直通式HAL,需要修改成如下所示才适用于纯绑定式HAL服务器。将控制生成并部署到机器的/vendor/bin/hw/[email protected]/vendor/etc/init/[email protected]

cc_binary {
    // FIXME: this should only be -impl for a passthrough hal.
    // In most cases, to convert this to a binderized implementation, you should:
    // - change '-impl' to '-service' here and make it a cc_binary instead of a
    //   cc_library_shared.
    // - add a *.rc file for this module.
    // - delete HIDL_FETCH_I* functions.
    // - call configureRpcThreadpool and registerAsService on the instance.
    // You may also want to append '-impl/-service' with a specific identifier like
    // '-vendor' or '-' etc to distinguish it.
    name: "[email protected]",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    vendor: true,
    init_rc: ["[email protected]"],
    srcs: [
        "Led.cpp",
        "service.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "liblog",
        "[email protected]",
    ],
}

四、C++实现 HAL 客户端

① 创建文件my_demo/jni/ledHidl_jni/ledNative.cpp并填充如下代码。我们在 JNI 代码中实现HAL客户端,当要使用HAL接口时,需要调用静态函数ILed::getService();来获取第三章注册到hwservicemanager的服务器实例,通过智能指针如hidlService->control(1)的形式调用服务器中的接口。

  • 代码第3、4、5、8和31行是hidl hal客户端必须包含的代码样式。
#define LOG_TAG "ledNative.cpp"
#include 
#include 
#include 
#include 
#include "jni.h"

using my_demo::hardware::led::V1_0::ILed;
using android::sp;
using android::status_t;

static const char *classPathName = "com/example/lowlevel/LedNative";

jint openLed(JNIEnv* /*env*/, jobject /*thiz*/)
{
    ALOGD("------%s", __FUNCTION__);
    return 0;
}

jint closeLed(JNIEnv* /*env*/, jobject /*thiz*/)
{
    ALOGD("------%s", __FUNCTION__);
    return 0;
}


jint ledOn(JNIEnv* /*env*/, jobject /*thiz*/)
{
    jint ret;
    ALOGD("------%s", __FUNCTION__);
    sp<ILed> hidlService = ILed::getService();
    if (hidlService == nullptr) {
        ALOGE("can't not get ILed service");
        return -1; 
    }   

    ret = hidlService->control(1);
    if(ret < 0) {
        ALOGE("hidlService->control(1) failed");
        return -1; 
    }   
    return 0;
}

jint ledOff(JNIEnv* /*env*/, jobject /*thiz*/)
{
    jint ret;
    ALOGD("------%s", __FUNCTION__);
    sp<ILed> hidlService = ILed::getService();
    if (hidlService == nullptr) {
        ALOGE("can't not get ILed service");
        return -1;
   }

    ret = hidlService->control(0);
    if(ret < 0) {
        ALOGE("hidlService->control(0) failed");
        return -1;
    }
    return 0;
}

static JNINativeMethod ledMethod[] = {
  {"openDev", "()I", (void*)openLed},
  {"closeDev", "()I", (void*)closeLed},
  {"devOn", "()I", (void*)ledOn},
  {"devOff", "()I", (void*)ledOff},
};

jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
    jint ret;
    JNIEnv* env = NULL;
    ALOGD("------%s", __FUNCTION__);
    ret = vm->GetEnv((void**)&env, JNI_VERSION_1_4);
    if (ret != 0) {
        ALOGE("vm->GetEnv error, ret = %d", ret);
        return -1;
    }

    jclass cls = env->FindClass(classPathName);
    if (cls == NULL) {
        ALOGE("Native registration unable to find class '%s'", classPathName);
        return JNI_FALSE;
    }

    ret = env->RegisterNatives(cls, ledMethod, sizeof(ledMethod)/sizeof(ledMethod[0]));
    if (ret < 0) {
        ALOGE("RegisterNatives failed for '%s'", classPathName);
        return JNI_FALSE;
    }

    return JNI_VERSION_1_4;
}

② 创建文件 my_demo/jni/ledHidl_jni/Android.bp 并填充如下代码。其中第9、10行的libhidlbase[email protected] 是HAL客户端模块必须连接的动态库样式。

cc_library_shared {
    name: "libled_jni",
    // All of the source files that we will compile.
    srcs: ["ledNative.cpp"],
    // All of the shared libraries we link against.
    shared_libs: [
        "liblog",
        "libutils",
        "libhidlbase",
        "[email protected]",
    ],
    // No static libraries.
    static_libs: [],
    cflags: [
        "-Wall",
        "-Werror",
    ],
}

五、JAVA实现用户界面APP

我们在第四章中已经实现JNI代码,在app中只需要常规调用JNI接口即可间接控制LED。
① 使用Android studio创建工程LedControl,创建native接口映射类LedControl/app/src/main/java/com/example/lowlevel/LedNative.java内容如下。

package com.example.lowlevel;

public class LedNative {
    static {
        System.loadLibrary("led_jni");
    }   
    public native int openDev();
    public native int closeDev();
    public native int devOn();
    public native int devOff();
}

② 创建主程序LedControl/app/src/main/java/com/example/ledcontrol/MainActivity.java代码如下:

package com.example.ledcontrol;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.lowlevel.LedNative;

public class MainActivity extends AppCompatActivity {
    private final String TAG = "LedControl";
    private Button btn_led = null;
    LedNative ledNative = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        ledNative = new LedNative();
        ledNative.openDev();
    }

    public void initView() {
        btn_led = (Button) findViewById(R.id.btn_led);
    }

    public void onClickLed(View v) {

        if (btn_led.getText().equals("开灯") ) {
            Log.d(TAG, "turn on led");
            btn_led.setText("关灯");
            ledNative.devOn();

        } else {
            Log.d(TAG, "turn off led");
            btn_led.setText("开灯");
            ledNative.devOff();

        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ledNative.closeDev();
    }
}

③ 创建app布局文件LedControl/app/src/main/res/layout/activity_main.xml,界面较为简单,只有一个用来控制LED亮灭的按钮。


<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_led"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开灯"
        android:textSize="@android:dimen/app_icon_size"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:onClick="onClickLed"/>

android.support.constraint.ConstraintLayout>

④ 将整个LedControl AS工程代码拷贝到目录aosp/my_demo/jni/ledHidl_jni/app中,参考《android studio项目嵌入到Android系统源码》或者我的github源码的修改提交commit c45c72caf,对app代码进行修改,方可在集成在aosp代码中。
  其中新增的模块编译控制文件my_demo/jni/ledHidl_jni/app/LedControl/Android.bp如下所示。第三行certificate: "platform",指定该APP为platform_app,使得可在下一章中赋予访问HIDL接口的权限。

android_app {
    name: "LedControl",
    certificate: "platform",
    //product_specific: true,
    srcs: ["app/src/main/java/**/*.java"],

    resource_dirs: ["app/src/main/res"],
    manifest: "app/src/main/AndroidManifest.xml",

    jni_libs: ["libled_jni"],
    static_libs: [
        "androidx-constraintlayout_constraintlayout",
        "androidx-constraintlayout_constraintlayout-solver",
    ],  

    optimize: {
        enabled: false,
    },  
    sdk_version: "current",
    dex_preopt: {
        enabled: false,
    },  
}

六、系统配置

HIDL源码和用于测试工具代码前面已经完成,还需要做些板级项目配置以及selinux配置,方可把测试程序正常运行起来。
① 把HIDL接口服务器可执行程序led jni库app添加到板级项目配置的PRODUCT_PACKAGES中,这些模块才真正被编进安卓镜像。配置文件device/linaro/hikey/hikey960/device-hikey960.mk加入如下内容:

PRODUCT_PACKAGES += \
        my_demo.hardware.led@1.0-service \
        my_demo.hardware.led@1.0.so \
        libled_jni \
        LedControl

② 在第二章的HAL接口实现中,我们使用sysfs中设备拓扑的led设备属性文件/sys/devices/platform/leds/leds/user_led3/brightness,进行led的亮灭控制,默认情况下只有root用户才有权限访问改属性文件,所以我们要在on post-fs阶段设置该设备属性文件的访问权限。修改文件device/linaro/hikey/hikey960/init.hikey960.rc加入chmod 0666 /sys/devices/platform/leds/leds/user_led3/brightness如下图所示。
android HIDL HAL控制LED demo(一)之C++作客户端_第2张图片
③ 在文件 device/linaro/hikey/manifest.xml 中添加如下代码用以声明我们提供的 HAL 实例。更多细节参考《aosp.设计.测试.供应商测试套件(VTS).测试框架.HAL可测试性检查.确定支持哪些 HAL》

    <hal format="hidl">
        <name>my_demo.hardware.ledname>
        <transport>hwbindertransport>
        <version>1.0version>
        <interface>
            <name>ILedname>
            <instance>defaultinstance>
        interface>
    hal>

④ 配置selinux。
  修改或创建device/linaro/hikey/sepolicy/attributes文件附加如下代码:

attribute hal_led;
attribute hal_led_client;
attribute hal_led_server;

  创建编辑device/linaro/hikey/sepolicy/hal_led_default.te。新建了一个hal_led_default类型的域,目的是用于后面标识HAL服务器/vendor/bin/hw/[email protected]
  第18行至22行,是赋予HAL服务器访问设备属性文件/sys/devices/platform/leds/leds/user_led3/brightness的规则,该设备属性文件的上下文名字默认在system/sepolicy/prebuilts/api/29.0/private/genfs_contexts被定义成genfscon sysfs /class/leds u:object_r:sysfs_leds:s0;所以第18行至22行应根据实际HAL接口所访问的资源来编写。

type hal_led_default, domain, mlstrustedsubject;
type hal_led_default_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(hal_led_default)
hal_server_domain(hal_led_default, hal_led)

# HwBinder IPC from client to server, and callbacks
binder_call(hal_led_client, hal_led_server)
binder_call(hal_led_server, hal_led_client)

add_hwservice(hal_led_server, hal_led_hwservice)
allow hal_led_client hal_led_hwservice:hwservice_manager find;

##########################################################
# allow HAL module to open/read/write/ioctl
# /sys/devices/platform/leds (/sys/class/leds)
##########################################################
allow hal_led sysfs_leds:lnk_file read;
allow hal_led sysfs_leds:file rw_file_perms;
allow hal_led sysfs_leds:dir r_dir_perms;

allow hal_led_default sysfs:file rw_file_perms;

  在device/linaro/hikey/sepolicy/file_contexts添加如下内容,用于声明守护进程/vendor/bin/hw/[email protected]为前面新定义的hal_led_default_exec type,从而这个进程属于hal_led_default的安全上下文。

/vendor/bin/hw/my_demo\.hardware\.led@1\.0-service  u:object_r:hal_led_default_exec:s0

  修改或创建device/linaro/hikey/sepolicy/hwservice.te文件附加如下代码。新定义了一个名为hal_led_hwservice的type,用于后面声明my_demo.hardware.led::ILed的安全上下文。

type hal_led_hwservice, hwservice_manager_type;

  修改或创建device/linaro/hikey/sepolicy/hwservice_contexts文件附加如下代码。

my_demo.hardware.led::ILed      u:object_r:hal_led_hwservice:s0

  修改或创建device/linaro/hikey/sepolicy/platform_app.te文件附加如下代码。在第五章中我们给用户界面app签名成platform_app,它虽然通过JNI来获取HIDL服务和接口,但这时JNI跟app在同样的安全上下文。在JNI中我们通过ILed::getService()来获取第三章注册到hwservicemanager的服务器实例,最后通过hwbinder进行实际HAL接口的调用,所以需要赋予相应的权限才可顺利执行。

allow platform_app hal_led_hwservice:hwservice_manager { find };
allow platform_app hal_led_default:binder { call };

  修改device/linaro/hikey/sepolicy/system_server.te文件附加如下代码:

hal_client_domain(system_server, hal_led)

七、测试和总结

用户界面APP如下所示,其已作为platform_app内置于系统。
android HIDL HAL控制LED demo(一)之C++作客户端_第3张图片
点击按钮开灯后,硬件呈现效果如下图所示。
android HIDL HAL控制LED demo(一)之C++作客户端_第4张图片
本文通过C++实现了HIDL HAL的客户端,另外还可以通过JAVA实现客户端,可以越过实现JNI的步骤,具体参考我的下一篇文章《android HIDL HAL控制LED demo(二)之JAVA作客户端》。

参考文献


  1. Google aosp > 设计 > 架构 > 硬件抽象层(HAL) > HAL类型 ↩︎

你可能感兴趣的:(Android,linux,github)