首页 > 其他分享 >Android HAL 是如何被调用的

Android HAL 是如何被调用的

时间:2023-04-30 19:05:22浏览次数:40  
标签:__ 调用 HAL DEFAULT GLOBAL module 00000000 Android


Android 对硬件的调用, google 推荐使用 HAL 的方式进行调用,对于 Andriod HAL 的写法,可以参考 android 源码里的 hardware 目录下几个模块的模版。

在看 HAL 的编写方法的过程中,会发现整个模块貌似没有一个入口。一般说来模块都要有个入口,比如应用程序有 main 函数,可以为加载器进行加载执行, dll 文件有 dllmain ,而对于我们自己写的动态链接库,我们可以对库中导出的任何符号进行调用。

问题来了, Android 中的 HAL 是比较具有通用性的,需要上层的函数对其进行加载调用, Android 的 HAL 加载器是如何实现对不同的 Hardware Module 进行通用性的调用的呢?

带着这个疑问查看 Android 源码,会发现 Android 中实现调用 HAL 是通过 hw_get_module 实现的。

int hw_get_module(const char *id, const struct hw_module_t **module);

这是其函数原型, id 会指定 Hardware 的 id ,这是一个字符串,比如 sensor 的 id 是

#define SENSORS_HARDWARE_MODULE_ID "sensors" 

如果找到了对应的 hw_module_t 结构体,会将其指针放入 *module 中。看看它的实现。。。。


1.  
2.  for(i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
3.    if(i < HAL_VARIANT_KEYS_COUNT) {  
4.        //获取ro.hardware/ro.product.board/ro.board.platform/ro.arch等key的值。 
5.        if(property_get(variant_keys[i], prop, NULL) == 0) {  
6.            continue;  
7.        }  
8.        snprintf(path, sizeof(path), "%s/%s.%s.so",  
9.                HAL_LIBRARY_PATH, id, prop);  
10.         //如果开发板叫做mmdroid,那么这里的path就是system/lib/hw/sensor.mmdroid.so 
11.    } else{  
12.        snprintf(path, sizeof(path), "%s/%s.default.so",  
13.                HAL_LIBRARY_PATH, id);//默认会加载/system/lib/hw/sensor.default.so 
14.  
15.    }  
16.    if(access(path, R_OK)) {  
17.        continue;  
18.    }  
19.     
20.    break;  
21. }  
22. status = -ENOENT;  
23.  if(i < HAL_VARIANT_KEYS_COUNT+1) {  
24.     
25.    status = load(id, path, module);//调用load函数打开动态链接库 
26. }



获取了动态链接库的路径之后,就会调用 load 函数打开它,下面会打开它。奥秘在 load 中




1.  staticintload(constchar*id,  
2.        constchar*path,  
3.        conststructhw_module_t **pHmi)  
4. {  
5.    intstatus;  
6.    void*handle;  
7.    structhw_module_t *hmi;  
8.   
9.     
10.    handle = dlopen(path, RTLD_NOW);//打开动态库 
11.    if(handle == NULL) {  
12.        charconst*err_str = dlerror();  
13.        LOGE("load: module=%s/n%s", path, err_str?err_str:"unknown");  
14.        status = -EINVAL;  
15.        gotodone;  
16.    }  
17.   
18.     
19.    constchar*sym = HAL_MODULE_INFO_SYM_AS_STR;//被定义为了“HMI” 
20.    hmi = (structhw_module_t *)dlsym(handle, sym);//查找“HMI”这个导出符号,并获取其地址 
21.    if(hmi == NULL) {  
22.        LOGE("load: couldn't find symbol %s", sym);  
23.        status = -EINVAL;  
24.        gotodone;  
25.    }  
26.   
27.     
28.  //找到了hw_module_t结构!!! 
29.    if(strcmp(id, hmi->id) != 0) {  
30.        LOGE("load: id=%s != hmi->id=%s", id, hmi->id);  
31.        status = -EINVAL;  
32.        gotodone;  
33.    }   
34.    hmi->dso = handle;  
35.       
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.  //凯旋而归 
49.    *pHmi = hmi;  
50.     returnstatus;  
51. }


从上面的代码中,会发现一个很奇怪的宏 HAL_MODULE_INFO_SYM_AS_STR ,它直接被定义为了

#define HAL_MODULE_INFO_SYM_AS_STR "HMI" 

为何根据它就能从动态链接库中找到这个 hw_module_t 结构体呢?我们查看一下我们用到的 hal 对应的 so 就可以了,在 linux 中可以使用 readelf XX.so –s 查看。





1. Symbol table '.dynsym' contains 28 entries:  
2.   Num:    Value Size Type    Bind   Vis      Ndx Name  
3.     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND  
4.     1: 00000594     0 SECTION LOCAL  DEFAULT    7  
5.     2: 00001104     0 SECTION LOCAL  DEFAULT   13  
6.     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND ioctl  
7.     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND strerror  
8.     5: 00000b84     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end  
9.     6: 00000000     0 OBJECT  GLOBAL DEFAULT  UND __stack_chk_guard  
10.     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0  
11.     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND __errno  
12.     9: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__  
13.    10: 00000000     0 FUNC    GLOBAL DEFAULT  UND malloc  
14.    11: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start__  
15.    12: 00000000     0 FUNC    GLOBAL DEFAULT  UND __android_log_print  
16.    13: 00000b3a     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_start  
17.    14: 00000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail  
18.    15: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_end__  
19.    16: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start  
20.    17: 00000000     0 FUNC    GLOBAL DEFAULT  UND memset  
21.    18: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_uidiv  
22.    19: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS __end__  
23.    20: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS _edata  
24.    21: 00001188     0 NOTYPE  GLOBAL DEFAULT  ABS _end  
25.    22: 00000000     0 FUNC    GLOBAL DEFAULT  UND open  
26.    23: 00080000     0 NOTYPE  GLOBAL DEFAULT  ABS _stack  
27.    24: 00001104  128 OBJECT  GLOBAL DEFAULT   13 HMI  
28.    25: 00001104     0 NOTYPE  GLOBAL DEFAULT   13 __data_start  
29.    26: 00000000     0 FUNC    GLOBAL DEFAULT  UND close  
30.    27: 00000000     0 FUNC    GLOBAL DEFAULT  UND free



从上面中,第24个符号,名字就是“HMI”,对应于hw_module_t结构体。再去对照一下HAL的代码。






    1.  
    2.  structcopybit_module_t HAL_MODULE_INFO_SYM = {  
    3.    common: {  
    4.        tag: HARDWARE_MODULE_TAG,  
    5.        version_major: 1,  
    6.        version_minor: 0,  
    7.        id: COPYBIT_HARDWARE_MODULE_ID,  
    8.        name: "QCT MSM7K COPYBIT Module",  
    9.        author: "Google, Inc.",  
    10.        methods: ©bit_module_methods  
    11.    }  
    12. };



    这里定义了一个名为 HAL_MODULE_INFO_SYM 的 copybit_module_t 的结构体, common 成员为 hw_module_t 类型。注意这里的 HAL_MODULE_INFO_SYM 变量必须为这个名字,这样编译器才会将这个结构体的导出符号变为“ HMI ”,这样这个结构体才能被 dlsym 函数找到!

    综上,我们知道了 andriod HAL 模块也有一个通用的入口地址,这个入口地址就是 HAL_MODULE_INFO_SYM 变量,通过它,我们可以访问到 HAL 模块中的所有想要外部访问到的方法。

    标签:__,调用,HAL,DEFAULT,GLOBAL,module,00000000,Android
    From: https://blog.51cto.com/u_548275/6237998

    相关文章

    • Android主流屏幕分辨率介绍
      对于Android游戏开发我们不得不像iPhone那样思考兼容Android平板电脑,苹果要考虑iPad、iPhone3GS和iPhone4等屏幕之间的兼容性,对于开发Android游戏而言也不例外,考虑的机型更多。常规的我们可能只考虑QVGA,HVGA,WVGA,FWVGA和DVGA,但是抛去了手机不谈,可能平板使用类似WSVGA的1024......
    • Android、iPhone和Java三个平台一…
      移动开发中遇到的最让人纠结的要属Java、Android和iPhone三个平台加解密不一致的问题。因为手机端后台通常是用JAVA开发的WebService,Android和iPhone客户端调用同样的WebService接口,为了数据安全考虑,要对数据进行加密。头疼的问题就来了,很难编写出一套加密程序,在3个平台间加解......
    • Android 通过HTTP POST&…
      HttpComponentslibraries.DownloadthelatestHttpClient(currently4.0.1)binarywithdependenciespackageandcopy apache-mime4j-0.6.jarand httpmime-4.0.1.jartoyourprojectandaddthemtoyourJavabuildpath.Youwillneedtoaddth......
    • 本实例实现了android上传手机图片…
      本实例实现了android上传手机图片至服务器,服务器进行保存服务器servlet代码Java代码 1.doPost(HttpServletRequestrequest,HttpServletResponseresponse)2.throwsServletException,IOException{3.4.......
    • Android平台下使用HttpUrlConnecti…
      publicstaticStringrequestByPost(Stringurlpath,StringrequestData)throwsIOException{//HTTPconnectionreusewhichwasbuggypre-froyoif(Build.VERSION.SDK_INT<Build.VERSION_CODES.FROYO){URLurl=newURL(urlpath);......
    • 用C/C++在Linux和Android NDK中获取设备的IP地址
      C/C++开发的获取设备IP地址的代码,下面链接中的版本是在Linuxx86-64环境中编译(Centos7.5)的,也可在其它版本的Linux中或者AndroidNDK('armeabi-v7a','arm64-v8a','x86','x86_64'等版本)中编译。下载地址(此版本须在Linuxx86-64环境中运行):金山文档https://kdocs.cn/l/cd4VM3e......
    • android异常:Can not p…
      本人某个android项目开发阶段一直运行良好,直到上线前夕,在某款跑着android4.03系统的手机运行却报出一下异常,导致forceclose:java.lang.IllegalStateException:CannotperformthisactionafteronSaveInstance!首先得了解一下我那项目的一些基本情况,UI结构是TabActivity包含着5......
    • Android程序中像素(px)跟单位dp(di…
      publicclassUnitTransformUtil{publicstaticintdip2px(Contextcontext,floatdpValue){finalfloatscale=context.getResources().getDisplayMetrics().density;......
    • Android Paint和Color类
        setAntiAlias:设置画笔的锯齿效果。   setColor:设置画笔颜色   setARGB: 设置画笔的a,r,p,g值。   setAlpha: 设置Alpha值   setTextSize:设置字体尺寸。   setStyle: 设置画笔风格,空心或者实心。   setStrokeWidth:设置空心的边框......
    • Android 应用开发之(StrictM…
      最新的Android平台中(Android2.3起),新增加了一个新的类,叫StrictMode(android.os.StrictMode)。这个类可以用来帮助开发者改进他们编写的应用,并且提供了各种的策略,这些策略能随时检查和报告开发者开发应用中存在的问题,比如可以监视那些本不应该在主线程中完成的工作或者其他的一些......