zoukankan      html  css  js  c++  java
  • <Android> Location Service 分析

      由于各种原因,老师希望我学习Android系统源码以应对可能参与的项目。我只好深入曹营,刺探军情了。

      定位服务是手机上最常用的功能之一,据说也是相对比较简单的服务,所以从这里入手。其他系统服务的架构都是类似的。明白其中一个之后,再去理解其他的会容易得多。下面以 Android 源码为基础,大致分析了 Android 系统中定位服务的架构和实现。版本是6.0.1。

    一. 应用层:
    1.在App中调用位置服务

    在Android App中使用定位服务,要先向系统请求一个LocationManager实例,
    LocationManager mLocationManager = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);

    然后用Criteria对其进行设置,获取一个provider,provider有3种基本定位类型 network/gps/passive
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    ...
    String provider = mLocationManager.getBestProvider(criteria, true);

    (1)LocationManager利用provider直接获取一个最新的位置信息
    Location location = mLocationManager.getLastKnownLocation(provider);

    (2)使用事件绑定的方式,获取更新的位置信息
    LocationListener{
     ...
     public void onLocationChanged(Location location)
    }

    二.框架层
    2.LocationManager类的实现(/frameworks/base/location/java/android/location/LocationManager.java)
    其代码的主要作用是访问系统位置服务LocationManagerService
    关键成员
    private final ILocationManager mService;

    构造器
    public LocationManager(Context context, ILocationManager service);
    ILocationManager与系统服务通信的接口

    mService=Service;

    如getProviders方法,实际是通过mService成员请求系统服务响应这个方法

    public List<String> getProviders(boolean enabledOnly) {
     ...
     return mService.getProviders(null, enabledOnly);
    }


    3.接口定义(/frameworks/base/location/java/android/location/ILocationManager.aidl)
    通过aidl定义通信接口,与系统位置服务进行进程间通信icp(涉及binder)


    4.LocationManagerService的实现(/frameworks/base/services/core/java/com/android/server/LocationManagerService.java)
    系统位置服务的实现,包括实现LocationManager调用的接口


    public List<String> getProviders(Criteria criteria, boolean enabledOnly)
    public Location getLastLocation(LocationRequest request, String packageName)
    ...

    在LocationManagerService中主要是有两种定位方式,一种通过网络,一种通过GPS模块。通过GPS模块定位的是GpsLocationProvider。


    5.GpsLocationProvider(frameworks/base/services/core/java/com/android/server/location/GpsLocationProvider.java)

    核心的涉及定位的方法是native的,通过JNI与HAL层C++语言函数交互

    如这个注入一条位置信息的函数,接下来主要以他为线索。
    private native void native_inject_location(double latitude, double longitude, float accuracy);

     三、硬件抽象层(HAL)
    6.GpsLocationProvider 本地方法在HAL层的实现(/frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp)
    #include "hardware/hardware.h"
    #include "hardware/gps.h"     //这里的hardware目录为/hardware/libhardware/include/hardware/
    ...

    上面第5点中native_inject_location方法对应的实现

    static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
            jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
    {
        if (sGpsInterface)
            sGpsInterface->inject_location(latitude, longitude, accuracy);
    }
    可以看出这里是通过sGpsInterface调用下一层函数去实现,他是一个GpsInterface结构体指针,
    static const GpsInterface* sGpsInterface = NULL;

    GpsInterface结构体定义在gps.h

    结构体包含函数指针,则sGpsInterface引用的实例包含函数的具体实现
        err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
        if (err == 0) {
            hw_device_t* device;
            err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
            if (err == 0) {
                gps_device_t* gps_device = (gps_device_t *)device;

        //在这里获得了device提供的具体的sGpsInterface
                sGpsInterface = gps_device->get_gps_interface(gps_device);
            }
        }


    7.上面提到的gps.h(/hardware/libhardware/include/hardware/gps.h)

    GpsInterface的定义

    typedef struct {
        ...
        /** 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);

        ...
    } GpsInterface;

    四、高通的一个实现

    硬件厂商主要的工作室引用gps.h, 实现一个gps.c,把GpsInterface等内容实现了。这里分析一下高通的一个实现。
    8.gps.c(/hardware/qcom/gps/loc_api/libloc_api_50001/gps.c)
    #include <hardware/gps.h>
    ...
    extern const GpsInterface* get_gps_interface();  //外部函数

    const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
    {
        return get_gps_interface();         
        //在高通的实现中,第6点中的gps_device->get_gps_interface()调用的函数来自于此,此处
        //返回的函数指针是一个外部函数,该外部函数实际在9.2中实现
    }
    ...

    //dev结构体
    struct gps_device_t *dev = (struct gps_device_t *) malloc(sizeof(struct gps_device_t));
    ...

    //给dev结构体get_gps_interface的函数指针指向前面高通实现的函数。
    dev->get_gps_interface = gps__get_gps_interface;

    9.loc.cpp(/hardware/qcom/gps/loc_api/libloc_api_50001/loc.cpp)
    9.1
    //这里定义的静态函数,供同一个文件里的sLocEngInterface使用
    static int  loc_init(GpsCallbacks* callbacks);
    static int  loc_start();
    static int  loc_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty);
    static int  loc_inject_location(double latitude, double longitude, float accuracy);
    ...

    //在gps.h中的GpsInterface,在这里被实现成了sLocEngInterface
    static const GpsInterface sLocEngInterface =
    {
       sizeof(GpsInterface),
       loc_init,
       loc_start,
       loc_inject_time,
       loc_inject_location,      
       ...
    };


    9.2
    // for gps.c
    extern "C" const GpsInterface* get_gps_interface(){
        ...
    }

    9.3

    这个文件里的静态函数的具体实现
    static int loc_inject_location(double latitude, double longitude, float accuracy)
    {
        ENTRY_LOG();

        int ret_val = 0;
        ret_val = loc_eng_inject_location(loc_afw_data, latitude, longitude, accuracy);

      //这里又是依靠调用其它函数,还要继续深挖到 loc_eng,在第10点

        EXIT_LOG(%d, ret_val);
        return ret_val;
    }

    10.loc_eng.cpp(/hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp)
    int loc_eng_inject_location(loc_eng_data_s_type &loc_eng_data, double latitude,
                                double longitude, float accuracy)
    {
        ENTRY_LOG_CALLFLOW();
        INIT_CHECK(loc_eng_data.adapter, return -1);
        LocEngAdapter* adapter = loc_eng_data.adapter;
        if(adapter->mSupportsPositionInjection)
        {
            adapter->sendMsg(new LocEngInjectLocation(adapter, latitude, longitude,
                                                      accuracy));

        //这里发出了消息
        }

        EXIT_LOG(%d, 0);
        return 0;
    }

    再往下就得是Linux kernel里面GPS模块的写的驱动程序了,应该通过UART,传送基本的数据和控制命令,我就没去看了。。。

    第一次看Android源码,简单分析,水平有限,如有错漏,还请包涵。

  • 相关阅读:
    JDBC连接各种数据库的字符串,就是不好记
    HTTP协议详解
    gson 简要使用
    maven 仓库地址:
    HTTP请求头详解
    HTTP协议---HTTP请求中的常用请求字段和HTTP的响应状态码及响应头
    如何终止java线程
    oracle 函数大全及运算符
    Java集合的线程安全用法
    哈希算法快速查表的原理
  • 原文地址:https://www.cnblogs.com/aureate-sunshine/p/5520207.html
Copyright © 2011-2022 走看看