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