Android GPS架构分析(转载二)
来源:互联网 发布:计算机c语言程序 编辑:程序博客网 时间:2024/05/18 15:52
Android GPS架构分析
来源:Linux社区 作者:Daniel Wood
首先是enable函数。
GpsLocationProvider.java
public void enable() {
synchronized (mHandler) {
mHandler.removeMessages(ENABLE);
Message m = Message.obtain(mHandler, ENABLE);
m.arg1 = 1;
mHandler.sendMessage(m);
}
}
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;
...
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;
}
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();
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);
}
...
}
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();
}
}
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);
}
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));
}
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();
}
Gps启动过程图(基于Google Android 2.2代码)
下面再贴一张从GoogleI/O大会文档里面截来的图
完了 感谢作者 Daniel Wood
- Android GPS架构分析(转载二)
- Android GPS架构分析(转载一)
- Android GPS架构分析(二)
- Android GPS架构分析(二)
- Android GPS架构分析(二)
- Android GPS架构分析<二>
- Android GPS架构分析之二
- Android GPS架构分析
- Android GPS架构分析
- Android GPS架构分析
- Android GPS架构分析
- Android GPS架构分析
- Android GPS架构分析(gps启动过程图)
- Android GPS架构分析(gps启动过程图)
- Android GPS架构分析(gps启动过程图)
- Android GPS架构分析(gps启动过程图)
- Android GPS架构分析(一)
- Android GPS架构分析(三)
- classification rules
- 单片机和工业无线网络
- 《Java编程思想》之内部类——深奥而复杂
- 第八周实验报告
- 软件大赛题目----(第九个)求牛的数目
- Android GPS架构分析(转载二)
- Linux下批量杀掉 包含某个关键字的 程序进程
- vim使用
- 终于自己学会做一个简单的人事管理系统软件了,做个纪念
- [Book Mark] 常用技术网站链接
- 使用cpufreq-bench评估cpufreq策略对系统性能的影响
- 《Java编程思想》之为什么需要内部类?
- 又要重新思考了
- PUCCH