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<HAL_VARIANT_KEYS_COUNT+1; i++){  

32.         if(i<HAL_VARIANT_KEYS_COUNT){  

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<HAL_VARIANT_KEYS_COUNT+1){  

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中查找一個名稱爲"<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將它加載到內

存中來,如下所示:

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中返回給調用者。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章