美文网首页
android 自定义驱动(第三篇:HIDL服务端)

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

作者: momxmo | 来源:发表于2020-05-25 23:08 被阅读0次

    简介

    在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服务端供上层使用;

    • 1.创建服务入口hardware/interfaces/hello/1.0/default/service.cpp文件,代码如下:
    #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>();
    }
    
    • 2.修改编译脚本,添加对服务的编译
      hardware/interfaces/hello/1.0/default/Android.bp
      这里主要目的将当前hardware/interfaces/hello/1.0/default项目定义为cc_binary可直接可执行的项目,因为service.cpp是包含main主函数入口的;
    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/目录中;

    • 3.创建启动rc脚本
      创建rc文件!(rc文件是被init进程访问的)
      hardware/interfaces/hello/1.0/default/android.hardware.hello@1.0-service.rc
    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
    • 4.提供外部访问配置修改
      为了让服务器被客户端访问到,还需要在device/huawei/angler/manifest.xml(不同厂商路径不同)添加如下:
        <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没有启动执行

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/yspaghtx.html