android HAL 教程(含实例)
http://www.cnblogs.com/armlinux/archive/2012/01/14/2396768.html
Android Hal 分析
-------rockchip Andy
本文是基于android4.0.3.对应其他低版本的代码,可能有所差异,但基本大同小异。
1.产生HAL的原因
Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚。思路是把控制硬件的动作都放到了Android HAL中,而linux driver仅仅完成一些简单的数据交互作用,甚至把硬件寄存器空间直接映射到user space。而Android是基于Apache的license,因此硬件厂商可以只提供二进制代码,所以说Android只是一个开放的平台,并不是一个开源的平台。也许也正是因为Android不遵从GPL,所以Greg Kroah-Hartman才在2.6.33内核将Andorid驱动从linux中删除。GPL和硬件厂商目前还是有着无法弥合的裂痕。Android想要把这个问题处理好也是不容易的。
总结下来,Android HAL存在的原因主要有:
- 并不是所有的硬件设备都有标准的linux kernel的接口
- KERNEL DRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方 式绕过GPL。
- 针对某些硬件,An有一些特殊的需求
现有HAL架构由Patrick Brady (Google) 在2008 Google I/O演讲中提出的,如下图:
2.源码目录介绍
- /hardware/libhardware_legacy/ 旧的架构、采取链接库模块的方式
- /hardware/libhardware 新架构、调整为 HAL stub。
- /hardware/ril 无线电抽象层
- 一般除了它们3个都是硬件厂商相关的hal目录。
2.1 libhardware目录的结构如下
/hardware/libhardware/hardware.c 编译成libhardware.s置于/system/lib
/hardware/libhardware/include/hardware目录下包含如下头文件:
hardware.h 通用硬件模块头文件
copybit.h copybit模块头文件
gralloc.h gralloc模块头文件
lights.h 背光模块头文件
overlay.h overlay模块头文件
qemud.h qemud模块头文件
sensors.h 传感器模块头文件
/hardware/libhardware/modules 目录下定义了很多硬件模块
2.2 下面几个是各个厂商平台相关的hal
/hardware/msm7k
/hardware/qcom
/hardware/ti
/device/Samsung
/device/moto
这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录
3.HAL层的两种架构与两种访问方式
3.1 两种架构
位于libhardware_legacy目录下的“旧HAL架构”和位于libhardware目录下的“新HAL架构”。两种框架如下图所示:
- libhardware_legacy 是将 *.so 文件当作shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通过直接函数调用的方式,来操作驱动程序。当然,应用程序也可以不需要通过 JNI 的方式进行,直接加载 *.so (dlopen)的做法调用*.so 里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。
- 现在的libhardware 架构,就有stub的味道了。HAL stub 是一种代理人(proxy)的概念,stub 虽然仍是以 *.so的形式存在,但HAL已经将 *.so 隐藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则是向 HAL 取得特定模块(stub)的 operations,再 callback 这些操作函数。这种以 indirect function call 的架构,让HAL stub 变成是一种包含关系,即 HAL 里包含了许许多多的 stub(代理人)。Runtime 只要说明类型,即 module ID,就可以取得操作函数。对于目前的HAL,可以认为Android定义了HAL层结构框架,通过几个接口访问硬件从而统一了调用方式。
Android的HAL的实现需要通过JNI(Java Native Interface),JNI简单来说就是java程序可以调用C/C++写的动态链接库,这样的话,HAL可以使用C/C++语言编写,效率更高。
3.2 调用过程如下
JNI->通用硬件模块->硬件模块->内核驱动接口.
具体一点:JNI->libhardware.so->xxx.xxx.so->kernel.
再具体来说:android frameworks中JNI调用hardware.c中定义的hw_get_module函数来获取硬件模块,然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能
3.3 两种访问方式
(1)Android的app可以直接通过service调用.so格式的jni
(2)经过Manager调用service
上面两种方法应该说是各有优缺点:
- 第一种方法简单高效,但不正规。
- 第二种方法实现起来比较复杂,但更符合目前的Android框架。第二种方法中,LegManager和LedService(java)在两个进程中,需要进程通讯。
在现在的android框架中,这两种方式都存在,比如对于lights,是直接透过LightsService调用JNI,而对于sensor,中间则是通过SensorsManager来调用JNI的。
4.通用硬件模块(libhardware.so)
一般来说HAL moudle需要涉及的是三个关键结构体:
- struct hw_module_t;
- struct hw_module_methods_t;
- struct hw_device_t;
这三个结构体定义在hardware.h中。
路径为:/hardware/libhardware/include/hardware/hardware.h
头文件中主要定义了通用硬件模块结构体hw_module_t,声明了JNI调用的接口函数hw_get_module。hw_module_t定义如下:
1 /** 2 3 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM 4 5 * and the fields of this data structure must begin with hw_module_t 6 7 * followed by module specific information. 8 9 */ 10 typedef struct hw_module_t { 11 12 /** tag must be initialized to HARDWARE_MODULE_TAG */ 13 uint32_t tag; 14 15 /** major version number for the module */ 16 uint16_t version_major; 17 18 /** minor version number of the module */ 19 uint16_t version_minor; 20 21 /** Identifier of module */ 22 const char *id; 23 24 /** Name of this module */ 25 const char *name; 26 27 /** Author/owner/implementor of the module */ 28 const char *author; 29 30 /** Modules methods */ 31 struct hw_module_methods_t* methods; //硬件模块的方法 32 33 /** module's dso */ 34 void* dso; 35 36 /** padding to 128 bytes, reserved for future use */ 37 uint32_t reserved[32-7]; 38 39 } hw_module_t;
如注释所说,所有的hal模块都要有一个以HAL_MODULE_INFO_SYM命名的结构,而且这个结构要以hw_module_t为第一个成员,即要继承hw_module_t这个结构,比如lights,sensor:
1 struct sensors_module_t { 2 struct hw_module_t common; 3 int (*get_sensors_list)(struct sensors_module_t* module, 4 struct sensor_t const** list); 5 }; 6 7 /* 8 * The lights Module 9 */ 10 struct light_module_t HAL_MODULE_INFO_SYM = { 11 .common: { 12 tag: HARDWARE_MODULE_TAG, 13 version_major: 1, 14 version_minor: 0, 15 id: LIGHTS_HARDWARE_MODULE_ID, 16 name: "Lights module", 17 author: "Rockchip", 18 methods: &light_module_methods, 19 } 20 }; 21 22 const struct sensors_module_t HAL_MODULE_INFO_SYM = { 23 .common = { 24 .tag = HARDWARE_MODULE_TAG, 25 .version_major = 1, 26 .version_minor = 0, 27 .id = SENSORS_HARDWARE_MODULE_ID, 28 .name = "Stingray SENSORS Module", 29 .author = "Motorola", 30 .methods = &sensors_module_methods, 31 }, 32 .get_sensors_list = sensors__get_sensors_list 33 34 };
hw_module_t中比较重要的是硬件模块方法结构体hw_module_methods_t定义如下:
1 typedef struct hw_module_methods_t { 2 3 /** Open a specific device */ 4 5 int (*open)(const struct hw_module_t* module, const char* id, 6 7 struct hw_device_t** device); 8 9 } hw_module_methods_t;
该方法在定义HAL_MODULE_INFO_SYM的时候被初始化。目前该结构中只定义了一个open方法,其中调用的设备结构体参数hw_device_t定义如下:
1 /** 2 * Every device data structure must begin with hw_device_t 3 * followed by module specific public methods and attributes. 4 */ 5 typedef struct hw_device_t { 6 7 /** tag must be initialized to HARDWARE_DEVICE_TAG */ 8 uint32_t tag; 9 10 /** version number for hw_device_t */ 11 uint32_t version; 12 13 /** reference to the module this device belongs to */ 14 struct hw_module_t* module; 15 16 /** padding reserved for future use */ 17 uint32_t reserved[12]; 18 19 /** Close this device */ 20 int (*close)(struct hw_device_t* device); 21 22 } hw_device_t; 23 24 struct light_device_t { 25 struct hw_device_t common; 26 int (*set_light)(struct light_device_t* dev, 27 struct light_state_t const* state); 28 }; 29 30 /** 31 32 * Every device data structure must begin with hw_device_t 33 * followed by module specific public methods and attributes. 34 */ 35 struct sensors_poll_device_t { 36 struct hw_device_t common; 37 int (*activate)(struct sensors_poll_device_t *dev, 38 int handle, int enabled); 39 40 int (*setDelay)(struct sensors_poll_device_t *dev, 41 int handle, int64_t ns); 42 43 int (*poll)(struct sensors_poll_device_t *dev, 44 sensors_event_t* data, int count); 45 46 };
亦如注释所说,每一个设备的数据结构都必须也以hw_device_t为第一个成员。
5.以lights模块为例进行分析
5.1 源文件位置:(android5.1源码)
- /frameworks/base/services/core/java/com/android/server/lights/
- /frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
- /hardware/libhardware/include/hardware/lights.h
5.2 访问设备大概流程
app--->frameworks--->hardware--->kernel驱动
frameworks通过jni调用hw_get_module()获得HAL对应的模块,它的声明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
- 参数id为模块标识,定义在/hardware/libhardware/include/hardware录下的硬件模块头文件中
- 参数module是硬件模块地址,定义在/hardware/libhardware/include/hardware/hardware.h中
在lights.h中定义有lights模块的ID.
#define LIGHTS_HARDWARE_MODULE_ID "lights"
在5.1源码frameworks/base/services/core/jni/com_android_server_LightsService.cpp的init_native方法中调用hw_ge_module(),代码如下:
1 static jint init_native(JNIEnv *env, jobject clazz) 2 { 3 int err; 4 hw_module_t* module; 5 Devices* devices; 6 devices = (Devices*)malloc(sizeof(Devices)); 7 err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); 8 if (err == 0) { 9 devices->lights[LIGHT_INDEX_BACKLIGHT] 10 = get_device(module, LIGHT_ID_BACKLIGHT); 11 //…………………………………………. 12 }
hw_get_module函数在hardware.c中实现:
1 int hw_get_module(const char *id, const struct hw_module_t **module) 2 { 3 return hw_get_module_by_class(id, NULL, module); 4 }
再看hw_get_module_by_class时如何实现的:
首先在hardware.c的开始有如下定义和注释:
1 /** Base path of the hal modules */ 2 #define HAL_LIBRARY_PATH1 "/system/lib/hw" 3 #define HAL_LIBRARY_PATH2 "/vendor/lib/hw" 4 5 /** 6 * There are a set of variant filename for modules. The form of the filename 7 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 8 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: 9 * 10 * led.trout.so 11 * led.msm7k.so 12 * led.ARMV6.so 13 * led.default.so 14 */ 15 16 static const char *variant_keys[] = { 17 "ro.hardware", /* This goes first so that it can pick up a different 18 file on the emulator. */ 19 "ro.product.board", 20 "ro.board.platform", 21 "ro.arch" 22 }; 23 24 static const int HAL_VARIANT_KEYS_COUNT = 25 (sizeof(variant_keys)/sizeof(variant_keys[0])); 26 27 int hw_get_module_by_class(const char *class_id, const char *inst, 28 const struct hw_module_t **module) 29 30 { 31 int status; 32 int i; 33 const struct hw_module_t *hmi = NULL; 34 char prop[PATH_MAX]; 35 char path[PATH_MAX]; 36 char name[PATH_MAX]; 37 38 if (inst) 39 snprintf(name, PATH_MAX, "%s.%s", class_id, inst); 40 else 41 strlcpy(name, class_id, PATH_MAX); 42 43 /* 44 * Here we rely on the fact that calling dlopen multiple times on 45 * the same .so will simply increment a refcount (and not load 46 * a new copy of the library). 47 * We also assume that dlopen() is thread-safe. 48 */ 49 50 /* Loop through the configuration variants looking for a module */ 51 for (i = 0 ; i < HAL_VARIANT_KEYS_COUNT + 1 ; i++) { 52 if (i < HAL_VARIANT_KEYS_COUNT) { 53 if (property_get(variant_keys[i], prop, NULL) == 0) { 54 continue; 55 } 56 snprintf(path, sizeof(path), "%s/%s.%s.so", 57 HAL_LIBRARY_PATH2, name, prop); 58 if (access(path, R_OK) == 0) break; 59 60 snprintf(path, sizeof(path), "%s/%s.%s.so", 61 HAL_LIBRARY_PATH1, name, prop); 62 if (access(path, R_OK) == 0) break; 63 } else { 64 snprintf(path, sizeof(path), "%s/%s.default.so", 65 HAL_LIBRARY_PATH1, name); 66 if (access(path, R_OK) == 0) break; 67 } 68 } 69 status = -ENOENT; 70 if (i < HAL_VARIANT_KEYS_COUNT + 1) { 71 /* load the module, if this fails, we're doomed, and we should not try 72 * to load a different variant. */ 73 status = load(class_id, path, module); 74 } 75 return status; 76 77 }
可以看到,在hw_get_module_by_class函数中:
- 先通过property_get获得varient_key中定义的系统属性,
- 如果系统中有定义该属性,就会获得一个模块名.属性名组成的一个so的名称,
- 然后去/system/lib/hw、/vendor/lib/hw下查看,该so是否存在,如果存在,调用load函数,打开.so.
例如在rockchip的rk29平台上,有定义ro.product.board = rk29sdk,在这里会得到lights.rk29sdk.so。
再看load函数的实现:
1 /** 2 * Load the file defined by the variant and if successful 3 * return the dlopen handle and the hmi. 4 * @return 0 = success, !0 = failure. 5 */ 6 static int load(const char *id, 7 const char *path, 8 const struct hw_module_t **pHmi) 9 { 10 int status; 11 void *handle; 12 struct hw_module_t *hmi; 13 14 /* 15 * load the symbols resolving undefined symbols before 16 * dlopen returns. Since RTLD_GLOBAL is not or'd in with 17 * RTLD_NOW the external symbols will not be global 18 */ 19 handle = dlopen(path, RTLD_NOW); 20 if (handle == NULL) { 21 char const *err_str = dlerror(); 22 ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); 23 status = -EINVAL; 24 goto done; 25 } 26 /* Get the address of the struct hal_module_info. */ 27 const char *sym = HAL_MODULE_INFO_SYM_AS_STR; 28 hmi = (struct hw_module_t *)dlsym(handle, sym); 29 if (hmi == NULL) { 30 ALOGE("load: couldn't find symbol %s", sym); 31 status = -EINVAL; 32 goto done; 33 } 34 35 /* Check that the id matches */ 36 if (strcmp(id, hmi->id) != 0) { 37 ALOGE("load: id=%s != hmi->id=%s", id, hmi->id); 38 status = -EINVAL; 39 goto done; 40 } 41 hmi->dso = handle; 42 /* success */ 43 status = 0; 44 done: 45 if (status != 0) { 46 hmi = NULL; 47 if (handle != NULL) { 48 dlclose(handle); 49 handle = NULL; 50 } 51 } else { 52 ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", 53 id, path, *pHmi, handle); 54 } 55 *pHmi = hmi; 56 return status; 57 }
在这里会打开对应了so,比如lights.rk29sdk.so,然后获得这个模块中定义的hw_module_t的地址。后面JNI就能通过这个接口和hal层进行沟通了。
6.HAL与frameworks关联代码如下
1 public class LightsService extends SystemService { 2 //... 3 private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) { 4 if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) { 5 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#" 6 + Integer.toHexString(color)); 7 mColor = color; 8 mMode = mode; 9 mOnMS = onMS; 10 mOffMS = offMS; 11 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")"); 12 try { 13 setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode); 14 } finally { 15 Trace.traceEnd(Trace.TRACE_TAG_POWER); 16 } 17 } 18 } 19 public LightsService(Context context) { 20 super(context); 21 22 mNativePointer = init_native(); 23 //... 24 } 25 private static native long init_native();//这里调用HAL层的hw_get_module 26 private static native void finalize_native(long ptr); 27 28 static native void setLight_native(long ptr, int light, int color, int mode, 29 int onMS, int offMS, int brightnessMode);//访问硬件 30 31 private long mNativePointer;//保存hal返回的句柄 32 }