每一个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. Linux基本命令 帮助命令

    命令名称:man 英文原意:manual 命令所在路径:/usr/bin/man 执行权限:所有用户 语法:man [命令或者配置文件] 功能描述:获取帮助信息 例如:man ls 查看ls命令的帮助 ...

  2. Python自然语言处理系列之模拟退火算法

    1.基本概念 模拟退火算法(Simulated Annealing,SA)是一种模拟固体降温过程的最优化算法.其模拟的过程是首先将固体加温至某一温度,固体内部的粒子随温度上升慢慢变为无序的状态,内能增 ...

  3. gstreamer-tips-picture-in-picture-compositing

    http://www.oz9aec.net/index.php/gstreamer/347-more-gstreamer-tips-picture-in-picture-compositing htt ...

  4. Linux基础三---打包压缩&vim&系统的初始化和服务

    一,常用命令——tar&vim 1. tar [参数]  文件名  [路径] 参数: -c :建立一个压缩文件的参数指令(create 的意思):     -x :解开一个压缩文件的参数指令! ...

  5. 七、golang中接口、反射

    一.接口定义 1.定义 interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量 package main import ( "fmt" ...

  6. LVS 负载均衡原理详解

    LVS简介 LVS是一个开源软件,由章文嵩博士于1998年5月创立,可以实现Linux平台下的简单负载均衡.LVS是Linux Virtual Server的简写,是一个虚拟的服务器集群系统. LVS ...

  7. 利用CXF框架开发webservice

    开发服务端代码 1. web.xml文件中添加cxf的servlet 2. 定义接口 @WebService(targetNamespace="http://UserInfo.ws.com& ...

  8. request.getPathInfo();

    request.getPathInfo(); 这个方法返回请求的实际URL相对于请求的serlvet的url的路径.(个人理解.)比如,有一个Servlet的映射是这样配置的: <servlet ...

  9. JavaWeb -- 四个域对比 request,servletContext, Session, pageContext

    requsest: 程序产生数据,用完了就没有用了, 用request, 作用范围:一个请求范围. Session: 程序产生数据,用完了 等一下还要使用, 用Session, 作用范围: 一个会话范 ...

  10. Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 贪心+优先队列

    D. Generating Sets time limit per test 2 seconds memory limit per test 256 megabytes input standard ...