hw_module_t 加载过程
每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数hw_get_module就可以将指定的模块加载到内存来,并且获得 一个hw_module_t接口来打开相应的设备。 函数hw_get_module实现在hardware/libhardware /hardware.c文件中,如下所示:
/** Base path of the hal modules */
- #define HAL_LIBRARY_PATH1 "/system/lib/hw"
- #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
- /**
- * 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"
- };
- static const int HAL_VARIANT_KEYS_COUNT =
- (sizeof(variant_keys)/sizeof(variant_keys[0]));
- ......
- 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;
- snprintf(path, sizeof(path), "%s/%s.%s.so",
- HAL_LIBRARY_PATH2, id, prop);
- if (access(path, R_OK) == 0) break;
- } 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);
- }
- return status;
- }
函数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文件中,如下所示:
- const char *path,
- const struct hw_module_t **pHmi)
- {
- int status;
- void *handle;
- struct hw_module_t *hmi;
- /*
- * load the symbols resolving undefined symbols before
- * dlopen returns. Since RTLD_GLOBAL is not or'd in with
- * RTLD_NOW the external symbols will not be global
- */
- handle = dlopen(path, RTLD_NOW);
- if (handle == NULL) {
- char const *err_str = dlerror();
- LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
- status = -EINVAL;
- goto done;
- }
- /* Get the address of the struct hal_module_info. */
- 每个模块定义了一个hw_module_t或hw_module_t子类型变量HAL_MODULE_INFO_SYM,通过这个导出符号可以得到hw_module_t变量对象。
- const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
- hmi = (struct hw_module_t *)dlsym(handle, sym);
- if (hmi == NULL) {
- LOGE("load: couldn't find symbol %s", sym);
- status = -EINVAL;
- goto done;
- }
- /* Check that the id matches */
- if (strcmp(id, hmi->id) != 0) {
- LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
- status = -EINVAL;
- goto done;
- }
- hmi->dso = handle;
- /* success */
- status = 0;
- done:
- if (status != 0) {
- hmi = NULL;
- if (handle != NULL) {
- dlclose(handle);
- handle = NULL;
- }
- } else {
- LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
- id, path, *pHmi, handle);
- }
- *pHmi = hmi;
- return status;
- }
在Linux系统中,后缀名为"so"的文件为动态链接库文件,可能通过函数dlopen来加载到内存中。硬件抽象层模块编写规范规定每一个硬件抽象层模块都必须导出一个符号名称为HAL_MODULE_INFO_SYM_AS_STR的符号,而且这个符号必须是用来描述一个类型为hw_module_t的结构体的。
HAL_MODULE_INFO_SYM_AS_STR是一个宏,定义在文件hardware/libhardware/include/hardware/hardware.h文件中,如下所示:
- #define HAL_MODULE_INFO_SYM_AS_STR "HMI"
将模块加载到内存中来之后,就可以调用函数dlsym来获得它所导出的符号HMI。由于这个符号指向的是一个hw_module_t结构体,因此,最后函
数load就可以强制地将这个符号转换为一个hw_module_t结构体指针,并且保存在输出参数pHmi中返回给调用者。
hw_module_t 加载过程的更多相关文章
- 工厂模式模拟Spring的bean加载过程
一.前言 在日常的开发过程,经常使用或碰到的设计模式有代理.工厂.单例.反射模式等等.下面就对工厂模式模拟spring的bean加载过程进行解析,如果对工厂模式不熟悉的,具体可以先去学习一下工厂 ...
- linux内核启动以及文件系统的加载过程
Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...
- Inside Flask - flask 扩展加载过程
Inside Flask - flask 扩展加载过程 flask 扩展(插件)通常是以 flask_<扩展名字> 为扩展的 python 包名,而使用时,可用 import flask. ...
- web.xml 的加载过程
初始化过程: 在启动Web项目时,容器(比如Tomcat)会读web.xml配置文件中的两个节点<listener>和<contex-param>. 接着容器会创建一个Serv ...
- Browser默认书签加载过程
Browser配置默认书签——string.xml中<string-array name="bookmarks" translatable="false" ...
- Android View的加载过程
大家都知道Android中加载view是从Activity的onCreate方法调用setContentView开始的,那么View的具体加载过程又是怎么的呢?这一节我们做一下分析. 首先追踪一下代码 ...
- 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)
前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...
- Ogre中Mesh的加载过程详述
转自:http://blog.csdn.net/yanonsoftware/article/details/1031891 如果新开始写一个3D渲染引擎,Mesh应该是一个很好的切入点.当一个看似简单 ...
- JVM——类的加载过程
附一张图方便理解,一个类的执行过程 类的加载过程,简明的来说 类装饰器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件.在Java中,类装载器把一个类装入JVM中,要经过以下步骤: 装载:查 ...
随机推荐
- $python正则表达式系列(5)——零宽断言
本文主要总结了python正则零宽断言(zero-length-assertion)的一些常用用法. 1. 什么是零宽断言 有时候在使用正则表达式做匹配的时候,我们希望匹配一个字符串,这个字符串的前面 ...
- Linux Shell基础 单引号、双引号、反引号、小括号和大括号
单引号和双引号 单引号和双引号用于变量值出现空格时将字符用引号括起来. 二者的主要区别在于, 被单引号括起来的字符都是普通字符,就算特殊字符也不再有特殊含义: 被双引号括起来的字符中,"$& ...
- Linux Shell基础 Shell的输入重定向和输出重定向
概述 在 Linux 中输入设备指的是键盘,输出设备指的是显示器.在 Linux 中,所有的内容都是文件,计算机硬件也是文件,标准输入设备(键盘)和标准输出设备(显示器)也是文件.这些设备的设备文件名 ...
- Android开发BUG及解决方法2
错误描述: 错误分析: 程序依赖的两个包冲突 解决方法: 在build.gradle文件中android节点下加packagingOptions节点
- vi高级命令集锦
.交换两个字符位置 xp .上下两行调换 ddp .把文件内容反转 :g/^/m0/ (未通过) .上下两行合并 J .删除所有行 dG .从当前位置删除到行尾 d$ .从当前位置复制到行尾 y$ 如 ...
- 防止iframe被别的网站引用
try{ top.location.hostname; if (top.location.hostname != window.location.hostname) { top.location.hr ...
- 老司机也该掌握的MySQL优化指南
当MySQL单表记录数过大时,增删改查性能都会急剧下降,所以我们本文会提供一些优化参考,大家可以参考以下步骤来优化: 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运 ...
- 通用Mapper(Mybatis)
1.Mapper的简单介绍 2.Mapper的作用 通用Mapper可以通过Mybatis的拦截器原理,动态的帮我们实现单表的增删改查功能,大大降低了我们的开发成本,减少了我们的工作量. 3.Mapp ...
- iBatis的Settings节点参数详解[转]
(1) cacheModelsEnabled: 是否启用SqlMapClient上的缓存机制.建议设为"true".默认值为“true”. (2) enhancementEnabl ...
- 算法总结之 最大值减去最小值或等于num的子数组数量
给定数组arr和整数num,共返回有多少个子数组满足 <= num 数组长度N 时间复杂度O(N) package TT; import java.util.LinkedList; pu ...