hw_module_t 加载过程



    每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数hw_get_module就可以将

指定的模块加载到内存来,并且获得 一个hw_module_t接口来打开相应的设备。 函数hw_get_module实现在

hardware/libhardware/hardware.c文件中,如下所示:   

1.  #define HAL_LIBRARY_PATH1 "/system/lib/hw"

2.  #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

3.  static const char *variant_keys[] = {  

4.      “ro.hardware”,  

5.      “ro.product.board”,  

6.      “ro.board.platform”,  

7.      “ro.arch”  

8.  };  

9.  // 由上面定义的字符串数组可知,HAL_VARIANT_KEYS_COUNT的值为4  

10. struct constint HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/sizeof(variant_keys[0]));  

11.   

12. int hw_get_module(const char *id, const struct hw_module_t **module){  

13. return hw_get_module_by_class(id, NULL, module);  

14. }  

15.   

16. int hw_get_module_by_class(const char *class_id, const char *inst,   

17. const struct hw_module_t **module){  

18.     int status;  

19.     int i;  

20.     // 声明一个hw_module_t指针变量hmi  

21.     const struct hw_module_t *hmi = NULL;  

22.     char prop[PATH_MAX};  

23.     char path[PATH_MAX];  

24.     char name[PATH_MAX];  

25.     // 由前面调用函数可知,inst  NULL,执行else部分,将硬件id名拷贝到name数组里  

26.     if(inst)  

27.         snprintf(name, PATH_MAX, “%s.%s”, class_id, inst);  

28.     else  

29.         strlcpy(name, class_id, PATH_MAX);  

30.     // i 循环5  

31.     for(i=0; i

32.         if(i

33.             // 从系统属性里依次查找前面定义的4个属性的值,找其中一个后,执行后面代码,找不到,进入else部分执行  

34.             if(property_get(variant_keys[i], prop, NULL) == 0){  

35.                 continue;  

36.             }  

37.             // 找到一个属性值prop后,拼写path的值为:/vendor/lib/hw/硬件id.prop.so  

38.             snprintf(path, sizeof(path), “%s/%s.%s.so”,  

39.                 HAL_LIBRARY_PATH2, name, prop);  

40.             if(access(path, R_OK) ==0) break;   // 如果path指向有效的库文件,退出for循环  

41.             // 如果vendor/lib/hw目录下没有库文件,查找/system/lib/hw目录下有没有:硬件id.prop.so的库文件  

42.             snprintf(path, sizeof(path), “%s/%s.%s.so”,  

43.                 HAL_LIBRARY_PATH1, name, prop);  

44.             If(access(path, R_OK) == 0) break;  

45.         } else {  

46.             // 如果4个系统属性都没有定义,则使用默认的库名:/system/lib/hw/硬件id.default.so  

47.             snprintf(path, sizeof(path), “%s/%s.default.so”,  

48.                 HAL_LIBRARY_PATH1, name);  

49.             If(access(path, R_OK) == 0) break;  

50.         }  

51.     }  

52.     status = -ENOENT;  

53.     if(i

54.         status = load(class_id, path, module);  // 难道是要加载前面查找到的so库??  

55.     }  

56.     return status;  

57. }  

58.      

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

       gralloc..so

       gralloc..so

       gralloc..so

       gralloc..so
      

       只要其中的一个文件存在,  函数hw_get_module就会停止查找过程,并且调用另外一个函数load来将这个文件加载到

内存中来。另一方面,如果在/system/lib/hw/vendor/lib/hw中均不存这些文件,那么函数hw_get_module就会在目录

/system/lib/hw中查找是否存在一个名称为gralloc.default.so的文件。如果存在的话,那么也会调用函数load将它加载到内

存中来,如下所示:

1.   static int load(const char *id, counst char *path, const struct hw_module_t **pHmi){  

2.      void *handle;  

3.      struct hw_module_t * hmi;  

4.      // 通过dlopen打开so  

5.      handle = dlopen(path, RTLD_NOW);  

6.      // sym的值为”HMI”  

7.      const char * sym = HAL_MODULE_INFO_SYM_AS_STR;  

8.  // 通过dlsym从打开的库里查找”HMI”这个符号,如果在so里有定义的函数名或变量名为HMIdlsym返回其地址hmi,将该地址转化成hw_module_t类型,即硬件对象

9.      hmi = (struct hw_module_t *)dlsym(handle, sym);   

10.     // 判断找到的硬件对象的id是否和要查找的id名一致,不一致出错退出  

11. 

12.     if(strcmp(id, hmi->id) != 0){  

13.         // 出错退出处理  

14.     }  

15.     // 将库的句柄保存到hmi硬件对象的dso成员里  

16.     hmi->dso = handle;  

17.     // 将硬件对象地址送给load函数者,最终将硬件对象返回到了hw_get_module的调用者  

18.     *pHmi = hmi;  

19.     // 成功返回  

20. }  

        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中返回给调用者。

 

你可能感兴趣的:(HAL)