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 ,hardwareframeworks/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>
相关文章推荐
- Android 2.2 源码结构分析
- Android2.2源码属性服务分析
- Camera源码分析(android2.2)
- 卷二 Dalvik与Android源码分析 第二章 进程与线程 2.2 Dalvik线程创建机制 图书版试读--请勿转发
- Camera源码分析(android2.2)
- Android2.2源码分析1.Manifest.permission
- Camera源码分析(android2.2)
- Android 2.2 源码结构分析
- Android2.2源码init机制分析
- 深入理解init_1----init分析(基于Android 2.2,源码来自Google)
- Camera源码分析(android2.2)
- 深入分析Android系统中SparseArray的源码
- android的消息处理机制(图+源码分析)——Looper,Handler,Message