0%

Android 定位系统介绍

  1. 定位方式简介
  2. 定位原理简介
    1. GNSS定位
    2. 蜂窝网络定位/Wi-Fi定位/蓝牙定位
  3. Android GNSS 系统结构
    1. Android SDK
    2. Android Framework
    3. HAL
    4. 驱动程序
    5. GNSS芯片
    6. 网络定位

定位方式简介

Android 的定位系统是一套用于获取设备地理位置信息的软件和硬件组件,它允许应用程序和服务访问设备的位置信息数据。按照定位原理分类, 主要有以下的几种定位方式:

  • GNSS定位
    全球导航卫星系统(GNSS)是一种使用卫星信号来确定设备精确地理位置的技术,Android 设备设备通常配备了GNSS接收器,可以通过计算卫星信号来获取经度和纬度坐标。这种定位手段可以不需要接入网络,一般用于户外位置获取。GNSS 是美国的GPS、欧盟的GALILEO、俄罗斯的GLONASS和中国的北斗导航系统等的统称。
  • 蜂窝网络定位
    这种方法使用移动蜂窝网络基站的信息来估算设备的位置,通常可以提供较粗略的位置信息。基站数据量大,定位时需要将基站信息上传到服务器获取基站位置信息,然后计算出设备的位置。
  • Wi-Fi定位
    Android 设备可以扫描周围的 Wi-Fi 网络,并根据已知 Wi-Fi 热点的位置信息和信号强度来估算设备的位置。 Wi-Fi 定位通常用于室内和城市环境中。
  • 蓝牙定位
    在一些特定的应用程序中还会使用蓝牙定位,通过扫描附近的特殊蓝牙基站设备来计算设备的位置。这种方法通常用于室内导航,会在室内布置一定数量的蓝牙基站。
  • 传感器融合定位:
    利用设备自带的陀螺仪、加速度计和磁力计等传感器,可以提高定位准确度。常见应用场景如行车导航,在卫星信号不良的情况下利用传感器进行惯性导航。

定位原理简介

基本原理简要概括:时间计算距离,三球测量单点。

不同的工作方式计算方式有所不同。

GNSS定位

GNSS 由三部分组成:

  • 运行在太空的卫星星座天空中的卫星星座组成的信标广播系统,会不断向地球发送包含卫星空间坐标和时间信息的信号;
  • 卫星地面控制部分处于地球的控制站能够控制天空中的卫星,控制卫星的飞行轨迹以及广播的星历、历书信息和时间信息,同时监控卫星飞行轨迹,不断修正卫星数据,保证卫星广播数据准确;
  • 用户设备部分
    用于接收卫星信号,通过解析广播中的卫星空间信息和时间信息,先计算出相对卫星的距离,然后通过至少三个卫星组成的球面计算出终端的空间坐标,带入地球模型,即可得到经纬度和高度信息;

星历:用来记录卫星的运行参数,通过星历,可以计算出任意时刻的导航卫星的位置和速度。星历表包含了非常详细的卫星轨道和位置信息,所以其数据量较大,传输时间较长,为了可以这个困难,人们设计了其简化集,即历书;
历书:包含卫星的位置等相关信息,精度较低;
时间:虽然卫星广播中附带了准确的时间,但由于电磁波在大气传播存在时延误差,所以一般使用更多的卫星来校准时间;

一次定位过程可以划分为三个阶段:

  1. 搜索卫星
  2. 下载星历/历书
  3. 计算位置

其中,搜索卫星和下载星历比较耗时,所以可以划分为三种情况:

  • 冷启动:
    手机第一次定位,没有保存星历和历书,则需要将上述流程完全走一遍,TTFF至少有12.5分钟;
  • 暖启动:
    保存有星历和历书,只是比较老(历书不超过180天,旧时间信息不超过20S,旧位置信息不超过100Km),需要更新,更新后进行定位。TTFF至少为30S;
  • 热启动:
    保存有效的星历,时间和位置信息,这种只需要测距定位就可以了,TTFF小于10S;

AGPS:
一些终端中会有一个 AGPS 的功能,它的作用是通过互联网下载星历后注入给芯片,降低搜星和下载星历的耗时,实现缩减冷暖启动首次定位时间的效果。

蜂窝网络定位/Wi-Fi定位/蓝牙定位

这几类定位方式的原理基本一致,均是扫描已知地理位置的物体或设备信息,然后通过电信号计算出相对已知物体的距离,进而通过三个已知点的距离求解目标点位置。差异在于数据源:

  • 基站:
    运营商的基站地理位置信息为已知条件(运营商或三方系统授权持有),终端设备可以扫描基站得到基站列表,通过向基站发送应答包计算设备到基站的距离(已知电磁波传播速度),最后通过基站已知坐标和对应的距离信息,可以推算出终端的位置。基站信息量庞大,终端设备一般仅扫描基站,然后通过网络将基站信息发回服务器进行计算。
    由于地面电磁波环境复杂容易发生衍射、多径传播等情况,会对定位精度造成较大干扰,所以此种方式定位精度较低,通常在几百米到几千米之间。
  • WIFI/蓝牙:
    WIFI和蓝牙原理相似,一般需要内建WIFI或蓝牙基站的位置信息数据库作为已知条件,终端设备扫描WIFI、蓝牙基站的信息和信号强度,再通过信号强度估算出终端和基站的距离(通过信号衰减程度计算),最后和数据库作对比计算终端的位置。

一句话总结:

  • GNSS 定位和网络定位都是通过空间已知点和距离计算终端的位置,差别有三:
    1. GNSS 使用独立的GNSS接收机硬件实现定位,网络定位通常依赖传感器的数据使用软件计算位置;
    2. GNSS 使用卫星作为位置计算参考点,网络定位使用各种地面的信标(基站、WIFI、蓝牙等)作为位置计算参考点;
    3. GNSS 计算过程在终端芯片内可以无需网络参与,网络定位计算过程在软件层面(终端或服务器),一般情况需要通过网络上下传数据;
  • GNSS 定位计算过程都在芯片内,基本无法干预; 网络定位计算过程一般在云端;

Android GNSS 系统结构

Android SDK

Android SDK 中提供了一组请求/停止请求定位信息的接口,请求定位的参数主要有进行定位的提供者(常用GNSS或NETWORK)、定位间隔参数(时间和距离)、接收定位结果的回调接口。
另外还有用于设置监听 GNSS 卫星状态的回调接口和监听 GNSS 芯片 NMEA 数据的回调接口,前者用于反馈当前的卫星数量、星座、以及型号质量等数据,后者用于展示、原始数据后处理、日志抓取等等。

请求定位的提供者常用的有GPS(GNSS)和NETWORK,另外还有 FUSED 和 PASSIVE:

  • GPS_PROVIDER(GNSS)
    期望系统启动卫星定位系统进行定位,这种方式会产生较高的功耗,精度较高;
  • NETWORK_PROVIDER
    期望系统启动基于网络的方式进行定位,这种方式相比卫星定位会有较低的功耗,但精确度相对会比卫星定位低;
  • FUSED_PROVIDER
    期望调用 GMS(谷歌移动服务) 进行定位,国内用不了;
  • PASSIVE_PROVIDER
    期望系统不主动定位,通过“蹭”系统内别的 PROVIDER 的定位结果的定位方式,不常用;

SDK 层面操作的类主要为 android.location.LocationManager,它暴露了请求定位,注册回调等方法。这个类包装了 ILocationManager AIDL 接口,用于和 Framework 通信。

相关的接口如下:

    public interface LocationListener {
        void onLocationChanged(Location location);
        @Deprecated
        void onStatusChanged(String provider, int status, Bundle extras);
        void onProviderEnabled(String provider);
        void onProviderDisabled(String provider);
    }
    public void requestSingleUpdate(@NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper)
    public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance, @NonNull LocationListener listener)
    public void removeUpdates(@NonNull LocationListener listener)

    public static abstract class Callback {
        public void onStarted() {}
        public void onStopped() {}
        public void onFirstFix(int ttffMillis) {}
        public void onSatelliteStatusChanged(GnssStatus status) {}
    }
    public boolean registerGnssStatusCallback(@NonNull GnssStatus.Callback callback)
    public void unregisterGnssStatusCallback(@NonNull GnssStatus.Callback callback)

    public interface OnNmeaMessageListener {
        void onNmeaMessage(String message, long timestamp);
    }
    public boolean addNmeaListener(@NonNull OnNmeaMessageListener listener)
    public void removeNmeaListener(@NonNull OnNmeaMessageListener listener)

Android Framework

Framework 层面主要的类为 android.server.LocationManagerService,它实现了 ILocationManager AIDL 接口,一面透过 SDK 和应用打交道,一面透过各种 PROVIDER 和定位实现打交道:

  • GPS_PROVIDER(GNSS)
    通过 GNSS HAL 接口和芯片打交道。
  • NETWORK_PROVIDER
    依赖设备厂商的具体实现,Android 默认实现依赖 Google 提供的 GMS 实现国内无法使用;一般厂商会实现为通过基站/WIFI/蓝牙进行融合定位。
  • FUSED_PROVIDER
    调用 GMS(谷歌移动服务) 进行定位,国内用不了;
  • PASSIVE_PROVIDER
    使用 PassiveProvider 在系统位置更新时通知给应用,分享其他 PROVIDER 的定位结果;

LocationManagerService 在系统开机时由 SystemServerstartOtherServices 方法中初始化并调用 systemRunning 方法拉起,然后初始化各种 PROVIDER,并且监听系统各种影响定位的状态(例如系统定位开关、低功耗模式、锁屏、用户切换等)。

LocationManagerService 的主要业务逻辑包括:

  • 管理 Location Provider
  • 应用定位权限管控
  • 监听定位相关功能开关状态
  • 监听系统状态(低功耗等特殊模式)变化,及时调整定位策略
  • 分发定位信息(定位结果、卫星信息、NMEA数据)

LocationManagerService 和应用交互包括:

  • 接收应用的定位请求
  • 检查应用定位权限
  • 回调应用的定位结果
  • 回调 GNSS 卫星状态
  • 回调 GNSS NMEA 数据

LocationManagerService 操作 GnssLocationProvider 和 GNSS HAL 交互包括:

  • 控制芯片启动、停止定位
  • 控制芯片的定位参数
  • 向芯片注入辅助定位的特定数据
  • 设置 HAL 解析定位信息的回调
  • 接收并上报 HAL 解析的定位信息

HAL

HAL 层面是 Framework 和芯片的中间角色,对外屏蔽了不同芯片的差异。主要的职责包括:

  • 控制定位芯片上下电
  • 控制芯片启动、停止工作
  • 处理 Framework 的定位请求
  • 转发向芯片注入辅助定位的信息(AGPS、RTK等)
  • 解析芯片输出的 NMEA 协议的报文数据
  • Framework 上报芯片输出的定位结果、卫星信息、NMEA数据等信息

驱动程序

GNSS 芯片上下电控制手段各不相同,有的使用GPIO,有的使用芯片平台的电源管理模块。

GNSS 芯片使能控制手段通常使用GPIO。

GNSS 芯片常见的通讯方式为串口,所以驱动程序以内核自带的串口驱动为主。

GNSS芯片

芯片厂商封装了 GNSS 射频单元、运算单元等功能的芯片。芯片能够接收卫星广播的星历、时间信息,内部进行计算后得到卫星信息和定位结果,通过串口对外输出使用 NMEA-0183 协议封装的报文。

网络定位

Android 初始化 LocationManagerService 时构造 LocationProviderProxy 实例,LocationProviderProxy 会寻找并绑定符合要求服务,作为网络定位的实现实例,然后应用请求网络定位时就会将定位请求发给绑定的服务实例处理。
被绑定的服务需要满足以下要求:

  • 声明 ACTIONcom.android.location.service.v3.NetworkLocationProvider 以便被系统绑定
  • 包名出现在 Frameworkconfig_locationProviderPackageNames 字段当中,系统会过滤不可信的定位服务实现
  • onBind 返回的实例需要继承自 LocationProviderBase,用以接收系统的定位请求和上报定位结果。
  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/188
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!