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中,打开这个文件可以看到定义如下:

     1 int hw_get_module(const char *id, const struct hw_module_t **module) 
     2 {
     3     int status;
     4     int i;
     5     const struct hw_module_t *hmi = NULL;
     6     char prop[PATH_MAX];
     7     char path[PATH_MAX];
     8 
     9     /*
    10      * Here we rely on the fact that calling dlopen multiple times on
    11      * the same .so will simply increment a refcount (and not load
    12      * a new copy of the library).
    13      * We also assume that dlopen() is thread-safe.
    14      */
    15 
    16     /* Loop through the configuration variants looking for a module */
    17     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
    18         if (i < HAL_VARIANT_KEYS_COUNT) {
    19             if (property_get(variant_keys[i], prop, NULL) == 0) {//获取属性
    20                 continue;
    21             }
    22             snprintf(path, sizeof(path), "%s/%s.%s.so",
    23                     HAL_LIBRARY_PATH1, id, prop);
    24             if (access(path, R_OK) == 0) break;//检查system路径是否有库文件
    25 
    26             snprintf(path, sizeof(path), "%s/%s.%s.so",
    27                      HAL_LIBRARY_PATH2, id, prop);
    28             if (access(path, R_OK) == 0) break;//检查vender路径是否有库文件
    29         } else {
    30             snprintf(path, sizeof(path), "%s/%s.default.so",//如果都没有,则使用缺省的
    31                      HAL_LIBRARY_PATH1, id);
    32             if (access(path, R_OK) == 0) break;
    33         }
    34     }
    35 
    36     status = -ENOENT;
    37     if (i < HAL_VARIANT_KEYS_COUNT+1) {
    38         /* load the module, if this fails, we're doomed, and we should not try
    39          * to load a different variant. */
    40         status = load(id, path, module);//装载库,得到module
    41     }
    42 
    43     return status;
    44 }

     看第一行我们知道有两个参数,第一参数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层搜索库的规则搞清楚了。

    下一篇我们将进入load函数,看看共享库是如何被加载的。

  • 相关阅读:
    20080619 SQL SERVER 输入 NULL 的快捷键
    20090406 Adobe的“此产品的许可已停止工作”错误的解决办法
    20080908 Office Powerpoint 2007 不能输入中文的解决办法
    20080831 ClearGertrude Blog Skin 's cnblogs_code class
    20080603 Facebook 平台正式开放
    20080519 安装 Microsoft SQL Server 2000 时提示 创建挂起的文件操作
    test
    Linux—fork函数学习笔记
    SOA的设计理念
    Why BCP connects to SQL Server instance which start with account of Network Service fail?
  • 原文地址:https://www.cnblogs.com/microliang/p/3427322.html
Copyright © 2011-2022 走看看