GPS 研究(Android2.3)
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: 2.2
frameworks/base/core/jni/android_location_GpsLocationProvider.cpp 2.3 /framework/base/services/jni/com_android_server_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中。 view plain copy to clipboard print ?
- /**RepresentsthestandardGPSinterface.*/
- typedefstruct{
- /**settosizeof(GpsInterface)*/
- size_tsize;
- /**
- *Openstheinterfaceandprovidesthecallbackroutines
- *totheimplemenationofthisinterface.
- */
- int(*init)(GpsCallbacks*callbacks);
- /**Startsnavigating.*/
- int(*start)(void);
- /**Stopsnavigating.*/
- int(*stop)(void);
- /**Closestheinterface.*/
- void(*cleanup)(void);
- /**Injectsthecurrenttime.*/
- int(*inject_time)(GpsUtcTimetime,int64_ttimeReference,
- intuncertainty);
- /**Injectscurrentlocationfromanotherlocationprovider
- *(typicallycellID).
- *latitudeandlongitudearemeasuredindegrees
- *expectedaccuracyismeasuredinmeters
- */
- int(*inject_location)(doublelatitude,doublelongitude,floataccuracy);
- /**
- *Specifiesthatthenextcalltostartwillnotusethe
- *informationdefinedintheflags.GPS_DELETE_ALLispassedfor
- *acoldstart.
- */
- void(*delete_aiding_data)(GpsAidingDataflags);
- /**
- *min_intervalrepresentsthetimebetweenfixesinmilliseconds.
- *preferred_accuracyrepresentstherequestedfixaccuracyinmeters.
- *preferred_timerepresentstherequestedtimetofirstfixinmilliseconds.
- */
- int(*set_position_mode)(GpsPositionModemode,GpsPositionRecurrencerecurrence,
- uint32_tmin_interval,uint32_tpreferred_accuracy,uint32_tpreferred_time);
- /**Getapointertoextensioninformation.*/
- constvoid*(*get_extension)(constchar*name);
- }GpsInterface;
- /**RepresentsthestandardGPSinterface.*/
- typedefstruct{
- /**settosizeof(GpsInterface)*/
- size_tsize;
- /**
- *Openstheinterfaceandprovidesthecallbackroutines
- *totheimplemenationofthisinterface.
- */
- int(*init)(GpsCallbacks*callbacks);
- /**Startsnavigating.*/
- int(*start)(void);
- /**Stopsnavigating.*/
- int(*stop)(void);
- /**Closestheinterface.*/
- void(*cleanup)(void);
- /**Injectsthecurrenttime.*/
- int(*inject_time)(GpsUtcTimetime,int64_ttimeReference,
- intuncertainty);
- /**Injectscurrentlocationfromanotherlocationprovider
- *(typicallycellID).
- *latitudeandlongitudearemeasuredindegrees
- *expectedaccuracyismeasuredinmeters
- */
- int(*inject_location)(doublelatitude,doublelongitude,floataccuracy);
- /**
- *Specifiesthatthenextcalltostartwillnotusethe
- *informationdefinedintheflags.GPS_DELETE_ALLispassedfor
- *acoldstart.
- */
- void(*delete_aiding_data)(GpsAidingDataflags);
- /**
- *min_intervalrepresentsthetimebetweenfixesinmilliseconds.
- *preferred_accuracyrepresentstherequestedfixaccuracyinmeters.
- *preferred_timerepresentstherequestedtimetofirstfixinmilliseconds.
- */
- int(*set_position_mode)(GpsPositionModemode,GpsPositionRecurrencerecurrence,
- uint32_tmin_interval,uint32_tpreferred_accuracy,uint32_tpreferred_time);
- /**Getapointertoextensioninformation.*/
- constvoid*(*get_extension)(constchar*name);
- }GpsInterface;
2.GpsCallbacks回调函数
这个是回调函数结构体,定义也在gps.h中。它们的实现是在com_android_server_android_location_GpsLocationProvider.cpp中,google已经实现了,我们不需要做任何动作。
2.2
view plain copy to clipboard print ? - /**GPScallbackstructure.*/
- typedefstruct{
- /**settosizeof(GpsCallbacks)*/
- size_tsize;
- gps_location_callbacklocation_cb;
- gps_status_callbackstatus_cb;
- gps_sv_status_callbacksv_status_cb;
- gps_nmea_callbacknmea_cb;
- }GpsCallbacks;
[c-sharp] view plain copy print ? - /**GPScallbackstructure.*/
- typedefstruct{
- /**settosizeof(GpsCallbacks)*/
- size_tsize;
- gps_location_callbacklocation_cb;
- gps_status_callbackstatus_cb;
- gps_sv_status_callbacksv_status_cb;
- gps_nmea_callbacknmea_cb;
- }GpsCallbacks;
2.3 中 多加入了 以下几个回调函数
view plain copy to clipboard print ?- gps_set_capabilitiesset_capabilities_cb;
- gps_acquire_wakelockacquire_wakelock_cb;
- gps_release_wakelockrelease_wakelock_cb;
- gps_create_threadcreate_thread_cb;
- gps_set_capabilitiesset_capabilities_cb;
- gps_acquire_wakelockacquire_wakelock_cb;
- gps_release_wakelockrelease_wakelock_cb;
- gps_create_threadcreate_thread_cb;
3. GpsLocation
表示Locatin数据信息,底层驱动获得Location的raw信息,通常是nmea码,然后通过解析就得到了location信息。
其中Android2.3比android2.2多加入了 size 属性 以获取其大小。
view plain copy to clipboard print ? - /**Representsalocation.*/
- typedefstruct{
- /**settosizeof(GpsLocation)*/
- size_tsize;
- /**ContainsGpsLocationFlagsbits.*/
- uint16_tflags;
- /**Representslatitudeindegrees.*/
- doublelatitude;
- /**Representslongitudeindegrees.*/
- doublelongitude;
- /**RepresentsaltitudeinmetersabovetheWGS84reference
- *ellipsoid.*/
- doublealtitude;
- /**Representsspeedinmeterspersecond.*/
- floatspeed;
- /**Representsheadingindegrees.*/
- floatbearing;
- /**Representsexpectedaccuracyinmeters.*/
- floataccuracy;
- /**Timestampforthelocationfix.*/
- GpsUtcTimetimestamp;
- }GpsLocation;
[cpp] view plain copy print ? - /**Representsalocation.*/
- typedefstruct{
- /**settosizeof(GpsLocation)*/
- size_tsize;
- /**ContainsGpsLocationFlagsbits.*/
- uint16_tflags;
- /**Representslatitudeindegrees.*/
- doublelatitude;
- /**Representslongitudeindegrees.*/
- doublelongitude;
- /**RepresentsaltitudeinmetersabovetheWGS84reference
- *ellipsoid.*/
- doublealtitude;
- /**Representsspeedinmeterspersecond.*/
- floatspeed;
- /**Representsheadingindegrees.*/
- floatbearing;
- /**Representsexpectedaccuracyinmeters.*/
- floataccuracy;
- /**Timestampforthelocationfix.*/
- GpsUtcTimetimestamp;
- }GpsLocation;
JNI层文件 2.2 frameworks/base/core/jni/android_location_GpsLocationProvider.cpp 2.3 /framework/base/services/jni/com_android_server_location_GpsLocationProvider.cpp 下面来看看gps的定位服务(LocationManager)的启动过程 LocationManager 这项服务是在SystemServer.java 中启动的,也就是系统启动之后,这个服务就已经启动了
在SystemServer.java的init2函数中启动了一个线程来注册Android的诸多服务,如:Bluetooth Service,NetworkManagement Service,Notification Manager等,当然也包括Location Service。
systemServer.java [framework/base/services/java/com/android/server]
- public static final void init2() {
- Slog.i(TAG, "Entered the Android system server!");
- Thread thr = new ServerThread();
- thr.setName("android.server.ServerThread");
- thr.start();
- }
在ServerThread线程的run函数中LocationManager服务的代码段如下:
- try {
- Slog.i(TAG, "Location Manager");
- location = new LocationManagerService(context);
- ServiceManager.addService(Context.LOCATION_SERVICE, location);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting Location Manager", e);
- }
在run函数的后半部分,是服务对系统的反馈,就是systemReady()函数。 LocationManager服务的反馈函数如下:
- final LocationManagerService locationF = location;
其中的locationF 是LocationManagerService的final类型,就是一旦赋值,不能更改。
- if (locationF != null) locationF.systemReady();
下面我们来看看2.3的 LocationManagerService 构造函数。
- /**
- * @param context the context that the LocationManagerService runs in
- */
- public LocationManagerService(Context context) {
- super();
- mContext = context;
- Resources resources = context.getResources();
- mNetworkLocationProviderPackageName = resources.getString(
- com.android.internal.R.string.config_networkLocationProvider);
- mGeocodeProviderPackageName = resources.getString(
- com.android.internal.R.string.config_geocodeProvider);
- mPackageMonitor.register(context, true);
- if (LOCAL_LOGV) {
- Slog.v(TAG, "Constructed LocationManager Service");
- }
- }
以下为2.2
- public LocationManagerService(Context context) {
- super();
- mContext = context;
- if (LOCAL_LOGV) {
- Slog.v(TAG, "Constructed LocationManager Service");
- }
- }
然后我们再看SystemReady()
- void systemReady() {
- // we defer starting up the service until the system is ready
- Thread thread = new Thread(null, this, "LocationManagerService");
- thread.start();
- }
在这个函数当中,我们创建了一个新线程。然后start之。
因此我们的视线也随之跟随到run函数里面。
- public void run()
- {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Looper.prepare();
- mLocationHandler = new LocationWorkerHandler();
- initialize();
- Looper.loop();
- }
在run函数中,又调用了initialize 函数
- private void initialize() {
- // 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();
- // Register for Network (Wifi or Mobile) updates
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- // Register for Package Manager updates
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
- mContext.registerReceiver(mBroadcastReceiver, intentFilter);
- IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mBroadcastReceiver, sdFilter);
- // listen for settings changes
- ContentResolver resolver = mContext.getContentResolver();
- Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
- "(" + Settings.System.NAME + "=?)",
- new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
- null);
- mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
- SettingsObserver settingsObserver = new SettingsObserver();
- mSettings.addObserver(settingsObserver);
- }
初始化函数中,最重要的便是 loadProviders()函数。
- private void loadProviders() {
- synchronized (mLock) {
- if (sProvidersLoaded) {
- return;
- }
- // Load providers
- loadProvidersLocked();
- sProvidersLoaded = true;
- }
- }
loadProvidersLocked函数
- private void loadProvidersLocked() {
- try {
- _loadProvidersLocked();
- } catch (Exception e) {
- Slog.e(TAG, "Exception loading providers:", e);
- }
- }
_loadProvidersLocked函数
- private void _loadProvidersLocked() {
- // Attempt to load "real" providers first
- if (GpsLocationProvider.isSupported()) {
- // Create a gps location provider
- GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
- mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
- mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
- addProvider(gpsProvider);
- mGpsLocationProvider = gpsProvider;
- }
- ...
- ...
- updateProvidersLocked();
- }
首先,我们看GpsLocationProvider.isSupported 这个函数, 这个函数很重要,我们跟进这个函数可以看到, 因为在这个语句中得到了HAL层的GPS接口GpsInterface。就是通过调用GpsLocationProvider的isSupported()函数才调用到gps.cpp[hardware/libhardware_legacy/gps]中的gps_get_interface()。这个isSupported函数才是第一个吃螃蟹的人。(而不是JNI层的init函数,这个下面会提到)。
- public static boolean isSupported() {
- return native_is_supported();
- }
函数中只有一句话, 这调用了native方法,既Jni层定义的方法。native_is_supported对应在
framework/base/services/jni/com_android_server_location_GpsLocationProvider.cpp文件中的android_location_GpsLocationProvider_is_supported方法。
- static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
- return (sGpsInterface != NULL || get_gps_interface() != NULL);
- }
这里的get_gps_interface指的是本文件中
- static const GpsInterface* get_gps_interface() {
- int err;
- hw_module_t* module;
- const GpsInterface* interface = NULL;
- err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
- if (err == 0) {
- hw_device_t* device;
- err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
- if (err == 0) {
- gps_device_t* gps_device = (gps_device_t *)device;
- interface = gps_device->get_gps_interface(gps_device);
- }
- }
- return interface;
- }
而在该get_gps_interface中,去打开模组,之后打开设备,然后通过设备区调用HAL层中的get_gps_interface(gps_device)。
在gps.c(hardware/qcom/gps/loc_api/libloc_api)文件中实现的gps__get_gps_interface调用了loc_eng.cpp里面的 get_gps_interface 接口。
- extern "C" const GpsInterface* get_gps_interface()
- {
- return &sLocEngInterface;
- }
- static const GpsInterface sLocEngInterface =
- {
- sizeof(GpsInterface),
- loc_eng_init,
- loc_eng_start,
- loc_eng_stop,
- loc_eng_cleanup,
- loc_eng_inject_time,
- loc_eng_inject_location,
- loc_eng_delete_aiding_data,
- loc_eng_set_position_mode,
- loc_eng_get_extension,
- };
到这里为止, 一句简单的isSupported()执行的内容终于告一段落了。 我们获取到了GPS 的接口。在上面的LocationManagerService.java中, 如果找到gps硬件,并获取了接口则我们据悉执行isSupported()的下一句。
- GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
注意GpsLocationProvider构造函数里面的两个参数:mContext, this。下面来看看GpsLocationProvider的构造函数的前面几句:
- public GpsLocationProvider(Context context, ILocationManager locationManager) {
- mContext = context;
- mLocationManager = locationManager;
- mNIHandler = new GpsNetInitiatedHandler(context, this);
- ...
- }
接着看_loadProvidersLocked函数。
- private void _loadProvidersLocked() {
- // Attempt to load "real" providers first
- if (GpsLocationProvider.isSupported()) {
- // Create a gps location provider
- GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
- mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
- mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
- addProvider(gpsProvider);
- mGpsLocationProvider = gpsProvider;
- }
- // create a passive location provider, which is always enabled
- PassiveProvider passiveProvider = new PassiveProvider(this);
- addProvider(passiveProvider);
- mEnabledProviders.add(passiveProvider.getName());
- // initialize external network location and geocoder services
- if (mNetworkLocationProviderPackageName != null) {
- mNetworkLocationProvider =
- new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
- mNetworkLocationProviderPackageName, mLocationHandler);
- addProvider(mNetworkLocationProvider);
- }
- if (mGeocodeProviderPackageName != null) {
- mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
- }
- updateProvidersLocked();
- }
在构造完GpsLocationProvider之后将其add到全局变量ArrayList<LocationProviderInterface> mProviders中,备以后调用。
PassiveProvider暂时未了解到其用意。
然后启动了nerwork location和geocoder 两个service。但是可惜的是这两个服务都无法启动,因为他们是通过配置文件conifg.xml [framework/base/core/res/res/values]得到服务的名字,然后启动服务的。但是在这个配置文件中,两个服务的名字都是null。
conifg.xml [framework/base/core/res/res/values]
<!-- Component name of the service providing network location support. --> |
其实这也导致了,在调用GetFromLocationName和GetFromLocation两个函数时提示“Service not Available”,这个是google Android 2.2中就存在的bug。
_loadProvidersLocked函数的最后一句是调用updateProvidersLocked函数,仍然在LocationManagerServic.java文件中。
2.3:
- private void updateProvidersLocked() {
- boolean changesMade = false;
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderInterface p = mProviders.get(i);
- boolean isEnabled = p.isEnabled();
- String name = p.getName();
- boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
- if (isEnabled && !shouldBeEnabled) {
- updateProviderListenersLocked(name, false);
- changesMade = true;
- } else if (!isEnabled && shouldBeEnabled) {
- updateProviderListenersLocked(name, true);
- changesMade = true;
- }
- }
- if (changesMade) {
- mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
- }
- }
依靠前面的代码我们可以推测在mProviders里面应该存在一个gpsProvider 和PassiveProvider,而gpsProvider是未被enable的。而passiveProvider是enable的。
这边我们对gpsProvider进行讨论,他执行的是updateProviderListenersLocked(name,true) 然后当有发生改变,就是changesMade=true时,它发送了广播,内容是告诉大家LocationManager发生了变化,让需要的接收者自己接收。
下面我们跟进updateProviderListenersLocked(name,true)函数。
在LocationManagerService.java文件中
- private void updateProviderListenersLocked(String provider, boolean enabled) {
- int listeners = 0;
- LocationProviderInterface p = mProvidersByName.get(provider);
- if (p == null) {
- return;
- }
- ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records != null) {
- final int N = records.size();
- for (int i=0; i<N; i++) {
- UpdateRecord record = records.get(i);
- // Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<Receiver>();
- }
- deadReceivers.add(record.mReceiver);
- }
- listeners++;
- }
- }
- if (deadReceivers != null) {
- for (int i=deadReceivers.size()-1; i>=0; i--) {
- removeUpdatesLocked(deadReceivers.get(i));
- }
- }
- if (enabled) {
- p.enable();
- if (listeners > 0) {
- p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
- p.enableLocationTracking(true);
- }
- } else {
- p.enableLocationTracking(false);
- p.disable();
- }
- }
这边我们看if(enable)内的主题部分。 enable为真, 则启动了GPS服务。然后执行p.enable()函数。
enable()函数在GPSLocationProvider.java中
- /**
- * Enables this provider. When enabled, calls to getStatus()
- * must be handled. Hardware may be started up
- * when the provider is enabled.
- */
- public void enable() {
- synchronized (mHandler) {
- sendMessage(ENABLE, 1, null);
- }
- }
- private void sendMessage(int message, int arg, Object obj) {
- // hold a wake lock while messages are pending
- synchronized (mWakeLock) {
- mPendingMessageBits |= (1 << message);
- mWakeLock.acquire();
- mHandler.removeMessages(message);
- Message m = Message.obtain(mHandler, message);
- m.arg1 = arg;
- m.obj = obj;
- mHandler.sendMessage(m);
- }
- }
我们看到enable函数中只是调用了sendMessage。 跟进函数,可看到sendMessage函数,首先做的是把相关的消息标志位给设置位。而后获取mWakeLock ?这边有点疑问,之前进入本段代码的时候不是获取了mWakeLock了? 然后将上一次的相关消息删除,重新构造心的消息,让后发送给mHandler。
收到消息后,Hnadler会自动去调用handleMessage去处理收到的消息。
- public void handleMessage(Message msg) {
- int message = msg.what;
- switch (message) {
- case ENABLE:
- if (msg.arg1 == 1) {
- handleEnable();
- } else {
- handleDisable();
- }
- break;
- ...
根据构造的消息,我们将执行hanleEnable()。
- private void handleEnable() {
- if (DEBUG) Log.d(TAG, "handleEnable");
- if (mEnabled) return;
- mEnabled = native_init();
- if (mEnabled) {
- mSupportsXtra = native_supports_xtra();
- if (mSuplServerHost != null) {
- native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
- }
- if (mC2KServerHost != null) {
- native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
- }
- } else {
- Log.w(TAG, "Failed to enable location provider");
- }
- }
这边handleEnable函数主要做了两件事。
1.调用JNI层的native_init()方法去初始化GPS。
2.试图启动agps服务。
我们先看第一件事。在com_android_server_location_GPSLocationProvider.cpp可以找到JNI层的相关实现
- static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
- {
- const GpsInterface* interface = GetGpsInterface(env, obj);
- if (!interface)
- return false;
- if (!sGpsDebugInterface)
- sGpsDebugInterface = (const GpsDebugInterface*)interface->get_extension(GPS_DEBUG_INTERFACE);
- return true;
- }
这边调用了GetGpsInterface去获取接口并初始化GPS。 后半部分试图去调用其相关的扩展接口。
- static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) {
- // this must be set before calling into the HAL library
- if (!mCallbacksObj)
- mCallbacksObj = env->NewGlobalRef(obj);
- if (!sGpsInterface) {
- sGpsInterface = get_gps_interface();
- if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) {
- sGpsInterface = NULL;
- return NULL;
- }
- }
- return sGpsInterface;
- }
GetGpsInterface里面也去调用了get_gps_interface(),而这个函数前面也有提到,最早的地方便是isSupported()的这个函数。在获取了这个接口之后,使用sGpsInterface->init函数进行了初始化。
在gps_qemu.c中(模拟器中)
- 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;
- }
这边qemu_gps_init函数即是sGpsInterface->init函数,其中里面做了gps_state_init初始化,并注册了callbacks回调函数,而这个函数也是在JNI层实现的,而且有JNI层传下来的函数。
- static void
- gps_state_init( GpsState* state )
- {
- state->init = 1;
- state->control[0] = -1;
- state->control[1] = -1;
- state->fd = -1;
- state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
- 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));
- goto Fail;
- }
- if ( pthread_create( &state->thread, NULL, gps_state_thread, state ) != 0 ) {
- LOGE("could not create gps thread: %s", strerror(errno));
- goto Fail;
- }
- D("gps state initialized");
- return;
- Fail:
- gps_state_done( state );
- }
在这个gps_state_init函数中,首先打开串口,然后建立socket通信,然后建立线程监听底层数据上报,分别对应于代码中黄低部分。
我们顺便看到qemu_gps_get_extension 函数,
- static const void*
- qemu_gps_get_extension(const char* name)
- {
- // no extensions supported
- return NULL;
- }
这是一个空函数,说明初始化的时候调用的相关扩展接口是没有用的。
在Android2.2中,handleEnable还做了一件事情,就是创建了一个监听线程 。
而android2.3中,在GPSlocationProvider构造的时候就创建了一个线程。
- public GpsLocationProvider(Context context, ILocationManager locationManager) {
- ... ...
- // wait until we are fully initialized before returning
- mThread = new GpsLocationProviderThread();
- mThread.start();
- while (true) {
- try {
- mInitializedLatch.await();
- break;
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
查看run函数相关内容:
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- initialize();
- Looper.prepare();
- mHandler = new ProviderHandler();
- // signal when we are initialized and ready to go
- mInitializedLatch.countDown();
- Looper.loop();
- }
run函数去调用了 initialize初始化函数,然后新建一个looper,新建一个providerHandler 用于处理该线程的消息。然后看是否初始化完成。然后进入消息循环,准备收发,处理消息。
- private void initialize() {
- // register our receiver on our thread rather than the main thread
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ALARM_WAKEUP);
- intentFilter.addAction(ALARM_TIMEOUT);
- mContext.registerReceiver(mBroadcastReciever, intentFilter);
- }
初始化主要是将线程的接收者注册到我们的线程上,而不是注册到主线程上。
到这边为止我们完成了 p.enable()函数的分析。
LocationManageService.java中- private void updateProviderListenersLocked(String provider, boolean enabled) {
- ... ...
- if (enabled) {
- p.enable();
- if (listeners > 0) {
- p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
- p.enableLocationTracking(true);
- }
- } else {
- p.enableLocationTracking(false);
- p.disable();
- }
- }
接上, 我们研究完了p.enable函数。接下去 如果有listeners ,我们去调用p.enableLocationTracking()函数。
enableLocationTracking 在GPSLocationProvider.java中。
- public void enableLocationTracking(boolean enable) {
- // FIXME - should set a flag here to avoid race conditions with single shot request
- synchronized (mHandler) {
- sendMessage(ENABLE_TRACKING, (enable ? 1 : 0), null);
- }
- }
- public void handleMessage(Message msg) {
- int message = msg.what;
- switch (message) {
- case ENABLE:
- if (msg.arg1 == 1) {
- handleEnable();
- } else {
- handleDisable();
- }
- break;
- case ENABLE_TRACKING:
- handleEnableLocationTracking(msg.arg1 == 1);
- break;
- private void handleEnableLocationTracking(boolean enable) {
- if (enable) {
- mTTFF = 0;
- mLastFixTime = 0;
- startNavigating(false);
- } else {
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
- mAlarmManager.cancel(mWakeupIntent);
- mAlarmManager.cancel(mTimeoutIntent);
- }
- stopNavigating();
- }
- }
- private void startNavigating(boolean singleShot) {
- if (!mStarted) {
- if (DEBUG) Log.d(TAG, "startNavigating");
- mStarted = true;
- mSingleShot = singleShot;
- mPositionMode = GPS_POSITION_MODE_STANDALONE;
- if (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
- if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
- mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
- } else if (hasCapability(GPS_CAPABILITY_MSB)) {
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
- }
- }
- int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
- if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
- interval, 0, 0)) {
- mStarted = false;
- Log.e(TAG, "set_position_mode failed in startNavigating()");
- return;
- }
- if (!native_start()) {
- mStarted = false;
- Log.e(TAG, "native_start failed in startNavigating()");
- return;
- }
- // reset SV count to zero
- updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
- mFixRequestTime = System.currentTimeMillis();
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
- // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
- // and our fix interval is not short
- if (mFixInterval >= NO_FIX_TIMEOUT) {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
- }
- }
- }
- }
这边我中主要关注两个native函数。native_set_position_mode 和native_start!
在com_android_server_location_GpslocationProvider.cpp中找到两个对应的函数。
首先是native_set_position_mode:
- static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
- jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
- {
- const GpsInterface* interface = GetGpsInterface(env, obj);
- if (interface)
- return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
- preferred_time) == 0);
- else
- return false;
- }
这边调用了interface->set_position_mode。我们到gps_qemu.c当中去找其相关实现
- static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
- {
- // FIXME - support fix_frequency
- return 0;
- }
显然其中没有相关的实现。
接下去我们看native_start函数。
- static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
- {
- const GpsInterface* interface = GetGpsInterface(env, obj);
- if (interface)
- return (interface->start() == 0);
- else
- return false;
- }
- static int 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);
- return 0;
- }
- static void
- gps_state_start( GpsState* s )
- {
- char cmd = CMD_START;
- int ret;
- 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));
- }
数据监听线程
- /* this is the main thread, it waits for commands from gps_state_start/stop and,
- * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
- * that must be parsed to be converted into GPS fixes sent to the framework
- */
- static void*
- gps_state_thread( void* arg )
- {
- GpsState* state = (GpsState*) arg;
- NmeaReader reader[1];
- int epoll_fd = epoll_create(2);
- int started = 0;
- int gps_fd = state->fd;
- int control_fd = state->control[1];
- nmea_reader_init( reader );
- // register control file descriptors for polling
- epoll_register( epoll_fd, control_fd );
- epoll_register( epoll_fd, gps_fd );
- D("gps thread running");
- // now loop
- for (;;) {
- struct epoll_event events[2];
- int ne, nevents;
- nevents = epoll_wait( epoll_fd, events, 2, -1 );
- if (nevents < 0) {
- if (errno != EINTR)
- LOGE("epoll_wait() unexpected error: %s", strerror(errno));
- continue;
- }
- D("gps thread received %d events", nevents);
- for (ne = 0; ne < nevents; ne++) {
- if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
- LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
- goto Exit;
- }
- if ((events[ne].events & EPOLLIN) != 0) {
- int fd = events[ne].data.fd;
- if (fd == control_fd)
- {
- char cmd = 255;
- int ret;
- D("gps control fd event");
- do {
- ret = read( fd, &cmd, 1 );
- } while (ret < 0 && errno == EINTR);
- if (cmd == CMD_QUIT) {
- D("gps thread quitting on demand");
- goto Exit;
- }
- 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) {
- if (started) {
- D("gps thread stopping");
- started = 0;
- nmea_reader_set_callback( reader, NULL );
- }
- }
- }
- else if (fd == gps_fd)
- {
- char buff[32];
- D("gps fd event");
- for (;;) {
- int nn, ret;
- ret = read( fd, buff, sizeof(buff) );
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- if (errno != EWOULDBLOCK)
- LOGE("error while reading from gps daemon socket: %s:", strerror(errno));
- break;
- }
- D("received %d bytes: %.*s", ret, ret, buff);
- for (nn = 0; nn < ret; nn++)
- nmea_reader_addc( reader, buff[nn] );
- }
- D("gps fd event end");
- }
- else
- {
- LOGE("epoll_wait() returned unkown fd %d ?", fd);
- }
- }
- }
- }
- Exit:
- return NULL;
- }
这个监听线程最主要的一个就是nmea_reader_set_callback( )函数
其实就是注册了一个回调函数,location_cb 这个回调函数就是对底层location数据上报的回调函数。
到此
enableLocationTracking函数完成了,
也就是LocationManageService.java中
updateProviderListenersLocked的完成
也就是updateProvidersLocked的完成,
也就是loadProviders函数的完成
也就是 initialize的完成,
也就是run的完成,
也就是systemReady的完成
所以完了更多相关文章
- android是如何做DNS解析的
- Android(安卓)native 开发总结
- MTK平台camera bsp学习之camera HW架构篇
- Android控件笔记——使用RadioGroup和RadioButton实现单选效果
- Android(安卓)客户端Socket 实现及简单封装。
- 利用签名机制进行程序自检——Android防破解
- 知识梳理系列之五——OkHttp的原理
- Android(安卓)JNI(实现自己的JNI_OnLoad函数)
- [置顶] [Android基础]Android中使用HttpURLConnection