Android GPS架构分析
Daniel Wood 20101224
转载时请注明出处和作者
文章出处:http://danielwood.cublog.cn
作者:Daniel Wood
--------------------------------------------------------------------------------
通过调用GpsLocationProvider类的enable和 enableLocationTracking函 数就把GPS的LocationManager服务启动起来了。下面对这两个函数进行分析。
首先是enable函数。
GpsLocationProvider.java
public void enable ( ) { synchronized ( mHandler) { mHandler. removeMessages( ENABLE ) ; Message m = Message. obtain( mHandler, ENABLE ) ; m. arg1 = 1; mHandler. sendMessage( m) ; } }
对了,这个要提一点,在2.2中加入了一个ProviderHandler类(extends Handler),这个在2.1中是没有的,其实是换汤不换药的,对于函数调用的过程来说没有本质的改变。对于Handler的机制我还没有研究过。
public void handleMessage( Message msg) { switch ( msg. what) { case ENABLE : if ( msg. arg1 = = 1) { handleEnable( ) ; } else { handleDisable( ) ; } break ; case ENABLE_TRACKING: handleEnableLocationTracking( msg. arg1 = = 1) ; break ;
...
在 handleMessage函数中,定义了各种message对应的处理函数。对于ENABLE消息还带有一个参数,enable函数里面带的参数值为1,所以调用handleEnable函数。
private void handleEnable( ) { if ( DEBUG) Log . d( TAG, "handleEnable" ) ; if ( mEnabled) return ; mEnabled = native_init( ) ; if ( mEnabled) { if ( mSuplServerHost ! = null ) { native_set_agps_server( AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort) ; } if ( mC2KServerHost ! = null ) { native_set_agps_server( AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort) ; } // run event listener thread while we are enabled mEventThread = new GpsEventThread( ) ; mEventThread. start ( ) ; } else { Log . w( TAG, "Failed to enable location provider" ) ; } }
在handleEnable函数中中主要做了3件事,不过有一件事情没有做成。先来看看哪三件事:
1)调用了 native 的初始化方法对 gps 进行初始化,
2)试图启动agps服务,
3)并启动一个线程去监听事件。
先 来说说它没有做成的第二件事,启动agps服务。其实在GpsLocationProvider类构造的时候就试图去读取agps的配置文件"/etc /gps.conf",该文件里面储存着agps的服务器地址以及端口号,但是服务器地址以及端口号都是错误的,所以它基本上无法启动agps服务,而且 对模拟器来说agps基本是个鸡肋。关于agps部分可能在以后的以后会提到。下面看它做成的第一和第三件事。
1) 调用native方法native_init,就是JNI层的android_location_GpsLocationProvider_init方法,在文件andoird_location_GpsLocationProvider.cpp中。
static jboolean android_location_GpsLocationProvider_init( JNIEnv* env, jobject obj) { if ( ! sGpsInterface) sGpsInterface = gps_get_interface( ) ; if ( ! sGpsInterface | | sGpsInterface- > init ( & sGpsCallbacks) ! = 0) return false ;
...
return true;
}
在初始化函数中会去确认 GpsInterface 是否已经得到,如果没有得到那么通过 gps_get_interface() 方法再次去得到,正如其实前面提到的那样该接口已经在 android_location_GpsLocationProvider_is_supported 函数(第一个吃螃蟹的人)中得到了。然后在第二个 if 语句中调用初始化方法 sGpsInterface- > init。
android_location_GpsLocationProvider_init的后半部分,试图通过GpsInterface->get_extension方法去得到gps相关的扩展接口,可是在2.2的模拟器实现中并没有实现这个函数,在gps_qume.c中明显写着return NULL。
gps_qume.c
static const void * qemu_gps_get_extension( const char * name) { return NULL ; }
言归正传,分析sGpsInterface- > init方法。
gps_qume.c
static int qemu_gps_init( GpsCallbacks* callbacks) { GpsState* s = _gps_state; if ( ! s- > init) gps_state_init( s) ; if ( s- > fd < 0) return - 1; s- > callbacks = * callbacks; return 0; }
在 sGpsInterface- > init中,也就是在qemu_gps_init方法,首先调用了gps_state_init,其次注册了回调函数,再说一次,这个回调函数就是在JNI层实现的,而且有JNI层传下来的函数。
static void gps_state_init( GpsState* state ) { state- > init = 1; state- > control[ 0] = - 1; state- > control[ 1] = - 1; state- > fd = - 1; state- > fd = qemu_channel_open ( & state- > channel, QEMU_CHANNEL_NAME, O_RDONLY ) ; if ( state- > fd < 0) { D( "no gps emulation detected" ) ; return ; } D( "gps emulation will read from '%s' qemud channel" , QEMU_CHANNEL_NAME ) ; if ( socketpair ( AF_LOCAL , SOCK_STREAM , 0, state- > control ) < 0 ) { LOGE( "could not create thread control socket pair: %s" , strerror ( errno ) ) ; goto Fail; } if ( pthread_create ( & state- > thread, NULL , gps_state_thread, state ) ! = 0 ) { LOGE( "could not create gps thread: %s" , strerror ( errno ) ) ; goto Fail; } D( "gps state initialized" ) ; return ; Fail: gps_state_done( state ) ; }
在这个gps_state_init函数中,首先打开串口,然后建立socket通信,然后建立线程监听底层数据上报,分别对应于代码中黄低部分。
3)建立线程监听事件
mEventThread = new GpsEventThread( ) ; mEventThread. start ( ) ;
来看看GpsEventThread的run函数。
public void run ( ) { if ( DEBUG) Log . d( TAG, "GpsEventThread starting" ) ; // Exit as soon as disable() is called instead of waiting for the GPS to stop. while ( mEnabled) { // this will wait for an event from the GPS, // which will be reported via reportLocation or reportStatus native_wait_for_event( ) ; } if ( DEBUG) Log . d( TAG, "GpsEventThread exiting" ) ; } }
run函数中还是需要调用native函 数:JNI:android_location_GpsLocationProvider_wait_for_event函数。这个函数就是在一个 while循环里面等待事件的触发(由回调函数触发),然后调用GpsLocationProvider类的数据上报函数(Location数据)。这个 在后面还会讲到。
static void android_location_GpsLocationProvider_wait_for_event( JNIEnv* env, jobject obj) { pthread_mutex_lock ( & sEventMutex) ; while ( sPendingCallbacks = = 0) { pthread_cond_wait ( & sEventCond, & sEventMutex) ; } . . . }