• Android HIDL(2) ----接口和服务


    1.接口和软件包

    1.1软件包

    软件包名称可以具有子级,如 package.subpackage。已发布的 HIDL 软件包的根目录为 hardware/interfaces 或 vendor/vendorName.
    vendor.company.xxx@1.0 文件在vendor/company/…/interfaces/xxx 下.
    软件包目录中包含扩展名为 .hal 的文件。每个文件均必须包含一个指定文件所属的软件包和版本的 package 语句。
    package vendor.company.xxx@1.0;

    1.2 接口

    types.hal 定义一些数据变量结构体
    除types.hal 之外,其他每个.hal文件均定义一个接口. 接口通常
    interface IDeviceXxx {
    init();
    }

    2.接口哈希

    本文档介绍了 HIDL 接口哈希,这是一种旨在防止意外更改接口并确保接口更改经过全面审查的机制。
    每个软件包根目录必须包含一个列出所有已发布 HIDL 接口文件的 current.txt 文件。

    hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport vendor.awesome.nfc@1.0::types
    9626fd18...f9d298a6 vendor.awesome.nfc@1.0::types
    hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport vendor.awesome.nfc@1.0::INfc
    07ac2dc9...11e3cf57 vendor.awesome.nfc@1.0::INfc
    hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport vendor.awesome.nfc@1.0
    9626fd18...f9d298a6 vendor.awesome.nfc@1.0::types
    07ac2dc9...11e3cf57 vendor.awesome.nfc@1.0::INfc
    f2fe5442...72655de6 vendor.awesome.nfc@1.0::INfcClientCallback
    hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport vendor.awesome.nfc@1.0 >> vendor/awesome/hardware/interfaces/current.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.服务和数据转移

    如何注册和发现服务,以及如何通过调用 .hal 文件内的接口中定义的方法将数据发送到服务。

    文件结构及编译出来的库

    mason@CH3UU0009:~/project/ct40_imager/hardware/interfaces/camera/provider$ tree 2.4
    2.4
    ├── Android.bp
    ├── default
    │   ├── Android.bp
    │   ├── android.hardware.camera.provider@2.4-external-service.rc
    │   ├── android.hardware.camera.provider@2.4-service_64.rc
    │   ├── android.hardware.camera.provider@2.4-service-lazy_64.rc
    │   ├── android.hardware.camera.provider@2.4-service-lazy.rc
    │   ├── android.hardware.camera.provider@2.4-service.rc
    │   ├── CameraProvider_2_4.cpp
    │   ├── CameraProvider_2_4.h
    │   ├── ExternalCameraProviderImpl_2_4.cpp
    │   ├── ExternalCameraProviderImpl_2_4.h
    │   ├── external-service.cpp
    │   ├── LegacyCameraProviderImpl_2_4.cpp
    │   ├── LegacyCameraProviderImpl_2_4.h
    │   ├── OWNERS
    │   └── service.cpp
    ├── ICameraProviderCallback.hal
    ├── ICameraProvider.hal
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    vendor/etc/init/vendor.xxx.imager@1.0-service.rc 会被拷贝到vendor.img里面的vendor/etc/init目录 
    vendor/lib64/hw/vendor.xxx.imager@1.0-impl.so  //接口文件 
    vendor/lib64/vendor.xxx.imager@1.0.so  //.hal 文件编译
    vendor/bin/hw/vendor.xxx.imager@1.0-service  // service.cpp可执行文件
    
    • 1
    • 2
    • 3
    • 4

    3.1注册服务

    在Treble架构中,framework/vendor之间的通信通过HIDL接口和dev/hwbinder的IPC域来完成。而且HIDL接口有两种通信模式Passthrough和Binderized。接下来我们介绍两种模式下的交互原理。创建HAL服务器有两种模式:

    3.2 Passthrough

    随便找了个例子
    hardware/interfaces/graphics/mapper/2.0

    default/passthrough.cpp
    extern "C" IMapper* HIDL_FETCH_IMapper(const char* name){
      return CrallocLoader::load();
    }
    hardware/interfaces/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
    
    • 1
    • 2
    • 3
    • 4
    • 5

    直通模式与 绑定模式最大的区别就是直通模式没有一个独立运行的服务进程,而绑定模式是作为一个独立运行的服务相当于Deamon进程在运行。直通模式是将android 8.0之前的版本的module 封装起来,供System以上的服务进行调用, 上层直接调用 HIDL_FETCH_XXX 来调用此接口的。

    3.3 Binderized

    绑定式可以用两种方式来绑定服务
    第一种通过 defaultPassthroughServiceImplementation 的调用来注册服务即绑定+直通式,
    另外一种是直接调用RegisterAsService来注册服务,这是一个比较标准的方式。

    defaultPassthroughServiceImplementation :

        android::ProcessState::initWithDriver("/dev/vndbinder");
        return defaultPassthroughServiceImplementation("6", /*maxThreads*/ 6); //6表示与/dev/vndbinder 通信的最大线程数
    
    android::ProcessState::initWithDriver :通过 /dev/vndbinder 驱动可与其他模块的HAL进行通信;
    defaultPassthroughServiceImplementation :创建默认为直通模式(passthrough)的 CameraProvider 服务;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    RegisterAsService:

    int main(){
        configureRpcThreadpool(4, true);
        Demo mDemo = new Demo();
        mDemo.registerAsService();
        joinRpcThreadpool();
        return 1;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4 发现服务

    上面已经说明了直通模式与绑定模式的初始化,现在我们来介绍下如何调用直通模式和绑定模式,两者调用的函数有没有什么区别呢? 答案是两者使用的调用接口是一样的,都是通过getService 来调用的。

    mMapper = IMapper::getService(mapperServiceName);
    
    
    • 1
    • 2
     mProvider = ICameraProvider::getService(service_name);
    
    • 1

    同样getService 也是HIDL的工具生成的函数执行的:

    中间文件在out 目录下
    out/soong/.intermediates/hardware/interfaces/graphics/mapper$ vi 2.0/android.hardware.graphics.mapper@2.0_genc++/gen/android/hardware/graphics/mapper/2.0/MapperAll.cpp
    
     ::android::sp IMapper::getService(const std::string &serviceName, const bool getStub) {
       return ::android::hardware::details::**getServiceInternal**(serviceName, true, getStub);
     }
    
    out/soong/.intermediates/hardware/interfaces/camera/provider/2.4/android.hardware.camera.provider@2.4_genc++/gen/android/hardware/camera/provider/2.4$ vi CameraProviderAll.cpp
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
     调用到system/libhidl/transport/include/hidl/HidlTransportSupport.h
    sp getServiceInternal(const std::string& instance, bool retry, bool getStub) {
        using ::android::hidl::base::V1_0::IBase;
    
        sp base = **getRawServiceInternal**(IType::descriptor, instance, retry, getStub);
    
        if (base == nullptr) {
            return nullptr;
        }
    
        if (base->isRemote()) {
            // getRawServiceInternal guarantees we get the proper class
            return sp(new BpType(getOrCreateCachedBinder(base.get())));
        }
    
        return IType::castFrom(base);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    调用到system/libhidl/transport/ServiceManagement.cpp
    sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                                 const std::string& instance,
                                                                 bool retry, bool getStub) {
        const sp sm = defaultServiceManager1_1();
    ....
    //绑定模式
        const bool vintfHwbinder = (transport == Transport::HWBINDER);
    //直通模式
        const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
    ......
    //绑定模式
        for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
            Return> ret = sm->get(descriptor, instance);
        }
    //直通模式
        if (getStub || vintfPassthru || vintfLegacy) {
            const sp pm = getPassthroughServiceManager();
                sp base = pm->get(descriptor, instance).withDefault(nullptr);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这里分成了二条路,绑定模式就直接通过IServiceManager->get的方法去获取.HIDL的hwbinder驱动是/dev/hwbinder

    关于直通模式,先通过getPassthroughServiceManager ,获取IServiceManager的句柄,然后再get得到对应的服务。

    sp getPassthroughServiceManager() {
        return getPassthroughServiceManager1_1();
    }
    sp getPassthroughServiceManager1_1() {
        static sp manager(new PassthroughServiceManager());
        return manager;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
     Return> get(const hidl_string& fqName,
                              const hidl_string& name) override {
            sp ret = nullptr;
            openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
                IBase* (*generator)(const char* name);
                //这里就会调用 到sym 也就是HIDL_FETCH_XXX ,然后通过dlsym 去链接调用了。
                *(void **)(&generator) = dlsym(handle, sym.c_str());
                ret = (*generator)(name.c_str());
            });
            return ret;
        }
     
    static void openLibs(
            const std::string& fqName,
            const std::function& eachLib) {
            std::string packageAndVersion = fqName.substr(0, idx);
            std::string ifaceName = fqName.substr(idx + strlen("::"));
     
            const std::string prefix = packageAndVersion + "-impl";
         //HIDL_FETCH_XXX 出现了,就是passthrough模式下需要被调用的方法。
            const std::string sym = "HIDL_FETCH_" + ifaceName;
    .....
            std::vector paths = {HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
                                              halLibPathVndkSp, HAL_LIBRARY_PATH_SYSTEM};
    ....
            for (const std::string& path : paths) {
                std::vector libs = search(path, prefix, ".so");
     
                for (const std::string &lib : libs) {
              //路径最后组装成/system 或者/vendor 下面的供调用的xxxxx-impl.so
                    const std::string fullPath = path + lib;
     
                    if (path == HAL_LIBRARY_PATH_SYSTEM) {
                        //这里就供dlopen了。
                        handle = dlopen(fullPath.c_str(), dlMode);
                    } else {
                        handle = android_load_sphal_library(fullPath.c_str(), dlMode);
                    }
    .....
            }
        }
    参考:https://blog.csdn.net/tovey2008/article/details/106681126/ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    5 服务终止

    想要在服务终止时收到通知的客户端会接收到框架传送的终止通知。如需接收通知,客户端必须:
    1.创建 HIDL 类/接口 hidl_death_recipient 的子类(在 C++ 代码中,而不是在 HIDL 中)。
    2.替换其 serviceDied() 方法。
    3. 实例化 hidl_death_recipient 子类的对象。
    4.在要监控的服务上调用 linkToDeath() 方法,并传入 IDeathRecipient 的接口对象。请注意,此方法并不具备在其上调用它的终止接收方或代理的所有权。

    class IMyDeathReceiver : hidl_death_recipient {
      virtual void serviceDied(uint64_t cookie,
                               wp& service) override {
        log("RIP service %d!", cookie);  // Cookie should be 42
      }
    };
    ....
    IMyDeathReceiver deathReceiver = new IMyDeathReceiver();
    m_importantService->linkToDeath(deathReceiver, 42);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    基于HTML5和CSS3搭建一个Web网页(二)
    【框架: Nodejs单机数据库选择】
    stm32定时器之简单封装
    P2P实现远程控制
    Springboot快递代拿系统43l40计算机毕业设计-课程设计-期末作业-毕设程序代做
    RabbitMQ 使用细节 → 优先级队列与ACK超时
    zcu106 lwip搭建以太网配置寄存器
    SwiftUI 视图“毁坏性”和“非毁坏性”刷新的应用场景
    指针到底是个什么玩意
    GitHub上标星23K+的Redis进阶笔记(应用+原理+集群+拓展+源码)
  • 原文地址:https://blog.csdn.net/h_8410435/article/details/126347171