摘抄至《Android技术内幕》上的一段话
Android HAL是Google应厂商希望不公开源码的要求所推出的新观念,它能以封闭源码形式提供硬件驱动模块。其目的是把Android Framework与Linux kernel隔开,让android不过度依赖Linux Kernel,以达成kernel Independent的概念,也让Android Framework的开发能在不考虑驱动程序的前提下进行发展。HAL提供了简单的设备驱动程序接口,应用程序使用设备驱动程序与底层硬件进行通信。另外,HAL应用程序接口和ANSIC标准库结合在一起,用户可以使用C语言库函数来访问Android文件系统。系统组织结构如下图:
在书中有介绍HAL访问的两种方式,这里做简要介绍
1.通过链接库模块实现
早期的Android HAL通过链接库模块实现,在"hardware/libhardware_legacy"目录中,它需要将HAL实现为一个*.so的共享库,然后在Runtime中通过函数直接调用HAL Module来操作驱动程序;如果使用C++编写应用程序,也可以直接通过dlopen来加载指定的*.so库。其调用流程如图:
由于采取直接调用的方式,可被多个进程使用,但会被映射到多个进程空间中,从而造成资源浪费,同时需要考虑代码能否安全重入的问题(thread safe)
2.通过HAL stub方式实现
HAL stub方式是Android改进后的方式,引入stub的概念,该方式同样存在HAL Module,也以*.so库的形式存在。但是应用程序不会直接装载该库,而是通过stub向HAL提供各种操作函数,然后Runtime通过HAL取得HAL取得HAL Module的stub的operations,再callback这些操作函数。和以链接库模块方式实现的不同在于:HAL stub是通过回调函数间接的调用操作。这就说明HAL中包含了各种各样的stub,Runtime只需要通过不同的类型(module id)就可以取得不同设备驱动的operations。调用流程如下
实际上,这种方式也将Android在不同的硬件中的移植工作进行了简化,统一了访问硬件的接口,不同的硬件只需要按照规则实现这些接口即可。因为采用了间接回调的方式,上层只需要HAL module提供的统一接口获取并操作HAL stub即可,因此,so文件只会被mapping到一个进程,也不存在mapping和重入的问题,从而避免了thread safe.
下面以GPS实例的方式来了解
首先了解一些结构体
struct hw_module_t; //module结构体 struct hw_module_methods_t; //module方法结构体 struct hw_device_t; //设备结构体
/** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; /** * The API version of the implemented module. The module owner is * responsible for updating the version when a module interface has * changed. * * The derived modules such as gralloc and audio own and manage this field. * The module user must interpret the version field to decide whether or * not to inter-operate with the supplied module implementation. * For example, SurfaceFlinger is responsible for making sure that * it knows how to manage different versions of the gralloc-module API, * and AudioFlinger must know how to do the same for audio-module API. * * The module API version should include a major and a minor component. * For example, version 1.0 could be represented as 0x0100. This format * implies that versions 0x0100-0x01ff are all API-compatible. * * In the future, libhardware will expose a hw_get_module_version() * (or equivalent) function that will take minimum/maximum supported * versions as arguments and would be able to reject modules with * versions outside of the supplied range. */ uint16_t module_api_version; #define version_major module_api_version /** * version_major/version_minor defines are supplied here for temporary * source code compatibility. They will be removed in the next version. * ALL clients must convert to the new version format. */ /** * The API version of the HAL module interface. This is meant to * version the hw_module_t, hw_module_methods_t, and hw_device_t * structures and definitions. * * The HAL interface owns this field. Module users/implementations * must NOT rely on this value for version information. * * Presently, 0 is the only valid value. */ uint16_t hal_api_version; #define version_minor hal_api_version /** Identifier of module */ const char *id; /** Name of this module */ const char *name; /** Author/owner/implementor of the module */ const char *author; /** Modules methods */ struct hw_module_methods_t* methods; /** module's dso */ void* dso; /** padding to 128 bytes, reserved for future use */ uint32_t reserved[32-7]; } hw_module_t;
typedef struct hw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device); } hw_module_methods_t; /** * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. */ typedef struct hw_device_t { /** tag must be initialized to HARDWARE_DEVICE_TAG */ uint32_t tag; /** * Version of the module-specific device API. This value is used by * the derived-module user to manage different device implementations. * * The module user is responsible for checking the module_api_version * and device version fields to ensure that the user is capable of * communicating with the specific module implementation. * * One module can support multiple devices with different versions. This * can be useful when a device interface changes in an incompatible way * but it is still necessary to support older implementations at the same * time. One such example is the Camera 2.0 API. * * This field is interpreted by the module user and is ignored by the * HAL interface itself. */ uint32_t version; /** reference to the module this device belongs to */ struct hw_module_t* module; /** padding reserved for future use */ uint32_t reserved[12]; /** Close this device */ int (*close)(struct hw_device_t* device); } hw_device_t;
在实际代码中GPS定义的结构体如下
struct gps_device_t { struct hw_device_t common; /** * Set the provided lights to the provided values. * * Returns: 0 on succes, error code on failure. */ const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev); };
static struct hw_module_methods_t gps_module_methods = { .open = open_gps }; const struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = GPS_HARDWARE_MODULE_ID,//这个必须唯一,而且需要与编译出的so库对应 .name = "Goldfish GPS Module", .author = "The Android Open Source Project", .methods = &gps_module_methods, };
/** * The id of this module */ #define GPS_HARDWARE_MODULE_ID "gps"
int hw_get_module_by_class(const char *class_id, const char *inst, 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]; char name[PATH_MAX]; if (inst)//inst为NULL snprintf(name, PATH_MAX, "%s.%s", class_id, inst); else strlcpy(name, class_id, 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. */ //在上述路径中查找是否存在该id代表的module /* 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_PATH2, name, prop); if (access(path, R_OK) == 0) break; snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH1, name, prop); if (access(path, R_OK) == 0) break; } else { snprintf(path, sizeof(path), "%s/%s.default.so", HAL_LIBRARY_PATH1, name); if (access(path, R_OK) == 0) 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(class_id, path, module);//如果存在该id,就加载该so库 } return status; } int hw_get_module(const char *id, const struct hw_module_t **module) { return hw_get_module_by_class(id, NULL, module);//根据id查找 }
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
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);//打开上述路径的动态库,handle为返回的句柄
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);//返回HMI项的地址,因为我们已经定义HAL_MODULE_INFO_SYM,所以此时不为NULL,这也是为什么定义的hw_module_t结构体必须以HAL_MODULE_INFO_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) {
LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
}
hmi->dso = handle;
/* 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;//填充*pHmi,即之前传入进来的module
return status;//返回状态值
}
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {//此时返回到这里
hw_device_t* device;//定义hw_device_t结构体指针
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);//根据返回的module,这里即将调用GPS的open方法,如下
if (err == 0) {
gps_device_t* gps_device = (gps_device_t *)device;//再次强制转换,得到gps_device句柄
sGpsInterface = gps_device->get_gps_interface(gps_device);//根据gps_device句柄就可以调用HAL中的函数
}
}
if (sGpsInterface) {
sGpsXtraInterface =
(const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
sAGpsInterface =
(const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
sGpsNiInterface =
(const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
sGpsDebugInterface =
(const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
sAGpsRilInterface =
(const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
}
}
static int open_gps(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
{
struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t*)module;
// dev->common.close = (int (*)(struct hw_device_t*))close_lights;
dev->get_gps_interface = gps__get_gps_interface;
//以上为填充dev结构体
*device = (struct hw_device_t*)dev;//将dev强转为hw_device_t指针。注意这里:根据gps_device_t结构体的定义,第一项为hw_device_t,首地址相同,所以这里才能够强制转换,务必hw_device_t处于gps_device_t结构体第一项!
return 0;
}
从上述分析,可以大体明白HAL新框架是如何起到作用的,当然这里还涉及到android service,及各对象之间的时序图,这里就没有涉及。