zoukankan      html  css  js  c++  java
  • Android硬件抽象层(HAL)深入剖析(二)【转】

    上一篇我们分析了android HAL层的主要的两个结构体hw_module_t(硬件模块)和hw_device_t(硬件设备)的成员,下面我们来具体看看上层app到底是怎么实现操作硬件的?

    我们知道,一些硬件厂商不愿意将自己的一些核心代码开放出去,所以将这些代码放到HAL层,但是怎么保证它不开放呢?HAL层代码不是也让大家知道下载吗?其实硬件厂商的HAL核心代码是以共享库的形式出现的,每次在需要的时候,hal会自动加载调用相关共享库。那么是怎么加载找到某一硬件设备对应的共享库的呢?这也是我们这篇都要说的。

    上层app通过jni调用hal层的hw_get_module函数获取硬件模块,这个函数是上层与hal打交道的入口。所以如果我们以程序调用执行的流程去看源码的话,这个函数就是hal层第一个被调用的函数,下面我们就

    从这个函数开始,沿着程序执行的流程走下去。

    hw_get_module函数定义在/hardware/libhardware/hardware.c中,打开这个文件可以看到定义如下:

    int hw_get_module(const char *id, const struct hw_module_t **module) 
    {
        int status;
        int i;
        const struct hw_module_t *hmi = NULL;
        char prop[PATH_MAX];
        char path[PATH_MAX];
    
        /*
         * Here we rely on the fact that calling dlopen multiple times on
         * the same .so will simply increment a refcount (and not load
         * a new copy of the library).
         * We also assume that dlopen() is thread-safe.
         */
    
        /* Loop through the configuration variants looking for a module */
        for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
            if (i < HAL_VARIANT_KEYS_COUNT) {
                if (property_get(variant_keys[i], prop, NULL) == 0) {//获取属性
                    continue;
                }
                snprintf(path, sizeof(path), "%s/%s.%s.so",
                        HAL_LIBRARY_PATH1, id, prop);
                if (access(path, R_OK) == 0) break;//检查system路径是否有库文件
    
                snprintf(path, sizeof(path), "%s/%s.%s.so",
                         HAL_LIBRARY_PATH2, id, prop);
                if (access(path, R_OK) == 0) break;//检查vender路径是否有库文件
            } else {
                snprintf(path, sizeof(path), "%s/%s.default.so",//如果都没有,则使用缺省的
                         HAL_LIBRARY_PATH1, id);
                if (access(path, R_OK) == 0) break;
            }
        }
    
        status = -ENOENT;
        if (i < HAL_VARIANT_KEYS_COUNT+1) {
            /* load the module, if this fails, we're doomed, and we should not try
             * to load a different variant. */
            status = load(id, path, module);//装载库,得到module
        }
    
        return status;
    }

     看第一行我们知道有两个参数,第一参数id就是要获取的硬件模块的id,第二个参数module就是我们想得到的硬件模块结构体的指针。

    所以可以看出,上层首先给hal需要获取的硬件模块的id,hw_get_module函数根据这个id去查找匹配和这个id对应的硬件模块结构体的。

    下面看看怎么找的。

    17行有个for循环,上限是HAL_VARIANT_KEYS_COUNT+1,那么这个HAL_VARIANT_KEYS_COUNT是什么呢?查看同文件下找到有:

    static const int HAL_VARIANT_KEYS_COUNT =
        (sizeof(variant_keys)/sizeof(variant_keys[0]));

    原来它是ariant_keys这个数组的元素个数。那么这个数组又是什么呢?在本文件找,有:

    /**
     * There are a set of variant filename for modules. The form of the filename
     * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
     * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
     *
     * led.trout.so
     * led.msm7k.so
     * led.ARMV6.so
     * led.default.so
     */
    
    static const char *variant_keys[] = {
        "ro.hardware",  /* This goes first so that it can pick up a different
                           file on the emulator. */
        "ro.product.board",
        "ro.board.platform",
        "ro.arch"
    };

    可以看到它其实是个字符串数组。站且不知道干什么的。继续看hw_get_module函数,进入for循环里面,看22行,其实它是将HAL_LIBRARY_PATH1, id, prop这三个串拼凑一个路径出来,

    HAL_LIBRARY_PATH1定义如下:

    /** Base path of the hal modules */
    #define HAL_LIBRARY_PATH1 "/system/lib/hw"
    #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

    id是上层提供的,prop这个变量的值是前面19行property_get(variant_keys[i], prop, NULL)函数获取到的,其实这个函数是通过ariant_keys数组的的属性查找到系统中对应的变种名称。不同的平台获取到prop值是不一样的。

    假如在获取到的prop值是tout,需要获取的硬件模块的id是leds,那么最后path组成的串是/system/lib/hw/leds.tout.so。

    后面24行access是检查这个路径下是否存在,如果有就break,跳出循环。如果没有,继续走下面,

    可以看到下面几行和刚才形式差不多,

    snprintf(path, sizeof(path), "%s/%s.%s.so",  HAL_LIBRARY_PATH2, id, prop);

    if (access(path, R_OK) == 0) break;//检查vender路径是否有库文件

    结合 HAL_LIBRARY_PATH2 为"/vendor/lib/hw",假设同样获取到的prop值是tout,需要获取的硬件模块的id是leds,这种情况下path拼出来的值是/vender/lib/hw/leds.tout.so,然后在判断文件是否存在。如果存在跳出循环。

    从以上分析,其实这就是hal层搜索动态共享库的方式,从中我们可以得到两点:

    1.动态共享库一般放在 "/system/lib/hw"和"/vendor/lib/hw"这两个路径下。

    2.动态库的名称是以"id.variant.so"的形式命名的,其中id为上层提供,中间variant为变种名称,是随系统平台变化的。

    接着,从29到32行我们可以看到,当所有变种名称形式的包都不存在时,就以"id.default.so"形式包名查找是否存在。

    37行, if (i < HAL_VARIANT_KEYS_COUNT+1),如果i小于变种名称数组的话,表示找到了对应的库,那么38行load(id, path, module);//装载库,得到module。


    以上就对hal层搜索库的规则搞清楚了。

  • 相关阅读:
    blog网页模版
    Sidebyside assembly
    几种hash算法
    [软件调试学习笔记]防止栈缓冲区溢出的基于Cookie的安全检查机制
    erlang注意(经典)
    erlang 的源代码保护机制(经典)
    erlang 的源代码保护机制(经典)
    java反编译工具jad
    erlang注意(经典)
    java反编译工具jad
  • 原文地址:https://www.cnblogs.com/vijozsoft/p/10606832.html
Copyright © 2011-2022 走看看