1 android HAL框架

Android HAL是google应厂商不希望公开源码的要求所推出的新概念。它能以封闭源码的形式提供硬件驱动模块,其目的是把Android Framework 和linux kernel隔开,让Android不至于过度以来linux kernel。HAL提供了简单的设备驱动程序接口,应用程序使用设备驱动程序与底层硬件通信

从上图看出,HAL位于linux Kernel与libraries和Android Runtime之间,也就是说HAL是底层硬件设备驱动程序提供给Framework的一个接口层,它将直接和底层的设备驱动程序挂接。因此当我们需要将Android移植到其他硬件上时,或者给Android系统添加新的硬件支持时,需要对Android的HAL层进行移植或者实现。Android HAL层实现位于源码中的路径如下:

n         hardware/libhardware_legacy

n         hardware/libhardware/

n         hardware/ril/

2 Android HAL的实现

2.1 重要结构体定义

HAL的实现是一个硬件抽象层的框架,其硬件设备的具体操作由对应的stub进行间接的回调。HAL框架位于如下两个文件:

n         hardware/libhardware/include/hardware/hardware.h

n         hardware/libhardware/hardware.c

hardware.h中定义了三个重要的结构体:

n         struct hw_device_t

n         struct hw_module_t

n         struct hw_module_methods_t

下面分别介绍这三个重要的结构体。

结构体hw_device_t表示硬件设备,存储了各种硬件设备的公共属性和方法,其定义如下:

typedef struct hw_device_t {

// 标记 HARDWARE_DEVICE_TAG */

uint32_t tag;

// 版本号 for hw_device_t */

uint32_t version;

// 该硬件属于哪一个module*/

struct hw_module_t* module;

//padding reserved for future use */

uint32_t reserved[12];

// 关闭设备操作

int (*close)(struct hw_device_t* device);

} hw_device_t;

如果要移植或者添加新的硬件,那么都需要实用该结构体进行注册,其中tag必须初始化,结构体hw_module_t在进行加载的时候用于判断属于哪一个module,其定义代码如下:

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;

//module 的id,通过这个id找到相应的so文件和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用于定义操作设备的方法,这里只是定义了打开设备的方法open,其定义如下:

typedef struct hw_module_methods_t {

// 打开设备 */

int (*open)(const struct hw_module_t* module, const char* id,

struct hw_device_t** device);

} hw_module_methods_t;

如果要执行打开设备的操作,可以使用

module->methods->open(module,GPS_HARDWARE_MUDOLE_ID,(struct hw_device_t**)device);

2.2如何获得HAL stub

当需要加载module时,调用hardware.c中的hw_get_module函数获取HAL,起代码如下:

int hw_get_module(const char *id, const struct hw_module_t **module)

{

return hw_get_module_by_class(id, NULL, module);

}

hw_get_module_by_class():

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.

//

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;

}

在上面函数中,Android系统首先在系统属性中查找硬件定义,然后通过该函数的参数id和查找到的模块路径(path)加载相应的HAL的特定模块so库文件。如果在系统属性中未定义硬件属性,则需要使用默认硬件HAL对应模块so库文件,其中property_get函数将根据定义的硬件属性配置查找对应的模块及路径,调用load函数加载。

加载了so库文件之后,就可以操作具体的硬件设备,对与不同的硬件设备,Android提供了一些接口,他们位于“hardware/libhareware/include/hardware”中。如果要自定义HAL,那么也要遵守这些已经提供的接口。

3 GPS HAL实现

在Android系统中,关于GPS的硬件抽象层实现:

n         hardware/libhardware_legacy/include/hardware_legacy/gps.h

gps.h定义了各种常量和信息,包括定位模式、状态等,并同时给JNI层调用的接口。对于GPS的具体实现,需要跟具体的GPS驱动来定,因为某些GPS设备能直接输出所需要的NMEA数据,有的则需要自己实现解析才能得到。

3.1重要数据结构定义

n         GpsLocation:

typedef struct {

// set to sizeof(GpsLocation) */

size_t          size;

//标志位. */

uint16_t        flags;

//维度

double          latitude;

//经度

double          longitude;

//以WSG 84坐标系统表示高度信息

double          altitude;

/速度

float           speed;

//方向

float           bearing;

//精确度

float           accuracy;

//时间戳

GpsUtcTime      timestamp;

} GpsLocation;

n         GpsStatus:

typedef struct {

size_t          size;

GpsStatusValue status;

} GpsStatus;

GpsLocation用于表示GPS的定位信息,GpsStatus表示状态信息,这些数据将和java层的GpsLocationProvider.java统一,状态信息如下:

typedef uint16_t GpsStatusValue;

// IMPORTANT: Note that the following values must match

// constants in GpsLocationProvider.java.

//未知

#define GPS_STATUS_NONE             0

//已经开始导航

#define GPS_STATUS_SESSION_BEGIN    1

//已经停止导航

#define GPS_STATUS_SESSION_END      2

//已经通电但是设备没有导航

#define GPS_STATUS_ENGINE_ON        3

//没有通电状态

#define GPS_STATUS_ENGINE_OFF       4

除了以上所述还包含了一些其他的数据结构体,比如GpsSvInfo(卫星信息),GpsSvStatus(卫星状态)、GpsAidingData(帮助数据)等。下面看最重要的结构体,GpsInterface定义如下:

typedef struct {

//

size_t          size;

//初始化GPS时设置回调函数的结构体GpsCallbacks

int   (*init)( GpsCallbacks* callbacks );

//开始导航

int   (*start)( void );

/停止导航

int   (*stop)( void );

//关闭接口

void  (*cleanup)( void );

//置入当前时间

int   (*inject_time)(GpsUtcTime time, int64_t timeReference,

int uncertainty);

//置入位置信息

int  (*inject_location)(double latitude, double longitude, float accuracy);

//删除帮助数据

void  (*delete_aiding_data)(GpsAidingData flags);

//设置位置模式

int   (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,

uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);

//得到扩展信息指针

const void* (*get_extension)(const char* name);

} GpsInterface;

初始化函数init被调用的时候,会传入一个GpsCallbacks指针,它是一个包含多个回调函数的结构体,定义如下:

typedef void (* gps_location_callback)(GpsLocation* location);

typedef void (* gps_status_callback)(GpsStatus* status);

typedef void (* gps_sv_status_callback)(GpsSvStatus* sv_info);

typedef void (* gps_nmea_callback)(GpsUtcTime timestamp, const char* nmea, int length);

typedef void (* gps_set_capabilities)(uint32_t capabilities);

typedef void (* gps_acquire_wakelock)();

typedef void (* gps_release_wakelock)();

typedef void (* gps_request_utc_time)();

typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);

typedef struct {

size_t      size;

gps_location_callback location_cb;

gps_status_callback status_cb;

gps_sv_status_callback sv_status_cb;

gps_nmea_callback nmea_cb;

gps_set_capabilities set_capabilities_cb;

gps_acquire_wakelock acquire_wakelock_cb;

gps_release_wakelock release_wakelock_cb;

gps_create_thread create_thread_cb;

gps_request_utc_time request_utc_time_cb;

} GpsCallbacks;

Init函数会注册这些回调函数,当触发某个状态时可以通过该回调函数像JNI层相应函数,JNI在回调到java层,完成数据的回调通知。另外,还定义了GpsXtraInterface结构体,它的作用是GPS定义的一个增强,当GPS没有搜索到卫星时候,通过网络下载数据,可以让GPS快速找到当前可以使用的卫星信息,定义如下:

typedef void (* gps_xtra_download_request)();

typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);

typedef struct {

gps_xtra_download_request download_request_cb;

gps_create_thread create_thread_cb;

} GpsXtraCallbacks;

typedef struct {

size_t          size;

int  (*init)( GpsXtraCallbacks* callbacks );

//植入XTRA数据到GPS

int  (*inject_xtra_data)( char* data, int length );

} GpsXtraInterface;

其中包含了inject_xtra_data函数,它通过网络下载的Xtra数据植入GPS中,同样在init函数中设置回调结构体GpsXtraCallbacks,作为下载Xtra数据的会的回调函数。

另外,对基于CellID的基站定位进行了扩展,定义了AGPS接口结构体AGpsInterface和其回调结构其AGpsCallbacks,实现方式和Gps类似。

Gps设备结构体gps_device_t:

struct gps_device_t {

struct hw_device_t common;

//获取Gps硬件接口

const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);

};

实现get_gps_interface方法在gps.c中,去实现查找具体的硬件接口,如果设备没有GPS硬件,可以模拟GPS接口,这样应用程序就不会因为没有硬件支持而挂掉。

3.2 gps.c实现

一下代码是模拟Gps接口的一部分代码:

// GpsInterface  结构体中函数初始化

static const GpsInterface  qemuGpsInterface = {

sizeof(GpsInterface),

qemu_gps_init,

qemu_gps_start,

qemu_gps_stop,

qemu_gps_cleanup,

qemu_gps_inject_time,

qemu_gps_inject_location,

qemu_gps_delete_aiding_data,

qemu_gps_set_position_mode,

qemu_gps_get_extension,

};

//获取Gps接口具体实现

const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)

{

return &qemuGpsInterface;

}

//打开模拟gps设备

static int open_gps(const struct hw_module_t* module, char const* name,

struct hw_device_t** device)

{

struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));

memset(dev, 0, sizeof(*dev));

dev->common.tag = HARDWARE_DEVICE_TAG;

dev->common.version = 0;

dev->common.module = (struct hw_module_t*)module;

dev->get_gps_interface = gps__get_gps_interface;

*device = (struct hw_device_t*)dev;

return 0;

}

//打开设备open函数的具体实现到open_gps

static struct hw_module_methods_t gps_module_methods = {

//设置open函数实现

.open = open_gps

};

//初始化hw_module_t结构体

const struct hw_module_t HAL_MODULE_INFO_SYM = {

.tag = HARDWARE_MODULE_TAG,

.version_major = 1,

.version_minor = 0,

.id = GPS_HARDWARE_MODULE_ID,

.name = "Goldfish GPS Module",

.author = "The Android Open Source Project",

.methods = &gps_module_methods,

};

在初始化module的结构体HAL_MODULE_INFO_SYM中,设置methods为gps_module_methods,而上面又对gps_module_methods进行了初始化,里面设置了open函数了open_gps, open_gps真正实现了打开gps设备。在open_pgs函数中,设置了gps_device_t结构体的get_gps_interface方法,获取接口。

3.3 Gps JNI层与HAL调用

经过上面的介绍,Gps HAL层已经实现了对JNI的接口,那么JNI是如何调用的呢?具体实现在:com_android_server_location_GpsLocationProvider.cpp。

static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {

int err;

hw_module_t* module;

err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

if (err == 0) {

hw_device_t* device;

err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);

if (err == 0) {

gps_device_t* gps_device = (gps_device_t *)device;

sGpsInterface = gps_device->get_gps_interface(gps_device);

}

}

……

}

在这个方法中,实际完成了硬件so库的加载,并获取得HAL的GPS接口。

n         hw_get_module()函数是hardware.c中实现的方法,具体完成module的获取并加载so库文件。

n         module->methods->open()实际上是调用到了gps.c文件中的open_gps()方法。

n         做了一个结构体的强制转换,讲hw_device_t转换为gps_device

n         调用get_gps_interface,实际上是调用gps.c中的gps__get_gps_interface,获取gps接口

接下来设置回调函数:

GpsCallbacks sGpsCallbacks = {

sizeof(GpsCallbacks),

location_callback,

status_callback,

sv_status_callback,

nmea_callback,

set_capabilities_callback,

acquire_wakelock_callback,

release_wakelock_callback,

create_thread_callback,

request_utc_time_callback,

};

static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)

{

// this must be set before calling into the HAL library

if (!mCallbacksObj)

mCallbacksObj = env->NewGlobalRef(obj);

// fail if the main interface fails to initialize

if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)

return false;

......

return true;

}

这里先初始化了回调结构体GpsCallbacks,并且实现了回调函数,回调函数中,又将会回调到java层。

到了这里gps初始化完成,等待这java发送的调用命令。

4 Location框架图

5 Gps初始化流程图


Android HAL原理实现 GPS HAL实现相关推荐

  1. 高通8155 GPS HAL层代码移植

    1.添加gps hal层代码包 将ublox gps芯片的hal层代码拷贝至apps/LINUX/android/hardware/ublox/路径下,树状图如下: 2.修改编译选项 将新增的ublo ...

  2. Android深度探索(卷1)HAL与驱动开发 第四章 源代码的下载和编译 读书笔记

    Android深度探索(卷1)HAL与驱动开发 第四章 源代码的下载和编译 读书笔记     本章学习了使用git下载两套源代码并搭建两个开发环境.分别为Android源代码和Linux内核源代码.A ...

  3. Android底层开发之Audio HAL Android Audio Overview

    http://blog.csdn.net/kangear/article/details/44939429 Android底层开发之Audio HAL 在Android音频底层调试-基于tinyals ...

  4. Android深度探索(卷1)HAL与驱动开发 心得体会 第十章 嵌入式Linux的调用技术

    Android深度探索(卷1)HAL与驱动开发 心得体会 第十章  嵌入式Linux的调用技术 对于复杂的Linux驱动以及HAL等程序库,需要使用各种方法对其进行调试.例如,设置断点,逐步跟踪代码. ...

  5. Android深度探索(卷1)HAL与驱动开发学习笔记(8)

    Android深度探索(卷1)HAL与驱动开发学习笔记(8) 第八章 蜂鸣器驱动   L i n u x驱动的代码重用有很多种方法.可以采用标准C程序的方式.将要重用的代码放在其他的文件(在头文件中声 ...

  6. Android 8.1 从零开始写 HAL -- (2) 实现 HAL 主体

    Android 8.1 从零开始写 HAL – (2) 实现 HAL 主体 注意:本文基于 Android 8.1 进行分析 Qidi 2020.07.18 (Markdown & Haroo ...

  7. Android底层开发之Audio HAL

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Andr ...

  8. 【转】Android Activity原理以及其子类描述,androidactivity

        Android Activity原理以及其子类描述,androidactivity 简介 Activity是Android应用程序组件,实现一个用户交互窗口,我们可以实现布局填充屏幕,也可以实 ...

  9. Android测试原理(三)——使用Eclipse的ADT进行测试

    原文链接:http://developer.android.com/tools/testing/testing_eclipse.html 1.使用Eclipse的ADT进行测试 这次的主题介绍了怎么使 ...

最新文章

  1. 雷林鹏分享:PHP 5 Directory 函数
  2. 初次安装Magento商城 后台报错的解决方案
  3. react之bind函数到组件通识篇
  4. mysql 默认当前时间_复制信息记录表|全方位认识 mysql 系统库
  5. 解决在 IntelliJ IDEA 中,输入代码时突然不会自动显示下拉框提示
  6. 使用脚本控制网页Table的显示隐藏(全代码)_AX
  7. java相对应的键盘输入_Java 实现输入键盘上任意键显示出相对应的ASCII
  8. 第九章:SpringCloud Feign几个坑
  9. FPGA实现cameralink解码
  10. java实现NC数据等值线等值面可视化
  11. [2019CCPC秦皇岛] G Game on Chessboard 状压dp
  12. 总以为猜对了结局,但烧脑推理电影却总是让我扭伤腰
  13. POM 标签大全详解
  14. php模拟QQ登录获得skey码,请教:QQ授权第三方登录论坛之authorize模拟访问,一直失败...
  15. 2019 google开发者大会 | tensorflow相关视频
  16. 新建xib适配iphone4尺寸的注意
  17. 将ppm格式转换为bmp格式的方式有哪些?
  18. ADS集成开发环境介绍
  19. spring中的事件监听机制
  20. 使用第三方软件设置在线客服系统——iBangKF网站免费在线客服系统

热门文章

  1. 网页实现从数据库读取数据并简单分页
  2. 天津2019全国计算机二级,2019年上半年全国计算机等级考试报名啦
  3. 随机梯度下降法、牛顿法、冲量法、AdaGrad、RMSprop以及Adam优化过程和理解
  4. 实现在GEF中被选中图形上的右键菜单
  5. 自动化运维为什么是必须的?
  6. 中学校长在开学典礼上的讲话
  7. 小知识(3) 解决谷歌翻译问题(浏览器/IDEA)
  8. 数据结构2.带控制信息的链表
  9. matlab 多项式表达,MATLAB多项式
  10. 弹弹堂服务器响应时间过长,弹弹堂游戏加载问题全攻略