目录
回顾
通过前面的学习,我们知道怎么通过andriod硬件访问服务控制硬件,再次贴出框图如下
其中红色圈出部分我们已经完成,我们知道在andriod系统中,java程序是无法直接访问硬件的,他访问硬件需要service_manager.c发出请求,才能操控硬件,之前我们通过com_android_server_LedService.cpp直接访问硬件,这种方法一般不被推荐,主要有以下几点
1.当我们需要修改对硬件的操作C函数时,必须修改com_android_server_LedService.cpp,每次都要编译整个framework重新生成system.img。
2.linux是遵循GPL协议的,则会公开你的com_android_server_xxxService.cpp文件,倒是很多厂家并不想公开自己对硬件操作的代码。
那么为了解决以上问题,我们可以让com_android_server_xxxService.cpp文件。仅仅注册本地C函数,对硬件的操作我们把他封装成.so文件导入工程。这样我们以上的两个问题就得以解决了,需要修改对硬件的操作函数时,我们只需要修改.生成.so的文件即可。
源码解读
既然我们的要把对硬件操作部分分离出来,那么
1.com_android_server_xxxService.cpp:成了一个纯粹的JIN文件,主要有两个作用,向上提供本地C函数,向下加载hal文件(Hardware Abstraction Layer:硬件抽象层)并且调用HAL函数
2.HAL(Hardware Abstraction Layer:硬件抽象层):负责访问驱动程序,执行硬件操作。
在android中,com_android_server_xxxService.cpp加载hal文件,并不是直接声明函数,指定库就可以了,他内部有一套封装的方法。即调用dlopen,那么他是怎么调用dlopen的呢?
调用过程如下
hw_get_module("led")
//1.模块名==>文件名
hw_get_module_by_class("led",NULL)
name = "led"
property_get //获取属性值
hw_module_exists //判断是否存在led.xxx.so
//2.加载
load
dlopen(filename)
dlsym("HMI")//从so文件中获取HMI的hw_module_t结构体
strcmp(id,hmi->id)//判断名字是否一致(hmi->id,"led")
上述是一个大概的过程,现在进行详细讲解,我们先在源码中查看hw_get_module函数,如下
hardware/libhardware/hardware.c
external/chromium_org/third_party/hwcplus/src/hardware.c
int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}
传入了两个参数,module为我们自己定义的hw_module_t **类型对象,调用hw_get_module_by_class,其中参数id为“led”,可以看到其中多次调用hw_module_exists函数,他主要用来判断开发板以下3个路径下面是否存在led.xxx.so文件
1.HAL_LIBRARY_PATH 环境变量
2./vendor/lib/hw
3./system/lib/hw
那么led.xxx.so中的xxx具体是什么内容?我们查看hw_get_module_by_class中的property_get函数如下:
if (property_get(variant_keys[i], prop, NULL) == 0)
其中传入的参数variant_keys如下所示
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different