实现Android系统的HAL(硬件适配层)
10/14/2010 9:20:51 AMAndroid系统作为一个开放的平台,为了适配千变万化的硬件平台,定义了一个硬件适配层(HAL)框架。如果你实现自己硬件平台的硬件适配层,那么Android系统将会调用你的硬件适配层来为系统加速。如果你未定义自己平台硬件适配层(HAL),那么Android系统将调用软实现,这样的话不会发挥出你的硬件平台的最大效能。本文简略介绍一下Android系统的HAL层,进而介绍怎样实现HAL层,以起到抛砖引玉的作用。
Android系统HAL层位于hardware目录下面。HAL层是以桩的形式实现的,请看如下取自hardware/hardware.c的代码:
int hw_get_module(const char *id, const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/
/* Loop through the configuration variants looking for a module */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
if (i < HAL_VARIANT_KEYS_COUNT) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH, id, prop);
} else {
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH, id);
}
if (access(path, R_OK)) {
continue;
}
/* we found a library matching this id/variant */
break;
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+1) {
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
status = load(id, path, module);
}
return status;
}
从代码中我们可以看出Android系统首先去系统属性查找硬件定义,然后再去加载相应硬件HAL层的特定模块(模块名字在函数参数id传入)so库文件,如果系统属性中未定义硬件属性则价值默认硬件HAL层对应模块的so库文件进行硬件加速。
你可能会问Android加载了HAL层的so库文件,那么他怎么知道调用哪个函数呢?其实所有的硬件模块需要实现的接口Android系统都已经定义好了,位于hardware/libhardware/include/hardware下面,你打开会发现下面有很多Android定义好的HAL层模块,比如gralloc,copybit等等。自定义的HAL层的任何模块都必须按上述目录中定义好的接口来实现,否则就会HAL层出错(后果很严重)。这样Android系统正确的加载了HAL层特定模块的so库文件之后,它就知道这个模块的so库中包含哪些函数,需要的时候直接调用就可以了。
Android系统其实是HAL层框架,大家实现HAL层必须要按照预先定义好的接口来实现。这样做的优势是扩展非常方便,当你有一个新的硬件平台需要跑Android,你只需要在hardware目录下面实现一个自己的HAL层就可以了,不需要修改Android框架的代码。因为现实世界中的平台千变万化,Simon也不可能对他们全部了解,所以这里就不具体介绍怎样实现具体的HAL层了,可供参考的实例很多,拿来模仿一下即可。
为了让系统正确加载你的代码,你需要在系统属性中定义好你的硬件属性,这样Android系统才会正确的加载你的HAL层so库文件。那么需要定义那些系统属性呢?我们继续看hardware/hardware.c文件,发现如下定义:
static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board", "ro.board.platform", "ro.arch" };
如果你仔细研究了上面hw_get_module函数的代码,会发现只要定义了上述系统属性中的一个就可以了。定义上述属性的方法有很多。我这里推荐一种方法就是在系统启动的时候,init进程会读取/proc/cpuinfo文件中的数据得到硬件信息,并且设置ro.hardware属性(具体请查看system/core/init/init.c文件),所以在kernal中定义好硬件信息是个很不错的想法。这样Android移植到一个新的硬件平台只需要移植Kernal(这步肯定是少不了的),另外定义好相应平台的HAL层就可以了,Android框架不需要做任何修改即可。