每一个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. C# partial 关键字

    C# partial关键字详解 partial关键字允许把类.结构或接口放在多个文件中.一般情况下,一个类存储在单个文件中.但有时,多个开发人员需要访问同一个类,或者某种类型的代码生成器生成了一个类的 ...

  2. 安装好MySQL后就开始学习如何后台创建自己的数据库吧!

    MySQL创建数据库的方式不像SQL Server那样有图形界面,而是使用DOS窗口创建的,接下来就是创建MySQL数据库的具体步骤. ↓↓↓↓↓↓↓↓      ↓↓↓↓↓↓↓↓      ↓↓↓↓ ...

  3. [原创]spring及springmvc精简版--IOC

    本篇博客为自己学习spring和springmvc的一个总结.主要以代码为主,至于文字性描述理解性东西,可以自行百度.有认识不妥的地方,还望指出,相互学习. 以前很困惑spring中的一些概念,在学习 ...

  4. jQuery仿苹果样式焦点图插件

    在线演示 本地下载

  5. 超酷Loading进度条

    在线演示 本地下载

  6. Go 模板语法

    Sprig the useful template functions for Go templates (http://masterminds.github.io/sprig/) Github -  ...

  7. Asp.net 5 (MVC6) Areas 分区

    1. Startup.cs 类的 Configure方法中, 加入Area路由设置代码: //app.UseMvcWithDefaultRoute(); app.UseMvc(routes=> ...

  8. FreeBSD 安装过程

    FreeBSD安装步骤: 回车 按默认回车 输入服务器的计算机名 去掉games,加上src安装如下图 Lib32 ports src这三项一定要安装上 回车 选择Manual 进入以后点create ...

  9. 为什么原生的servlet是线程不安全的而Struts2是线程安全的?

    因为原生的servlet在整个application生命周期中,只在初次访问的时候实例化一次,以后都不会再实例化,只会调用Server方法进行响应,所以如果在servlet类中定义成员变量,那么就会让 ...

  10. CentOS/Linux 卸载MATLAB

    rm -rf /usr/local/MATLAB/R2012arm /usr/local/bin/matlab /usr/local/bin/mcc /usr/local/bin/mex /usr/l ...