• 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地图导航功能>

  • 相关阅读:
    小工具之文件整合
    [JavaWeb基础] 031.dom4j写入xml的方法
    AES128_CBC模式加密
    eatwhatApp开发实战(九)
    [Objective-C] 021 KVC、KVO
    eatwhatApp开发实战(八)
    eatwhatApp开发实战(七)
    [Objective-C] 020_ Block
    eatwhatApp开发实战(六)
    年终总结--我的2019
  • 原文地址:https://www.cnblogs.com/hzl6255/p/14660255.html
Copyright © 2020-2023  润新知