android 自定义驱动(第三篇:HIDL服务端)

2020-05-25  本文已影响0人  momxmo

简介

在android 8.0之前,HAL是一个个的.so库,通过dlpen来打开,库和framework位于同一个进程中;
android系统进入8.0时代之后,framework和hal运行于不同的进程,所有的HAL采用HIDL技术来完成。运行Android8.0的设备必须支持绑定式和直通式HAL:

当前的类型为:
Java -> Jni -> Binder 客户端 ====== Binder 通信 ======> Binder 服务端 -> Hal -> Kernel

这一篇文章则是HIDL中的Binder服务端;
HIDL制作主要流程如下:
1.定义接口文件;
2.使用工具,根据接口文件生成代码;
3.完善接口函数
4.编译

一、HIDL接口文件定义

进入hardware/interfaces/目录下建立新的接口文件.
首先建立对应的文件夹:

mkdir -p hardware/interfaces/hello/1.0/defaul

并在hardware/interfaces/hello/1.0/defaul下创建接口描述文件IHello.hal:

package android.hardware.hello@1.0;
interface IHello{
    open();
    close();
    read() generates (int32_t val);
    write(int32_t val);
};

hidl-gen工具
Google提供了一些工具来帮助制作HIDL的框架:
在aosp根目录下执行

make hidl-gen

源码中编译生成hidl-gen.注意:编译前需要执行全编译的环境变量加载
使用hidl-gen工具生成代码

$ PACKAGE=android.hardware.hello@1.0
$ LOC=hardware/interfaces/hello/1.0/default/
$ hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
$ hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

执行完后,hardware/interfaces/hello/1.0/default/会生成三个文件Android.dpHello.cppHello.h

)Z{KLQZ64)GQHWZ_1R(WRKK.png
接着使用脚本来更新Makefile:
./hardware/interfaces/update-makefiles.sh

执行完后,hardware/interfaces/hello/1.0会生成Android.bpAndroid.mk

上面生成的Hello.cppHello.h是实现接口的关键文件;

二、 硬件访问实现

Hello.h修改为直通式
hardware/interfaces/hello/1.0/default/Hello.h头文件

#ifndef ANDROID_HARDWARE_HELLO_V1_0_HELLO_H
#define ANDROID_HARDWARE_HELLO_V1_0_HELLO_H

#include <android/hardware/hello/1.0/IHello.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace hello {
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 Hello : public IHello {
    // Methods from IHello follow.
    Return<void> open() override;
    Return<void> close() override;
    Return<int32_t> read() override;
    Return<void> write(int32_t val) override;

    // Methods from ::android::hidl::base::V1_0::IBase follow.

};

// FIXME: most likely delete, this is only for passthrough implementations
 extern "C" IHello* HIDL_FETCH_IHello(const char* name);

}  // namespace implementation
}  // namespace V1_0
}  // namespace hello
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_HELLO_V1_0_HELLO_H

去掉注释.采用直通模式.

//  extern "C" IHello* HIDL_FETCH_IHello(const char* name);

Hello.cpp调用硬件抽象层
hardware/interfaces/hello/1.0/default/Hello.cpp源文件

#define LOG_TAG "HelloService HIDL"
#include "Hello.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <stdio.h>


namespace android {
namespace hardware {
namespace hello {
namespace V1_0 {
namespace implementation {

/* 通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
static inline int hello_device_open(const struct hw_module_t* module, struct hello_device_t** device) {
    return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}

/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h> */
struct hello_device_t* hello_device = NULL;

// Methods from IHello follow.
Return<void> Hello::open() {
    hello_module_t* module;
    if(hello_device) {
        ALOGI("Hello JNI: hello_init, device is open, no need to init.");
        return Void();
    }
        
    ALOGI("Hello JNI: initializing......");
    if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**) &module) == 0) {
        ALOGI("Hello JNI: hello Stub found.");
        if(hello_device_open(&(module->common), &hello_device) == 0) {
            ALOGI("Hello JNI: hello device is open.");
            return Void();
        }
        ALOGE("Hello JNI: failed to open hello device.");
        return Void();
    }
    ALOGE("Hello JNI: failed to get hello stub module.");
    return Void();
}

Return<void> Hello::close() {
    // TODO implement
    return Void();
}

Return<int32_t> Hello::read() {
     int32_t val = 0;
    if(!hello_device) {
         ALOGI("Hello JNI: device is not open.");
         return val;
    }
    ALOGI("Hello JNI:get value from device start.");
    hello_device->get_val(hello_device, &val);
    ALOGI("Hello JNI:get value %d from device.", val);
    return val;
}

Return<void> Hello::write(int32_t value) {
    int32_t val = value;
        ALOGI("Hello JNI: set value %d to device.", val);
        if(!hello_device) {
            ALOGI("Hello JNI: device is not open.");
            return Void();
        }
    hello_device->set_val(hello_device, val);

    return Void();
}


// Methods from ::android::hidl::base::V1_0::IBase follow.

IHello* HIDL_FETCH_IHello(const char* /* name */) {
    return new Hello();
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace hello
}  // namespace hardware
}  // namespace android

这里引用了硬件抽象层的include <hardware/hardware.h>include <hardware/hello.h>,需要在hardware/interfaces/hello/1.0/default/Android.dp引入共享库libhardwareandroid.hardware.hello@1.0这个是上一篇文章定义的;
编译

$ mmm hardware/interfaces/hello/1.0/default/

以上已经实现了访问硬件抽象层的访问,下面我们需要创建HIDL service服务端,提供给上层访问;

三、 构建HIDL service服务

虽然上一步已经能访问硬件抽象层,有了库,我们还需要构建HDIL服务端供上层使用;

#define LOG_TAG "android.hardware.hello@1.0-service"
#include <android/hardware/hello/1.0/IHello.h>
#include <hidl/LegacySupport.h>

using android::hardware::hello::V1_0::IHello;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
    return defaultPassthroughServiceImplementation<IHello>();
}
cc_library_shared {
    name: "android.hardware.hello@1.0-impl",
    relative_install_path: "hw",
    proprietary: true,
    srcs: [
        "Hello.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
         "liblog",
            "libhardware",
        "android.hardware.hello@1.0",
    ],
}

cc_binary {
    name: "android.hardware.hello@1.0-service",
    defaults: ["hidl_defaults"],
    relative_install_path: "hw",
    proprietary: true,
    srcs: ["service.cpp"],
    init_rc: ["android.hardware.hello@1.0-service.rc"],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "liblog",
    "libhardware",
        "android.hardware.hello@1.0",
        "android.hardware.hello@1.0-impl",
    ],
}

编译成功可执行文件android.hardware.hello@1.0-service放在/vendor/bin/hw/目录中;

service hello_service /vendor/bin/hw/android.hardware.hello@1.0-service
    class hal
    user system
    group system

注意:这里定义了hello_service服务进程所属用户和用户组都是system,而且启动执行文件位于/vendor/bin/hw/android.hardware.hello@1.0-service
最后HIDL service服务会随着开机一起启动
最后目录结构如下:

image.png
、 构建HIDL
    <hal format="hidl">
        <name>android.hardware.hello</name>
        <transport>hwbinder</transport>
        <impl level="generic"></impl>
        <version>1.0<version>
        <interface>
            <name>IHello</name>
            <instance>default</instance>
        </interface>
    </hal>

四、编译

$ mmm hardware/interfaces/hello/1.0/default/

最后会生成以下文件:

/vendor/lib64/hw/android.hardware.hello@1.0-impl.so
/vendor/etc/init/android.hardware.hello@1.0-service.rc 
/vendor/bin/hw/android.hardware.hello@1.0-service
/system/lib64/android.hardware.hello@1.0.so  

注意:在编译system.img和vendor.img镜像的过程中,如何以上文件没有合入,可以使用adb push的方式验证

问题点:

1.system_servre进程访问HDIL 服务进程 的selinux权限问题

SELinux: avc:  denied  { find } for interface=android.hardware.hello::IHello pid=865 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_hwservice:s0 tclass=hwservice_manager permissive=0

我们上层framework的system_server进程没有权限访问default_android_hwservice服务,可以看这篇文章解决
第一步:打开device/huawei/angler/sepolicy/system_server.te文件,添加权限

allow system_server default_android_hwservice:hwservice_manager{ find add read}

第二步:打开system/sepolicy/public/domain.te文件,找到

注释掉这一行
#neverallow * default_android_hwservice:hwservice_manager{add find}

或者可以修改为

neverallow { domain –system_server} default_android_hwservice:hwservice_manager {add find};

参考:https://www.freesion.com/article/945159695/

遗留问题

服务端main没有启动执行

上一篇下一篇

猜你喜欢

热点阅读