看Android的GPS模块有两个月了吧,终于可以写点东西出来。首先来看看GPS模块的代码结构: Framework:
1.frameworks/base/location/java/android/location
这里主要是用来被App调用的,API包是android.location。
2.frameworks/base/location/java/com/android/internal/location
这个目录是Framework对Location服务的内部实现。
3.framework/services/java/com/android/server
这个目录只有一个文件 |-- LocationManagerService.java
是Location服务对内部实现的一种封装。 JNI: frameworks/base/core/jni/android_location_GpsLocationProvider.cpp
JNI层只有一个文件,起到承上启下的作用。上层承接Framework,下层调用HAL层具体硬件抽象实现。
HAL:Hardware Abstract Layer 硬件抽象层
hardware/libhardware_legacy/gps
hardware/libhardware_legacy/include/hardware_legacy/gps.h
HAL层相当于一个linux应用程序接口,通过open,close等操作,操作硬件设备。Android的源代码只实现了模拟器的gps接口,具体在文件gps_qemu.c中。在2.2版本中提供了对QCOM公司的gps的实现,在以下目录:
/hardware/qcom
下面介绍几个重要的数据结构:
1. GpsInterface接口是gps模块中最重要的数据结构,它是底层驱动实现的接口,如果要porting到自己的板子上,就需要实现这些接口。该接口的定义在gps.h中,模拟器实现在gps_qemu.c中。 /** Represents the standard GPS interface. */ typedef struct { /** * 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); /** * fix_frequency represents the time between fixes in seconds. * Set fix_frequency to zero for a single-shot fix. */ int (*set_position_mode)(GpsPositionMode mode, int fix_frequency); /** Get a pointer to extension information. */ const void* (*get_extension)(const char* name); } GpsInterface; |
2. GpsCallbacks回调函数
这个是回调函数结构体,定义也在gps.h中。它们的实现是在android_location_GpsLocationProvider.cpp中,google已经实现了,我们不需要做任何动作。
/** GPS callback structure. */ typedef struct { gps_location_callback location_cb; gps_status_callback status_cb; gps_sv_status_callback sv_status_cb; gps_nmea_callback nmea_cb; } GpsCallbacks; /** Callback with location information. */ typedef void (* gps_location_callback)(GpsLocation* location); /** Callback with status information. */ typedef void (* gps_status_callback)(GpsStatus* status); /** Callback with SV status information. */ typedef void (* gps_sv_status_callback)(GpsSvStatus* sv_info); /** Callback for reporting NMEA sentences. */ typedef void (* gps_nmea_callback)(GpsUtcTime timestamp, const char* nmea, int length); |
3. GpsLocation
表示Locatin数据信息,底层驱动获得Location的raw信息,通常是nmea码,然后通过解析就得到了location信息。
/** Represents a location. */
typedef struct {
/** Contains GpsLocationFlags bits. */
uint16_t flags;
/** Represents latitude in degrees. */
double latitude;
/** Represents longitude in degrees. */
double longitude;
/** Represents altitude in meters above the WGS 84 reference
* ellipsoid. */
double altitude;
/** Represents speed in meters per second. */
float speed;
/** Represents heading in degrees. */
float bearing;
/** Represents expected accuracy in meters. */
float accuracy;
/** Timestamp for the location fix. */
GpsUtcTime timestamp;
} GpsLocation;
initialize函数
LocationManagerService.java[frameworks/base/services/java/com/android/server]
privatevoidinitialize(){ // Create a wake lock, needs to be done before calling loadProviders() below PowerManager powerManager=(PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mWakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,WAKELOCK_KEY); // Load providers loadProviders(); ... |
initialize函数中最重要的就是loadProviders函数了,该函数调用loadProvidersLocked,然后loadProvidersLocked函数又调用_loadProvidersLocked函数。为什么要这么折腾呢?
先来看一部分的_loadProvidersLocked函数:
privatevoid_loadProvidersLocked(){ // Attempt to load "real" providers first if(GpsLocationProvider.isSupported()){ // Create a gps location provider GpsLocationProvider gpsProvider=newGpsLocationProvider(mContext,this); mGpsStatusProvider=gpsProvider.getGpsStatusProvider(); mNetInitiatedListener=gpsProvider.getNetInitiatedListener(); addProvider(gpsProvider); mGpsLocationProvider=gpsProvider; } ... |
注意这个if语句,狠重要,因为在这个语句中得到了HAL层的GPS接口GpsInterface。就是通过调用GpsLocationProvider的isSupported()函数才调用到gps.cpp[hardware/libhardware_legacy/gps]中的gps_get_interface()。这个isSupported函数才是第一个吃螃蟹的人。(而不是JNI层的init函数,这个下面会提到)。
GpsLocationProvider.cpp[frameworks/base/location/java/com/android/internal/location]
publicstaticboolean isSupported(){ returnnative_is_supported(); } |
然而isSupported只有一句话,果然是高手,一击必中。然后就调用native方法,也就是JNI层定义的方法。native_is_supported函数对于JNI层是android_location_GpsLocationProvider_is_supported方法。
android_location_GpsLocationProvider.cpp [frameworks/base/core/jni]
staticjboolean android_location_GpsLocationProvider_is_supported(JNIEnv*env,jclass clazz){ if(!sGpsInterface) sGpsInterface=gps_get_interface(); return(sGpsInterface!=NULL); } |
前面已经提到JNI起到承上启下的作用,gps_get_interface函数属于HAL层的调用,在文件gps.cpp中。
gps.cpp [hardware/libhardware_legacy/gps]
constGpsInterface* gps_get_interface() { if(sGpsInterface==NULL) gps_find_hardware(); returnsGpsInterface; } |
然后通过 gps_find_hardware函数去得到gps接口,下面只模拟器中的gpsinterface。
staticvoid gps_find_hardware(void) { #ifdefHAVE_QEMU_GPS_HARDWARE if(qemu_check()){ sGpsInterface=gps_get_qemu_interface(); if(sGpsInterface){ LOGD("using QEMU GPS Hardware emulation/n"); return; } } #endif #ifdefHAVE_GPS_HARDWARE sGpsInterface=gps_get_hardware_interface(); #endif if(!sGpsInterface) LOGD("no GPS hardware on this device/n"); } |
gps_qemu.c [hardware/libhardware_legacy/gps]
constGpsInterface*gps_get_qemu_interface() { return&qemuGpsInterface; } |
qemuGpsInterface的整体实现就在文件gps_qemu.c中。
staticconstGpsInterface qemuGpsInterface={
qemu_gps_init,
qemu_gps_start,
qemu_gps_stop,
qemu_gps_cleanup,
qemu_gps_inject_time,
qemu_gps_inject_location,
qemu_gps_delete_aiding_data,
qemu_gps_set_position_mode,
qemu_gps_get_extension,
};
-------------------------------------------------------------------------------- 在底层得到gps的接口之后,if (GpsLocationProvider.isSupported())(在文件LocationManagerService.java中调用)语句得到true,然后进行下一步操作,在这里new了一个GpsLocationProvider对象。代码如下:
GpsLocationProvider gpsProvider=newGpsLocationProvider(mContext,this); |
注意GpsLocationProvider构造函数里面的两个参数:mContext, this。下面来看看GpsLocationProvider的构造函数的前面几句:
publicGpsLocationProvider(Context context,ILocationManager locationManager){ mContext=context; mLocationManager=locationManager; mNIHandler=newGpsNetInitiatedHandler(context,this); ... } |
在GpsLocationProvider类里面的成员变量mLocationManager是构造函数的第二个参数,就是说是LocationManagerService对象。这一点在这里先明确。
接着看_loadProvidersLocked函数。
privatevoid_loadProvidersLocked(){ // Attempt to load "real" providers first if(GpsLocationProvider.isSupported()){ // Create a gps location provider GpsLocationProvider gpsProvider=newGpsLocationProvider(mContext,this); mGpsStatusProvider=gpsProvider.getGpsStatusProvider(); mNetInitiatedListener=gpsProvider.getNetInitiatedListener(); addProvider(gpsProvider); mGpsLocationProvider=gpsProvider; } // create a passive location provider, which is always enabled PassiveProvider passiveProvider=newPassiveProvider(this); addProvider(passiveProvider); mEnabledProviders.add(passiveProvider.getName()); // initialize external network location and geocoder services Resources resources=mContext.getResources(); StringserviceName=resources.getString( com.android.internal.R.string.config_networkLocationProvider); if(serviceName!=null){ mNetworkLocationProvider= newLocationProviderProxy(mContext,LocationManager.NETWORK_PROVIDER, serviceName,mLocationHandler); addProvider(mNetworkLocationProvider); } serviceName=resources.getString(com.android.internal.R.string.config_geocodeProvider); if(serviceName!=null){ mGeocodeProvider=newGeocoderProxy(mContext,serviceName); } updateProvidersLocked(); } |
在构造完GpsLocationProvider之后将其add到全局变量ArrayList<LocationProviderInterface> mProviders中,备以后调用。
在2.2中采取了一种PassiveProvider的类,而在2.1中是通过LocationProviderProxy代理类的方式。2.1中LocationProviderProxy作为GpsLocationProvider的代理作用在LocationManagerService中,而2.2中的PassiveProvider感觉这个类是个空壳。。。。。。。。有待研究。
然后启动了nerwork location和geocoder 两个service。但是可惜的是这两个服务都无法启动,因为他们是通过配置文件conifg.xml[framework/base/core/res/res/values]得到服务的名字,然后启动服务的。但是在这个配置文件中,两个服务的名字都是null。
conifg.xml [framework/base/core/res/res/values]
<!--Componentnameofthe service providing network location support.--> <stringname="config_networkLocationProvider">@null</string> <!--Componentnameofthe service providing geocoder API support.--> <stringname="config_geocodeProvider">@null</string> |
其实这也导致了,在调用GetFromLocationName和GetFromLocation两个函数时提示“Service not Available”,这个google Android 2.2的bug。
_loadProvidersLocked函数的最后一句是调用updateProvidersLocked函数,仍然在LocationManagerServic.java文件中。
LocationManagerServic.java
privatevoidupdateProvidersLocked(){ for(inti=mProviders.size()-1;i>=0;i--){ LocationProviderInterface p=mProviders.get(i); booleanisEnabled=p.isEnabled(); Stringname=p.getName(); booleanshouldBeEnabled=isAllowedBySettingsLocked(name); if(isEnabled&&!shouldBeEnabled){ updateProviderListenersLocked(name,false); }elseif(!isEnabled&&shouldBeEnabled){ updateProviderListenersLocked(name,true); } } } |
从上面_loadProvidersLocked函数的代码来看,在mProviders这个ArrayList中有两个元素(这一点未求证),一个是gpsProvider,另一个是passiveProvider。gpsProvider是GpsLocationProvider类型的,它的isEnabled函数返回的是false,因为它并没有被enable。而passiveProvider是PassiveProvider类型,它总是enable的。所以gpsProvider会调用else语句中的updateProviderListenersLocked(name,true)函数。我们主要分析这个else语句,对于passiveProvider不做分析。
言归正传,分析sGpsInterface->init方法。
gps_qume.c
staticint 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; return0; } |
在 sGpsInterface->init中,也就是在qemu_gps_init方法,首先调用了gps_state_init,其次注册了回调函数,再说一次,这个回调函数就是在JNI层实现的,而且有JNI层传下来的函数。
staticvoid 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)); gotoFail; } if(pthread_create(&state->thread,NULL,gps_state_thread,state)!=0){ LOGE("could not create gps thread: %s",strerror(errno)); gotoFail; } D("gps state initialized"); return; Fail: gps_state_done(state); } |
在这个gps_state_init函数中,首先打开串口,然后建立socket通信,然后建立线程监听底层数据上报,分别对应于代码中黄低部分。
3)建立线程监听事件
mEventThread=newGpsEventThread(); mEventThread.start(); |
来看看GpsEventThread的run函数。
publicvoidrun(){ 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数据)。这个在后面还会讲到。
staticvoidandroid_location_GpsLocationProvider_wait_for_event(JNIEnv*env,jobject obj) { pthread_mutex_lock(&sEventMutex); while(sPendingCallbacks==0){ pthread_cond_wait(&sEventCond,&sEventMutex); } ... } |
分析完了enable函数以后就轮到enableLocationTracking函数了。 GpsLocationProvider.java publicvoidenableLocationTracking(booleanenable){ synchronized(mHandler){ mHandler.removeMessages(ENABLE_TRACKING); Message m=Message.obtain(mHandler,ENABLE_TRACKING); m.arg1=(enable?1:0); mHandler.sendMessage(m); } } |
同样地,也采取Handler的方式。调用的是handleEnableLocationTracking函数。
privatevoidhandleEnableLocationTracking(booleanenable){ if(enable){ mTTFF=0; mLastFixTime=0; startNavigating(); }else{ mAlarmManager.cancel(mWakeupIntent); mAlarmManager.cancel(mTimeoutIntent); stopNavigating(); } } |
调用startNavigating函数。
privatevoidstartNavigating(){ if(!mStarted){ if(DEBUG)Log.d(TAG,"startNavigating"); mStarted=true; intpositionMode; if(Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ASSISTED_GPS_ENABLED,1)!=0){ positionMode=GPS_POSITION_MODE_MS_BASED; }else{ positionMode=GPS_POSITION_MODE_STANDALONE; } if(!native_start(positionMode,false,1)){ mStarted=false; Log.e(TAG,"native_start failed in startNavigating()"); return; } ... |
在startNavigating函数中,最有作用的语句就是调用native方法native_start。调用到了JNI层的android_location_GpsLocationProvider_start函数。
android_location_GpsLocationProvider.cpp
在startNavigating函数中,最有作用的语句就是调用native方法native_start。调用到了JNI层的android_location_GpsLocationProvider_start函数。
android_location_GpsLocationProvider.cpp
staticjboolean android_location_GpsLocationProvider_start(JNIEnv*env,jobject obj,jint positionMode, jboolean singleFix,jint fixFrequency) { intresult=sGpsInterface->set_position_mode(positionMode,(singleFix?0:fixFrequency)); if(result){ returnfalse; } return(sGpsInterface->start()==0); } |
接下去就会调用sGpsInterface接口的实现gps_qemu.c中具体实现的函数。
staticint qemu_gps_start() { GpsState*s=_gps_state; if(!s->init){ D("%s: called with uninitialized state !!",__FUNCTION__); return-1; } D("%s: called",__FUNCTION__); gps_state_start(s); return0; } |
通过向底层发送命令,CMD_START来启动gps。其实这个所谓的底层就是在enable/init函数中启动的等待数据的线程。
staticvoid gps_state_start(GpsState*s) { charcmd=CMD_START; intret; do{ret=write(s->control[0],&cmd,1);} while(ret<0&&errno==EINTR); if(ret!=1) D("%s: could not send CMD_START command: ret=%d: %s", __FUNCTION__,ret,strerror(errno)); } |
数据监听线程
staticvoid* gps_state_thread(void*arg) { ... // now loop for(;;){ ... if(cmd==CMD_QUIT){ D("gps thread quitting on demand"); gotoExit; }else if(cmd==CMD_START){ if (!started) { D("gps thread starting location_cb=%p", state>callbacks.location_cb); started = 1; nmea_reader_set_callback( reader, state->callbacks.location_cb ); }} else if (cmd == CMD_STOP) { ... } |
其实就是注册了一个回调函数,location_cb这个回调函数就是对底层location数据上报的回调函数。
在enableLocationTracking函数调用完成以后,基本上gps服务已经启动完成了,也就是LocationManagerService中的updateProvidersLocked函数的完成,也就是loadProviders函数的完成,也就是initialize函数的完成,也就是run函数的完成,也就是2.2中反馈机制systemReady的完成。
voidsystemReady(){
// we defer starting up the service until the system is ready
Threadthread=newThread(null,this,"LocationManagerService");
thread.start();
}
- 详解 Android(安卓)的 Activity 组件
- Android应用开发提高系列(5)——Android动态加载(下)——加载已安装A
- android流式布局热门标签的实现
- android progressDialog的使用
- android如何调用显示和隐藏系统默认的输入法
- 详解Android中的Activity生命周期
- Android(安卓)Eclipse JNI 调用 .so文件加载
- Android之UI学习篇七:ImageView实现适屏和裁剪图片的功能
- Android(安卓)C 语言读取系统属性
随机推荐
-
Android(安卓)获取当前连接 Cid和lac
-
Android(安卓)调用.NET webservice
-
android http post 参数
-
android volley 上传文件
-
Make UDC & Android(安卓)ADB Gadget dri
-
android 根据短信地址匹配联系人姓名
-
Android(安卓)Exception异常汇集【不定时
-
Android(安卓)VideoView播放视频
-
Android(安卓)Develop Challenge
-
Android(安卓)studio 57 MP3 音乐播放器