Android开发入门之五—Android HAL

1 HAL产生的原因

Android HAL(Hardware Abstraction Libraries)是处于user space的最下层,是Android定义的要求Linux内核空间来具体实现的驱动接口。根据Google的说法,使用user-space HAL的原因为:

1 Not all components have standardizedkernel driver interface

2 Kernel driver are GPL which exposes anyproprietary IP

3 Android has specific requirements forhardware drivers

但这其中最重要的原因为第二个,把控制硬件的动作都放到了user space中,在kernel driver里面只有最简单的读写寄存器的操作。Android user space的代码就可以不必受到GPL的束缚而封装成库,避免了暴露硬件厂商使用的硬件型号。

2 HAL的重要性

HAL的重要性主要表现在两个方面:

1 从学习的角度看,HAL通常是Linux内核开发者想学习整个Android系统架构时选择的突破口,这是由于HAL所处在整个系统架构的位置决定的;同样Android user-space的开发者,想要从APP和中间件进一步深入贯通到内核,HAL也是必经之路。如果把Kernel比作关内,Android user-space比作关外,HAL就是进出关的唯一通道,兵家必争之地。

2 从使用的频度来看,随着对SOC性能要求的进一步提高,越来越多的模块将使用硬件加速,甚至以前使用DSP来加速的一些模块,由于性能和功耗的要求,都改用硬件实现,特别是多媒体相关的领域,GPU也几乎成了最近2年出来的SOC的标配,Android也集成了方便使用硬件加速的标准OpenMAX, OpenGL等。

3 HAL的2种模式

3.1 直接调用(旧的模式)

1 源码路径:\hardware\libhardware_legacy

2 模式简介:libhardware_legacy是将 *.so 文件当作shared library来使用,JNI以 direct function call 使用 HAL module。通过直接函数调用的方式,来操作驱动程序。

3 实例:PowerManager

JNI层:android_os_Power.cpp(frameworks\base\core\jni)

static void
acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)
{
    if (idObj == NULL) {
        throw_NullPointerException(env, "id is null");
        return ;
    }

    const char *id = env->GetStringUTFChars(idObj, NULL);

    acquire_wake_lock(lock, id);

    env->ReleaseStringUTFChars(idObj, id);
}

HAL层:Power.c(hardware\libhardware_legacy\power)
int
acquire_wake_lock(int lock, const char* id)
{
    initialize_fds();

//    LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);

    if (g_error) return g_error;

    int fd;

    if (lock == PARTIAL_WAKE_LOCK) {
        fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
    }
    else {
        return EINVAL;
    }

    return write(fd, id, strlen(id));
}

3.2 通过回调函数调用并统一接口(新的模式)

1 源码路径:\hardware\libhardware

2 模式简介:hardware.c和hardware.h(hardware\libhardware\include\hardware)提供了使用这种模式的HAL的方式,并规定统一接口。上层通过hardware.c中的函数hw_get_module获取相应module的stub,然后通过stub来访问HAL。

3 接口源码hardware.c和hardware.h说明

(1)Hardware.h用2个结构体规定了统一接口

/**
 * 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;

    /** 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;

由注释可知,每个HAL模块都必须继承这个结构体,继承方式为,定义一个结构体,其第一个元素为hw_module_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;

由注释可知,每个HAL模块必须继承这个结构体,继承方式类似地,定义一个结构体,其第一个元素为hw_device_t,之后是自己模块独有的方法和属性。

(2)hardware.c使用hw_get_module函数,通过id查找并加载相应HAL模块,并获得相应模块的Stub。相关的解释见这篇文章http://my.unix-center.net/~Simon_fu/?p=630

4 实例:overlay

Service层:DisplayHardware.cpp(frameworks\base\services\surfaceflinger\displayhardware)

void DisplayHardware::init(uint32_t dpy)
{
    mNativeWindow = new FramebufferNativeWindow();
    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
    mDpiX = mNativeWindow->xdpi;
    mDpiY = mNativeWindow->ydpi;
    mRefreshRate = fbDev->fps;

    mOverlayEngine = NULL;
    hw_module_t const* module;
    if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
        overlay_control_open(module, &mOverlayEngine);
    }
	....
}

HAL层:Overlay.h(hardware\libhardware\include\hardware)

/**
 * 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.
 */
struct overlay_module_t {
    struct hw_module_t common;
};

/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 */

struct overlay_control_device_t {
    struct hw_device_t common;
    
    /* get static informations about the capabilities of the overlay engine */
    int (*get)(struct overlay_control_device_t *dev, int name);

    /* creates an overlay matching the given parameters as closely as possible.
     * returns an error if no more overlays are available. The actual
     * size and format is returned in overlay_t. */
    overlay_t* (*createOverlay)(struct overlay_control_device_t *dev,
            uint32_t w, uint32_t h, int32_t format);
    
    /* destroys an overlay. This call releases all
     * resources associated with overlay_t and make it invalid */
    void (*destroyOverlay)(struct overlay_control_device_t *dev,
            overlay_t* overlay);

    /* set position and scaling of the given overlay as closely as possible.
     * if scaling cannot be performed, overlay must be centered. */
    int (*setPosition)(struct overlay_control_device_t *dev,
            overlay_t* overlay, 
            int x, int y, uint32_t w, uint32_t h);

    /* returns the actual position and size of the overlay */
    int (*getPosition)(struct overlay_control_device_t *dev,
            overlay_t* overlay, 
            int* x, int* y, uint32_t* w, uint32_t* h);

    /* sets configurable parameters for this overlay. returns an error if not
     * supported. */
    int (*setParameter)(struct overlay_control_device_t *dev,
            overlay_t* overlay, int param, int value);

    int (*stage)(struct overlay_control_device_t *dev, overlay_t* overlay);
    int (*commit)(struct overlay_control_device_t *dev, overlay_t* overlay);
};

Overlay.cpp (hardware\libhardware\modules\overlay)

static int overlay_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device);

static struct hw_module_methods_t overlay_module_methods = {
    open: overlay_device_open
};

struct overlay_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
        version_major: 1,
        version_minor: 0,
        id: OVERLAY_HARDWARE_MODULE_ID,
        name: "Sample Overlay module",
        author: "The Android Open Source Project",
        methods: &overlay_module_methods,
    }
};

4 后记

在理解HAL的时候,2种模式的区别万不可纠结于上层是用JNI调用,manager调用,还是用service调用,mokoid在这方面也许会造成一些误导。其关键为:旧的模式为直接调用,新的模式为通过hw_get_module获取到相应HAL模块的stub,以回调的方式进行调用。

5 Reference

http://android.tgbus.com/Android/tutorial/201104/350065.shtml

http://blog.csdn.net/k229650014/article/details/5801397

http://my.unix-center.net/~Simon_fu/?p=630

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值