Android HAL原理实现& GPS HAL实现


1 android HAL
框架

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

Android HAL原理实现& GPS HAL实现_第1张图片

     从上图看出,HAL位于linux KernellibrariesAndroid Runtime之间,也就是说HAL是底层硬件设备驱动程序提供给Framework的一个接口层,它将直接和底层的设备驱动程序挂接。因此当我们需要将Android移植到其他硬件上时,或者给Android系统添加新的硬件支持时,需要对AndroidHAL层进行移植或者实现。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中,设置methodsgps_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库的加载,并获取得HALGPS接口。

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框架图



Android HAL原理实现& GPS HAL实现_第2张图片

5 Gps初始化流程图

Android HAL原理实现& GPS HAL实现_第3张图片

你可能感兴趣的:(Android HAL原理实现& GPS HAL实现)