下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

详细分析Android系统Gps教程

作者:课课家教育     来源: http://www.kokojia.com点击数:1567发布时间: 2016-04-15 16:14:23

标签: androidGpsAndroid系统Android

  说起GPS,很多人都不陌生,现在我们出门找个不熟悉的地方都会使用百度地图,其实也就是定位导航,开车的大哥更是用得更多,车上都会有一个手机或者卫星导航或者车上自备有导航的功能,那么本文就谁谁GPS。

      GPS是全球定位系统简称,利用GPS定位卫星,在全球范围内实时进行定位、导航的系统,称为全球卫星定位系统,简称GPS。GPS是一种具有全方位、全天候、全时段、高精度的卫星导航系统,能为全球用户提供低成本、高精度的三维位置、速度和精确定时等导航信息,是卫星通信技术在导航领域的应用典范,它极大地提高了地球社会的信息化水平。

  1 GPS架构

  

详细分析Android系统Gps教程_androidGps_Android系统_Android_课课家

 

  2 GPS分析

  2.1 头文件

  头文件定义在:hardware/libhardware/include/hardware/gps.h,定义了GPS底层相关的结构体和接口

  GpsLocation

  GPS位置信息结构体,包含经纬度,高度,速度,方位角等。

  GpsStatus

  GPS状态包括5种状态,分别为未知,正在定位,停止定位,启动未定义,未启动。

  GpsSvInfo

  GPS卫星信息,包含卫星编号,信号强度,卫星仰望角,方位角等。

  GpsSvStatus

  GPS卫星状态,包含可见卫星数和信息,星历时间,年历时间等。

  GpsCallbacks

  回调函数定义

 

  GpsInterface

  GPS接口是最重要的结构体,上层是通过此接口与硬件适配层交互的。

  gps_device_t

  GPS设备结构体,继承自hw_device_tcommon,硬件适配接口,向上层提供了重要的get_gps_interface接口。

  2.2硬件适配层

  GPS硬件适配层的源码位于:hardware/qcom/gps目录下。

  我们看gps/loc_api/llibloc_api/gps.c,首先定义了gps设备模块实例:

  这里的methods指向gps.c文件中的gps_module_methods

  gps_module_methods定义了设备的open函数为open_gps,我们看open_gps函数:

  此处可以看作是GPS设备的初始化函数,在使用设备前必须执行此函数。函数里面指定了hw_device_t的module成员,以及gps_device_t的get_gps_interface成员。上层可通过gps_device_t的get_gps_interface调用gps__get_gps_interface函数。gps__get_gps_interface的定义如下:

  用代码跟踪可看到,此函数返回了gps/loc_eng.cpp文件的sLocEngInterface变量,sLocEngInterface定义如下:

  sLocEngInterface指定了GpsInterface结构体的各个回调函数,如启动定位/取消定位等,这些回调函数的实现均在loc_eng.cpp中实现。

  2.2 JNI适配层

  GPSJNI适配层的源码位于:frameworks/base/services/jni/com_Android_server_location_GpsLocationProvider.cpp

  首先看注册JNI方法的函数定义:

  此函数被同目录下onload.cpp文件调用,调用地方在:

  从这里可以看到,JNI初始化的时候,即会进行JNI方法的注册,从而使上层应用能通过JNI调用c/c++本地方法。

  回到register_android_server_location_GpsLocationProvider函数,变量sMethods定义如下:

  这里定义了GPS所有向上层提供的JNI本地方法,这些本地方法是如何与硬件适配层交互的呢?我们看其中一个本地方法android_location_GpsLocationProvider_start:

  它调用了GetGpsInterface获得GpsInterface接口,然后直接调用该接口的start回调函数。GetGpsInterface方法定义如下:

  这个函数返回了sGpsInterface,而sGpsInterface又是从get_gps_interface()获得的,我们继续查看get_gps_interface()函数的实现:

  这里面调用hw_get_module加载硬件适配模块.so文件,接着通过hw_device_t接口调用open()函数,实际执行gps/loc_api/llibloc_api/gps.c定义的open_gps函数,而后调用gps_device_t接口的get_gps_interface函数,此函数也是在gps.c中定义的,最后返回硬件适配层中loc_eng.cpp文件的sLocEngInterface,从而打通了上层到底层的通道。

  2.3 java Framework

  GPSFramework源码位于:frameworks/base/location

  2.3.1接口和类简介

  首先对GPSFramework重要的接口和类作一个简单的介绍

  接口

  GpsStatus.Listener用于当Gps状态发生变化时接收通知

  GpsStatus.NmeaListener用于接收Gps的NMEA数据

  LocationListener用于接收当位置信息发生变化时,LocationManager发出的通知

  类

  Address地址信息类

  Criteria用于根据设备情况动态选择provider

  Geocoder用于处理地理编码信息

  GpsSatellite用于获取当前卫星状态

  GpsStatus用于获取当前Gps状态

  Location地理位置信息类

  LocationManager用于获取和操作gps系统服务

  LocationProvider抽象类,用于提供位置提供者(Locationprovider)

  2.3.2 使用Gps编程接口

  下面,我们用一个代码示例说明如何在应用层写一个简单的gps程序。

  首先在AndroidManifest.XML中添加位置服务权限:

 

     接着获取地理位置信息:

 

  设置侦听,当位置信息发生变化时,自动更新相关信息

  2.3.3接口和类分析

  下面对相关的类或接口进行分析,LocationManager的代码文件位于:frameworks/base/location/java/location/LocationManager.java

  我们看其构造函数:

  

  其中mService为ILocationManager接口类型,构造函数的参数为service,外部调用时传入LocationManagerService实例。LocationManager是android系统的gps位置信息系统服务,在稍后将会对其进行分析。由带参构造函数实例化LocationManager类的方式用得不多,一般用的方式是由getSystemService获得LocationManagerService服务,再强制转换为LocationManager。例如在2.3.2中的代码示例中是这样获取gps服务的:

 

  这里的Context.LOCATION_SERVICE为”location”,标识gps服务。

  LocationManagerService服务是整个GpsFramework的核心,首先看它是如何加载的,代码文件位于:frameworks/base/services/java/com/android/server/systemserver.java

  此处向ServiceManger系统服务管理器注册了新的服务,其名称为”location”,类型为LocationManagerService。注册此服务后,Java应用程序可通过ServiceManager获得LocationManagerService的代理接口ILocationManager.Stub,从而调用LocationManagerService提供的接口函数。ILocationManager位于:

  frameworks/base/location/java/location/ILocationManager.aidl,其代码如下:

  android系统通过ILocationManager.aidl文件自动生成IlocationManager.Stub代理接口,在Java客户端获取LocationManagerService的方式如下:

  客户端通过mLocationManager即可操作LocationMangerService继承自ILocationManager.Stub的的公共接口。之前提到了通过getSystemSerivice方式也可以获得LocationManagerService,但getSystemService()返回的是Object,必须转换为其他接口,我们可以看到之前的是强制转换为LocationManager类型,而此处由ServiceManager.getService返回IBinder接口,再通过ILocationManager.Stub转换为ILocationManager类型,是更加规范的做法。

  LocationMangerService的代码文件位于:

  frameworks/base/services/java/com/android/server/LocationMangerService.java

  我们首先看其中的systemReady()函数

  此处启动自身服务线程,因LocationMangerService继承自Runnable接口,当启动此线程后,会执行继承自Runnable接口的run()函数,我们看run()函数的定义:

  此处调用了initialize()进行初始化,initialize()函数定义如下:

  此处调用了loadProviders()函数,loadProviders()函数调用了_loadProvidersLocked(),其代码如下:

  在这里对GpsLocationProvider和NETworkLocationProvider类作了初始化,并添加到provider集合中。GpsLocationProvider和NetworkLocationProvider继承自LocationProviderInterface接口,分别代表两种位置提供者(LocationProvider):

  (1)LocationManager.GPS_PROVIDER:GPS模式,精度比较高,但是慢而且消耗电力,而且可能因为天气原因或者障碍物而无法获取卫星信息,另外设备可能没有GPS模块(2)LocationManager.NETWORK_PROVIDER:通过网络获取定位信息,精度低,耗电少,获取信息速度较快,不依赖GPS模块。

  Android提供criteria类,可根据当前设备情况动态选择位置提供者。我们在之前2.3.2的代码示例中,有这样一句代码:

  String provider = locationManager.getBestProvider(criteria, true);

  getBestProvider其实是根据Criteria的条件遍历mProviders集合,返回符合条件的provider名称。我们再看GpsLocationProvider的实现,其代码文件位于:

  frameworks/base/services/java/com/android/server/location/GpsLocationProvider.java

  在GpsLocationProvider的构造函数中:

  这里注册了广播接受者mBroadcastReciever,用于接收广播消息,消息过滤在intentFilter中定义。下面看它接收广播消息时的动作:

  当接收ALARM_EAKEUP时,执行startNavigating函数,当接收到ALARM_TIMEOUT广播时,执行hibernate函数。这两个函数很关键,下面看他们的实现:

  看到没有,这里调用了native_set_position_mode和native_start方法,而这些方法正是我们之前在JNI适配层提到的注册的本地方法。同样的,hibernate函数调用了JNI提供的native_stop方法。我们再看GpsLocationProvider的内部私有函数:

  可以看到所有这些本地方法,都是在JNI层注册的,GpsLocationProvider类是从JNI层到Framework层的通道。

  下面回到LocationManagerService,分析如何获取最新的位置信息(Location),获取最新的location的函数是getLastKnownLocation,其实现如下:

  这里mLastKnownLocation类型为HashMap,所以mLastKnownLocation.get(provider)表示通过provider的名称在哈希字典中获取相应的location,那么这些location是什么时候被存入到哈希字典中的呢?

  我们回到LocationManagerService的run函数:

  这里对类型为LocationWorkerHandler的变量进行初始化,LocationWorkerHandler是在LocationManagerService的一个内部类,它继承自Handler类,Handler是Android系统用于应用程序内部通信的组件,内部通信指同个进程的主线程与其他线程间的通信,Handler通过Message或Runnable对象进行通信。我们继续看LocationWorkerHandler的实现:

  这里重写Handle类的handleMessage方法,处理用Handle接收的Message对象消息。当接受到位置信息变化的消息MESSAGE_LOCATION_CHANGED时,调用p.updateLocationhandleLocationChangedLocked方法,其实现如下:

  可以看到是在handleLocationChangedLocked函数中实现对lastknownlocation的更新的,那么在LocationWorkerHandler类中处理的MESSAGE_LOCATION_CHANGED消息是谁发送出来的呢?答案是在LocationManagerService类的reportLocation函数中:

  此处构造了新的Message对象,然后发送到消息队列的首位置。在GpsLocationProvider类的reportLocation函数中,有这样一段代码:

  所以实际是由GpsLocationProvider主动调用LocationManagerService的reportLocation方法,从而更新最新的位置信息。

  实际上,GpsLocationoProvider的reportLocation对应了硬件适配层中的GpsCallbacks结构体中的回调函数gps_location_callback

  那么GpsLocationProvider中的reportLocation函数是如何与GpsCallbacks的gps_location_callback挂钩的呢?我们回到JNI适配层的代码文件:

  frameworks/base/services/jni/com_android_server_location_GpsLocationProvider.cpp

  其中定义的GetGpsInterface函数:

  这里面的sGpsInterface->init(&sGpsCallbacks)调用了GpsInterface的init回调函数,即初始化GpsCallbacks结构体变量sGpsCallbacks,sGpsCallbacks定义如下:

  我们再次看GpsCallbacks的定义(其代码文件在硬件适配层的头文件gps.h中):

  比较sGpsCallbacks与GpsCallbacks,可以看到location_callback与gps_location_callback对应。再看location_callback函数的定义:

  这里面利用JNI调用了Java语言的方法method_reportLocation,method_reportLocation是一个jmethodID变量,表示一个由Java语言定义的方法。下面我们看method_reportLocation的赋值代码:

  这里表示method_reportLocation指向Java类clazz里的方法reportLocation,那么这个Java类clazz是不是表示GpsLocationProvider呢?我们找到注册JNI方法的方法表:

  这里说明_GpsLocationProvider_class_init_native对应的native方法名称是class_init_native,下面我们只要确定在Java中的某个类A调用了class_init_native方法,即可以说明A类的reportLocation函数是GpsCallbacks的回调函数。

  我们回到GpsLocationProvider的代码文件:

  frameworks/base/services/java/com/android/server/location/GpsLocationProvider.java

  其中有一段代码:

  说明是在GpsLocationProvider中调用了class_init_native方法,从而说明GpsLocationProvider的reportLocation函数是GpsCallbacks的回调函数,即当Gps设备的位置信息发生变化时,它调用GpsLocationProvider的回调函数reportLocation,继而调用LocationManagerService的reportLocation函数,从而更新应用层的位置信息。

  3 参考文章

  基于android的GPS移植——主要结构体及接口介绍

  androidGPS定位,定位城市称,经纬度

     上文详细分析了头文件,硬件适配层、 JNI适配层、Java Framework和使用Gps编程接口等等知识来介绍Android系统Gps,想要深入学习的朋友可以自行网上查阅。

赞(1)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程