Android中HAL如何向上层提供接口总结

                       在Android系统中,对于硬件的操作,使用HAL Stub的方式来实现。HAL Stub的具体写法请参照Android中HAL如何向上层提供接口总结
       在我们写完HAL Stub之后,这个HAL Stub是如何被应用获取,如何被应用程序调用的呢?
       显然,由于HAL Stub本质上是一个.so,在调用之后,需要上层应用对其进行加载,然后才能调用。哪么,HAL Stub的加载器是如何实现对不同的Hardware HAL Stub进行通用性调用的呢? 按常规,每个Hareware HAL Stub应该有一个唯一的名字,且有一个通用的规则和一个入口函数。下面看看HAL Stub是如何实现这两个功能的。下面的描述以gralloc为例。

1. 唯一的id

#define GRALLOC_HARDWARE_MODULE_ID "gralloc"


2. hw_module_t实例

每个硬件模块都有一个包含hw_module_t(为第一个成员)数据结构的实例,且实例的名字为:HAL_MODULE_INFO_SYM,它本身是一个宏定义,其定义如下:

hardware.h (通用的东东都在hardware.h和hardware.c中)

/** * Name of the hal_module_info */#define HAL_MODULE_INFO_SYM         HMI //.so中将一个符号HMI,获取此符号的地址,就获取到了对应的hw_module_t地址/** * Name of the hal_module_info as a string */#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
/** * 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 gralloc_module_t {    struct hw_module_t common;        int (*registerBuffer)(struct gralloc_module_t const* module,            buffer_handle_t handle);    int (*unregisterBuffer)(struct gralloc_module_t const* module,            buffer_handle_t handle);        int (*lock)(struct gralloc_module_t const* module,            buffer_handle_t handle, int usage,            int l, int t, int w, int h,            void** vaddr);        int (*unlock)(struct gralloc_module_t const* module,            buffer_handle_t handle);    /* reserved for future use */    int (*perform)(struct gralloc_module_t const* module,            int operation, ... );    /* reserved for future use */    void* reserved_proc[7];}
struct private_module_t {    gralloc_module_t base;    struct private_handle_t* framebuffer;    uint32_t flags;    uint32_t numBuffers;    uint32_t bufferMask;    pthread_mutex_t lock;    buffer_handle_t currentBuffer;    int pmem_master;    void* pmem_master_base;    unsigned long master_phys;    int gpu;    void* gpu_base;    int fb_map_offset;    struct fb_var_screeninfo info;    struct fb_fix_screeninfo finfo;    float xdpi;    float ydpi;    float fps;};

其实例为:

static struct hw_module_methods_t gralloc_module_methods = {        open: gralloc_device_open};
struct private_module_t HAL_MODULE_INFO_SYM = {    base: {        common: {            tag: HARDWARE_MODULE_TAG,            version_major: 1,            version_minor: 0,            id: GRALLOC_HARDWARE_MODULE_ID,            name: "Graphics Memory Allocator Module",            author: "The Android Open Source Project",            methods: &gralloc_module_methods        },        registerBuffer: gralloc_register_buffer,        unregisterBuffer: gralloc_unregister_buffer,        lock: gralloc_lock,        unlock: gralloc_unlock,    },    framebuffer: 0,    flags: 0,    numBuffers: 0,    bufferMask: 0,    lock: PTHREAD_MUTEX_INITIALIZER,    currentBuffer: 0,};


 3. 从HAL Stub(.so)中获取hw_module_t(即private_module_t)

       调用函数int hw_get_module(const char *id, const struct hw_module_t **module),其中id为就是1中所讲的GRALLOC_HARDWARE_MODULE_ID,第二个参数为我们要获取的hw_module_t。

        下面以在FramebufferNativeWindow::FramebufferNativeWindow中的调用流程为例(FramebufferNativeWindow实现FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程序使用。在本质上,它在Framebuffer之上实现了一个ANativeWindow,目前它只管理两个buffers:front and back buffer.)

FramebufferNativeWindow::FramebufferNativeWindow()     : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false){    hw_module_t const* module;    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {        int stride;        int err;        int i;        err = framebuffer_open(module, &fbDev);        LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));                err = gralloc_open(module, &grDev);        LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));        // bail out if we can't initialize the modules        if (!fbDev || !grDev)            return;                mUpdateOnDemand = (fbDev->setUpdateRect != 0);                // initialize the buffer FIFO        mNumBuffers = NUM_FRAME_BUFFERS;        mNumFreeBuffers = NUM_FRAME_BUFFERS;        mBufferHead = mNumBuffers-1;        for (i = 0; i < mNumBuffers; i++)        {                buffers[i] = new NativeBuffer(                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);        }        for (i = 0; i < mNumBuffers; i++)        {                err = grDev->alloc(grDev,                        fbDev->width, fbDev->height, fbDev->format,                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);                LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",                        i, fbDev->width, fbDev->height, strerror(-err));                if (err)                {                        mNumBuffers = i;                        mNumFreeBuffers = i;                        mBufferHead = mNumBuffers-1;                        break;                }        }        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;         const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;        const_cast<int&>(ANativeWindow::minSwapInterval) =             fbDev->minSwapInterval;        const_cast<int&>(ANativeWindow::maxSwapInterval) =             fbDev->maxSwapInterval;    }     else     {         LOGE("Couldn't get gralloc module");    }    ANativeWindow::setSwapInterval = setSwapInterval;    ANativeWindow::dequeueBuffer = dequeueBuffer;    ANativeWindow::lockBuffer = lockBuffer;    ANativeWindow::queueBuffer = queueBuffer;    ANativeWindow::query = query;    ANativeWindow::perform = perform;}


       看看关键的hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)都做了些什么?它在hardware.c中实现。相关代码如下:

/** Base path of the hal modules */#define HAL_LIBRARY_PATH1 "/system/lib/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"/** * There are a set of variant filename for modules. The form of the filename * is "<MODULE_ID>.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. */    "ro.product.board",    "ro.board.platform",    "ro.arch"};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;    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);    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);    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;    return status;}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)        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.     */    /* 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);    }    return status;}int hw_get_module(const char *id, const struct hw_module_t **module){    return hw_get_module_by_class(id, NULL, module);}


       其关键在于load函数中的下面两行代码:

    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;    hmi = (struct hw_module_t *)dlsym(handle, sym);


       在打开的.so中查找HMI符号的地址,并保存在hmi中。至此,.so中的hw_module_t已经被成功获取,从而可以根据它获取别的相关接口。

 4. 使用实例

代码如下:

GraphicBufferAllocator::GraphicBufferAllocator()    : mAllocDev(0){    hw_module_t const* module;    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);    LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);    if (err == 0) {        gralloc_open(module, &mAllocDev);    }}


 5. 总结

1)HAL通过hw_get_module函数获取hw_module_t

2)HAL通过hw_module_t->methods->open获取hw_device_t指针,并在此open函数中初始化hw_device_t的包装结构中的函数及hw_device_t中的close函数,如gralloc_device_open。
3)三个重要的数据结构:

    a) struct hw_device_t: 表示硬件设备,存储了各种硬件设备的公共属性和方法       

    b)struct hw_module_t: 可用hw_get_module进行加载的module

    c)struct hw_module_methods_t: 用于定义操作设备的方法,其中只定义了一个打开设备的方法open.  

typedef struct hw_module_t {    /** tag must be initialized to HARDWARE_MODULE_TAG */    uint32_t tag;    /** major version number for the module */    uint16_t version_major;    /** minor version number of the module */    uint16_t version_minor;    /** 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 number for hw_device_t */    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;


hw_device_t通过open方法获取。 

           

猜你喜欢

转载自blog.csdn.net/qq_44884706/article/details/89309371