[Android 基础] -- 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]));

        原来它是 variant_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) 函数获取到的,其实这个函数是通过 variant_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 拼出来的值是 /vendor/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 函数,看看共享库是如何被加载的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值