android系统开发--HAL层开发基础

android系统开发--HAL层开发基础

 

 

android HAL浅探

又挖一个坑,好久没写了,看得代码多而繁乱,又没有专精一块,到头来还是困惑丛生,不管了,做个笔记,写写自己对android hal层的一点理解。

涉及的代码来自android-4.0版本。

1.概念和原因

android hal的概念和存在的原因,不必多说,其实就两点。1.隔离具体驱动接口的变化,2.保护硬件厂商的关键信息。

通过这一层的封装

1.各类硬件(fb,gps,sensor)只需要实现规定的接口即可,驱动接口的不兼容(比如各种硬件设备的ioctl,很可能是厂商自己规定的命令),可以隔离变化。

2.硬件厂商在封装的接口,只需提供一个so即可,使用时,用dlopen hook到相关的接口,不用开放源代码,可以保护一些敏感信息。

总体来说,这层位于kernel/driver之上,framework层之下。

(都是废话,没有干货,呵呵)

2.硬件相关代码位置

在hardware/libhardware/include/hardware目录里面,可以看到目前使用这种方式抽象的硬件种类大致有如下几种。(btw,android貌似还有另外的方式操作硬件,具体的我没看明白,貌似wifi的方式就不太一样,好像是通过协议栈来操作的,对这块不熟悉,只是随便看了看)

audio(声卡,我姑且这么叫,这块驱动层次都有若干标准,让人头晕眼花,比如oss/alsa/jack/等等等。。。这还不是最可恶的,他们还可以互为后端,比oss接口封装成alsa,或者反过来,我去。。。)

camera(摄像头,不多说, 主要我也不太懂,这块linux到是有标准接口,v4l2--->video for linux 2,移植所需要做的工作就是把v4l2接口封装成android规定的,呵呵)

gps(定位,这个真是一点没研究过了)

sensor(传感器,指南针,重力加速度,压力,位置,。。。)

lights(背光,调节背光强弱的)

display(显示相关的几个设备,fb-->framebuffer,应该对应的是屏幕,仅仅是屏幕,不包括显存,gralloc这个设备,才对应的是真正的显存及其操作,hwcomposer,其实就是overlay了,播放视频时需要,ps:这里的display仅仅指lcd,不包括hdmi,vga等等,呵呵)

 3.display设备被调用的方式

我主要看了display所需要的硬件设备,其他设备,精力和兴趣的原因,没有多看。

android display最终的显示的数据都会交给surfaceflinger(直译,屏幕投递者,呵呵),所以操作display硬件的代码这里一定会有。

在framework/base/services/surfaceflinger/displayhardware目录下面,封装了这部分接口,我们可以通过研究这块接口封装,来看到具体硬件是如何被抽象的。

首先,我对surfaceflinger也没非常通彻的理解,只了解一个大概,所以,我只说流程,不说细节。

1.先看surfaceflinger构造函数能不能发现什么,貌似没有发现new displayhardware之类的语句,那这些操作在哪里?我们知道surfaceflinger从Thread和sp继承,那还有两个地方可以去瞧瞧。

1).onfirstref,sp模板构造出来的类,这个函数是首先会被调用的,不过貌似这里也没有,只有一个run(启动线程)

2).readyToRun,这个函数,在run之前一定会被调用一把的,进去一看,发现我们想要的DisplayHardware* const hw = new DisplayHardware(this, dpy)语句,哈哈,这里构造了display硬件的对应的类。

2.DisplayHardware构造函数

这个类上面所说的三类硬件,又归结了两类,

1).FramebufferNativeWindow(这个对应了fb与gralloc,抽象的具体代码在framework/base/libs/ui,这个库里面包括了ui相关所有东西,显示,输入消息,按键映射等等),

2).HWComposer(这个对应了hwcomposer)

(感觉都是一堆废话,都明白的东西,居然还没讲到如何调用)

好吧,我们再简单一点,直接进去看hwcomposer是如何调用的

hardware.h里面给了两个函数,

hw_get_module

hw_get_module_by_class

具体就是,你传一个硬件id(每种硬件,对应一个id,id是字符串,各不相同)下来,我把这个module对应的接口给你。

来看hwcomposer的构造函数。里面调用了hw_get_module,他对应的id是HWC_HARDWARE_MODULE_ID,

在hardware/libhardware/include/hwcomposer.h看到 #define HWC_HARDWARE_MODULE_ID "hwcomposer"

同时其他对应的文件里面,fb的id是      #define GRALLOC_HARDWARE_FB0 "fb0"

        gralloc的id是    #define GRALLOC_HARDWARE_MODULE_ID "gralloc"

我们看看最关键的地方hw_get_module是如何实现的。这个关键点在于load函数。

load函数dlopen相关的vendor库,然后通过dlsym找一个HAL_MODULE_INFO_SYM_AS_STR的全局变量(#define HAL_MODULE_INFO_SYM_AS_STR  "HMI",其实就是对应了HAL_MODULE_INFO_SYM这个)

这个我认为是最关键的点,就找这个全局变量,所有设备编译出来的so库,都要包括这个hmi的变量,可以通过查看代码来验证这个猜测。

这个地方找到之后,就完全了软硬件合体了。

这里不仅可以找到common的open接口,也可以找到各种私有接口,

比如fb就规定了六个接口

int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);

int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);

int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);

int (*compositionComplete)(struct framebuffer_device_t* dev);

void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);

int (*enableScreen)(struct framebuffer_device_t* dev, int enable);

底层实现这几个接口即可。

看完overlay硬件的抽象方式,再按这个思路去看fb,gralloc,gps,会发现他们的过程完全一致。也许大家一直这么做的,但是我是从android里面知道这样的隔离变化方案的,很好很强大。谢谢谷歌。

over。

有点乱,过程就是这样了,自己的笔记,不喜勿喷。

==================================================================================================

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目录

 

2HAL层的实现方式

JNI->通用硬件模块->硬件模块->内核驱动接口

具体一点:JNI->libhardware.so->xxx.xxx.so->kernel

具体来说:android frameworksJNI调用/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<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_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

idhw_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,内核驱动

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

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值