Android8.0 硬件抽象层实现分析

众所周知Android是基于Linux内核的开放性系统,我们可以看到Google开放的大部分操作系统实现代码。之所以说它是开放的而不是开源的,是因为Android系统代码不是完全开源的。这始于Linux内核开源协议和第三方厂商隐私安全的矛盾,为了绕过之一矛盾,Google构建了HAL,通过它在在遵守Linux协议的同时,又能保护第三方厂商的利益;既然能这么牛,那么Google是如何做到的呢,秘密就在硬件抽象层(HAL)。So, shutup, Let’s read the fucking sourcecode !

这里写图片描述

硬件抽象层 (HAL)。HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。HAL 实现会被封装成模块,并会由 Android 系统适时地加载。HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。HAL 实现会被封装成模块,并由 Android 系统适时地加载。

这里写图片描述

为了能够清晰的分析硬件抽象层,我们选取power来分析,一来衔接上一篇中Hw中的服务,二来power部分结构较为简单易于分析理解;

1. HARDWARE抽象结构

hardware/libhardware/include/hardware.h

主要是三个结构体 hw_module_t ,hw_module_methods_t ,hw_device_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

    /** Identifier of module */ 模块识别ID
    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;

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

模块方法结构体,用于打开模块对应的设备

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;

具体设备对应的结构体

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;

hardware/libhardware//hardware.c

熟悉的方法 hw_get_module

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

动态库文件和数量

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

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

检查动态库是否存在,查找动态库并执行动态库加载

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

    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) { //模块存在
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    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. */
    return load(class_id, path, module); //加载模块
}

按照 class_id, path, module 加载动态库

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

2. Power的调用

回到上上一篇绑定模式下加载动态库时的代码段会执行 hw_get_module 方法

//ServiceManagement.cpp -> PassthroughServiceManager 载入动态库
IPower* HIDL_FETCH_IPower(const char* /* name */) {
    const hw_module_t* hw_module = nullptr;
    power_module_t* power_module = nullptr;
    //取Power驱动模型结构
    int err = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module);
    if (err) {
        ALOGE("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, err);
        return nullptr;
    }

    if (!hw_module->methods || !hw_module->methods->open) {
        power_module = reinterpret_cast<power_module_t*>(
            const_cast<hw_module_t*>(hw_module)); //强转
    } else {
        //打开
        err = hw_module->methods->open(
            hw_module, POWER_HARDWARE_MODULE_ID,
            reinterpret_cast<hw_device_t**>(&power_module));
        if (err) {
            ALOGE("Passthrough failed to load legacy HAL.");
            return nullptr;
        }
    }
    return new Power(power_module);
}

hardware/libhardware/include/power.h

头文件中有一个包含 hw_module_t 的结构体

typedef struct power_module {

    struct hw_module_t common; // 模块结构体 hw_module_t 

    void (*init)(struct power_module *module);

    void (*setInteractive)(struct power_module *module, int on);

    void (*powerHint)(struct power_module *module, power_hint_t hint,
                      void *data);

    void (*setFeature)(struct power_module *module, feature_t feature, int state);

    int (*get_platform_low_power_stats)(struct power_module *module,
        power_state_platform_sleep_state_t *list);

    ssize_t (*get_number_of_platform_modes)(struct power_module *module);

    int (*get_voter_list)(struct power_module *module, size_t *voter);

} power_module_t;

hardware\libhardware\modules\power\power.c

static void power_init(struct power_module *module UNUSED_ARGUMENT)
{
}

static void power_set_interactive(struct power_module *module UNUSED_ARGUMENT,
                                  int on UNUSED_ARGUMENT)
{
}

static void power_hint(struct power_module *module UNUSED_ARGUMENT,
                       power_hint_t hint,
                       void *data UNUSED_ARGUMENT) {
    switch (hint) {
    default:
        break;
    }
}

static struct hw_module_methods_t power_module_methods = {
    .open = NULL,
};

//关键数据结构
struct power_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = POWER_MODULE_API_VERSION_0_2,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = POWER_HARDWARE_MODULE_ID,
        .name = "Default Power HAL",
        .author = "The Android Open Source Project",
        .methods = &power_module_methods, //关联 hw_module_methods_t 
    },

    .init = power_init, //关联本地方法
    .setInteractive = power_set_interactive,
    .powerHint = power_hint,
};

通过结构体转换后就可以绕过Linux协议的限制,通过调用Linux内核的方法打开位于内核之外的驱动。不得不说这种做法保护了各厂商的利益,却失去了打造一个完全开源的操作系统的机会。今天就到这里,再回。

猜你喜欢

转载自blog.csdn.net/u013928208/article/details/81480278