转自:http://blog.csdn.net/jiajie961/archive/2010/11/22/6026585.aspx

 

Android HAL层,即硬件抽象层,是Google响应厂家“希望不公开源码”的要求推出的新概念
1,源代码和目标位置
源代码: /hardware/libhardware目录,该目录的目录结构如下:
/hardware/libhardware/hardware.c编译成libhardware.so,目标位置为/system/lib目录
/hardware/libhardware/include/hardware目录下包含如下头文件:
hardware.h 通用硬件模块头文件
copybit.h copybit模块头文件
gralloc.h gralloc模块头文件
lights.h  背光模块头文件
overlay.h overlay模块头文件
qemud.h  qemud模块头文件
sensors.h 传感器模块头文件
/hardware/libhardware/modules目录下定义了很多硬件模块
这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录

2,HAL层的实现方式
JNI->通用硬件模块->硬件模块->内核驱动接口
具体一点:JNI->libhardware.so->xxx.xxx.so->kernel
具体来说:android frameworks中JNI调用/hardware/libhardware/hardware.c中定义的hw_get_module函数来获取硬件模块,
然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能

3,通用硬件模块(libhardware.so)
(1)头文件为:/hardware/libhardware/include/hardware/hardware.h
头文件中主要定义了通用硬件模块结构体hw_module_t,声明了JNI调用的接口函数hw_get_module
hw_module_t定义如下:
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;
硬件模块方法结构体hw_module_methods_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;
只定义了一个open方法,其中调用的设备结构体参数hw_device_t定义如下:
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_get_module函数声明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
参数id为模块标识,定义在/hardware/libhardware/include/hardware目录下的硬件模块头文件中,
参数module是硬件模块地址,定义了/hardware/libhardware/include/hardware/hardware.h中

(2)hardware.c中主要是定义了hw_get_module函数如下:
#define HAL_LIBRARY_PATH "/system/lib/hw"
static const char *variant_keys[] = {
    "ro.hardware",
    "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(const char *id, 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];
    for (i=0 ; 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_PATH, id, prop);
        }
        else
        {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                    HAL_LIBRARY_PATH, id);
        }
        if (access(path, R_OK))
        {
            continue;
        }
        /* we found a library matching this id/variant */
        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(id, path, module);
    }

    return status;
}
从源代码我们可以看出,hw_get_module完成的主要工作是根据模块id寻找硬件模块动态连接库地址,然后调用load函数去打开动态连接库
并从动态链接库中获取硬件模块结构体地址。硬件模块路径格式如下:
HAL_LIBRARY_PATH/id.prop.so
HAL_LIBRARY_PATH定义为/system/lib/hw
id是hw_get_module函数的第一个参数所传入,prop部分首先按照variant_keys数组中的名称逐一调用property_get获取对应的系统属性,
然后访问HAL_LIBRARY_PATH/id.prop.so,如果找到能访问的就结束,否则就访问HAL_LIBRARY_PATH/id.default.so
举例如下:
假定访问的是背光模块,id定义为"lights"则系统会按照如下的顺序去访问文件:
/system/lib/hw/lights.[ro.hardware属性值].so
/system/lib/hw/lights.[ro.product.board属性值].so
/system/lib/hw/lights.[ro.board.platform属性值].so
/system/lib/hw/lights.[ro.arch属性值].so
/system/lib/hw/lights.default.so
所以开发硬件模块的时候Makefile文件(Android.mk)中模块的命名LOCAL_MODULE要参考上面的内容,否则就会访问不到没作用了。

load函数的关键部分代码如下:
    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;
    }

    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;
    }
HAL_MODULE_INFO_SYM_AS_STR是硬件模块在动态链接库中的标志,定义在hardware.h中如下:
#define HAL_MODULE_INFO_SYM         HMI
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

4,硬件模块
硬件模块的开发主要是完成/hardware/libhardware/include/hardware目录下对应的头文件中的内容,主要是硬件模块头文件和hardware.h中
的结构体中定义了一些函数指针,调用内核提供的接口将具体的函数实现,然后编译成指定名称的动态链接库放到/system/lib/hw目录下即可。
用一句话来概括:硬件模块的开发就是定义一个hardware.h中定义的hw_module_t结构体,结构体名称为宏HAL_MODULE_INFO_SYM,然后实现结构体
的相关内容即可。

5,内核驱动
主要是要向用户层开放接口,让硬件模块和内核可以交互。

 

转自:http://blogold.chinaunix.net/u/22630/showart_2190386.html

 

HAL module 执行过程分析


1. 其初始化过程如下:

System.loadLibrary("led_runtime")->JNI_OnLoad()->registerMethods()-> ->env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0]))

 

onCreate () -> led_srv = new LedService() ->_init()->led_init() -> hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) ->

  led_control_open(&module->common,&sLedDevice)-> module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device) -> led_device_open ()

如此就完成了 app 到底层的初始化工作。

2. 接下来看一下 hw_get_module() 函数。

hw_get_module()->property_get(variant_keys[i],prop,NULL)->__system_property_get(key, value) ->__system_property_find(const char *name)-> __system_property_read(pi, 0, value)-> load(id, prop, &hmi)->snprintf(path,sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant )-> handle = dlopen (path, RTLD_NOW)-> const char *sym = HAL_MODULE_INFO_SYM_AS_STR ; hmi = (const struct hw_module_t *) dlsym (handle, sym)

3. 最后我们看一下 property_get(variant_keys[i],prop,NULL)

这个其实就是获取 ro.hardware 属性,我们关心的就是这个值是什么。在 system/core/init/init.c 文件中的 main 函数中有这么一句: property_set("ro.hardware", hardware); 无疑 ro.hardware 的值就是 hardware 中的内容了。我们再找一下 hardware 赋的什么值,就 ok 了。其实就是在这个函数中完成的 get_hardware_name()

open("/proc/cpuinfo", O_RDONLY)

hw = strstr(data, "/nHardware")

while (*x && !isspace(*x))

   hardware[n++] = tolower(*x);

   x++;

   if (n == 31) break;

  }

Ok ,我们看到了,它是从 /proc/cpuinfo 中读出来的。我们再打开 cpuinfo 文件看一下: Hardware Goldfish 。好了,我们确定了 property_get ()得到的是 goldfish ,那么 snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant ) 构造出来的 path 就是 /system/lib/hw/led.goldfish.so 。终于找到咱们的 so 文件了。

 

 

 

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


//dlsym在bionic/linker/dlfcn.c里定义

 

lookup_in_library-> //bionic/linker/linker.c


_elf_lookup->//bionic/linker/linker.c

static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
{
    Elf32_Sym *s;
    Elf32_Sym *symtab = si->symtab;
    const char *strtab = si->strtab;
    unsigned n;

    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %[email protected]%08x %08x %d/n", pid,
               name, si->name, si->base, hash, hash % si->nbucket);
    n = hash % si->nbucket;

    for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
        s = symtab + n;
        if(strcmp(strtab + s->st_name, name)) continue;

            /* only concern ourselves with global and weak symbol definitions */
        switch(ELF32_ST_BIND(s->st_info)){
        case STB_GLOBAL:
        case STB_WEAK:
                /* no section == undefined */
            if(s->st_shndx == 0) continue;

            TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d/n", pid,
                       name, si->name, s->st_value, s->st_size);
            return s;
        }
    }

    return NULL;
}

 

**********************dlopen

    handle = dlopen(path, RTLD_NOW);

 

//dlopen 在bionic/linker/dlfcn.c里定义

 

->find_library              / /bionic/linker/linker.c

->load_library

->init_library

更多相关文章

  1. android自定义标题栏progressBar
  2. Android(安卓)自定义Dialog的实现
  3. Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现)
  4. Android(安卓)虚拟按键驱动实现
  5. Android(安卓)实现自定义闹钟
  6. Android多个React-Native模块的实现及源码解读
  7. Android 简单的自定义view loading circle
  8. Android(安卓)自定义Toolbar的Menu菜单
  9. android mk file 描述

随机推荐

  1. Android(安卓)解决支付宝对接问题com.ali
  2. android 短信格式
  3. 【简单的学生管理界面】Android的Activit
  4. Handler、Looper与MessageQueue源码分析
  5. Android(安卓)刷机Nexus5 4.4.3
  6. Android获取Contact Number的例子
  7. 仿qq未读消息
  8. 关于Android的几种事件处理
  9. Android(安卓)浅析 EventBus (一) 使用
  10. Android获取手机联系人的方法