HAL

作者: 龙遁流 | 来源:发表于2020-04-19 17:03 被阅读0次

    androidHAL

    架构

    源码解析

    以Android 9.0 TV CEC 相关解析,主要是整个框架

    hal层关键定义

    • Pie\hardware\libhardware\include\hardware\hardware.h
    • Pie\hardware\libhardware\hardware.c
    struct hw_module_t;
    struct hw_module_methods_t;
    struct hw_device_t;
    

    hw_module_t

    描述抽象硬件,关键成员methods

    typedef struct hw_module_t {
        ...
        /** Identifier of module */
        const char *id;
        /** Name of this module */
        const char *name;
        /** Author/owner/implementor of the module */
        const char *author;
        /** Modules methods */
        struct hw_module_methods_t* methods;
        ...
    }hw_module_t;
    

    hw_module_methods_t

    设定打开硬件方法,或的一个device

    typedef struct hw_module_methods_t {
        /** Open a specific device */
        int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
    
    } hw_module_methods_t;
    

    hw_device_t

    描述抽象设备

    typedef struct hw_device_t {
        ...
        /** reference to the module this device belongs to */
        struct hw_module_t* module;
        /** Close this device */
        int (*close)(struct hw_device_t* device);
        ...
    } hw_device_t;
    

    hw_get_module、hw_get_module_by_class

    加载硬件模块,获取hw_module_t

    int hw_get_module(const char *id, const struct hw_module_t **module); //根据id
    int hw_get_module_by_class(const char *class_id, const char *inst,
                               const struct hw_module_t **module); //根据class_id和实例
    

    一些模块关联多个interface,如

    audio.primary.<variant>.so
    audio.a2dp.<variant>.so

    hal模块加载路径

    path:
    PATH1:"/system/lib[64]/hw"
    PATH2:"/vendor/lib[64]/hw"
    PATH3:"/odm/lib[64]/hw"
    

    hal模块名构造

    name.prop.so:
    
    name:"<MODULE_ID>" 或 "<MODULE_ID>[.<inst>]"
        
    prop:即variant
    variant 来自系统配置属性值,通过getprop xxx 可以获取
    "ro.hardware.<name>",
    "ro.hardware",
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
    以上值都为空则为默认值 "default"
    

    hal模块搜寻顺序

    1. 构造基本名字 name "<MODULE_ID>" 或 "<MODULE_ID>[.<inst>]"
    2. 查询是否有属性 property_get,判断是否存在,尝试加载
    3. 以上都不存在,则尝试加载default的

    检测是否存在

    依次检查以下各路径
    PATH3/name.prop.so
    PATH2/name.prop.so
    PATH1/name.prop.so
    

    加载流程

    1. 通过dlopen加载系统分区的库,或android_load_sphal_library 加载sphal命名空间的。

    2. 获取hw_module_t结构

      const char *sym = HAL_MODULE_INFO_SYM_AS_STR; //"HMI"
      hmi = (struct hw_module_t *)dlsym(handle, sym);
      

    CEC 整体架构实现

    Linux驱动层

    Pie\common\drivers\amlogic\cec
    

    创建/dev/cec 字符设备,后续通过访问该设备访问CEC功能。

    驱动封装层

    Pie\vendor\amlogic\common\frameworks\services\hdmicec\libhdmi_cec
    

    打开/dev/cec驱动,封装CEC命令操作,

    hal模块层

    Pie\hardware\libhardware\include\hardware\hdmi_cec.h
    

    定义模块及设备

    #define HDMI_CEC_HARDWARE_MODULE_ID "hdmi_cec"
    
    typedef struct hdmi_cec_module {
        struct hw_module_t common;
    } hdmi_module_t;
    
    typedef struct hdmi_cec_device {
        struct hw_device_t common;
        int (*add_logical_address)(const struct hdmi_cec_device* dev, 
                                   cec_logical_address_t addr);
        void (*clear_logical_address)(const struct hdmi_cec_device* dev);
        int (*get_physical_address)(const struct hdmi_cec_device* dev, uint16_t* addr);
        int (*send_message)(const struct hdmi_cec_device* dev, const cec_message_t*);
        void (*register_event_callback)(const struct hdmi_cec_device* dev,
                event_callback_t callback, void* arg);
        void (*get_version)(const struct hdmi_cec_device* dev, int* version);
        void (*get_vendor_id)(const struct hdmi_cec_device* dev, uint32_t* vendor_id);
        void (*get_port_info)(const struct hdmi_cec_device* dev,
                struct hdmi_port_info* list[], int* total);
        void (*set_option)(const struct hdmi_cec_device* dev, int flag, int value);
        void (*set_audio_return_channel)(const struct hdmi_cec_device* dev, int port_id, 
                                         int flag);
        int (*is_connected)(const struct hdmi_cec_device* dev, int port_id);
        void* reserved[16 - 11];
    } hdmi_cec_device_t;
    
    // 定义打开和关闭操作
    static inline int hdmi_cec_open(const struct hw_module_t* module,
            struct hdmi_cec_device** device) {
        return module->methods->open(module,
                HDMI_CEC_HARDWARE_INTERFACE, TO_HW_DEVICE_T_OPEN(device));
    }
    
    static inline int hdmi_cec_close(struct hdmi_cec_device* device) {
        return device->common.close(&device->common);
    }
    
    // 定义HAL回调函数,驱动可以回调到上层
    typedef void (*event_callback_t)(const hdmi_event_t* event, void* arg);
    

    service 层

    service 启动
    • 直通式

      int main() {
          return defaultPassthroughServiceImplementation<IHdmiCec>();
      }
      
    • 绑定式

      int main(int argc __unused, char** argv __unused) 
      {
          bool treble = property_get_bool("persist.vendor.hdmi_cec.treble", true);
          if (treble) {
              android::ProcessState::initWithDriver("/dev/vndbinder");
          }
          ALOGI("hdmi_cec starting in %s mode", treble?"treble":"normal");
      
        configureRpcThreadpool(5, false);
          sp<ProcessState> proc(ProcessState::self());
      
          if (treble) {
              sp<IHdmiCec> hdmicec = new HdmiCec();
              if (hdmicec == nullptr) {
                  ALOGE("Cannot create HdmiCec HAL service");
              } else if (hdmicec->registerAsService() != android::OK) {
                  ALOGE("Cannot register HdmiCec HAL service.");
              } else {
                  ALOGI("Treble HdmiCec HAL service created.");
              }
          } else{
          }
      
          IPCThreadState::self()->joinThreadPool();
          return 1;
      }
      

      启动服务,通过启动脚本启动

      service vendor.cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
          class hal
          user system
          group system
      
    service实现
    class HdmiCec : public IHdmiCec, public hidl_death_recipient {
        ... // 声明HAL 接口
        ... 
        virtual void serviceDied(uint64_t /*cookie*/,
                                 const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
            ... //服务死亡处理
        }
        
        private:
        static sp<IHdmiCecCallback> mCallback;
        const hdmi_cec_device_t* mDevice;
    }
    

    hal层

    关键文件路径

    Pie\hardware\interfaces\tv\cec\1.0   // HIDL 接口定义
    Pie\hardware\interfaces\tv\cec\1.0\default // HIDL 接口默认实现
    
    • 接口定义部分

      • Android.bp 构建hidl interface脚本
    • IHdmiCec.hal IHdmiCecCallback.hal 定义接口及回调接口

      • type.hal 接口中用到的自定义类型
    • 接口实现部分

    草稿

    【CEC Linux驱动】
    common\drivers\amlogic\cec

    可选 AMLOGIC_M8B_CEC AMLOGIC_AO_CEC 两种类型

    /sys/class/hdmirx/hdmirx0/cec

    【CEC 驱动封装层】
    Pie\vendor\amlogic\common\frameworks\services\hdmicec\libhdmi_cec
    生成 libhdmi_cec_static.so,打开/dev/cec驱动,封装CEC命令操作

    hdmi_device_t 代表一个hdmi设备,包括设备类型,逻辑地址,CEC相关设置等,作用是记录CEC的状态信息


    class HdmiCecControl : public HdmiCecBase
    {
    init <== 初始化
    openCecDevice <== 打开 /dev/cec,ioctl 设置驱动,记录CEC设备信息
    closeCecDevice <== 关闭 /dev/cec 驱动
    HdmiCecControl::cec_process_func <== 通过 ioctl 设置参数,执行动作
    threadLoop <== readMessage (从CEC驱动中读取消息==> 通过CEC驱动read消息),
    messageValidateAndHandle(消费消息,
    post到MsgHandler::handleMessage ==> HdmiCecControl::send 或 HdmiCecControl::cec_process_func 处理掉),
    post给 HdmiCecEventListener

    sendMessage\sendExtMessage ==> HdmiCecControl::send ==> 通过CEC驱动write发送消息

    setEventObserver === 将 HdmiCecEventListener 设置
    }

    【CEC 服务层】
    Pie\vendor\amlogic\common\frameworks\services\hdmicec\server
    生成 hdmicecd 可执行文件,hdmicecd.rc 启动文件,启动/vendor/bin/hdmicecd


    main_hdmicec.cpp
    main === 创建 DroidHdmiCec ,注册服务 DroidHdmiCec::registerAsService()


    class DroidHdmiCec : public IDroidHdmiCEC, public HdmiCecEventListener
    {
    构造函数 === 创建 HdmiCecControl,cecControl->setEventObserver(this HdmiCecEventListener)
    setCallback === 把 IDroidHdmiCecCallback 设置给 mClients

    openCecDevice === cecControl->openCecDevice
    closeCecDevice === cecControl->closeCecDevice
    cec_process_func == cecControl->cec_process_func
    sendMessage === cecControl->sendMessage

    onEventUpdate == 将 hdmi_cec_event_t 通知给Client。mClients[i]->notifyCallback

    HdmiCecControl* cecControl
    IDroidHdmiCecCallback mClients
    }

    【CEC 客户端层】
    Pie\vendor\amlogic\common\frameworks\services\hdmicec\binder
    生成 libhdmicec.so


    HdmiCecBase.h 定义了 HdmiCecBase 和 HdmiCecEventListener
    HdmiCecHidlClient.h 定义了 HdmiCecHidlClient HdmiCecHidlCallback


    HdmiCecHidlClient
    {
    connect === 构造 HdmiCecHidlClient
    构造 === 通过 getHdmiCecService 获取 hdmicec [hdmicec.setCallback(callback)]
    getHdmiCecService === IDroidHdmiCEC::tryGetService

    openCecDevice === hdmicec->openCecDevice
    closeCecDevice === hdmicec->closeCecDevice
    cec_process_func === hdmicec->cec_process_func
    sendMessage === hdmicec->sendMessage

    setEventObserver == 设置 mEventListener

    HdmiCecHidlCallback* callback
    IDroidHdmiCEC* hdmicec
    HdmiCecEventListener * mEventListener
    }


    class HdmiCecHidlCallback : public IDroidHdmiCecCallback
    {
    构造 === 传入 HdmiCecHidlClient
    notifyCallback === 传入 CecEvent, mEventListener ==> HdmiCecEventListener

    HdmiCecHidlClient *cecClient
    }


    HdmiCecEventListener
    {
    onEventUpdate(hdmi_cec_event_t)
    }

    【CEC jni层】
    Pie\vendor\amlogic\common\frameworks\core\jni\hdmi_cec
    生成 libhdmicec_jni.so

    【CEC java层】
    Pie\vendor\amlogic\common\frameworks\core\java\com\droidlogic
    通过 /sys/class/xxx 文件访问CEC驱动

    【】
    Pie\hardware\amlogic\hdmi_cec
    生成 hdmi_cec.amlogic.so,使用HdmiCecHidlClient 访问cec服务

    aml_cec_hal_t{ hdmi_cec_device_t 入口参数,上层传递
    HdmiCecHidlClient,
    event_callback_t,
    fd}

    struct hdmi_cec_module <= .common.methods <= struct hw_module_methods_t.open <= open_cec()

    open_cec() ==do==> (HdmiCecHidlClient <==create== HdmiCecHidlClient::connect),
    (HdmiCecHidlClient <==set== HdmiCecCallback,
    (fd <==set== HdmiCecHidlClient::openCecDevice),
    (hdmi_cec_device_t.funcxxx <==set== cec_process_func)

    cec_close ==do==> (HdmiCecHidlClient::closeCecDevice)

    cec_process_func ==do==> (HdmiCecHidlClient::xxx_process_func)

    class HdmiCecCallback : public HdmiCecEventListener
    {
    onEventUpdate(hdmi_cec_event_t) <== 执行event_callback_t()
    }

    【设置应用】
    Pie\vendor\amlogic\common\apps\DroidTvSettings\src\com\droidlogic\tv\settings
    Pie\vendor\amlogic\common\frameworks\core\java\com\droidlogic\app

    【CEC语言设置流程】
    HdmiCecControl::init-->mCecDevice.isPlaybackDeviceType = true
    HdmiCecControl::openCecDevice--> mCecDevice.mTvOsdName = 0; GET_MENU_LANGUAGE-->驱动send CEC_MESSAGE_GET_MENU_LANGUAGE
    --> readMessage-->CEC_MESSAGE_SET_MENU_LANGUAGE-->persist.vendor.sys.cec.set_menu_language-->handleSetMenuLanguage
    --> mEventListener->onEventUpdate

    ./vendor/amlogic/common/frameworks/core/res/src/com/droidlogic/BootComplete.java:44://import com.droidlogic.HdmiCecExtend;

    Pie/bionic/libc/include\dlfcn.h
    Pie\hardware\libhardware\include\hardware\hardware.h
    Pie\hardware\libhardware\hardware.c
    Pie\frameworks\base\services\core\java\com\android\server\hdmi
    Pie\hardware\interfaces\tv\cec\1.0
    Pie\hardware\libhardware\include\hardware\hdmi_cec.h
    Pie/frameworks/base/services/java/com/android/server/SystemServer.java
    Pie\frameworks\base\services\core\jni\com_android_server_hdmi_HdmiCecController.cpp

    相关文章

      网友评论

        本文标题:HAL

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