Chinaunix首页 | 论坛 | 博客
  • 博客访问: 228684
  • 博文数量: 29
  • 博客积分: 1477
  • 博客等级: 上尉
  • 技术积分: 451
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-06 14:48
文章分类
文章存档

2012年(1)

2011年(14)

2010年(14)

我的朋友

分类: 嵌入式

2010-12-24 13:26:38

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);
    }
...
}


阅读(3914) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2011-05-31 17:59:37

我遇到了和一楼同样的问题。

chinaunix网友2011-04-28 12:56:33

博主 你好 我用GPS接收模块,串口是R232,接到开发板上 但一点反应都没有 在PC机试过 能打印出来一些信息 求解 谢谢!