前面分析了android HAL层是如何搜索硬件模块的动态共享库的,其实就是在"system/lib/hw/"或者"/vendor/lib/hw/"这两个路径下找到共享库modueid.variant.so后,经过调用load函数加载库。android
下面咱们进入load函数,看看具体是如何实现加载共享库的。架构
如下为load函数定义,一样在/hardware/libhardware/hardware.c中实现的。函数
/** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */ static int load(const char *id, const char *path, const struct hw_module_t **pHmi) {//传入硬件模块id和库所在路径,获取到硬件模块结构体 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. */ 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) {//匹配解析出硬件模块的id和传入咱们实际想要获得的模块id是否一致 LOGE("load: id=%s != hmi->id=%s", id, hmi->id); status = -EINVAL; goto done; } hmi->dso = handle; //将打开库获得句柄传给硬件模块的dso /* 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;//将获得的module的结果经过第三个参数传给hw_module_t return status; }
能够看到load函数传入的几个参数,第一个参数就是须要加载的硬件模块对应动态库的硬件模块的id,spa
第二个参数就是动态库存放的路径,就是在hw_get_module函数前部分搜索库获得的path,指针
第三个参数就是咱们须要获得的硬件模块结构体,经过它传给hw_get_module,hw_get_module函数在经过参数传给jni。code
第19行,首先调用dlopen打开共享库,该函数经过传入的库的路径找到库,而且打开它,传回一个操做句柄handle,而后再调用dlsym函数解析这个打开的库,下面第29行,获得库中包含的硬件模块结构体,并将它返回回来。因此硬件厂商或者硬件移植者都必须根据hal的这个架构去实现填充这个和本身硬件相关的硬件模块结构体hw_module_t,供使用。blog
经过dlsym解析以后就获得了hw_module_t,随后第37行,将从库中解析获得的结构体中的id和传入的id作比较,看是否一致。get
若是一致则证实就是获得正确的硬件模块了。it
最后第60行,将hw_module_t结构体指针传给第三个参数,传给hw_get_module函数。class
到此,hw_get_module函数就获得了硬件模块结构体hw_module_t.
有了hw_module_t,那么经过其内部的method open就能打开硬件模块对应的设备了,经过结构体中的一些方法就能操做硬件设备了。