Android GPS框架分析,如何由APP提供定位信息

客户需求:

安卓设备要共享车上已有设备的GPS信息,通过网络连接发送坐标信息过来,具体对策简单梳理如下(基于全志T3平台):

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

android\hardware\libhardware\include\hardware\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