每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数hw_get_module就可以将指定的模块加载到内存来,并且获得 一个hw_module_t接口来打开相应的设备。 函数hw_get_module实现在hardware/libhardware /hardware.c文件中,如下所示:

/** Base path of the hal modules */

  1. #define HAL_LIBRARY_PATH1 "/system/lib/hw"
  2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
  3. /**
  4. * There are a set of variant filename for modules. The form of the filename
  5. * is "<MODULE_ID>.variant.so" so for the led module the Dream variants
  6. * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
  7. *
  8. * led.trout.so
  9. * led.msm7k.so
  10. * led.ARMV6.so
  11. * led.default.so
  12. */
  13. static const char *variant_keys[] = {
  14. "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */
  15. "ro.product.board",
  16. "ro.board.platform",
  17. "ro.arch"
  18. };
  19. static const int HAL_VARIANT_KEYS_COUNT =
  20. (sizeof(variant_keys)/sizeof(variant_keys[0]));
  21. ......
  22. int hw_get_module(const char *id, const struct hw_module_t **module)
  23. {
  24. int status;
  25. int i;
  26. const struct hw_module_t *hmi = NULL;
  27. char prop[PATH_MAX];
  28. char path[PATH_MAX];
  29. /*
  30. * Here we rely on the fact that calling dlopen multiple times on
  31. * the same .so will simply increment a refcount (and not load
  32. * a new copy of the library).
  33. * We also assume that dlopen() is thread-safe.
  34. */
  35. /* Loop through the configuration variants looking for a module */
  36. for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
  37. if (i < HAL_VARIANT_KEYS_COUNT) {
  38. if (property_get(variant_keys[i], prop, NULL) == 0) {
  39. continue;
  40. }
  41. snprintf(path, sizeof(path), "%s/%s.%s.so",
  42. HAL_LIBRARY_PATH1, id, prop);
  43. if (access(path, R_OK) == 0) break;
  44. snprintf(path, sizeof(path), "%s/%s.%s.so",
  45. HAL_LIBRARY_PATH2, id, prop);
  46. if (access(path, R_OK) == 0) break;
  47. } else {
  48. snprintf(path, sizeof(path), "%s/%s.default.so",
  49. HAL_LIBRARY_PATH1, id);
  50. if (access(path, R_OK) == 0) break;
  51. }
  52. }
  53. status = -ENOENT;
  54. if (i < HAL_VARIANT_KEYS_COUNT+1) {
  55. /* load the module, if this fails, we're doomed, and we should not try
  56. * to load a different variant. */
  57. status = load(id, path, module);
  58. }
  59. return status;
  60. }

函数hw_get_module依次在目录/system/lib /hw和/vendor/lib/hw中查找一个名称为"<MODULE_ID>.variant.so"的文件,其 中,<MODULE_ID>是一个模块ID,而variant表 示"ro.hardware"、"ro.product.board"、"ro.board.platform"和"ro.arch"四个系统属性值之一。例如,对于Gralloc模块来说,函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中检查是否存在以下四个文件:

       gralloc.<ro.hardware>.so

       gralloc.<ro.product.board>.so

       gralloc.<ro.board.platform>.so

       gralloc.<ro.arch>.so

只要其中的一个文件存在,  函数hw_get_module就会停止查找过程,并且调用另外一个函数load来将这个文件加载到内存中来。另一方面,如果在/system/lib/hw和/vendor/lib/hw中均不存这些文件,那么函数hw_get_module就会在目录/system/lib/hw中查找是否存在一个名称为gralloc.default.so的文件。如果存在的话,那么也会调用函数load将它加载到内存中来。函数load也是实现在文件hardware/libhardware/hardware.c文件中,如下所示:

  1. const char *path,
  2. const struct hw_module_t **pHmi)
  3. {
  4. int status;
  5. void *handle;
  6. struct hw_module_t *hmi;
  7. /*
  8. * load the symbols resolving undefined symbols before
  9. * dlopen returns. Since RTLD_GLOBAL is not or'd in with
  10. * RTLD_NOW the external symbols will not be global
  11. */
  12. handle = dlopen(path, RTLD_NOW);
  13. if (handle == NULL) {
  14. char const *err_str = dlerror();
  15. LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
  16. status = -EINVAL;
  17. goto done;
  18. }
  19. /* Get the address of the struct hal_module_info. */
  20. 每个模块定义了一个hw_module_t或hw_module_t子类型变量HAL_MODULE_INFO_SYM,通过这个导出符号可以得到hw_module_t变量对象。
  21. const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
  22. hmi = (struct hw_module_t *)dlsym(handle, sym);
  23. if (hmi == NULL) {
  24. LOGE("load: couldn't find symbol %s", sym);
  25. status = -EINVAL;
  26. goto done;
  27. }
  28. /* Check that the id matches */
  29. if (strcmp(id, hmi->id) != 0) {
  30. LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
  31. status = -EINVAL;
  32. goto done;
  33. }
  34. hmi->dso = handle;
  35. /* success */
  36. status = 0;
  37. done:
  38. if (status != 0) {
  39. hmi = NULL;
  40. if (handle != NULL) {
  41. dlclose(handle);
  42. handle = NULL;
  43. }
  44. } else {
  45. LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
  46. id, path, *pHmi, handle);
  47. }
  48. *pHmi = hmi;
  49. return status;
  50. }

Linux系统中,后缀名为"so"的文件为动态链接库文件,可能通过函数dlopen来加载到内存中。硬件抽象层模块编写规范规定每一个硬件抽象层模块都必须导出一个符号名称为HAL_MODULE_INFO_SYM_AS_STR的符号,而且这个符号必须是用来描述一个类型为hw_module_t的结构体的。

HAL_MODULE_INFO_SYM_AS_STR是一个宏,定义在文件hardware/libhardware/include/hardware/hardware.h文件中,如下所示:

  1. #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

将模块加载到内存中来之后,就可以调用函数dlsym来获得它所导出的符号HMI。由于这个符号指向的是一个hw_module_t结构体,因此,最后函
数load就可以强制地将这个符号转换为一个hw_module_t结构体指针,并且保存在输出参数pHmi中返回给调用者。

hw_module_t 加载过程的更多相关文章

  1. 工厂模式模拟Spring的bean加载过程

    一.前言    在日常的开发过程,经常使用或碰到的设计模式有代理.工厂.单例.反射模式等等.下面就对工厂模式模拟spring的bean加载过程进行解析,如果对工厂模式不熟悉的,具体可以先去学习一下工厂 ...

  2. linux内核启动以及文件系统的加载过程

    Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...

  3. Inside Flask - flask 扩展加载过程

    Inside Flask - flask 扩展加载过程 flask 扩展(插件)通常是以 flask_<扩展名字> 为扩展的 python 包名,而使用时,可用 import flask. ...

  4. web.xml 的加载过程

    初始化过程: 在启动Web项目时,容器(比如Tomcat)会读web.xml配置文件中的两个节点<listener>和<contex-param>. 接着容器会创建一个Serv ...

  5. Browser默认书签加载过程

    Browser配置默认书签——string.xml中<string-array name="bookmarks" translatable="false" ...

  6. Android View的加载过程

    大家都知道Android中加载view是从Activity的onCreate方法调用setContentView开始的,那么View的具体加载过程又是怎么的呢?这一节我们做一下分析. 首先追踪一下代码 ...

  7. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  8. Ogre中Mesh的加载过程详述

    转自:http://blog.csdn.net/yanonsoftware/article/details/1031891 如果新开始写一个3D渲染引擎,Mesh应该是一个很好的切入点.当一个看似简单 ...

  9. JVM——类的加载过程

    附一张图方便理解,一个类的执行过程 类的加载过程,简明的来说 类装饰器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件.在Java中,类装载器把一个类装入JVM中,要经过以下步骤: 装载:查 ...

随机推荐

  1. swift的值类型和引用类型

    前言 最近在学设计模式中,发现 Swift 中的 struct,class 以及 enum 在一般的使用中能够做到互相替换,因此探究其背后的逻辑就十分有必要.而这一问题又引出了 Swift 中的值类型 ...

  2. mysql中int(3)与int(11)有什么区别吗?

    注意:这里的M代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的. 其实当我们在选择使用int的类型的时 ...

  3. 【HackerRank】Find the Median(Partition找到数组中位数)

    In the Quicksort challenges, you sorted an entire array. Sometimes, you just need specific informati ...

  4. Python编程-函数进阶

    一.函数对象 函数是第一类对象,即函数可以当作数据传递 1 可以被引用 2 可以当作参数传递 3 返回值可以是函数 4 可以当作容器类型的元素 def foo(): print('from foo') ...

  5. nodejs文件追加内容

    const fs = require("fs"); // fs.appendFile 追加文件内容 // 1, 参数1:表示要向那个文件追加内容,只一个文件的路径 // 2, 参数 ...

  6. Centos7.4 Nginx反向代理+负载均衡配置

    Ningx是一款高性能的HTTP和反向代理服务器,配置起来也比较简单. 测试环境: 172.16.65.190 Nginx-反向代理 172.16.65.191 Ningx-Web 172.16.65 ...

  7. linux安装Zabbix监控

    源码包3.4.0下载  https://nchc.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/3.4.0/zabbix-3.4 ...

  8. KestrelHttpServer

    source code of Kestrel of documentation https://github.com/aspnet/KestrelHttpServer https://github.c ...

  9. Dom4j quick start guide

    Parsing XML Using Iterators Powerful Navigation with XPath Fast Looping Creating a new XML document ...

  10. 通过YUM命令查找对应命令是通过何种软件提供的

    # yum whatprovides [命令]