Jimmy Chen

A Programmer

(原创)Android HAL详解

  其实挺久之前就了解过HAL的相关内容,只是好久没看有点遗忘,现在刚好写个博客重新学习下。

三个重要的结构体

struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;

  下面一个一个结构体来看:

hw_module_t结构体

/**
 * 每个硬件模块都必须要有一个名为HAL_MODULE_INFO_SYM的结构体
 * 并且该结构体必须以hw_module_t字段开头
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;

    uint16_t module_api_version;
#define version_major module_api_version

    uint16_t hal_api_version;
#define version_minor hal_api_version

    const char *id;

    const char *name;

    const char *author;

    struct hw_module_methods_t* methods;

    void* dso;

#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
#endif

} hw_module_t;

  hw_module_t结构体的内容如上面,该结构体内带有一个hw_module_methods_t结构体,hw_module_methods_t结构体的内容下面再列出,其次就是hw_module_t结构体主要注意最前面的注释就好,其他没什么好说的。

hw_module_methods_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;

  里面只带有一个open的方法指针,如上面的内容所示,该结构体的内容被包含在hw_module_t结构体中。所以,获得了特定设备的hw_module_t结构体内容,就可以通过open函数指针来回调device的open方法了。

hw_device_t结构体

typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;

    uint32_t version;

    /** reference to the module this device belongs to */
    struct hw_module_t* module;

    /** padding reserved for future use */
#ifdef __LP64__
    uint64_t reserved[12];
#else
    uint32_t reserved[12];
#endif

    /** Close this device */
    int (*close)(struct hw_device_t* device);

} hw_device_t;

  hw_device_t结构体内含有一个close函数指针。在设备卸载的时候会调用到。

这三个结构体的内容就这些,下面拿个实际的例子来看看。代码在AOSP源码的hardware/libhardware/include/hardware/fingerprint.h文件中:

typedef struct fingerprint_module {
    /**
     * Common methods of the fingerprint module. This *must* be the first member
     * of fingerprint_module as users of this structure will cast a hw_module_t
     * to fingerprint_module pointer in contexts where it's known
     * the hw_module_t references a fingerprint_module.
     */
    struct hw_module_t common;
} fingerprint_module_t;

typedef struct fingerprint_device {
    /**
     * Common methods of the fingerprint device. This *must* be the first member
     * of fingerprint_device as users of this structure will cast a hw_device_t
     * to fingerprint_device pointer in contexts where it's known
     * the hw_device_t references a fingerprint_device.
     */
    struct hw_device_t common;

    fingerprint_notify_t notify;

    int (*set_notify)(struct fingerprint_device *dev, fingerprint_notify_t notify);

    uint64_t (*pre_enroll)(struct fingerprint_device *dev);

    int (*enroll)(struct fingerprint_device *dev, const hw_auth_token_t *hat,
                    uint32_t gid, uint32_t timeout_sec);

    int (*post_enroll)(struct fingerprint_device *dev);

    uint64_t (*get_authenticator_id)(struct fingerprint_device *dev);

    int (*cancel)(struct fingerprint_device *dev);

    int (*enumerate)(struct fingerprint_device *dev);

    int (*remove)(struct fingerprint_device *dev, uint32_t gid, uint32_t fid);

    int (*set_active_group)(struct fingerprint_device *dev, uint32_t gid,
                            const char *store_path);

    int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid);

    void *reserved[4];
} fingerprint_device_t;

  上面的代码中定义了两个和fingerprint相关的结构体。首先是fingerprint_module_t结构体,里面只包含一个hw_module_t结构体,看源码注释可以知道如果自己定义一个hardware module的话,必须将hw_module_t作为自定义结构体的第一个字段,主要是为了方便在代码中做hw_module_t结构体和自定义结构体之间进行转化,下面会在代码中进行讲解。

另一个结构体就是fingerprint_device_t结构体了,这个结构体的要求和hw_module_t的要求类似,也是要将hw_device_t结构体作为第一个字段,然后可以在自定义的device结构体后添加一些设备的操作函数指针。

所以,要添加自己的Hardware module就简单很多了,自定义两个结构体,一个xxx_module_t结构体,该结构体的第一个字段为hw_module_t结构体,另一个xxx_device_t结构体,该结构体的第一个字段为hw_devict_t结构体即可。

hardware module的加载过程

上面了解了基本的结构体后,接下来看看hardware module的加载过程。

源码在AOSP的hardware/libhardware/hardware.c文件下,获取hardware module以hw_get_module函数作为入口,例如获取fingerprint时,就是在hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp文件下调用的:

......

fingerprint_device_t* BiometricsFingerprint::openHal() {
    int err;
    const hw_module_t *hw_mdl = nullptr;
    ALOGD("Opening fingerprint hal library...");
    // 调用hw_get_module获取到hardware的hw_module_t内容
    // 其中 FINGERPRINT_HARDWARE_MODULE_ID被define为"fingerprint"
    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) {
        ALOGE("Can't open fingerprint HW Module, error: %d", err);
        return nullptr;
    }
......

// id字符串"fingerprint"的首地址
int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

直接调用hw_get_module_by_class函数,下面看看hw_get_module_by_class函数的代码


#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif

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"
};

// class_id="fingerprint", inst = NULL
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};

    // 这里inst为NULL,所以name=class_id="fingerprint"
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    // 这里开始查找对应module的so库,主要是到系统默认的路径下面查找,默认路径已在上面列出
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    // 查询是否有ro.hardware.fingerprint这个属性
    if (property_get(prop_name, prop, NULL) > 0) {
        // 结合hw_module_exit的代码,在上面列出的路径下检查是否存在fingerprint.$(prop)的这个文件
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    // 检查是否存在variant_keys对应的属性,获取属性值,然后从默认路径下检查对应文件是否存在
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    // 最后找到对应so库的话,就将其load到系统中
    return load(class_id, path, module);
}

static int hw_module_exists(char *path, size_t path_len, const char *name,
                            const char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH3, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    return -ENOENT;
}


static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;

    if (strncmp(path, "/system/", 8) == 0) {
        /* If the library is in system partition, no need to check
         * sphal namespace. Open it with dlopen.
         */
        handle = dlopen(path, RTLD_NOW);
    } else {
        handle = android_load_sphal_library(path, RTLD_NOW);
    }
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("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);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("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 {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }

    *pHmi = hmi;

    return status;
}

这样HAL层的so库就被加载到系统中了。接下来说明一下为什么需要将hw_device_t和hw_module_t作为自定义结构体的第一个字段。

我们以BiometricsFingerprint作为实例看看

BiometricsFingerprint::openHal简单分析

fingerprint_device_t* BiometricsFingerprint::openHal() {
    int err;
    const hw_module_t *hw_mdl = nullptr;
    ALOGD("Opening fingerprint hal library...");
    // 调用hw_get_module方法,获取hardware module保存到hw_mdl中
    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) {
        ALOGE("Can't open fingerprint HW Module, error: %d", err);
        return nullptr;
    }

    if (hw_mdl == nullptr) {
        ALOGE("No valid fingerprint module");
        return nullptr;
    }

    // 通过reinterpret_cast将hw_module_t类型的hw_mdl强制转换为fingerprint_module_t类型
    fingerprint_module_t const *module =
        reinterpret_cast(hw_mdl);
    if (module->common.methods->open == nullptr) {
        ALOGE("No valid open method");
        return nullptr;
    }

    hw_device_t *device = nullptr;

    // 调用module里面的open函数,获取到对应的hw_device_t
    if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) {
        ALOGE("Can't open fingerprint methods, error: %d", err);
        return nullptr;
    }

    if (kVersion != device->version) {
        // enforce version on new devices because of HIDL@2.1 translation layer
        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
        return nullptr;
    }

    // 通过reinterpret_cast将hw_device_t类型的fp_device强制转换为fingerprint_device_t类型
    fingerprint_device_t* fp_device =
        reinterpret_cast(device);

    // 设置Fingerprint的notify函数
    if (0 != (err =
            fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) {
        ALOGE("Can't register fingerprint module callback, error: %d", err);
        return nullptr;
    }

    return fp_device;
}

所以从这里可以知道为什么在自定义硬件设备的module结构体和device结构体时需要将第一个字段分别设置为hw_module_t结构体和hw_device_t结构体。一切的一切都是为了在使用reinterpret_cast进行强制类型转换的时候能够兼容。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: