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

简介

在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 [email protected];
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工具生成代码

$ [email protected]
$ 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 
#include 
#include 

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 open() override;
    Return close() override;
    Return read() override;
    Return 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 
#include 
#include 
#include 
#include 


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);
}

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

// Methods from IHello follow.
Return 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 Hello::close() {
    // TODO implement
    return Void();
}

Return 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 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 include ,需要在hardware/interfaces/hello/1.0/default/Android.dp引入共享库libhardware[email protected]这个是上一篇文章定义的;
编译

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

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

三、 构建HIDL service服务

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

  • 1.创建服务入口hardware/interfaces/hello/1.0/default/service.cpp文件,代码如下:
#define LOG_TAG "[email protected]"
#include 
#include 

using android::hardware::hello::V1_0::IHello;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
    return defaultPassthroughServiceImplementation();
}
  • 2.修改编译脚本,添加对服务的编译
    hardware/interfaces/hello/1.0/default/Android.bp
    这里主要目的将当前hardware/interfaces/hello/1.0/default项目定义为cc_binary可直接可执行的项目,因为service.cpp是包含main主函数入口的;
cc_library_shared {
    name: "[email protected]",
    relative_install_path: "hw",
    proprietary: true,
    srcs: [
        "Hello.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
         "liblog",
            "libhardware",
        "[email protected]",
    ],
}

cc_binary {
    name: "[email protected]",
    defaults: ["hidl_defaults"],
    relative_install_path: "hw",
    proprietary: true,
    srcs: ["service.cpp"],
    init_rc: ["[email protected]"],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "liblog",
    "libhardware",
        "[email protected]",
        "[email protected]",
    ],
}

编译成功可执行文件[email protected]放在/vendor/bin/hw/目录中;

  • 3.创建启动rc脚本
    创建rc文件!(rc文件是被init进程访问的)
    hardware/interfaces/hello/1.0/default/[email protected]
service hello_service /vendor/bin/hw/[email protected]
    class hal
    user system
    group system

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

image.png

、 构建HIDL

  • 4.提供外部访问配置修改
    为了让服务器被客户端访问到,还需要在device/huawei/angler/manifest.xml(不同厂商路径不同)添加如下:
    
        android.hardware.hello
        hwbinder
        
        1.0
        
            IHello
            default
        
    

四、编译

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

最后会生成以下文件:

/vendor/lib64/hw/[email protected]
/vendor/etc/init/[email protected] 
/vendor/bin/hw/[email protected]
/system/lib64/[email protected]  

注意:在编译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服务端))