看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。就是通过调用GpsLocationProviderisSupported()函数才调用到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();
}




更多相关文章

  1. 详解 Android(安卓)的 Activity 组件
  2. Android应用开发提高系列(5)——Android动态加载(下)——加载已安装A
  3. android流式布局热门标签的实现
  4. android progressDialog的使用
  5. android如何调用显示和隐藏系统默认的输入法
  6. 详解Android中的Activity生命周期
  7. Android(安卓)Eclipse JNI 调用 .so文件加载
  8. Android之UI学习篇七:ImageView实现适屏和裁剪图片的功能
  9. Android(安卓)C 语言读取系统属性

随机推荐

  1. Android(安卓)获取当前连接 Cid和lac
  2. Android(安卓)调用.NET webservice
  3. android http post 参数
  4. android volley 上传文件
  5. Make UDC & Android(安卓)ADB Gadget dri
  6. android 根据短信地址匹配联系人姓名
  7. Android(安卓)Exception异常汇集【不定时
  8. Android(安卓)VideoView播放视频
  9. Android(安卓)Develop Challenge
  10. Android(安卓)studio 57 MP3 音乐播放器