摘抄至《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;//返回状态值}

回到GpsLocationProvider.cpp中

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,及各对象之间的时序图,这里就没有涉及。


综上所述,可知大体流程如下









更多相关文章

  1. Android中ScrollView隐藏进度条方法
  2. [置顶] Android项目组织和代码重用
  3. Android(安卓)APK应用安装原理(1)-解析AndroidManifest原理-Pack
  4. android休眠唤醒流程:
  5. 【Android】调用Android中的软键盘
  6. android的adb详解(多设备时adb调用)
  7. Android的布局和Intent笔记和常用实例
  8. Android(安卓)项目结构图
  9. Android之pull解析服务端的XML

随机推荐

  1. 如何在Android(安卓)内核源码树中添加app
  2. @android, ?attr/ 和 ?android 的区别
  3. Android(安卓)2.2的开发语言
  4. android 8.0 新特性:通知渠道
  5. Android(安卓)RxJava 实际应用讲解:网络请
  6. Android录音mp3格式实例详解
  7. 当透明状态栏遇到输入框
  8. 谷歌宣布Android(安卓)3.0暂停开源
  9. Android开发系列(二十一):Spinner的功能和用
  10. Android(安卓)实现微信分享好友和朋友圈