• <Android HAL 之路> HAL 简介


    HAL层概述

    名称: HAL, Hardware Abstracting Layer,中文名字:硬件抽象层。
    作用:对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。向上衔接Android Runtime和Framework,向下衔接驱动程序
    产生原因:利益,竞争

    Android代码结构中,HAL层的内容主要集中在Hardware目录中,结合之前讲解Camera模块的时候提到的
    system/lib/hw/camera.$(TARGET_BOARD_PLATFORM).so

    HAL层的内容集成在动态库中,然后CameraService通过这个So访问其中的内容。

    如何访问?

    void CameraService::onFirstRef()
    hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule)
    每一个独立的HAL层的so,有一个与其对应的Id
    #define CAMERA_HARDWARE_MODULE_ID “camera”
    定义在hardware/libhardware/include/hardware/camera_common.h
    又或者
    system/lib/hw/audio.primary.$(TARGET_BOARD_PLATFORM)
    frameworks/av/services/audioflinger/AudioFlinger.cpp
    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    #define AUDIO_HARDWARE_MODULE_ID “audio”
    定义在
    hardware/libhardware/include/hardware/audio.h
    当然这里只是举个例子,Audio需要加载的模块不止这一个。

    基本上每一个模块对应一个So,命名方式也是比较相似,xxx.$(TARGET_BOARD_PLATFORM),存放路径
    system/lib/hw
    system/lib64/hw

    hw_get_module ->hw_get_module_by_class
    定义在hardware/libhardware/include/hardware/hardware.h
    实现在hardware/libhardware/hardware.c

    int hw_get_module(const char *id, const struct hw_module_t **module)
    {
        return hw_get_module_by_class(id, NULL, module);
    }
    ……
    int hw_get_module_by_class(const char *class_id, const char *inst,
                               const struct hw_module_t **module)
    {
        int i = 0;
        char prop[PATH_MAX] = {0};
        char path[PATH_MAX] = {0};
        char name[PATH_MAX] = {0};
        char prop_name[PATH_MAX] = {0};
    
    
        if (inst)//如果inst不为空,name= class_id.inst
            snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
        else //如果为空的话,name = class_id
            strlcpy(name, class_id, PATH_MAX);
    
        //判断是否有配置项定义了对应的Hal层
        snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
        if (property_get(prop_name, prop, NULL) > 0) {
            if (hw_module_exists(path, sizeof(path), name, prop) == 0) {//若存在则跳转
                goto found;
            }
        }
    
        //循环查找ro.hardware,ro.product.board,ro.board.platform,ro.arch
        for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
                goto found;
            }
        }
    
        /* Nothing found, try the default */
        if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
            goto found;
        }
    
        return -ENOENT;
    
    found:
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        return load(class_id, path, module);
    }

    再看看hw_module_exists这个方法

    static int hw_module_exists(char *path, size_t path_len, const char *name,
                                const char *subname)
    {
       //拼凑HAL so库的名字 /vendor/lib/hw/name.subname.so或者/vendor/lib64/hw/name.subname.so
        snprintf(path, path_len, "%s/%s.%s.so",
                 HAL_LIBRARY_PATH2, name, subname);
        if (access(path, R_OK) == 0)
            return 0;
       //拼凑HAL so库的名字 /system/lib/hw/name.subname.so或者/system/lib64/hw/name.subname.so
        snprintf(path, path_len, "%s/%s.%s.so",
                 HAL_LIBRARY_PATH1, name, subname);
        if (access(path, R_OK) == 0)
            return 0;
    
        return -ENOENT;
    }

    以audio其中的一个so为例,在源码中找一个芯片平台高通msm8974
    system/lib/hw/audio.primary.msm8974.so
    顺着以上的代码很好理解,当然这个msm8974必然是可以用过循环的那几个配置项其中的一个获取,否则就是
    system/lib/hw/audio.promary.default.so

    如何加载

    以上代码跳转到found之后
    return load(class_id, path, module);

    static int load(const char *id,
            const char *path,
            const struct hw_module_t **pHmi)
    {
        ……  //打开so,获取句柄  
        handle = dlopen(path, RTLD_NOW);
        ……
    
        /* Get the address of the struct hal_module_info. */
        //获取地址空间的入口
        const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
        hmi = (struct hw_module_t *)dlsym(handle, sym);
        ……
        ……
    
        hmi->dso = handle;
        ……
        *pHmi = hmi; //赋值给传入参数
        ……
    }

    最后上层拿到的就是hw_module_t *
    然后通过这个入口操作库中的内容,并且每一个HAL模块在定义自己的结构的时候也是需要按照一定的规范来执行。这个留着明天再写吧……

  • 相关阅读:
    网线接线分类
    MongoDB修改用户密码
    win10计算器和商店英文改中文
    电脑微信双开
    ajax
    get和post的区别
    javascript中各种继承方式的优缺点
    原型
    高阶函数的封装
    深浅拷贝
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467213.html
Copyright © 2020-2023  润新知