您的位置:首页 > 移动开发 > Android开发

Android2.2源码分析[GPS模块]

2010-11-10 10:36 134 查看

内容来源于网络以及自己的一些总结。

GPS JAVA API 示例

下面这个程序在会监听GPS 开启,关闭,位置改变,
public class MainActivity extends Activity implements LocationListener {
/** Called when the activity is first created. */
private final static String TAG = "LocationTest";
TextView tv;
Button btn;
private LocationManager lm;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 与Location_service建立连接
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 注册activity到监听队列中
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1l, 1l, this);
}
// Location发生变化时会调用这个
public void onLocationChanged(Location location) {
Log.d(TAG, "location: " + location);
}
// 关闭GPS卫星会调用这个
public void onProviderDisabled(String provider) {
Log.d(TAG, "provider disable" + provider);
}
// 启用GPS卫星会调用这个
public void onProviderEnabled(String provider) {
Log.d(TAG, "provider enable");
}
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(TAG, "status changed status = " + status);
}
}


使用GPS 需要这个权限:
< uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" >
</ uses-permission >
使用GPS 相关的资源,需要先用getSystemService 获得一个LOCATION_SERVICE 的实例,获得这个实例之后就可以进行相关操作了。
@frameworks/base/services/java/com/android/server/SystemServer.java
LOCATION_SERVICE 是在SystemServer.java 中启动的,也就是系统启动之后,这个服务就已经启动了:
ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context));

源码结构

主要分为四部分,client ,service ,jni ,hardware
frameworks/base/location/* (client 部分)
frameworks/base/services/java/com/android/serverLocationManagerService.java (server 部分)
frameworks/base/core/jni/android_location_GpsLocationProvider.cpp (JNI 部分)
hardware/libhardware_legacy/gps/* (hardware 接口部分)

1. frameworks/base/location/java (Client 部分)
.
├── android
│ └── location
│ ├── Address.aidl
│ ├── Address.java 描述地理位置信息
│ ├── Criteria.aidl
│ ├── Criteria.java 定位提供商的应用标准
│ ├── Geocoder.java 地理编码,好像是定位信息转换用的
│ ├── GpsSatellite.java 描述当前GPS satellite 信息
│ ├── GpsStatus.java 描述当前GPS engine 信息
│ ├── IGeocodeProvider.aidl
│ ├── IGpsStatusListener.aidl
│ ├── IGpsStatusProvider.aidl
│ ├── ILocationListener.aidl
│ ├── ILocationManager.aidl
│ ├── ILocationProvider.aidl
│ ├── INetInitiatedListener.aidl
│ ├── Location.aidl
│ ├── Location.java 描述定位的详细信息经度,纬度等等
│ ├── LocationListener.java 监听定位服务
│ ├── LocationManager.java 用来访问定位服务AIDL
│ ├── LocationProvider.java 定位提供者信息
│ └── package.html
└── com
└── android
└── internal
└── location
├── DummyLocationProvider.java
├── GpsLocationProvider.java
├── GpsNetInitiatedHandler.java
├── GpsXtraDownloader.java
├── LocationProviderProxy.java
├── MockProvider.java
└── NmeaParser.java

2. frameworks/base/services/java/com/android/server/ LocationManagerService.java (server 部分)

3. frameworks/base/core/jni/android_location_GpsLocationProvider.cpp (JNI 部分)

4. (hardware 接口部分)
hardware/libhardware_legacy/gps.h
hardware/libhardware_legacy/gps_ni.h
hardware/libhardware_legacy/gps/*
.
├── Android.mk
├── gps.cpp
└── gps_qemu.c

代码分析

1. 控制通道,也就是由app 层发起的比如enable 或disable 的控制命令,这个在”设置/ 位置和安全设置/ 使用GPS 卫星”里面设置。
LocationManager.java 主要负责通信。具体的实现在LocationManagerService.java 中,通过AIDL 实现通信,接口文件是ILocationManager.aidl 。在LocationManagerService 在初始化的时候,会判断是否有GPS 设备,如果存在则创建了一个GpsLocationProvider.java ,并通过JNI 调 android_location_GpsLocationProvider.cpp ,该文件再通过GPSInterface 来调用硬件的具体实现代码。

2. enable 后的Location 数据和状态上报。对于数据的上报过程,主要就是关注几个callback 函数。主要代码分析如下:
在 GpsLocationProvider.java 文件中enable() 一个GpsLocationProvider 时,会启动一个 GpsEventThread, 该线程主要就是调用了native_wait_for_event(); 通过JNI 调用到了android_location_GpsLocationProvider_wait_for_event()@ anroid_location_GpsLocationProvider.cpp ,而该event 的触发是由来自硬件驱动 Location 数据包的上报,底层的硬件驱动程序会把raw gps data 通过串口或其他的方式送出来,这个要看gps 驱动的实现了,我们通过自己实现的GpsInterface 来解析raw gps data 并调用loaction_callback() 来触发event 并copy Location 数据,等待到event 后再调用GpsLocationProvider.java 中的reportLocation() 上报Location.

另外一部分就是hardware/libhardware_legacy/gps 部分的实现,这个主要就是实现gps.h 里面的几个数据结构:
typedef struct {
gps_location_callback location_cb;
gps_status_callback status_cb;
gps_sv_status_callback sv_status_cb;
} GpsCallbacks;
typedef struct {
int   (*init)( GpsCallbacks* callbacks );
int   (*start)( void );
int   (*stop)( void );
void  (*set_fix_frequency)( int frequency );
void  (*cleanup)( void );
int   (*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);
void  (*delete_aiding_data)(GpsAidingData flags);
int   (*set_position_mode)(GpsPositionMode mode, int fix_frequency);
const void* (*get_extension)(const char* name);
} GpsInterface;
typedef struct {
uint16_t        flags;
double          latitude;
double          longitude;
double          altitude;
float           speed;
float           bearing;
float           accuracy;
GpsUtcTime      timestamp;
} GpsLocation;


在GpsInterface->init() 的时候要把上层的GpsCallbacks 传进来,然后start 后,从驱动那里poll 获得gps raw data ,并对raw data 进行解析并填充GpsLocation 数据结构,然后调用location_cb 上报location 数据。

//初始化的时候,得到GpsInterface,调用init,并且设置callback函数:
static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
{
if (!sGpsInterface)
sGpsInterface = gps_get_interface();
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return false;
…...
}
GpsCallbacks sGpsCallbacks = {
location_callback,
status_callback,
sv_status_callback,
nmea_callback
};
打开串口,注册sGpsCallbacks
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;
}
打开串口,建立Socket连接,创建线程:
static void gps_state_init( GpsState*  state )
{
...
state->fd = qemu_channel_open( &state->channel,
QEMU_CHANNEL_NAME,
O_RDONLY );
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;
}
…...
}

location回调函数:
static void location_callback(GpsLocation* location)
{
pthread_mutex_lock(&sEventMutex);
sPendingCallbacks |= kLocation;
memcpy(&sGpsLocation, location, sizeof(sGpsLocation));
pthread_cond_signal(&sEventCond); // 线程同步
pthread_mutex_unlock(&sEventMutex);
}
下面这个函数就是由上层的 java调用的,并且等待底层的硬件发送数据,其中由EventCond同步:
static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
{
pthread_mutex_lock(&sEventMutex);
while (sPendingCallbacks == 0) {
pthread_cond_wait(&sEventCond, &sEventMutex);
}
// copy and clear the callback flags
int pendingCallbacks = sPendingCallbacks;
sPendingCallbacks = 0;
int nmeaSentenceCount = mNmeaSentenceCount;
mNmeaSentenceCount = 0;
// copy everything and unlock the mutex before calling into Java code to avoid the possibility
// of timeouts in the GPS engine.
if (pendingCallbacks & kLocation)
memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
if (pendingCallbacks & kStatus)
memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
if (pendingCallbacks & kSvStatus)
memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
if (pendingCallbacks & kAGpsStatus)
memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
if (pendingCallbacks & kNmeaAvailable)
memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
if (pendingCallbacks & kNiNotification)
memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
pthread_mutex_unlock(&sEventMutex);
if (pendingCallbacks & kLocation) {
env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
(jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
(jdouble)sGpsLocationCopy.altitude,
(jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
(jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
}
if (pendingCallbacks & kStatus) {
env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
}
if (pendingCallbacks & kSvStatus) {
env->CallVoidMethod(obj, method_reportSvStatus);
}
if (pendingCallbacks & kAGpsStatus) {
env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
}
if (pendingCallbacks & kNmeaAvailable) {
for (int i = 0; i < nmeaSentenceCount; i++) {
env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
}
}
if (pendingCallbacks & kXtraDownloadRequest) {
env->CallVoidMethod(obj, method_xtraDownloadRequest);
}
if (pendingCallbacks & kDisableRequest) {
// don't need to do anything - we are just poking so wait_for_event will return.
}
if (pendingCallbacks & kNiNotification) {
LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
env->CallVoidMethod(obj, method_reportNiNotification,
sGpsNiNotificationCopy.notification_id,
sGpsNiNotificationCopy.ni_type,
sGpsNiNotificationCopy.notify_flags,
sGpsNiNotificationCopy.timeout,
sGpsNiNotificationCopy.default_response,
reqId,
text,
sGpsNiNotificationCopy.requestor_id_encoding,
sGpsNiNotificationCopy.text_encoding,
extras
);
}
}


hardware 那部分有个线程gps_state_thread 一直在读串口的内容并进行解析,最后解析到location 的信息
由cpp 文件的GpsCallbacks sGpsCallbacks = { location_callback....} 同步上层的线程。

从Framework 到HAL 调用过程大致如下:
android_location_GpsLocationProvider_init
gps_get_interface 获取GPS接口
gps_find_hardware来获取硬件设备信息,根据宏定义来判断
#ifdef HAVE_QEMU_GPS_HARDWARE
sGpsInterface = gps_get_qemu_interface()  源码中只有对qemu的实现,
#ifdef HAVE_GPS_HARDWARE
sGpsInterface = gps_get_hardware_interface();	这部分是需要自己根据硬件情况来实现
gps_get_qemu_interface
qemu_gps_init(GpsCallbacks* callbacks)

gps_state_init( GpsState*  state )
qemu_channel_open	打开GPS串口设备
socketpair	创建SOCKET用来控制下面的Thread

pthread_create(…, gps_state_thread, …)
gps_state_thread( void*  arg )

epoll_create
nmea_reader_init( reader );
epoll_register( epoll_fd, control_fd );
epoll_register( epoll_fd, gps_fd );
for (;;) {	//创建循环不停的扫描串口
nevents = epoll_wait( epoll_fd, events, 2, -1 );
if (fd == control_fd){
ret = read( fd, &cmd, 1 );
nmea_reader_set_callback
}

if (fd == gps_fd) {
for (;;) {
int  nn, ret;
ret = read( fd, buff, sizeof(buff) );
for (nn = 0; nn < ret; nn++)
nmea_reader_addc( reader, buff[nn] );
}
nmea_reader_addc( NmeaReader*  r, int  c )

nmea_reader_parse( NmeaReader*  r )
nmea_tokenizer_init

nmea_tokenizer_get
GGA数据处理
nmea_reader_update_time	// 更新时间
nmea_reader_update_latlong	// 更新经度,纬度
nmea_reader_update_altitude	// 更新高度

RMC数据处理
nmea_reader_update_date
nmea_reader_update_latlong
nmea_reader_update_bearing
nmea_reader_update_speed
r->callback( &r->fix );		// 解析后的数据上报


Android 2.2 Settings 程序GPS 设置:

在Settings -> Location & security ->My Location 里面有”Use wireless networks” 和”Use GPS satelites” 两个选项。一个是通过网络定位(Internet/Mobile networks ),另一个是通过GPS 芯片定位。

这部分相应的代码:
packages/apps/Settings/src/com/android/settings/SecuritySettings.java

SecuritySettings.java 中的大概调用流程如下:
首先加载XML 绑定视图:
onCreate()
createPreferenceHierarchy()
addPreferencesFromResource(R.xml.security_settings);
mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS);

然后onPreferenceTreeClick 方法会监听check ,uncheck 事件。
如果Use GPS satelites 被选择,就会调用:
@/frameworks/base/core/java/android/provider/Settings.java
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.GPS_PROVIDER , enabled);
putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider);
putString(ContentResolver resolver, Uri uri, String name, String value)
values.put(NAME, name); // name = location_providers_allowed
values.put(VALUE, value);
resolver.insert(uri, values);
最后会调用resolver.insert(uri, values); 把写到数据库(uri=”content://settings/secure” )中。

如果Use wireless networks 被选中:
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.NETWORK_PROVIDER , mNetwork.isChecked());
后续的调用都是一样的,只是参数不同。

Google Android 2.2 AGPS 说明:

谷歌在security_settings.xml 文件中注释掉了AGPS 的部分,解释如下:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:key="location_category"
android:title="@string/location_title">
<CheckBoxPreference
android:key="location_network"
android:title="@string/location_network_based"
android:summaryOn="@string/location_neighborhood_level"
android:summaryOff="@string/location_networks_disabled"/>
<CheckBoxPreference
android:key="location_gps"
android:title="@string/location_gps"
android:summaryOn="@string/location_street_level"
android:summaryOff="@string/location_gps_disabled"/>
<!-- Disabled to avoid confusion on devices with no AGPS
For Google experience devices we want AGPS on by default (if supported) so we don't really need this.
<CheckBoxPreference
android:key="assisted_gps"
android:title="@string/assisted_gps"
android:summaryOn="@string/assisted_gps_enabled"
android:summaryOff="@string/assisted_gps_disabled"/>
-->
</PreferenceCategory>
</PreferenceScreen>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: