Android HAL 硬件抽象层分析

1) 在分析 Android HAL 硬件抽象层之前,首先在看一下 Android 系统架构图:

HAL 层是干什么的呢,参考 https://groups.google.com/forum/#!topic/android-porting/_696kIx9pTc 可以有很好的理解:

Think of the HAL as a published API for functionality to be provided by shared libraries that are to be provided by ODMs. That API is what's

used by Android's core services to talk to the hardware. Those services know nothing of the hardware other than that API.

So long as the requisite shared libraries (i.e. ".so" files) are available, "Android"  (i.e. the system's core services) will be able to interface with the hardware.


There are two general categories of HAL components, those explicitly loaded (through a runtime dlopen()) and those automatically loaded by
the dynamic linker (libhardware_legacy.so). The API for the former are in <aosp>/hardware/libhardware/include/hardware and the API for the
latter are in <aosp>/hardware/libhardware_ legacy/include/hardware_ legacy. The trends seems to have been moving away from "legacy".

The interface between those ".so" files and the actual drivers through /dev entries or otherwise is up to the ODM to specify. Android doesn't
care about that. It only cares about the HAL .so modules.


Android service 不会真正作为处理和内核驱动交互(Userspace 最普遍的通过/sys ,/dev 接口)控制硬件的工作,相反,这部分的工作就是 Android HAL层承担的工作。

而Android core service 通过 JNI 和 HAL 层的动态库(*.so) 交互。


2) 下面以背光为例讲述整个code flow:

HAL 层开发,主要工作就是定义一个名为 HAL_MODULE_INFO_SYM 的结构体,实现这个结构体相关的内容,hardware/libhardware/include/hardware/hardware.h 中定义了 hardware module 相关的数据结构。

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

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;

/**
 * Name of the hal_module_info
 */
#define HAL_MODULE_INFO_SYM         HMI


3) linux 驱动方面的知识

要想控制 背光,linux kernel 必然实现了相关的驱动,并实现了ioctl/open/read/write 等驱动操作的方法。

这里以milestone 为例,撇开 HAL 层不管,通过ADB 直接控制背光。

在 /sys 下面搜索 brightness

# find -name "brightness"
./devices/platform/i2c_omap.1/i2c-1/1-0038/leds/lcd-backlight/brightness
./devices/platform/i2c_omap.3/i2c-3/3-0053/leds/torch-flash/brightness
./devices/platform/i2c_omap.3/i2c-3/3-0053/leds/spotlight/brightness
./devices/platform/ld-keyboard-backlight/leds/keyboard-backlight/brightness
./devices/platform/ld-button-backlight/leds/button-backlight/brightness
./devices/platform/notification-led/leds/red/brightness
./devices/platform/notification-led/leds/green/brightness
./devices/platform/notification-led/leds/blue/brightness

这里只看 lcd backlight, 在点亮屏幕的情况下,

# cat ./devices/platform/i2c_omap.1/i2c-1/1-0038/leds/lcd-backlight/brightness
164

# echo 10 > ./devices/platform/i2c_omap.1/i2c-1/1-0038/leds/lcd-backlight/brightness

可以看到可以成功的控制背光的亮度。

而 Android HAL 层就是在 用户态实现这样的控制硬件驱动的逻辑,并提供出方法给 Android core service JNI 调用。


4) 背光 hardware module 的实现

一般实现hardware module的代码要么在  device 对应的target 下面,要么在 vendor 下面,编译之后在 /system/lib/hw/lights.mini6410.so

Tiny 6410 代码分析:

Android-2.3.4/device/samsung/crespo/liblight/lights.c

上来就看到了 /sys 接口文件的定义,想必是通过 /sys 接口与驱动程序交互:

char const *const LCD_FILE = "/sys/class/backlight/s5p_bl/brightness";

static struct hw_module_methods_t lights_module_methods = {
	.open =  open_lights,
};

const struct hw_module_t HAL_MODULE_INFO_SYM = {
	.tag = HARDWARE_MODULE_TAG,
	.version_major = 1,
	.version_minor = 0,
	.id = LIGHTS_HARDWARE_MODULE_ID,
	.name = "lights Module",
	.author = "Google, Inc.",
	.methods = &lights_module_methods,
};

需要包含的头文件
/hardware/libhardware/include/hardware目录下的hardware.h和lights.h
其中hardware.h中定义了通用硬件模块,lights.h中定义了背光设备相关的内容


5) Android framework service JNI 实现

看下 Android-2.3.4/frameworks/base/services/jni/com_android_server_LightsService.cpp

通过获取 hardware module, 进而 获得device 和HAL 层进行交互。

static light_device_t* get_device(hw_module_t* module, char const* name)
{
    int err;
    hw_device_t* device;
    err = module->methods->open(module, name, &device);
    if (err == 0) {
        return (light_device_t*)device;
    } else {
        return NULL;
    }
}

static jint init_native(JNIEnv *env, jobject clazz)
{
    int err;
    hw_module_t* module;
    Devices* devices;
    
    devices = (Devices*)malloc(sizeof(Devices));

    err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    if (err == 0) {
        devices->lights[LIGHT_INDEX_BACKLIGHT]
                = get_device(module, LIGHT_ID_BACKLIGHT);
        devices->lights[LIGHT_INDEX_KEYBOARD]
                = get_device(module, LIGHT_ID_KEYBOARD);
        devices->lights[LIGHT_INDEX_BUTTONS]
                = get_device(module, LIGHT_ID_BUTTONS);
        devices->lights[LIGHT_INDEX_BATTERY]
                = get_device(module, LIGHT_ID_BATTERY);
        devices->lights[LIGHT_INDEX_NOTIFICATIONS]
                = get_device(module, LIGHT_ID_NOTIFICATIONS);
        devices->lights[LIGHT_INDEX_ATTENTION]
                = get_device(module, LIGHT_ID_ATTENTION);
        devices->lights[LIGHT_INDEX_BLUETOOTH]
                = get_device(module, LIGHT_ID_BLUETOOTH);
        devices->lights[LIGHT_INDEX_WIFI]
                = get_device(module, LIGHT_ID_WIFI);
    } else {
        memset(devices, 0, sizeof(Devices));
    }

    return (jint)devices;
}

static void finalize_native(JNIEnv *env, jobject clazz, int ptr)
{
    Devices* devices = (Devices*)ptr;
    if (devices == NULL) {
        return;
    }

    free(devices);
}

static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
        int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)
{
    Devices* devices = (Devices*)ptr;
    light_state_t state;

    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
        return ;
    }

    memset(&state, 0, sizeof(light_state_t));
    state.color = colorARGB;
    state.flashMode = flashMode;
    state.flashOnMS = onMS;
    state.flashOffMS = offMS;
    state.brightnessMode = brightnessMode;

    devices->lights[light]->set_light(devices->lights[light], &state);
}


而上层 APP 如果需要设置 backlight 则只需要通过JNI 调用相应的设置函数就行了:

static JNINativeMethod method_table[] = {
    { "init_native", "()I", (void*)init_native },
    { "finalize_native", "(I)V", (void*)finalize_native },
    { "setLight_native", "(IIIIIII)V", (void*)setLight_native },
};


这样, Android 从上到下的机制是不是已经很明了了,而背光模块只是众多 hardware module 中的一个,分析明白了这个再去分析其他模块的代码也就容易多了。

参考:

http://blog.csdn.net/jiajie961/article/details/6030405


另外, 推荐一个讲解 Android HAL 硬件抽象层特别好的文档: http://download.csdn.net/detail/chenqiang0721/5944409


That's all !  Enjoy Android HAL development Now !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值