当前位置:首页 >> 机械/仪表 >>

Android GPS架构分析-摘自Daniel Wood的博客


的博客: 以下摘自 Daniel Wood 的博客: http://blogold.chinaunix.net/u4/123238/article_150426.html 架构分析( 启动过程图) Android GPS 架构分析(gps 启动过程图)

Gps 启动过程图(基于 Google Android 2.2 代码)

架构分析

Android GPS 架构分析-preview

Android GPS 架构分析
Daniel Wood 20101222

转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ---------------------------------------------------------看 Android 的 GPS 模块有两个月了吧,终于可以写点东西出来。首先来看看 GPS 模块的代码结构: Framework: 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: JNI: frameworks/base/core/jni/android_location_GpsLocationProvider.cpp JNI 层只有一个文件, 起到承上启下的作用。 上层承接 Framework, 下层调用 HAL 层具体硬件抽象实现。 HAL:Hardware Abstract Layer 硬件抽象层 AL: 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 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;

架构分析( Android GPS 架构分析(一)

Android GPS 架构分析
Daniel Wood 20101222

转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn

作者:Daniel Wood -------------------------------------------------------------------介绍完了主体代码结构以及重要的数据结构后,下面来看看 gps 的定位服务 (LocationManager)的启动过程。我总是喜欢追本溯源地从源头去认识事物。 因为“人之初,性本善”,从事物的本性去认识事物。 LocationManager 这项服务是在 SystemServer.java 中启动的,也就是系统启 动之后,这个服务就已经启动了: systemServer.java [framework\base\services\java\com\android\server] 在 SystemServer.java 的 init2 函数中启动了一个线程来注册 Android 的诸 多服务,如:Bluetooth Service,NetworkManagement Service,Notification Manager 等,当然也包括 Location Service。 SystemServer.java [frameworks\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 服务的代码段如下: 2.1 版本 try { Log.i(TAG, "Location Manager"); ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context)); } catch (Throwable e) { Log.e(TAG, "Failure starting Location Manager", e); } 2.2 的代码中代码段如下形式: 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 在 run 函数的后半部分,是服务对系统的反馈,就是 systemReady()函数。 LocationManager 服务的反馈函数如下: if (locationF != null) locationF.systemReady(); 其中的 locationF 是 LocationManagerService 的 final 类型,就是一旦赋值,不能 更改。 final LocationManagerService locationF = location; 哇!locationManager 这项服务的反馈机制只在 2.2 的代码里面才有啊。2.1 中的 反馈机制中并没有 locationManager(当然有其他的服务反馈)。 而在 2.1 版本中 LocationManagerService 的构造函数如下: LocationManagerService.java [frameworks\base\services\java\com\android\server] public LocationManagerService(Context context) { super(); mContext = context; Thread thread = new Thread(null, this, "LocationManagerService"); thread.start(); if (LOCAL_LOGV) { Log.v(TAG, "Constructed LocationManager Service"); } } 2.2 版本 public LocationManagerService(Context context) { super();

mContext = context; if (LOCAL_LOGV) { Slog.v(TAG, "Constructed LocationManager Service"); } } 2.1 是在构造函数的时候就启动一个自身服务线程。见构造函数。 2.2 是在反馈机制中通过 systemReady 函数启动自身服务线程。如下: void systemReady() { // we defer starting up the service until the system is ready Thread thread = new Thread(null, this, "LocationManagerService"); thread.start(); } 通过线程 run 函数,调用 initialize 函数: public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUN D); Looper.prepare(); mLocationHandler = new LocationWorkerHandler(); initialize(); Looper.loop(); } 发表于: 2010-12-22,修改于: 2010-12-24 09:37,

架构分析( Android GPS 架构分析(二)

Android GPS 架构分析
Daniel Wood 20101222

转载时请注明出处和作者

文章出处:http://danielwood.cublog.cn 作者:Daniel Wood -----------------------------------------------------------initialize 函数 LocationManagerService.java[frameworks\base\services\java\com\andro id\server] 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(); ... initialize 函数中最重要的就是 loadProviders 函数了,该函数调用 loadProvidersLocked,然后 loadProvidersLocked 函数又调用 _loadProvidersLocked 函数。为什么要这么折腾呢? 先来看一部分的_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; } ... 注意这个 if 语句,狠重要,因为在这个语句中得到了 HAL 层的 GPS 接口
GpsInterface。就是通过调用 GpsLocationProvider 的 isSupported()函数才调用到 gps.cpp[hardware/libhardware_legacy/gps]中的 gps_get_interface()。 这个 isSupported 函数才是第一个吃螃蟹的人。(而不是 JNI 层的 init 函数,这个下面会提到)。

GpsLocationProvider.cpp
[frameworks\base\location\java\com\android\internal\location]

public static boolean isSupported() { return native_is_supported(); } 然而 isSupported 只有一句话,果然是高手,一击必中。然后就调用 native 方 法,也就是 JNI 层定义的方法。native_is_supported 函数对于 JNI 层是 android_location_GpsLocationProvider_is_supported 方法。 android_location_GpsLocationProvider.cpp [frameworks\base\core\jni] static jboolean 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] const GpsInterface* gps_get_interface() { if (sGpsInterface == NULL) gps_find_hardware(); return sGpsInterface; } 然后通过 gps_find_hardware 函数去得到 gps 接口,下面只模拟器中的 gpsinterface。 static void gps_find_hardware( void ) { #ifdef HAVE_QEMU_GPS_HARDWARE if (qemu_check()) { sGpsInterface = gps_get_qemu_interface(); if (sGpsInterface) { LOGD("using QEMU GPS Hardware emulation\n"); return; } } #endif #ifdef HAVE_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]

const GpsInterface* gps_get_qemu_interface() { return &qemuGpsInterface; } qemuGpsInterface 的整体实现就在文件 gps_qemu.c 中。 static const GpsInterface 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, }; 发表于: 2010-12-22,修改于: 2010-12-24 10:42,已浏览 574 次,

架构分析( Android GPS 架构分析(三)

Android GPS 架构分析
Daniel Wood 20101222

转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ------------------------------------------------------------------------------在底层得到 gps 的接口之后, if (GpsLocationProvider.isSupported())(在文件 LocationManagerService.java 中调用)语句得到 true,然后进行下一步操作,在这 里 new 了一个 GpsLocationProvider 对象。代码如下: 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); ... } 在 GpsLocationProvider 类里面的成员变量 mLocationManager 是构造函数的 第二个参数,就是说是 LocationManagerService 对象。这一点在这里先明确。 接着看_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

Resources resources = mContext.getResources(); String serviceName = resources.getString( com.android.internal.R.string.config_networkLocatio nProvider); if (serviceName != null) { mNetworkLocationProvider = new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER, serviceName, mLocationHandler); addProvider(mNetworkLocationProvider); } serviceName = resources.getString(com.android.internal.R.string.config_geocodePro vider); if (serviceName != null) { mGeocodeProvider = new GeocoderProxy(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]

<!-- Component name of the service providing network location support. --> <string name="config_networkLocationProvider">@null</string> <!-- Component name of the service providing geocoder API support. --> <string name="config_geocodeProvider">@null</string> 其实这也导致了, 在调用 GetFromLocationName 和 GetFromLocation 两个函数时 提示“Service not Available”,这个 google Android 2.2 的 bug。 _loadProvidersLocked 函数的最后一句是调用 updateProvidersLocked 函数,仍 然在 LocationManagerServic.java 文件中。 LocationManagerServic.java private void updateProvidersLocked() { 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); } else if (!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 不做分析。 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) { //enabled 的值是 true p.enable(); if (listeners > 0) { p.setMinTime(getMinTimeLocked(provider)); p.enableLocationTracking(true); } } else { p.enableLocationTracking(false); p.disable(); } } 我们只关注主体部分代码,就是在 if(enabled)这个语句段里面,启动了 gps 的 服务,具体将在下一篇进行分析。 发表于: 2010-12-24,修改于: 2010-12-24 13:29,已浏览 852 次,有评论 5 条

架构分析( Android GPS 架构分析(四)

Android GPS 架构分析
Daniel Wood 20101224

转载时请注明出处和作者

文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ------------------------------------------------------------------------------通过调用 GpsLocationProvider 类的 enable 和 enableLocationTracking 函数就把 GPS
的 LocationManager 服务启动起来了。下面对这两个函数进行分析。

首先是 enable 函数。
GpsLocationProvider.java

public void enable() { synchronized (mHandler) { mHandler.removeMessages(ENABLE); Message m = Message.obtain(mHandler, ENABLE); m.arg1 = 1; mHandler.sendMessage(m); } } 对了,这个要提一点,在 2.2 中加入了一个 ProviderHandler 类(extends Handler),这个在 2.1 中是没有的,其实是换汤不换药的,对于函数调用的过 程来说没有本质的改变。对于 Handler 的机制我还没有研究过。 public void handleMessage(Message msg) { switch (msg.what) { case ENABLE: if (msg.arg1 == 1) { handleEnable(); } else { handleDisable(); } break; case ENABLE_TRACKING: handleEnableLocationTracking(msg.arg1 == 1);

break; ... 在 handleMessage 函数中,定义了各种 message 对应的处理函数。对于 ENABLE 消息还带有一个参数, enable 函数里面带的参数值为 1, 所以调用 handleEnable 函数。 private void handleEnable() { if (DEBUG) Log.d(TAG, "handleEnable"); if (mEnabled) return; mEnabled = native_init(); if (mEnabled) { if (mSuplServerHost != null) { native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); } if (mC2KServerHost != null) { native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); } // run event listener thread while we are enabled mEventThread = new GpsEventThread(); mEventThread.start(); } else { Log.w(TAG, "Failed to enable location provider"); } } 在 handleEnable 函数中中主要做了 3 件事,不过有一件事情没有做成。先来看看哪
三件事: 1)调用了 native 的初始化方法对 gps 进行初始化, 2)试图启动 agps 服务,

3)并启动一个线程去监听事件。 先 来说说它没有做成的第二件事,启动 agps 服务。其实在 GpsLocationProvider 类构 造的时候就试图去读取 agps 的配置文件"/etc /gps.conf",该文件里面储存着 agps 的 服务器地址以及端口号,但是服务器地址以及端口号都是错误的,所以它基本上无法启 动 agps 服务,而且 对模拟器来说 agps 基本是个鸡肋。关于 agps 部分可能在以后的以 后会提到。下面看它做成的第一和第三件事。 1)调用 native 方法 native_init,就是 JNI 层的

android_location_GpsLocationProvider_init 方法,在文件 andoird_location_GpsLocationProvider.cpp 中。 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) { if (!sGpsInterface) sGpsInterface = gps_get_interface(); if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) return false; ... return true; }

在初始化函数中会去确认 GpsInterface 是否已经得到,如果没有得到那么通过 gps_get_interface()方法再次去得到,正如其实前面提到的那样该接口已经在 android_location_GpsLocationProvider_is_supported 函数 (第一个吃螃蟹的人) 中得到了。 然后在第二个 if 语句中调用初始化方法 sGpsInterface->init。

android_location_GpsLocationProvider_init 的后半部分,试图通过
GpsInterface->get_extension 方法去得到 gps 相关的扩展接口,可是在 2.2 的模拟器实现 中并没有实现这个函数,在 gps_qume.c 中明显写着 return NULL。 gps_qume.c

static const void*

qemu_gps_get_extension(const char* name) { return NULL; } 言归正传,分析 sGpsInterface->init 方法。
gps_qume.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; } 在 sGpsInterface->init 中,也就是在 qemu_gps_init 方法,首先调用了 gps_state_init,其次注册了回调函数,再说一次,这个回调函数就是在 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 = 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)); 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 通信,然后建 立线程监听底层数据上报,分别对应于代码中黄低部分。 3)建立线程监听事件

mEventThread = new GpsEventThread(); mEventThread.start(); 来看看 GpsEventThread 的 run 函数。 public void run() { 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 数据)。这个 在后面还会 讲到。 static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj) { pthread_mutex_lock(&sEventMutex); while (sPendingCallbacks == 0) { pthread_cond_wait(&sEventCond, &sEventMutex); }

... } 发表于: 2010-12-24,修改于: 2010-12-24 14:19,

Android GPS 架构分析(五) 架构分析(

Android GPS 架构分析
Daniel Wood 20101224

转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ------------------------------------------------------------------------------分析完了 enable 函数以后就轮到 enableLocationTracking 函数了。
GpsLocationProvider.java

public void enableLocationTracking(boolean enable) { synchronized (mHandler) { mHandler.removeMessages(ENABLE_TRACKING); Message m = Message.obtain(mHandler, ENABLE_TRACKING); m.arg1 = (enable ? 1 : 0); mHandler.sendMessage(m); } } 同样地,也采取 Handler 的方式。调用的是 handleEnableLocationTracking 函 数。 private void handleEnableLocationTracking(boolean enable) { if (enable) { mTTFF = 0; mLastFixTime = 0; startNavigating(); } else { mAlarmManager.cancel(mWakeupIntent);

mAlarmManager.cancel(mTimeoutIntent); stopNavigating(); } } 调用 startNavigating 函数。 private void startNavigating() { if (!mStarted) { if (DEBUG) Log.d(TAG, "startNavigating"); mStarted = true; int positionMode; 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 static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode, jboolean singleFix, jint fixFrequency) { int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency)); if (result) { return false; } return (sGpsInterface->start() == 0); }
接下去就会调用 sGpsInterface 接口的实现 gps_qemu.c 中具体实现的函数。

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; } 通过向底层发送命令,CMD_START 来启动 gps。其实这个所谓的底层就是在 enable/init 函数中启动的等待数据的线程。 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)); } 数据监听线程 static void* gps_state_thread( void* arg ) { ... // now loop for (;;) { ... 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) { ... } 其实就是注册了一个回调函数,location_cb 这个回调函数就是对底层 location 数据上报的回调函数。 在 enableLocationTracking 函数调用完成以后,基本上 gps 服务已经启动 完成了,也就是 LocationManagerService 中的 updateProvidersLocked 函数的 完成,也就是 loadProviders 函数的完 成,也就是 initialize 函数的完成,也 就是 run 函数的完成,也就是 2.2 中反馈机制 systemReady 的完成。 void systemReady() { // we defer starting up the service until the system is ready Thread thread = new Thread(null, this, "LocationManagerService"); thread.start(); } 发表于: 2010-12-24,修改于: 2010-12-24 14:49

GpsLocationProvider 中的消息处理机制

GpsLocationProvider 中的消息处理机制
Daniel Wood 20110129 转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ----------------------------------------------------------------------GpsLocationProvider.java 文件是连接 framew 层和 JNI 本地代码的纽带,其中 有两个线程,分别为 GpsEventThread 和 GpsLocationProviderThread。 GpsEventThread 线程是用来处理底层事件触发的,GpsLocationProviderThread 是用来处理上层对底层消息命令的。今天就分析这个线程,顺便讲讲 Android 的 Looper 消息处理机制。

GpsLocationProviderThread 线程的启动是在 GpsLocationProvider 的构造函数 里,代码如下: mThread = new GpsLocationProviderThread(); mThread.start(); 我们来看看它的 run 函数。 public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKG ROUND); initialize(); Looper.prepare(); mHandler = new ProviderHandler(); // signal when we are initialized and ready to go mInitializedLatch.countDown(); Looper.loop(); } run 函数第一句指定了这个线程是后台运行的线程。 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); } initialize 函数,只是注册了一个 BroadcastReciever。 然后调用 Looper.prepare();prepare()是 Looper 的 static 函数,所以可以直 接通过类名来调用,基础知识狠重要。

public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } 在 prepare()函数里面首先判断 sThreadLocal.get 是否为空,你没有 set 直 接 get 当然为空。 然后通过 sThreadLocatl 的 set 方法调用 Looper 的构造函数。 private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } 每一个 Looper 都有一个属于自己的消息队列,就是 MessageQueue,就是其内部 成员变量 mQueue。而且每个线程只能有一个 Looper。然后通过 Thread.currentThread()返回当前的线程。 在 Looper 的 prepare 函数调用完了以后就新建一个 Handle 来分发和处理,消息 队列中的消息。 mHandler = new ProviderHandler(); 在哪个线程中,创建 Handler,那个创建的 Handler 就和哪个线程的消息队列绑 定了,不过在非主线程中创建 Handler 需要先调用 Looper.prepaer()函数,上 例就是这种情况。 我们来看一下 ProviderHandler 的构造函数,发现 ProviderHandler 是继承自 Handler,自己没有构造函数,当然调用父类 Handler 的构造函数,并且是无参数 构造函数。 public Handler() { if (FIND_POTENTIAL_LEAKS) {

final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; } FIND_POTENTIAL_LEAKS 的值为 false,所以前面的 if 语句块我们不管它。然后 它调用 Looper 的 myLooper 函数。通过这个函数可以获得当前的 Looper 对象。 /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get();

} 然后通过得到的 Looper 对象,将 Handler 中的消息队列赋值,Handler 是用来 处理消息的,当然会有一个消息队列。可见 Handler 和 Looper 两者的消息队列 指的是同一个消息队列,当然和线程(GpsLocationProviderThread)的消息队列 也是同一个。 创建完 Handler 之后,调用 Looper.loop();函数,进入消息循环。 /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //}

if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me. null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what );

msg.target.dispatchMessage(msg); if (me. null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } } loop 函数是个死循环, 一直从消息队列 mQueue 中获取消息 queue.next(), 然后交 给 msg.target 进行消息的处理,这里的 msg.target 当然是那个 Handler (ProviderHandler)。 我们来举个例子,看看具体是如何进程消息处理的。上层 LocationMangerService 调用 GPSLocationProvider 的 enable 函数,(具体如何调用可以参考其他文章) public void enable() { synchronized (mHandler) { mHandler.removeMessages(ENABLE); Message m = Message.obtain(mHandler, ENABLE); m.arg1 = 1; mHandler.sendMessage(m); } }

首先从 mHandler 的消息移除 ENABLE 这个消息,这个不管。然后调用 Message 的 static 方法 obtain(mHandler, ENABLE)。 public static Message obtain(Handler h, int what) { Message m = obtain(); m.target = h; m.what = what;

return m; }

public static Message obtain() { synchronized (mPoolSync) { if (mPool != null) { Message m = mPool; mPool = m.next; m.next = null; return m; } } return new Message(); }

通过 Message 的 obtain 方法可以创建一个 Message,并且指定它的 target 为 mHandler。 然后通过 mHandler 的 sendMessage 方法将这个消息 Message 放入到消息队列中 去。(代码略) 下面就是 Looper.loop 这个函数, 不是一直从消息队列里面取消息然后分发给消 息的 target 去处理吗? msg.target.dispatchMessage(msg); 来看看 mHandler 的 dispatchMessage 函数,ProviderHandler 当然没有也不需要实 现了,它只实现了消息处理函数 handleMessage,而 dispatchMessage 函数最终调 用的也是 handleMessage 函数去处理,ENABLE 这个消息。 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else {

if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 处理函数为 handleMessage 中的第一个 switch 语句。 public void handleMessage(Message msg) { switch (msg.what) { case ENABLE: if (msg.arg1 == 1) { handleEnable(); } else { handleDisable(); } ... }

至此,从 GpsLocationProvider 的消息处理上面,我们就可以看到整个 Android 的消息处理过程。 明天放假了,还有 4 分钟下班,时间相当仓促,不足之处,忘见谅。 发表于: 2011-01-29,修改于: 2011-01-29 16:57


相关文章:
更多相关标签: