Android GNSS介绍

1. 介绍

在Android中定位方式通常有两种,GNSS和网络

GNSS(Global Navigation Satellite System)一般是指全球导航卫星系统,如美国的GPS、俄罗斯的Glonass、欧洲的Galileo、中国的北斗卫星导航系统
网络定位是当设备通过基站或WiFi连入网络后,设备可以获取附近基站/AP的位置,再通过一些计算得到设备当前的位置信息

这里主要讨论Android中GNSS的实现

2. 架构

在Android中, Location以分层的方式实现, 从上到下依次为

- 应用框架: 提供android.location API

定位管理器: LocationManager
定位提供者: LocationProvider
位置信息: Location
定位监听者: LocationListener

- Framework Services: 服务实现, 主要涉及文件如下

frameworks/base/location/java/android/location/*
frameworks/base/services/core/java/com/android/server/location/*
frameworks/base/services/core/java/com/android/server/LocationManagerService.java
frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java

- JNI: 封装GNSS hal层接口(IGnss)给GnssLocationProvider使用体现

frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp

- HAL层: 实现了IGnss接口和IGnss服务

hardware/libhardware/include/hardware/gps.h

hardware/interfaces/gnss/1.0/                        ====>   android.hardware.gnss@1.0.so
hardware/interfaces/gnss/1.0/default/         ====>   android.hardware.gnss@1.0-impl.so  android.hardware.gnss@1.0-service

hardware/interfaces/gnss/1.1/                        ====>   android.hardware.gnss@1.1.so
hardware/interfaces/gnss/1.1/default/         ====>   android.hardware.gnss@1.1-service

3. 服务层

framework层Location服务的启动主要流程如下

SystemServer::startOtherServices()
    new LocationManagerService(context);
    // 向servicemanager注册服务
    ServiceManager.addService(Context.LOCATION_SERVICE, location);
    LocationManagerService.systemRunning();
        LocationManagerService.loadProvidersLocked()
            if (GnssLocationProvider.isSupported()) {
                GnssLocationProvider gnssProvider = new GnssLocationProvider(...);
                    GnssLocationProvider.class_init_native()
                        android_location_GnssLocationProvider_class_init_native()
                        [ return IGnss_V1_1::getService() ]
                addProviderLocked(gnssProvider);
            }

其中LocationManagerService实现了ILocationManager的服务端, APP调用LocationManager则作为其客户端运行
GnssLocationProvider实现了LocationProviderInterface接口并作为GNSS定位提供者为LocationManagerService提供服务

LocationProviderInterface接口定义如下

public interface LocationProviderInterface {
    public String getName();

    public void enable();
    public void disable();
    public boolean isEnabled();
    public void setRequest(ProviderRequest request, WorkSource source);

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args);

    // --- deprecated (but still supported) ---
    public ProviderProperties getProperties();
    public int getStatus(Bundle extras);
    public long getStatusUpdateTime();
    public boolean sendExtraCommand(String command, Bundle extras);
}

4. JNI层

com_android_server_location_GnssLocationProvider.cpp封装了IGnss,并且实现了部分GnssLocationProvider的native接口,主要包括

public class GnssLocationProvider implements LocationProviderInterface {
    ...

    // GNSS releated
    private static native void class_init_native();
    private static native boolean native_is_supported();
    private static native boolean native_is_agps_ril_supported();
    private static native boolean native_is_gnss_configuration_supported();
    private static native void native_init_once();
    private native boolean native_init();
    private native void native_cleanup();
    private native boolean native_set_position_mode(...);
    private native boolean native_start();
    private native boolean native_stop();
    private native void native_delete_aiding_data(int flags);
    private native int native_read_nmea(byte[] buffer, int bufferSize);
    private native void native_inject_best_location(...);
    private native void native_inject_location(...);

    // XTRA Support
    private native void native_inject_time(...);
    private native boolean native_supports_xtra();
    private native void native_inject_xtra_data(byte[] data, int length);

    // DEBUG Support
    private native String native_get_internal_state();

    // AGPS Support
    private native void native_agps_data_conn_open(String apn, int apnIpType);
    private native void native_agps_data_conn_closed();
    private native void native_agps_data_conn_failed();
    private native void native_agps_ni_message(byte[] msg, int length);
    private native void native_set_agps_server(...);

    // Network-initiated (NI) Support
    private native void native_send_ni_response(...);

    // AGPS ril suport
    private native void native_agps_set_ref_location_cellid(...);
    private native void native_agps_set_id(int type, String setid);
    private native void native_update_network_state(...);

    // GNSS Configuration
    private static native boolean native_set_supl_version(int version);
    private static native boolean native_set_supl_mode(int mode);
    private static native boolean native_set_supl_es(int es);
    private static native boolean native_set_lpp_profile(int lppProfile);
    private static native boolean native_set_gnss_pos_protocol_select(...);
    private static native boolean native_set_gps_lock(int gpsLock);
    private static native boolean native_set_emergency_supl_pdn(...);
    private static native boolean native_set_satellite_blacklist(...);
}

GNSS JNI实际并没有多少逻辑,只是对HAL层接口的封装,实际上在HIDL出现之前,JNI是直接调用gps的hw_module_t来实现的.

5. HAL层

GNSS HAL有1.0和1.1两个版本,1.1在1.0基础上进行了扩展

目前单GPS模组通常以UART方式和主芯片通信,或者以GPS和Modem复合模组方式存在;而在实现HAL时一般是将对应的命令通过UART发往对应的芯片即可。
需要说明的是高通平台GNSS HAL层实现采用的是C/S架构,HAL层仅仅将上层请求转成QMI(QC MSM Interface)消息并发送给相关服务去处理

5.1 HAL结构体

在实现gps_device_t设备时会用到如下结构体

typedef struct {
    // 注册callback
    int   (*init)( GpsCallbacks* callbacks );
    // 启动定位
    int   (*start)( void );
    // 停止定位
    int   (*stop)( void );
    /** Closes the interface. */
    void  (*cleanup)( void );
    ......
    /** Get a pointer to extension information. */
    const void* (*get_extension)(const char* name);
} GpsInterface;

typedef struct {
    uint16_t        flags;            // 标志位
    double          latitude;         // 纬度
    double          longitude;        // 经度
    double          altitude;         // 高度
    float           speed;            // 速度, m/s
    float           bearing;          // 方位角
    float           accuracy;         // 精度, m
    GpsUtcTime      timestamp;        // GPS时间戳
} GpsLocation;

typedef struct {
    gps_location_callback   location_cb;   // 位置信息
    gps_status_callback     status_cb;     // GPS状态信息
    gps_sv_status_callback  sv_status_cb;  // 卫星信息
    gps_nmea_callback       nmea_cb;       // NMEA信息
    gps_set_capabilities    set_capabilities_cb;  // GPS能力
    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;

    gnss_set_system_info    set_system_info_cb;
    gnss_sv_status_callback gnss_sv_status_cb;
} GpsCallbacks;

typedef struct {
    int     prn;        // 卫星编号
    float   snr;        // 信号强度
    float   elevation;  // 仰望角
    float   azimuth;    // 方位角
} GpsSvInfo;

5.2 HIDL接口

GNSS HAL 1.0主要是IGnss.hal

/** Represents the standard GNSS (Global Navigation Satellite System) interface. */
interface IGnss {
    start() generates (bool success);
    stop() generates (bool success);
    cleanup();
    setCallback(IGnssCallback callback) generates (bool success);
    injectTime(GnssUtcTime timeMs, int64_t timeReferenceMs, int32_t uncertaintyMs)
        generates (bool success);
    injectLocation(double latitudeDegrees, double longitudeDegrees, float accuracyMeters)
        generates (bool success);
    deleteAidingData(GnssAidingData aidingDataFlags);
    setPositionMode(GnssPositionMode mode, GnssPositionRecurrence recurrence,
                    uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
                    uint32_t preferredTimeMs)
        generates (bool success);

    getExtensionAGnssRil() generates (IAGnssRil aGnssRilIface);
    getExtensionGnssGeofencing() generates(IGnssGeofencing gnssGeofencingIface);
    getExtensionAGnss() generates (IAGnss aGnssIface);
    getExtensionGnssNi() generates (IGnssNi gnssNiIface);
    getExtensionGnssMeasurement() generates (IGnssMeasurement gnssMeasurementIface);
    getExtensionGnssNavigationMessage() generates (IGnssNavigationMessage gnssNavigationIface);
    getExtensionXtra() generates (IGnssXtra xtraIface);
    getExtensionGnssConfiguration() generates (IGnssConfiguration gnssConfigIface);
    getExtensionGnssDebug() generates (IGnssDebug debugIface);
    getExtensionGnssBatching() generates (IGnssBatching batchingIface);
};

注意:在manifest.xml中需要添加如下接口才能使用GNSS HAL层(以1.0版本为例)接口

<hal format="hidl">
    <name>android.hardware.gnss</name>
    <transport>hwbinder</transport>
    <version>1.0</version>
    <interface>
        <name>IGnss</name>
        <instance>default</instance>
    </interface>
</hal>

5.3 HIDL服务端

Android原生提供了两种类型的HIDL服务端参考实现

1.0: 直通模式的实现,需要实现旧版gps_device_t设备,可参考device/generic/goldfish/gps/gps_qemu.c的实现
1.1: Binder化实现,目前只是一个实例,并没有实现

这里以1.0服务端实现为例

/* android.hardware.gnss@1.0-service.rc */
service vendor.gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
    class hal
    user gps
    group system gps radio

/*
 * android.hardware.gnss@1.0-service
 * 由[hardware/interfaces/gnss/1.0/default/service.cpp]生成
 * 注册IGnss HIDL服务
 */
int main() {
    // The GNSS HAL may communicate to other vendor components via
    // /dev/vndbinder
    android::ProcessState::initWithDriver("/dev/vndbinder");
    return defaultPassthroughServiceImplementation<IGnss>();
}

/*
 * android.hardware.gnss@1.0-impl.so
 * 由如下文件生成
 *     hardware/interfaces/gnss/1.0/default/Gnss.cpp
 *     hardware/interfaces/gnss/1.0/default/AGnss.cpp
 *     hardware/interfaces/gnss/1.0/default/AGnssRil.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssBatching.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssConfiguration.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssGeofencing.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssMeasurement.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssNavigationMessage.cpp
 *     hardware/interfaces/gnss/1.0/default/GnssMeasurement.cpp
 *     ......
 * 实现IGnss HIDL服务
 */
// Gnss.cpp文件中HIDL_FETCH_IGnss函数实现如下
IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
    hw_module_t* module;
    IGnss* iface = nullptr;
    int 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) {
            iface = new Gnss(reinterpret_cast<gps_device_t*>(device));
        } else {
            ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
        }
    } else {
      ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
    }
    return iface;
}

参考:
<GPS定位技术>
<GPS-NMEA sentence information>
<安卓平台下的GPS架构介绍及驱动移植记录>
<如何在i.MX8QM Android上实现GPS地图导航功能>

原文地址:https://www.cnblogs.com/hzl6255/p/14660255.html