LocationService中GPS定位实现研究

LocationService即Android系统服务中的定位服务,其运行于系统进程中,APP要使用其实用到了Binder进程间通信机制,不过APP使用时,直接使用的是LocationManager对象,APP基本感觉不到Binder的存在,这是因为LocationManager中封装了Binder通信实现.
Binder进程间通信是Android的标准框架,使用模式固定,比较简单,故略过.本文主要偏向于JNI层的实现及JNI层与HAL层的通信.
除开应用层,整个服务其实分为四层:JAVA层、JNI层、HAL层、硬件层,其中JAVA层通过JNI层实现与HAL层的通信,HAL层采用高通的RPC协议与硬件通信.

一、首先,讲一下后面分析要用到的基础
1.相关源代码
HAL层所涉及到的主要代码:gps.h gps.c hardware.h loc_eng.cpp loc_api_rpc_glue.cpp loc_apicb_appinit.c
与HAL层通信的JNI层代码:GpsLocationProvider.cpp
与JNI对应的JAVA代码:GpsLocationProvider.java
Service实现代码:LocationManagerServicer.java
应用层与Service通讯的代码:LocationManager.java

2.gps.h里面定义了两个非常重要的结构体:

/** GPS callback structure. */
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;


/** Represents the standard GPS interface. */
typedef struct {
/** set to sizeof(GpsInterface) */
size_t size;
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)( GpsCallbacks* callbacks );

/** Starts navigating. */
int (*start)( void );

/** Stops navigating. */
int (*stop)( void );

/** Closes the interface. */
void (*cleanup)( void );

/** Injects the current time. */
int (*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);

/** Injects current location from another location provider
* (typically cell ID).
* latitude and longitude are measured in degrees
* expected accuracy is measured in meters
*/
int (*inject_location)(double latitude, double longitude, float accuracy);

/**
* Specifies that the next call to start will not use the
* information defined in the flags. GPS_DELETE_ALL is passed for
* a cold start.
*/
void (*delete_aiding_data)(GpsAidingData flags);

/**
* min_interval represents the time between fixes in milliseconds.
* preferred_accuracy represents the requested fix accuracy in meters.
* preferred_time represents the requested time to first fix in milliseconds.
*/
int (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);

/** Get a pointer to extension information. */
const void* (*get_extension)(const char* name);
} GpsInterface;


GpsCallbacks这个结构体里成员变量基本上都是函数指针,
具体的实现都在GpsLocationProvider.cpp中,这些函数指针变量最终会赋给HAL层,供HAL层回调,见GpsLocationProvider.cpp里第138行:
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,
};


sGpsCallbacks是一个全局变量,结构体在初始化时就对各个变量进行了赋值,各成员变量的值为GpsLocationProvider.cpp
里的一些函数,此变量通过GpsInterface里的(*init)( GpsCallbacks* callbacks )函数传递给HAL层,
见GpsLocationProvider.cpp里第287行:
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return false;


GpsInterface这个结构体也有一堆函数指针成员变量,这个结构体是在HAL层实现的,主要作用是给JNI层调用,达到
JNI向HAL层传递信息的作用;sGpsInterface是在初始化时取到的,下面会讲到.

3.综合起来说:GpsInterface与GpsInterface达到了JNI层与HAL层交互的目的,分别实现JNI层操作HAL层及HAL层往JNI层传递数据的作用,
比如:JNI层通过调用GpsInterface里的(*start)( void ),这个函数告诉HAL层启动定位,而HAL层通过location_callback向JNI层传递GPS位置信息


二、初始化与启动
Service里的Java层,JNI层与HAL层,都是运行在一个进程中的,Service启动时会进行一系列初始化工作,比如启动服务Looper线程、HAL层的工作线程等等
1.入口函数
系统进程随开机启动,会自动调用Location服务的systemReady()函数来启动定位服务线程,见SystemServer.java第946行:
try {
if (locationF != null) locationF.systemReady();
} catch (Throwable e) {
reportWtf("making Location Service ready", e);
}

此处locationF即为LocationManagerService的实例.

2.入口函数LocationManagerService.systemReady()的作用
此函数很简单,开始了一个线程并建立消息循环及执行init()函数,见LocationManagerService.java第199行:
  @Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Looper.prepare();
mLocationHandler = new LocationWorkerHandler();
init();
Looper.loop();
}

重点在init()函数里,此函数里调用了两个非常重要的函数:
loadProvidersLocked();与updateProvidersLocked();
分别见LocationManagerService.java的219行与252行

3. loadProvidersLocked()函数作用
加载各种Provider,最重要的一项就是创建GpsLocationProvider对象,见LocationManagerService.java的330行:
 if (GpsLocationProvider.isSupported()) {
// Create a gps location provider
GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
addProviderLocked(gpsProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
}

GpsLocationProvider里与JNI层进行了交互,GpsLocationProvider承担了GPS定位的主要的工作.
mGpsStatusProvider是GPS模块向上层提供的一个窗口,可以add与remove IGpsStatusListener接口,而此接口在APP层对应GpsStatus.Listener接口即GPS状态监听器
mNetInitiatedListener用来初始化网络监听

GpsLocationProvider.java里有一段static代码,执行了class_init_native()函数,在此函数中获取了HAL层开放给上层的GpsInterface接口,
见GpsLocationProvider.java的1606行:
static { class_init_native(); }

class_init_native()函数对应JNI函数即GpsLocationProvider.cpp里的android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz)
此函数还有一个重要作用,即提取出GpsLocationProvider.java里部分函数的id,当HAL层通知消息给JNI层时,JNI层再通过调用这些函数通知上层

4.updateProvidersLocked()函数
此函数在切换用户的时候也会被调用,最重要的作用是调用GpsLocationProvider.java的enable()与disable()函数
而enable()最终调用了native_init()函数与native_supports_xtra()函数、
disable()最终调用了 native_stop()函数native_cleanup()函数

native_init()是非常重要的函数,对应于JNI函数:android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
它将GpsCallbacks传给了HAL层
即上面提到的一段代码:
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)

5.loc_eng_init()函数
此函数由native_init()调用,位于loc_eng.cpp的第177行
因为native_init()实际上是GpsLocationProvider.cpp中的android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)函数,android_location_GpsLocationProvider_init中调用了sGpsInterface->init(&sGpsCallbacks),而sGpsInterface变量是由loadProvidersLocked()函数执行而得到的,
所以找到了sGpsInterface变量的由来,就知道为什么sGpsInterface->init实际上是loc_eng.cpp的loc_eng_init()函数

从第3条的分析得知,loadProvidersLocked()最终会调用到
android_location_GpsLocationProvider_class_init_native()函数,里面最重要的一段,见GpsLocationProvider.cpp第253行:

 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函数是从lib动态库中获取到gps模块的hw_module_t变量,这块属于HAL框架,先不管是怎么取到的,
先看看hw_module_t变量在哪里设置的,见gps.c里的第60行:
const struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = GPS_HARDWARE_MODULE_ID,
.name = "loc_api GPS Module",
.author = "Qualcomm USA, Inc.",
.methods = &gps_module_methods,
};

HAL_MODULE_INFO_SYM这个变量即为hw_module_t结构体的实例,再看这段代码:
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);

这里调用了hw_module_t里的methods结构体里的open函数,
methods结构体值为gps_module_methods,见gps.c的56行:
static struct hw_module_methods_t gps_module_methods = {
.open = open_gps
};

其中的open函数指针指向了open_gps函数, 即module->methods->open实际上调用的是open_gps()函数,定义见gps.c的第41行:
static int open_gps(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
{
struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
memset(dev, 0, sizeof(*dev));

dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t*)module;
dev->get_gps_interface = gps__get_gps_interface;

*device = (struct hw_device_t*)dev;
return 0;
}


重点为这句:
dev->get_gps_interface = gps__get_gps_interface;

再回过头去分析
sGpsInterface = gps_device->get_gps_interface(gps_device);

可知sGpsInterface的值为gps__get_gps_interface函数所返回的值,gps__get_gps_interface定义在gps.c的第36行:
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
{
return get_gps_interface();
}

而get_gps_interface()函数的定义在loc_eng.cpp的第1530行:
extern "C" const GpsInterface* get_gps_interface()
{
return &sLocEngInterface;
}

再看sLocEngInterface的定义,loc_eng.cpp的第97行:
static const GpsInterface sLocEngInterface =
{
sizeof(GpsInterface),
loc_eng_init,
loc_eng_start,
loc_eng_stop,
loc_eng_cleanup,
loc_eng_inject_time,
loc_eng_inject_location,
loc_eng_delete_aiding_data,
loc_eng_set_position_mode,
loc_eng_get_extension,
};

结合GpsInterface的声明,最终找到了loc_eng_init()函数即为sGpsInterface->init(&sGpsCallbacks)中的init

loc_eng_init()里作了什么呢?
最重要的就是调了函数
loc_api_glue_init()与sGpsCallbacks的函数create_thread_callback;

loc_api_glue_init()位于loc_api_rpc_glue.c的第158行

create_thread_callback函数在GpsLocationProvider.cpp里第133行:
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}

很明显是启动了一个线程,start为线程执行的函数,此参为在loc_eng_init()里传入,见loc_eng.cpp第236行:
loc_eng_data.deferred_action_thread = callbacks->create_thread_cb("loc_api",loc_eng_process_deferred_action, NULL);

里面的create_thread_cb即为create_thread_callback,所以最终执行的是loc_eng_process_deferred_action函数,见loc_eng.cpp第1422行
里面是一个while循环

loc_api_glue_init函数作用:创建一个与ARM9 RPC通讯的通道,与loc_eng_process_deferred_action线程配合使用,loc_eng_process_deferred_action线程会等待数据到来,当RPC通道从硬件取到数据时,会激活线程中的等待循环,从全局变量loc_eng_data里拿数据
loc_eng_process_deferred_action函数作用:当GPS有数据解析上报时,回调JNI函数,JNI函数会执行JAVA里的对应函数,最终通知给上层

还往下面分析涉及到高通自有的RPC协议实现与GPS专业知识,暂不作深究.

6.到此可以进行一下小结:
LocationManagerSerivce线程启动时,同时作了两个工作:
a.初始化GpsLocationProvider对象并获取HAL层的操作接口
b.将上层的回调接口GpsCallbacks传递给HAL层,供HAL进行回调,同时HAL层创建RPC通讯与上报数据线程

三、回调接口的设置
要分两部分讲,一部分是Framework层的回调接口设置,一部分是JNI层的回调接口设置
为什么是两部分,主要是因为JAVA与C++的回调有点不一样,JAVA层采用的是设置接口的方式
而C++采用的是设置函数指针的方式,整个设置分两部分,那么回调也就分两部分
1.JNI层的回调接口设置在前面提到过,即在Service初始化时完成,由前面提到的
“if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)”
这句代码完成;其中的函数变量sGpsCallbacks为JNI的结构体,里面成员为一系列的函数指针,指向JNI里实现的函数,供HAL层调用;
JNI层也是C++代码,JAVA层的监听器设置不能设置到JNI层的,那么如何衔接的呢?主要是由JNI机制实现的,即JNI里可以直接调用java对象里的函数,
在初始化时,GpsLocationProvider.cpp的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_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");


这一系列的代码目的就是先缓存JAVA里的函数id到JNI本地,当GPS数据上来时,由JNI调用,达到JNI层向JAVA层传送数据的目的

再来看sGpsCallbacks被传到HAL层后,是怎么被HAL层保存的
通过前面的分析,sGpsInterface->init(&sGpsCallbacks)这句其实调用的是static int loc_eng_init(GpsCallbacks* callbacks),
里面与callbacks相关的逻辑如下:
loc_eng_data.location_cb    = callbacks->location_cb;
loc_eng_data.sv_status_cb = callbacks->sv_status_cb;
loc_eng_data.status_cb = callbacks->status_cb;
loc_eng_data.nmea_cb = callbacks->nmea_cb;
loc_eng_data.acquire_wakelock_cb = callbacks->acquire_wakelock_cb;
loc_eng_data.release_wakelock_cb = callbacks->release_wakelock_cb;

所以这些接口函数又保存到了本地的变量loc_eng_data中,实际上GPS有数据通知上层时,最先调用的就是loc_eng_data里的这些函数
对比一下loc_eng_data_s_type结构体与GpsCallbacks

typedef struct
{
rpc_loc_client_handle_type client_handle;

gps_location_callback location_cb;
gps_status_callback status_cb;
gps_sv_status_callback sv_status_cb;
agps_status_callback agps_status_cb;
gps_nmea_callback nmea_cb;
gps_ni_notify_callback ni_notify_cb;
gps_acquire_wakelock acquire_wakelock_cb;
gps_release_wakelock release_wakelock_cb;
int agps_status;

// used to defer stopping the GPS engine until AGPS data calls are done
boolean agps_request_pending;
boolean stop_request_pending;
pthread_mutex_t deferred_stop_mutex;

loc_eng_xtra_data_s_type xtra_module_data;

loc_eng_ioctl_data_s_type ioctl_data;

// data from loc_event_cb
rpc_loc_event_mask_type loc_event;
rpc_loc_event_payload_u_type loc_event_payload;

// TBD:
char agps_server_host[256];
int agps_server_port;
uint32 agps_server_address;
char apn_name[100];
int position_mode;
rpc_loc_server_connection_handle conn_handle;

// GPS engine status
GpsStatusValue engine_status;

// Aiding data information to be deleted, aiding data can only be deleted when GPS engine is off
GpsAidingData aiding_data_for_deletion;

// Data variables used by deferred action thread
pthread_t deferred_action_thread;
// Mutex used by deferred action thread
pthread_mutex_t deferred_action_mutex;
// Condition variable used by deferred action thread
pthread_cond_t deferred_action_cond;

// flags for pending events for deferred action thread
int deferred_action_flags;
} loc_eng_data_s_type;



 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;



其对应关系很明显


2.JAVA层回调接口设置比较简单即设置接口,当然与一般的JAVA接口设置有点不一样,主要是因为涉及到进程间通讯,APP接口要先转成Binder机制支持的接口形式,然后再传给Service
以设置GPS状态监听为例:
APP层的监听器为GpsStatus.Listener,因为此接口不能直接跨进程设置,故在LocationManager.java中会自动转化为GpsStatusListenerTransport,
此类其实是实现了IGpsStatusListener.Stub接口,符合Binder机制要求,所以应用层添加GPS状态监听最初是调用LocationManager.addGpsStatusListener(GpsStatus.Listener listener),
实际上被转化成调用service的addGpsStatusListener(IGpsStatusListener listener),GpsStatusListenerTransport中保存了GpsStatus.Listener引用.
而Service的addGpsStatusListener里实际调用了mGpsStatusProvider.addGpsStatusListener(listener);而mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
gpsProvider为GpsLocationProvider类的实例,实际getGpsStatusProvider()函数只是返回变量mGpsStatusProvider
其初始化语句为,见GpsLocationProvider.java 312行:
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
@Override
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
if (listener == null) {
throw new NullPointerException("listener is null in addGpsStatusListener");
}

synchronized (mListeners) {
IBinder binder = listener.asBinder();
int size = mListeners.size();
for (int i = 0; i < size; i++) {
Listener test = mListeners.get(i);
if (binder.equals(test.mListener.asBinder())) {
// listener already added
return;
}
}

Listener l = new Listener(listener);
binder.linkToDeath(l, 0);
mListeners.add(l);
}
}

@Override
public void removeGpsStatusListener(IGpsStatusListener listener) {
if (listener == null) {
throw new NullPointerException("listener is null in addGpsStatusListener");
}

synchronized (mListeners) {
IBinder binder = listener.asBinder();
Listener l = null;
int size = mListeners.size();
for (int i = 0; i < size && l == null; i++) {
Listener test = mListeners.get(i);
if (binder.equals(test.mListener.asBinder())) {
l = test;
}
}

if (l != null) {
mListeners.remove(l);
binder.unlinkToDeath(l, 0);
}
}
}
};


这里比较奇怪,因为LocationManagerservice.java在调用GpsLocationProvider时实际是处于同进程的,但是这里却用到了Binder机制,其实不用这个机制应该是没什么关系的;通过上面代码可知,添加的监听接口最后保存在了mListeners里,看mListeners的定义:private ArrayList<Listener> mListeners = new ArrayList<Listener>();
一个普通List而已
到此可知JAVA层回调接口设置就这么简单
再看看最后是哪里调用了mListeners里的这些接口,比如reportLocation函数,这个函数的id在JNI里对应于method_reportLocation这个变量,
很明显了,JNI会调用到这些接口,来通知上层.

移除接口就是添加的反操作,比较简单,不再分析,但有一点要注意,删除时虽然传入的变量与添加的变量是同一个,但是到了服务端时,实际上是不一样的,主要就是因为进程间通讯的原因,接口都做了转化;那删除时如何能找到添加时对应的接口呢,也比较简单,因为两者的asBinder()是一样的,通过比较
二者的asBinder()值即可


四、底层消息上传
前面讲的回调接口的设置就是为底层消息上传服务的,GPS模块有定位数据后利用回调机制一级级上传,最后发送给应用
以GPS状态数据为例
首先Service初始化时,HAL层通过loc_api_glue_init函数创建与硬件的RPC通讯通道,同进启动线程不断等待数据的到来;
当硬件有数据后,会激活线程,线程里会调用相关函数:
loc_event = loc_eng_data.loc_event;
此句是线程循环里的一句代码,即获取由RPC通道传递来的GPS数据,接下来会调用
if (loc_event != 0) {
loc_eng_process_loc_event(loc_event, &loc_event_payload);
}
在loc_eng_process_loc_event里有一句:
if (loc_event & RPC_LOC_EVENT_STATUS_REPORT)
{
loc_eng_report_status (&(loc_event_payload->rpc_loc_event_payload_u_type_u.status_report));
}
再看 loc_eng_report_status函数里会执行loc_eng_data.status_cb(&status);
通过之前的分析:loc_eng_data.status_cb = callbacks->status_cb;而callbacks即为sGpsCallbacks变量,
callbacks->status_cb对应于JNI函数:status_callback
可知,最终是调用了JNI传过来的函数status_callback,其定义见GpsLocationProvider.cpp第82行:
 static void status_callback(GpsStatus* status)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}

mCallbacksObj即java层的GpsLocationProvider对象;再看初始化时的这句:
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");


其最终是调用了JAVA函数reportStatus,再看它的定义:
  
private void reportStatus(int status) {
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);

synchronized (mListeners) {
boolean wasNavigating = mNavigating;

switch (status) {
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
mEngineOn = true;
break;
case GPS_STATUS_SESSION_END:
mNavigating = false;
break;
case GPS_STATUS_ENGINE_ON:
mEngineOn = true;
break;
case GPS_STATUS_ENGINE_OFF:
mEngineOn = false;
mNavigating = false;
break;
}

if (wasNavigating != mNavigating) {
int size = mListeners.size();
for (int i = 0; i < size; i++) {
Listener listener = mListeners.get(i);
try {
if (mNavigating) {
listener.mListener.onGpsStarted();
} else {
listener.mListener.onGpsStopped();
}
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in reportStatus");
mListeners.remove(listener);
// adjust for size of list changing
size--;
}
}

// send an intent to notify that the GPS has been enabled or disabled.
Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
}


这里很明显了,最后是调用了之前设置的监听器IGpsStatusListener
看看应用层监听器与Binder监听器之间的关系:
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {

private final GpsStatus.Listener mListener;
private final GpsStatus.NmeaListener mNmeaListener;

// This must not equal any of the GpsStatus event IDs
private static final int NMEA_RECEIVED = 1000;

private class Nmea {
long mTimestamp;
String mNmea;

Nmea(long timestamp, String nmea) {
mTimestamp = timestamp;
mNmea = nmea;
}
}
private ArrayList<Nmea> mNmeaBuffer;

GpsStatusListenerTransport(GpsStatus.Listener listener) {
mListener = listener;
mNmeaListener = null;
}

GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
mNmeaListener = listener;
mListener = null;
mNmeaBuffer = new ArrayList<Nmea>();
}

@Override
public void onGpsStarted() {
if (mListener != null) {
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_STARTED;
mGpsHandler.sendMessage(msg);
}
}

@Override
public void onGpsStopped() {
if (mListener != null) {
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_STOPPED;
mGpsHandler.sendMessage(msg);
}
}

@Override
public void onFirstFix(int ttff) {
if (mListener != null) {
mGpsStatus.setTimeToFirstFix(ttff);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
mGpsHandler.sendMessage(msg);
}
}

@Override
public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
float[] elevations, float[] azimuths, int ephemerisMask,
int almanacMask, int usedInFixMask) {
if (mListener != null) {
mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
ephemerisMask, almanacMask, usedInFixMask);

Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
// remove any SV status messages already in the queue
mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
mGpsHandler.sendMessage(msg);
}
}

@Override
public void onNmeaReceived(long timestamp, String nmea) {
if (mNmeaListener != null) {
synchronized (mNmeaBuffer) {
mNmeaBuffer.add(new Nmea(timestamp, nmea));
}
Message msg = Message.obtain();
msg.what = NMEA_RECEIVED;
// remove any NMEA_RECEIVED messages already in the queue
mGpsHandler.removeMessages(NMEA_RECEIVED);
mGpsHandler.sendMessage(msg);
}
}

private final Handler mGpsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == NMEA_RECEIVED) {
synchronized (mNmeaBuffer) {
int length = mNmeaBuffer.size();
for (int i = 0; i < length; i++) {
Nmea nmea = mNmeaBuffer.get(i);
mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
}
mNmeaBuffer.clear();
}
} else {
// synchronize on mGpsStatus to ensure the data is copied atomically.
synchronized(mGpsStatus) {
mListener.onGpsStatusChanged(msg.what);
}
}
}
};
}

从上可知,Service调用IGpsStatusListener实际触发应用层调用了GpsStatus.Listener

五、对HAL层的操作
JNI层保留对HAL层操作的接口GpsInterface,对应的实例HAL层见loc_eng.cpp第97行:
static const GpsInterface sLocEngInterface =
{
sizeof(GpsInterface),
loc_eng_init,
loc_eng_start,
loc_eng_stop,
loc_eng_cleanup,
loc_eng_inject_time,
loc_eng_inject_location,
loc_eng_delete_aiding_data,
loc_eng_set_position_mode,
loc_eng_get_extension,
};

JNI层为GpsLocationProvider.cpp中的sGpsInterface变量,
前面已经讲过了一个操作,即将JNI层回调接口传递到HAL层,用到其中的loc_eng_init函数
这里再分析一下loc_eng_start操作,其调用在GpsLocationProvider.cpp中第320行:
static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
{
if (sGpsInterface)
return (sGpsInterface->start() == 0);
else
return false;
}
android_location_GpsLocationProvider_start对应JAVA函数native_start()在startNavigating()中被调用,
此函数在好几个地方有被调用,其中有setRequest()函数,在Service被requestLocationUpdates函数间接调用,
此函数应用层能通过进程间通讯调用,目的是注册位置通知的接收器,见LocationManager.java里的requestLocationUpdates函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值