Android GPS架构分析(转载一)


Android GPS架构分析

来源:Linux社区  作者:Daniel Wood            

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;

介绍完了主体代码结构以及重要的数据结构后,下面来看看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();

其中的locationFLocationManagerServicefinal类型,就是一旦赋值,不能更改。

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_BACKGROUND);
        Looper.prepare();
        mLocationHandler = new LocationWorkerHandler();
        initialize();
        Looper.loop();
}


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<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”,这个googleAndroid 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的服务,具体将在下一篇进行分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值