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-permissionandroid: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
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
后续的调用都是一样的,只是参数不同。
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>