一直做车载导航的产品,GPS是都有用的,不过基本都是串口的GPS模组,所以也没有怎么去关心过GPS的框架,最近一个客户提出安卓要共享车上已有设备的GPS信息,通过网络连接发送坐标信息过来,所以就对GPS框架大概看了下,简单梳理如下(基于全志T3平台):

1、HAL层:android\device\softwinner\t3-common\hardware\gps\gps.c

gps.h

2、JNI: android\frameworks\base\services\core\jni\com_android_server_location_GpsLocationProvider.cpp

               gps.c与GpsLocationProvider.java 沟通的桥梁

3、Framework层及本次实例要关注的文件:

1)、android\frameworks\base\services\core\java\com\android\server\location
         Framework对Location服务的内部实现
        GpsLocationProvider.java
 
 
2)、android\frameworks\base\location\java\android\location\
                这里主要是提供一些供APP调用的功能
                LocationManager.java
                ILocationManager.aidl
 
 
3)、android\frameworks\base\services\core\java\com\android\server\LocationManagerService.java

        这个文件主要是封装了一些Location服务,是对应用的接口

好像应该说GPS框架了,不过这种东西网上太多了,还是自己度吧,人家都写的都比我写的好,所以我这里就偷懒了,我这里直接说一下我用APP接收NMEA数据给系统提供定位信息的过程:

上面提到的gps.c就是GPS模块的HAL层实现,没有几行代码,实现也比较简单,就是实现一个GpsInterface接口,其他的我们基本不用去管,只要实现这个接口的几个函数,把不管任何方式获取的NMEA数据解析后报给系统就可以了,所以我就直接修改这里增加了一个APP给GPS模块写NMEA数据的接口,协议解析还是用他自己的,并且调用这个接口后就把NMEA的获取从串口转过来,忽略串口数据(备注:以下修改红色为新增加的内容)

static const GpsInterface  athrGpsInterface = {
       .size =sizeof(GpsInterface),
       .init = athr_gps_init,
       .start = athr_gps_start,
       .stop = athr_gps_stop,
       .cleanup = athr_gps_cleanup,
       .inject_time = athr_gps_inject_time,
       .inject_location = athr_gps_inject_location,
       .delete_aiding_data = athr_gps_delete_aiding_data,
       .set_position_mode = athr_gps_set_position_mode,
       .get_extension = athr_gps_get_extension,
.nmea_from_app = athr_gps_nmea_from_app, //sunlei
};
 
对应上面gps.c的修改,gps.h对这个结构定义也做对应修改,如下:
/** Represents the standard GPS interface. */
typedef struct {
        /** set to sizeof(GpsInterface) */
        size_t          size;
        ……………………
        /** Get a pointer to extension information. */
        const void* (*get_extension)(const char* name);
      
/** App write Nmea data to hal, instead of nmea form uart GPS module. */
         const void* (*nmea_from_app)(const char* nmeaStr);//sunlei
} GpsInterface;
修改com_android_server_location_GpsLocationProvider.cpp,增加如下:
//sunlei start
static void android_location_GpsLocationProvider_app_send_nmeaStr(JNIEnv* env, jobject obj,
        jstring nmeaStr)
{
    if (sGpsInterface) {  
           const char *c_nmeaStr = env->GetStringUTFChars(nmeaStr, NULL);
           sGpsInterface->nmea_from_app(c_nmeaStr);
           ALOGD("JNI app_send_nmeaStr:%s", nmeaStr);
           env->ReleaseStringUTFChars(nmeaStr, c_nmeaStr);             
    }    
}
//sunlei end
static JNINativeMethod sMethods[] = {
        /* name, signature, funcPtr */
        {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
           ……………………
         {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
//sunlei note A:@20200715 for app send nmea Str to hal gps module
         {"native_app_send_nmeaStr", "(Ljava/lang/String;)V",(void*)android_location_GpsLocationProvider_app_send_nmeaStr},
           ……………………
};
 
修改GpsLocationProvider.java
//sunlei start
public static void sendNmeaStrToHAL(String nmeaStr) {
        Log.d(TAG, "GpsLocationProvider.java sendNmeaStrToHAL: " + nmeaStr);
        if (nmeaStr != null) {
            native_app_send_nmeaStr(nmeaStr);
        }
 }
 //sunlei end
 
修改LocationManagerService.java在LocationManagerService类中增加以下代码,为应用提供调用接口
//sunlei start
       public void appSendNmeaStr(String nmeaStr) {
              GpsLocationProvider.sendNmeaStrToHAL(nmeaStr);
       }
       //sunlei end
 
修改LocationManager.java,增加如下代码:
//sunlei start
       public void appSendNmeaStr(String nmeaStr) {
              try {
                      mService.appSendNmeaStr(nmeaStr);
              } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException", e);
              }
       }
       //sunlei end

修改ILocationManager.aidl增加如下代码:

void appSendNmeaStr(String nmeaStr);//sunlei

以上代码因修改因为我们增加了一个新的系统API,所以要先如下编译:

$: make update-api
$: make –j32; pack

使用我们新译出来的IMG文件烧录后,系统就增加了APP向HAL写入NMEA数据的API,下面就是APP从网络接收数据并下发了

 

应用调用:

import android.location.LocationManager;
       ……………………
    LocationManager locationManager = (LocationManager)                                                                                                                                                    getApplicationContext().getSystemService(Context.LOCATION_SERVICE);

然后在合适的位置获取NMEA数据并做如下调用:

locationManager.appSendNmeaStr(nmeaStr);

 

如果使用AndroidStudio的话,那么我们新增加的这个API他使用默认的SDK是不能被识别的,解决的方式就是把LocationManager.java编译出来的LocationManager.class替换掉Android\Sdk\platforms\android-26\android.jar里面对应的文件即可,我是直接用WinRAR打开找到对应位置粘贴,自动重新压缩就可以了,LocationManager.clas的位置在:

android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/location/LocationManager.class