看Android的GPS模块有两个月了吧,终于可以写点东西出来。首先来看看GPS模块的代码结构: 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:
frameworks/base/core/jni/android_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中。

/** 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

表示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;


initialize函数

LocationManagerService.java[frameworks/base/services/java/com/android/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。就是通过调用GpsLocationProviderisSupported()函数才调用到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,
};


--------------------------------------------------------------------------------

在底层得到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_networkLocationProvider);
        if (serviceName != null) {
            mNetworkLocationProvider =
                new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
                        serviceName, mLocationHandler);
            addProvider(mNetworkLocationProvider);
        }
        serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
        if (serviceName != null) {
            mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
        }
        updateProvidersLocked();
    }

在构造完GpsLocationProvider之后将其add到全局变量ArrayList 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不做分析。


言归正传,分析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);
    }
...
}



分析完了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

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




更多相关文章

  1. C语言函数以及函数的使用
  2. Android call setting 源码分析 从顶层到底层(下)
  3. android底层开发-android基础架构
  4. Android OpenGL ES学习笔记之实现OpenGL ES接口
  5. Android支付宝接口集成
  6. Android’s HTTP Clients(Android的HTTP客户端接口)
  7. 【Android】_MyContentProvider_外部访问接口
  8. android底层的学习
  9. android NDK JNI设置自己的log输出函数

随机推荐

  1. Android padding
  2. Android面试系列文章2018之内存管理之Bit
  3. android的路径问题
  4. Android测试总结
  5. Android开发心得
  6. Android Widget添加自定义控件
  7. android基础进度条原理
  8. xorg-server-1.12.1 for android done--x
  9. Android中 判断是平板还是手机
  10. android解析plist文件