GPS机制分析(2)

1. 概述

​ 在android系统中,GPS对应的系统服务为LocationManagerService,本文主要论述LocationManagerService服务的启动以及初始化过程。

​ SystemServer.java的startOtherServices方法中添加LocationManagerService方法的代码如下,

location = new LocationManagerService(context);
ServiceManager.addService(Context.LOCATION_SERVICE, location);

apk中获取gps服务代理的代码如下,

mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

当然, LocationManager只是系统服务的一个代理。

添加gps服务到系统之后, SystemServer.java的startOtherServices方法中

locationF.systemRunning();

调用LocationManagerService的systemRunning方法,完成LocationManagerService服务的初始化。

2. 回调方法的实现

​ 当然在调用systemRunning之前,在添加到系统过程中,会调用LocationManagerService的构造方法,构造方法如下,

mContext = context; //传入系统服务进程上下文

​ systemRunning方法中会调用loadProvidersLocked方法,

loadProvidersLocked();
updateProvidersLocked();

​ loadProvidersLocked方法主要是添加设备上支持的GPS定位Provider,

if (GpsLocationProvider.isSupported()) {
            // Create a gps location provider
            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
                    mLocationHandler.getLooper());
            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
            addProviderLocked(gpsProvider);
            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
            mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
            mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
            mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
        }

​ 设备如果支持GpsLocationProvider,就会新建GpsLocationProvider对象,然后添加到mProviders和mProvidersByName等list中。

在这里分为3个步骤:

  1. isSupported方法的判断。

  2. updateProvidersLocked方法。

在这个章节,主要论述回调方法的实现以及isSupported方法,下个章节论述updateProvidersLocked方法。

在GpsLocationProvider的构造方法和isSupported之前,会调用class_init_native方法,

static { class_init_native(); }

该方法是一个native方法,

private static native void class_init_native();

GpsLocationProvider.java对应的C/C++文件为com_android_server_location_GpsLocationProvider.cpp。

2.1 Framework调用JNI层方法

GpsLocationProvider.java中调用的native方法较多,部分如下,

img

com_android_server_location_GpsLocationProvider.cpp的sMethods中详细的列举了对应的native方法,部分如下,

{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
{"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
{"native_is_agps_ril_supported", "()Z", (void*)android_location_GpsLocationProvider_is_agps_ril_supported},
•••

这样Java上层就可以通过JNI调用natvie的方法了。

2.2 JNI层调用Framework方法

com_android_server_location_GpsLocationProvider还定义着对GpsLocationProvide.java的回调方法。部分定义如下,

static jmethodID method_reportLocation;
static jmethodID method_reportStatus;
static jmethodID method_reportSvStatus;
•••

这些回调方法都在android_location_GpsLocationProvider_class_init_native方法中进行赋值,部分代码如下,

method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
•••

因此,method_reportLocation 对应GpsLocationProvide.java的reportLocation方法。

这样com_android_server_location_GpsLocationProvider就可以回调Java方法了。

2.3 JNI层调用gps库方法

com_android_server_location_GpsLocationProvider的class_init_native方法中获取gps.so库中的sGpsInterface结构代码如下,

hw_module_t* module;
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) {
            gps_device_t* gps_device = (gps_device_t *)device;
            sGpsInterface = gps_device->get_gps_interface(gps_device);
        }
    }

首先调用hw_get_module方法加载gps相关的so库,获取hw_module_t结构体。

然后利用该结构体打开so库,获取hw_device_t结构体,

最后利用hw_device_t结构体获取GpsInterface结构体。

这样,com_android_server_location_GpsLocationProvider就可以通过GpsInterface结构体调用so库中的方法了。

根据 HAL 加载so文章分析,

​ GpsInterface结构体指向hardware\qcom\gps\loc_api\libloc_api_50001中loc.cpp的sLocEngInterface。除了GpsInterface结构体之外,so库中还定义了其他大量的结构体(包含回调方法以及变量供上层调用),因此com_android_server_location_GpsLocationProvider还需要获取,

static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
static const AGpsInterface* sAGpsInterface = NULL;
static const GpsNiInterface* sGpsNiInterface = NULL;
static const GpsDebugInterface* sGpsDebugInterface = NULL;
static const AGpsRilInterface* sAGpsRilInterface = NULL;
static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;

这些结构体都通过GpsInterface的get_extension方法获取,不同方法只是以字符区分,

sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
•••

这些字符都定义在gps.h文件中,

#define GPS_XTRA_INTERFACE      "gps-xtra"
#define GPS_DEBUG_INTERFACE      "gps-debug"
#define AGPS_INTERFACE      "agps"
•••

loc.cpp的loc_get_extension方法如下,

const void* loc_get_extension(const char* name)
{
    ENTRY_LOG();
    const void* ret_val = NULL;
 
   LOC_LOGD("%s:%d] For Interface = %s\n",__func__, __LINE__, name);
   if (strcmp(name, GPS_XTRA_INTERFACE) == 0)
   {
       ret_val = &sLocEngXTRAInterface;
   }
   else if (strcmp(name, AGPS_INTERFACE) == 0)
   {
       ret_val = &sLocEngAGpsInterface;
   }
•••
EXIT_LOG(%p, ret_val);
    return ret_val;
}

根据不同的字符返回不同的结构体。

这些结构体和GpsInterface完全一样,在gps.h文件中定义,然后在loc.cpp中实现。

这样, com_android_server_location_GpsLocationProvider就可以通过这些结构体调用so库中的方法了。

2.4 gps库调用JNI层方法

com_android_server_location_GpsLocationProvider.cpp中定义了一些gps库调回调的结构体,

例如sGpsCallbacks,主要是gps库中上传数据的信息,定义如下,

GpsCallbacks sGpsCallbacks = {
    sizeof(GpsCallbacks),
    location_callback,
    status_callback,
    sv_status_callback,
    nmea_callback,
    set_capabilities_callback,
    acquire_wakelock_callback,
    release_wakelock_callback,
    create_thread_callback,
    request_utc_time_callback,
};

这些结构体在gps库中也都有对应的结构体,相当于JNI到so库中的一个转换。

都是通过android_location_GpsLocationProvider_init方法中调用gps库中sGpsInterface/ sGpsXtraInterface

等结构体的init方法传递到so库中。部分代码如下,

if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
        return JNI_FALSE;
if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
        sGpsXtraInterface = NULL;
if (sAGpsInterface)
        sAGpsInterface->init(&sAGpsCallbacks);
•••

gps库中gps.h对应的GpsCallbacks定义如下,

typedef struct {
    /** set to sizeof(GpsCallbacks) */
    size_t      size;
    gps_location_callback location_cb;
    gps_status_callback status_cb;
    gps_sv_status_callback sv_status_cb;
    gps_nmea_callback nmea_cb;
    gps_set_capabilities set_capabilities_cb;
    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;
} GpsCallbacks;

​ 因此,gps库中调用location_cb方法就是相当于调用JNI的location_callback方法,其他的结构体方法也完全相同,都是一一对应。

这样,gps库就可以回调JNI层的方法了。

最后,GpsLocationProvider的isSupported也是一个native方法,

public static boolean isSupported() {
        return native_is_supported();
    }

JNI中的android_location_GpsLocationProvider_is_supported方法如下,

static jboolean android_location_GpsLocationProvider_is_supported(
        JNIEnv* /* env */, jclass /* clazz */)
{
    return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
}

如果可以打开so库,获取sGpsInterface结构体就说明支持GPS,否则就不支持。

小结:

​ 主要论述了Java层,JNI层以及so库的回调方法的实现,这样就打通了架构中方法的互相调用。其实, com_android_server_location_GpsLocationProvide只是Framework和HAL之间的一个桥梁。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值