HAL层分析
阅读原文时间:2023年07月10日阅读:2

1. 安卓HAL模块基本

2. 定义hal层代码的5个特性

1)硬件抽象层具有与硬件的密切相关性。

2) 硬件抽象层具有与操作系统无关性。

3) 接口定义的功能应该包含硬件或者系统所需硬件支持的所有功能。

4) 接口简单明了,太多接口函数会增加软件模拟的复杂性。

5) 具有可预测的接口设计有利于系统的软、硬件测试和集成。

3. 安卓中hal层相关目录

1)libhardware_legacy :过去的目录,采取链接库模块观念来架构

2)libhardware: 新版的目录,被调整为用HAL stub 观念来架构

3)ril: 是Radio 接口层

4)msm7k : 和QUAL 平台相关的信息

4. hal module基本介绍

4.1.1 struct hw_module_t

/*

  • Value for the hw_module_t.tag field

    */

define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))

define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', '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;

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;

  1. 从hw_module_t 注释可以看出,每个硬件抽象层模块都必须有一个名称为 HAL_MODULE_INFO_SYM 的结构体,且这个结构体的第一个字段必须是hw_module_t
  2. hw_module_t.tag 的值必须是 HARDWARE_MODULE_TAG ,即(H) << 24) | ((W) << 16) | ((M) << 8) | (T) ,用来标识硬件抽象层模块结构体。
  3. hw_module_t.methods定义了一个硬件抽象层模块的操作列表

4.1.2 struct hw_modulemethods_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;

  1. hw_module_methods_t 只有一个函数指针成员变量,用来打开硬件抽闲层模块中的硬件设备。

    2)成员变量的参数module表示要打开的硬件设备所在模块;

    3)成员变量的参数id表示要打开的硬件设备的ID;

    4)成员变量的参数device是一个输出参数,用来描述一个已经打开的硬件设备。

  2. struct hw_device_t

define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', '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 */

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;

1)从hw_device_t 注释可以看出硬件抽象层模块的每一个硬件设备都必须自定义一个硬件设备结构体,且他的第一个成员变量的类型必须是hw_device_t。

2)hw_device_t.tag 的值必须是 **HARDWARE_DEVICE_TAG ** ,即(H) << 24) | ((W) << 16) | ((D) << 8) | (T) ,用来标识硬件抽象中的硬件设备结构体。

3)结构体hw_device_t 的成员变量close是一个函数指针,它用来关闭一个硬件设备。

4.1.4

函数hw_get_module()。

5. hal源码分析

define LOG_TAG "HAL"

/** Base path of the hal modules */

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

/**

  • There are a set of variant filename for modules. The form of the filename

  • is ".variant.so" so for the led module the Dream variants

  • of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:

  • led.trout.so

  • led.msm7k.so

  • led.ARMV6.so

  • led.default.so

    */

static const char _variant_keys[] = {

"ro.hardware", /_ This goes first so that it can pick up a different

file on the emulator. */ //emulator : 仿真器;pick up :获取

"ro.product.board",

"ro.board.platform",

"ro.arch"

};

  1. 硬件抽象模块文件的命名规范为.variant.so”,其中MODULE_ID 标识模块的ID,variant 表示四个系统属性 ro.hardware、ro.product.board、ro.board.platform、ro.arch之一。
  2. 系统在加载硬件抽象层模块时,依次按照 ro.hardware.MODULE_ID、ro.hardware、ro.product.board、ro.board.platform、ro.arch的顺序来取他们的属性值。
  3. 如果其中一个系统属性存在,那么就把它的值作为variant的值,然后在检查对应的文件是否存在,如果存在,那么就找到要加载的硬件抽象层文件了;
  4. 如果四个属性都不存在,或者四个属性对应的系统硬件抽象层文件不存在,就是用 “.default.so” 来作为要加载的硬件抽象层模块文件的名称

static const int HAL_VARIANT_KEYS_COUNT =

(sizeof(variant_keys)/sizeof(variant_keys[0]));

/**

  • Load the file defined by the variant and if successful

  • return the dlopen handle and the hmi.

  • @return 0 = success, !0 = failure.

    */

    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;

    /*

    • 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

      _/

      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;

    }

/*

  • Check if a HAL with given name and subname exists, if so return 0, otherwise

  • otherwise return negative. On success path will contain the path to the HAL.

    */

    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;

    }

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 (inst)
    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.
 */

/* First try a property specific to the class and possibly instance */
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
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);

}

int hw_get_module(const char *id, const struct hw_module_t **module)

{

return hw_get_module_by_class(id, NULL, module);

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章