LocationService中GPS定位实现研究

      LocationService即Android系统服务中的定位服务,其运行于系统进程中,APP要使用其实用到了Binder进程间通信机制,不过APP使用时,直接使用的是LocationManager对象,APP基本感觉不到Binder的存在,这是因为LocationManager中封装了Binder通信实现.
      Binder进程间通信是Android的标准框架,使用模式固定,比较简单,故略过.本文主要偏向于JNI层的实现及JNI层与HAL层的通信.
      除开应用层,整个服务其实分为四层:JAVA层、JNI层、HAL层、硬件层,其中JAVA层通过JNI层实现与HAL层的通信,HAL层采用高通的RPC协议与硬件通信.
     
一、首先,讲一下后面分析要用到的基础
1.相关源代码
   HAL层所涉及到的主要代码:gps.h gps.c hardware.h loc_eng.cpp loc_api_rpc_glue.cpp loc_apicb_appinit.c
    与HAL层通信的JNI层代码:GpsLocationProvider.cpp
    与JNI对应的JAVA代码:GpsLocationProvider.java
    Service实现代码:LocationManagerServicer.java
    应用层与Service通讯的代码:LocationManager.java
     
2.gps.h里面定义了两个非常重要的结构体:

/** GPS callback structure. */
typedef struct {
    /** set to sizeof(GpsCallbacks) */
    size_t      size;
    gps_location_callback location_cb;
    gps_status_callback status_cb;
    gps_sv_status_callback sv_status_cb;
    gps_nmea_callback nmea_cb;
    gps_set_capabilities set_capabilities_cb;
    gps_acquire_wakelock acquire_wakelock_cb;
    gps_release_wakelock release_wakelock_cb;
    gps_create_thread create_thread_cb;
    gps_request_utc_time request_utc_time_cb;
} GpsCallbacks;


/** Represents the standard GPS interface. */
typedef struct {
    /** set to sizeof(GpsInterface) */
    size_t          size;
    /**
     * 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);

    /**
     * min_interval represents the time between fixes in milliseconds.
     * preferred_accuracy represents the requested fix accuracy in meters.
     * preferred_time represents the requested time to first fix in milliseconds.
     */
    int   (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
            uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);

    /** Get a pointer to extension information. */
    const void* (*get_extension)(const char* name);
} GpsInterface;


GpsCallbacks这个结构体里成员变量基本上都是函数指针,
具体的实现都在GpsLocationProvider.cpp中,这些函数指针变量最终会赋给HAL层,供HAL层回调,见GpsLocationProvider.cpp里第138行:
GpsCallbacks sGpsCallbacks = {
    sizeof(GpsCallbacks),
    location_callback,
    status_callback,
    sv_status_callback,
    nmea_callback,
    set_capabilities_callback,
    acquire_wakelock_callback,
    release_wakelock_callback,
    create_thread_callback,
    request_utc_time_callback,
};


sGpsCallbacks是一个全局变量,结构体在初始化时就对各个变量进行了赋值,各成员变量的值为GpsLocationProvider.cpp
里的一些函数,此变量通过GpsInterface里的(*init)( GpsCallbacks* callbacks )函数传递给HAL层,
见GpsLocationProvider.cpp里第287行:
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
       return false;


GpsInterface这个结构体也有一堆函数指针成员变量,这个结构体是在HAL层实现的,主要作用是给JNI层调用,达到
JNI向HAL层传递信息的作用;sGpsInterface是在初始化时取到的,下面会讲到.

3.综合起来说:GpsInterface与GpsInterface达到了JNI层与HAL层交互的目的,分别实现JNI层操作HAL层及HAL层往JNI层传递数据的作用,
比如:JNI层通过调用GpsInterface里的(*start)( void ),这个函数告诉HAL层启动定位,而HAL层通过location_callback向JNI层传递GPS位置信息


二、初始化与启动
    Service里的Java层,JNI层与HAL层,都是运行在一个进程中的,Service启动时会进行一系列初始化工作,比如启动服务Looper线程、HAL层的工作线程等等
1.入口函数
  系统进程随开机启动,会自动调用Location服务的systemReady()函数来启动定位服务线程,见SystemServer.java第946行:
   
try {
        if (locationF != null) locationF.systemReady();
    } catch (Throwable e) {
        reportWtf("making Location Service ready", e);
    }

  此处locationF即为LocationManagerService的实例.
 
2.入口函数LocationManagerService.systemReady()的作用
   此函数很简单,开始了一个线程并建立消息循环及执行init()函数,见LocationManagerService.java第199行:
  @Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Looper.prepare();
        mLocationHandler = new LocationWorkerHandler();
        init();
        Looper.loop();
    }

  重点在init()函数里,此函数里调用了两个非常重要的函数:
  loadProvidersLocked();与updateProvidersLocked();
  分别见LocationManagerService.java的219行与252行
 
3. loadProvidersLocked()函数作用
   加载各种Provider,最重要的一项就是创建GpsLocationProvider对象,见LocationManagerService.java的330行:
 if (GpsLocationProvider.isSupported()) {
        // Create a gps location provider
        GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
        mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
        mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
        addProviderLocked(gpsProvider);
        mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
   }

   GpsLocationProvider里与JNI层进行了交互,GpsLocationProvider承担了GPS定位的主要的工作.
   mGpsStatusProvider是GPS模块向上层提供的一个窗口,可以add与remove IGpsStatusListener接口,而此接口在APP层对应GpsStatus.Listener接口即GPS状态监听器
   mNetInitiatedListener用来初始化网络监听
  
   GpsLocationProvider.java里有一段static代码,执行了class_init_native()函数,在此函数中获取了HAL层开放给上层的GpsInterface接口,
   见GpsLocationProvider.java的1606行:
  
static { class_init_native(); }
  
   class_init_native()函数对应JNI函数即GpsLocationProvider.cpp里的android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz)
   此函数还有一个重要作用,即提取出GpsLocationProvider.java里部分函数的id,当HAL层通知消息给JNI层时,JNI层再通过调用这些函数通知上层
  
4.updateProvidersLocked()函数
  此函数在切换用户的时候也会被调用,最重要的作用是调用GpsLocationProvider.java的enable()与disable()函数
  而enable()最终调用了native_init()函数与native_supports_xtra()函数、
  disable()最终调用了 native_stop()函数native_cleanup()函数
 
  native_init()是非常重要的函数,对应于JNI函数:android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
  它将GpsCallbacks传给了HAL层
  即上面提到的一段代码:
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
 
5.loc_eng_init()函数
  此函数由native_init()调用,位于loc_eng.cpp的第177行
  因为native_init()实际上是GpsLocationProvider.cpp中的android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)函数,android_location_GpsLocationProvider_init中调用了sGpsInterface->init(&sGpsCallbacks),而sGpsInterface变量是由loadProvidersLocked()函数执行而得到的,
所以找到了sGpsInterface变量的由来,就知道为什么sGpsInterface->init实际上是loc_eng.cpp的loc_eng_init()函数
 
  从第3条的分析得知,loadProvidersLocked()最终会调用到
  android_location_GpsLocationProvider_class_init_native()函数,里面最重要的一段,见GpsLocationProvider.cpp第253行:
  
  
 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;
            sGpsInterface = gps_device->get_gps_interface(gps_device);
        }
    }


    其中hw_get_module函数是从lib动态库中获取到gps模块的hw_module_t变量,这块属于HAL框架,先不管是怎么取到的,
    先看看hw_module_t变量在哪里设置的,见gps.c里的第60行:
   
const struct hw_module_t HAL_MODULE_INFO_SYM = {
      .tag = HARDWARE_MODULE_TAG,
      .version_major = 1,
      .version_minor = 0,
      .id = GPS_HARDWARE_MODULE_ID,
      .name = "loc_api GPS Module",
      .author = "Qualcomm USA, Inc.",
      .methods = &gps_module_methods,
     };
   
  HAL_MODULE_INFO_SYM这个变量即为hw_module_t结构体的实例,再看这段代码:
 
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);

这里调用了hw_module_t里的methods结构体里的open函数,
  methods结构体值为gps_module_methods,见gps.c的56行:
 
static struct hw_module_methods_t gps_module_methods = {
    .open = open_gps
  };

  其中的open函数指针指向了open_gps函数, 即module->methods->open实际上调用的是open_gps()函数,定义见gps.c的第41行:
 
static int open_gps(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)
  {
    struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
    memset(dev, 0, sizeof(*dev));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t*)module;
    dev->get_gps_interface = gps__get_gps_interface;

    *device = (struct hw_device_t*)dev;
    return 0;
  }

 
  重点为这句:
 
dev->get_gps_interface = gps__get_gps_interface;
 
再回过头去分析
sGpsInterface = gps_device->get_gps_interface(gps_device);

  可知sGpsInterface的值为gps__get_gps_interface函数所返回的值,gps__get_gps_interface定义在gps.c的第36行:
 
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
  {
    return get_gps_interface();
  }

  而get_gps_interface()函数的定义在loc_eng.cpp的第1530行:
 
extern "C" const GpsInterface* get_gps_interface()
  {
    return &sLocEngInterface;
  }

  再看sLocEngInterface的定义,loc_eng.cpp的第97行:
 
static const GpsInterface sLocEngInterface =
  {
    sizeof(GpsInterface),
    loc_eng_init,
    loc_eng_start,
    loc_eng_stop,
    loc_eng_cleanup,
    loc_eng_inject_time,
    loc_eng_inject_location,
    loc_eng_delete_aiding_data,
    loc_eng_set_position_mode,
    loc_eng_get_extension,
  };

  结合GpsInterface的声明,最终找到了loc_eng_init()函数即为sGpsInterface->init(&sGpsCallbacks)中的init
 
  loc_eng_init()里作了什么呢?
  最重要的就是调了函数
  loc_api_glue_init()与sGpsCallbacks的函数create_thread_callback;

  loc_api_glue_init()位于loc_api_rpc_glue.c的第158行
 
  create_thread_callback函数在GpsLocationProvider.cpp里第133行:
 
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
  {
    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
  }

  很明显是启动了一个线程,start为线程执行的函数,此参为在loc_eng_init()里传入,见loc_eng.cpp第236行:
 
loc_eng_data.deferred_action_thread = callbacks->create_thread_cb("loc_api",loc_eng_process_deferred_action, NULL);
 
里面的create_thread_cb即为create_thread_callback,所以最终执行的是loc_eng_process_deferred_action函数,见loc_eng.cpp第1422行
  里面是一个while循环
 
  loc_api_glue_init函数作用:创建一个与ARM9 RPC通讯的通道,与loc_eng_process_deferred_action线程配合使用,loc_eng_process_deferred_action线程会等待数据到来,当RPC通道从硬件取到数据时,会激活线程中的等待循环,从全局变量loc_eng_data里拿数据
  loc_eng_process_deferred_action函数作用:当GPS有数据解析上报时,回调JNI函数,JNI函数会执行JAVA里的对应函数,最终通知给上层
 
  还往下面分析涉及到高通自有的RPC协议实现与GPS专业知识,暂不作深究.
 
6.到此可以进行一下小结:
LocationManagerSerivce线程启动时,同时作了两个工作:
a.初始化GpsLocationProvider对象并获取HAL层的操作接口
b.将上层的回调接口GpsCallbacks传递给HAL层,供HAL进行回调,同时HAL层创建RPC通讯与上报数据线程

三、回调接口的设置
  要分两部分讲,一部分是Framework层的回调接口设置,一部分是JNI层的回调接口设置
为什么是两部分,主要是因为JAVA与C++的回调有点不一样,JAVA层采用的是设置接口的方式
而C++采用的是设置函数指针的方式,整个设置分两部分,那么回调也就分两部分
1.JNI层的回调接口设置在前面提到过,即在Service初始化时完成,由前面提到的
“if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)”
  这句代码完成;其中的函数变量sGpsCallbacks为JNI的结构体,里面成员为一系列的函数指针,指向JNI里实现的函数,供HAL层调用;
  JNI层也是C++代码,JAVA层的监听器设置不能设置到JNI层的,那么如何衔接的呢?主要是由JNI机制实现的,即JNI里可以直接调用java对象里的函数,
  在初始化时,GpsLocationProvider.cpp的android_location_GpsLocationProvider_class_init_native函数中,有一段代码:
 
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");

   
    这一系列的代码目的就是先缓存JAVA里的函数id到JNI本地,当GPS数据上来时,由JNI调用,达到JNI层向JAVA层传送数据的目的
   
    再来看sGpsCallbacks被传到HAL层后,是怎么被HAL层保存的
    通过前面的分析,sGpsInterface->init(&sGpsCallbacks)这句其实调用的是static int loc_eng_init(GpsCallbacks* callbacks),
    里面与callbacks相关的逻辑如下:
   
loc_eng_data.location_cb    = callbacks->location_cb;
    loc_eng_data.sv_status_cb   = callbacks->sv_status_cb;
    loc_eng_data.status_cb      = callbacks->status_cb;
    loc_eng_data.nmea_cb        = callbacks->nmea_cb;
    loc_eng_data.acquire_wakelock_cb = callbacks->acquire_wakelock_cb;
    loc_eng_data.release_wakelock_cb = callbacks->release_wakelock_cb;
  
所以这些接口函数又保存到了本地的变量loc_eng_data中,实际上GPS有数据通知上层时,最先调用的就是loc_eng_data里的这些函数
    对比一下loc_eng_data_s_type结构体与GpsCallbacks

   
typedef struct
    {
      rpc_loc_client_handle_type  client_handle;

      gps_location_callback           location_cb;
      gps_status_callback             status_cb;
      gps_sv_status_callback          sv_status_cb;
      agps_status_callback            agps_status_cb;
      gps_nmea_callback               nmea_cb;
      gps_ni_notify_callback          ni_notify_cb;
      gps_acquire_wakelock            acquire_wakelock_cb;
      gps_release_wakelock            release_wakelock_cb;
      int                             agps_status;

      // used to defer stopping the GPS engine until AGPS data calls are done
      boolean                         agps_request_pending;
      boolean                         stop_request_pending;
      pthread_mutex_t                 deferred_stop_mutex;

      loc_eng_xtra_data_s_type        xtra_module_data;

      loc_eng_ioctl_data_s_type       ioctl_data;

      // data from loc_event_cb
      rpc_loc_event_mask_type         loc_event;
      rpc_loc_event_payload_u_type    loc_event_payload;

      // TBD:
      char                            agps_server_host[256];
      int                             agps_server_port;
      uint32                          agps_server_address;
      char                            apn_name[100];
      int                             position_mode;
      rpc_loc_server_connection_handle  conn_handle;

      // GPS engine status
      GpsStatusValue                  engine_status;

      // Aiding data information to be deleted, aiding data can only be deleted when GPS engine is off
      GpsAidingData                   aiding_data_for_deletion;

      // Data variables used by deferred action thread
      pthread_t                       deferred_action_thread;
      // Mutex used by deferred action thread
      pthread_mutex_t                 deferred_action_mutex;
      // Condition variable used by deferred action thread
      pthread_cond_t                  deferred_action_cond;

      // flags for pending events for deferred action thread
      int                             deferred_action_flags;
   } loc_eng_data_s_type;

   
   
  
 typedef struct {
    /** set to sizeof(GpsCallbacks) */
    size_t      size;
    gps_location_callback location_cb;
    gps_status_callback status_cb;
    gps_sv_status_callback sv_status_cb;
    gps_nmea_callback nmea_cb;
    gps_set_capabilities set_capabilities_cb;
    gps_acquire_wakelock acquire_wakelock_cb;
    gps_release_wakelock release_wakelock_cb;
    gps_create_thread create_thread_cb;
    gps_request_utc_time request_utc_time_cb;
  } GpsCallbacks;


 
  其对应关系很明显
   
   
2.JAVA层回调接口设置比较简单即设置接口,当然与一般的JAVA接口设置有点不一样,主要是因为涉及到进程间通讯,APP接口要先转成Binder机制支持的接口形式,然后再传给Service
  以设置GPS状态监听为例:
  APP层的监听器为GpsStatus.Listener,因为此接口不能直接跨进程设置,故在LocationManager.java中会自动转化为GpsStatusListenerTransport,
  此类其实是实现了IGpsStatusListener.Stub接口,符合Binder机制要求,所以应用层添加GPS状态监听最初是调用LocationManager.addGpsStatusListener(GpsStatus.Listener listener),
  实际上被转化成调用service的addGpsStatusListener(IGpsStatusListener listener),GpsStatusListenerTransport中保存了GpsStatus.Listener引用.
  而Service的addGpsStatusListener里实际调用了mGpsStatusProvider.addGpsStatusListener(listener);而mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
  gpsProvider为GpsLocationProvider类的实例,实际getGpsStatusProvider()函数只是返回变量mGpsStatusProvider
  其初始化语句为,见GpsLocationProvider.java 312行:
 
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
        @Override
        public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
            if (listener == null) {
                throw new NullPointerException("listener is null in addGpsStatusListener");
            }

            synchronized (mListeners) {
                IBinder binder = listener.asBinder();
                int size = mListeners.size();
                for (int i = 0; i < size; i++) {
                    Listener test = mListeners.get(i);
                    if (binder.equals(test.mListener.asBinder())) {
                        // listener already added
                        return;
                    }
                }

                Listener l = new Listener(listener);
                binder.linkToDeath(l, 0);
                mListeners.add(l);
            }
        }

        @Override
        public void removeGpsStatusListener(IGpsStatusListener listener) {
            if (listener == null) {
                throw new NullPointerException("listener is null in addGpsStatusListener");
            }

            synchronized (mListeners) {
                IBinder binder = listener.asBinder();
                Listener l = null;
                int size = mListeners.size();
                for (int i = 0; i < size && l == null; i++) {
                    Listener test = mListeners.get(i);
                    if (binder.equals(test.mListener.asBinder())) {
                        l = test;
                    }
                }

                if (l != null) {
                    mListeners.remove(l);
                    binder.unlinkToDeath(l, 0);
                }
            }
        }
    };

 
   这里比较奇怪,因为LocationManagerservice.java在调用GpsLocationProvider时实际是处于同进程的,但是这里却用到了Binder机制,其实不用这个机制应该是没什么关系的;通过上面代码可知,添加的监听接口最后保存在了mListeners里,看mListeners的定义:private ArrayList<Listener> mListeners = new ArrayList<Listener>();
   一个普通List而已
   到此可知JAVA层回调接口设置就这么简单
   再看看最后是哪里调用了mListeners里的这些接口,比如reportLocation函数,这个函数的id在JNI里对应于method_reportLocation这个变量,
   很明显了,JNI会调用到这些接口,来通知上层.
  
   移除接口就是添加的反操作,比较简单,不再分析,但有一点要注意,删除时虽然传入的变量与添加的变量是同一个,但是到了服务端时,实际上是不一样的,主要就是因为进程间通讯的原因,接口都做了转化;那删除时如何能找到添加时对应的接口呢,也比较简单,因为两者的asBinder()是一样的,通过比较
   二者的asBinder()值即可
  
  
四、底层消息上传
  前面讲的回调接口的设置就是为底层消息上传服务的,GPS模块有定位数据后利用回调机制一级级上传,最后发送给应用
  以GPS状态数据为例
  首先Service初始化时,HAL层通过loc_api_glue_init函数创建与硬件的RPC通讯通道,同进启动线程不断等待数据的到来;
  当硬件有数据后,会激活线程,线程里会调用相关函数:
 
loc_event = loc_eng_data.loc_event;
此句是线程循环里的一句代码,即获取由RPC通道传递来的GPS数据,接下来会调用
 
if (loc_event != 0) {
    loc_eng_process_loc_event(loc_event, &loc_event_payload);
  }
  在loc_eng_process_loc_event里有一句:
 
if (loc_event & RPC_LOC_EVENT_STATUS_REPORT)
  {
     loc_eng_report_status (&(loc_event_payload->rpc_loc_event_payload_u_type_u.status_report));
  }
  再看 loc_eng_report_status函数里会执行loc_eng_data.status_cb(&status);
  通过之前的分析:loc_eng_data.status_cb      = callbacks->status_cb;而callbacks即为sGpsCallbacks变量,
  callbacks->status_cb对应于JNI函数:status_callback
  可知,最终是调用了JNI传过来的函数status_callback,其定义见GpsLocationProvider.cpp第82行:
 static void status_callback(GpsStatus* status)
  {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
    checkAndClearExceptionFromCallback(env, __FUNCTION__);
  }
 
  mCallbacksObj即java层的GpsLocationProvider对象;再看初始化时的这句:
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");

 
  其最终是调用了JAVA函数reportStatus,再看它的定义:
  
private void reportStatus(int status) {
       if (DEBUG) Log.v(TAG, "reportStatus status: " + status);

        synchronized (mListeners) {
            boolean wasNavigating = mNavigating;

            switch (status) {
                case GPS_STATUS_SESSION_BEGIN:
                    mNavigating = true;
                    mEngineOn = true;
                    break;
                case GPS_STATUS_SESSION_END:
                    mNavigating = false;
                    break;
                case GPS_STATUS_ENGINE_ON:
                    mEngineOn = true;
                    break;
                case GPS_STATUS_ENGINE_OFF:
                    mEngineOn = false;
                    mNavigating = false;
                    break;
            }

            if (wasNavigating != mNavigating) {
                int size = mListeners.size();
                for (int i = 0; i < size; i++) {
                    Listener listener = mListeners.get(i);
                    try {
                        if (mNavigating) {
                            listener.mListener.onGpsStarted();
                        } else {
                            listener.mListener.onGpsStopped();
                        }
                    } catch (RemoteException e) {
                        Log.w(TAG, "RemoteException in reportStatus");
                        mListeners.remove(listener);
                        // adjust for size of list changing
                        size--;
                    }
                }

                // send an intent to notify that the GPS has been enabled or disabled.
                Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
                intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
            }
        }
    }

 
   这里很明显了,最后是调用了之前设置的监听器IGpsStatusListener
   看看应用层监听器与Binder监听器之间的关系:
  
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {

        private final GpsStatus.Listener mListener;
        private final GpsStatus.NmeaListener mNmeaListener;

        // This must not equal any of the GpsStatus event IDs
        private static final int NMEA_RECEIVED = 1000;

        private class Nmea {
            long mTimestamp;
            String mNmea;

            Nmea(long timestamp, String nmea) {
                mTimestamp = timestamp;
                mNmea = nmea;
            }
        }
        private ArrayList<Nmea> mNmeaBuffer;

        GpsStatusListenerTransport(GpsStatus.Listener listener) {
            mListener = listener;
            mNmeaListener = null;
        }

        GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
            mNmeaListener = listener;
            mListener = null;
            mNmeaBuffer = new ArrayList<Nmea>();
        }

        @Override
        public void onGpsStarted() {
            if (mListener != null) {
                Message msg = Message.obtain();
                msg.what = GpsStatus.GPS_EVENT_STARTED;
                mGpsHandler.sendMessage(msg);
            }
        }

        @Override
        public void onGpsStopped() {
            if (mListener != null) {
                Message msg = Message.obtain();
                msg.what = GpsStatus.GPS_EVENT_STOPPED;
                mGpsHandler.sendMessage(msg);
            }
        }

        @Override
        public void onFirstFix(int ttff) {
            if (mListener != null) {
                mGpsStatus.setTimeToFirstFix(ttff);
                Message msg = Message.obtain();
                msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
                mGpsHandler.sendMessage(msg);
            }
        }

        @Override
        public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
                float[] elevations, float[] azimuths, int ephemerisMask,
                int almanacMask, int usedInFixMask) {
            if (mListener != null) {
                mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
                        ephemerisMask, almanacMask, usedInFixMask);

                Message msg = Message.obtain();
                msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
                // remove any SV status messages already in the queue
                mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
                mGpsHandler.sendMessage(msg);
            }
        }

        @Override
        public void onNmeaReceived(long timestamp, String nmea) {
            if (mNmeaListener != null) {
                synchronized (mNmeaBuffer) {
                    mNmeaBuffer.add(new Nmea(timestamp, nmea));
                }
                Message msg = Message.obtain();
                msg.what = NMEA_RECEIVED;
                // remove any NMEA_RECEIVED messages already in the queue
                mGpsHandler.removeMessages(NMEA_RECEIVED);
                mGpsHandler.sendMessage(msg);
            }
        }

        private final Handler mGpsHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == NMEA_RECEIVED) {
                    synchronized (mNmeaBuffer) {
                        int length = mNmeaBuffer.size();
                        for (int i = 0; i < length; i++) {
                            Nmea nmea = mNmeaBuffer.get(i);
                            mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
                        }
                        mNmeaBuffer.clear();
                    }
                } else {
                    // synchronize on mGpsStatus to ensure the data is copied atomically.
                    synchronized(mGpsStatus) {
                        mListener.onGpsStatusChanged(msg.what);
                    }
                }
            }
        };
    }

    从上可知,Service调用IGpsStatusListener实际触发应用层调用了GpsStatus.Listener
  
五、对HAL层的操作
  JNI层保留对HAL层操作的接口GpsInterface,对应的实例HAL层见loc_eng.cpp第97行:
 
static const GpsInterface sLocEngInterface =
  {
    sizeof(GpsInterface),
    loc_eng_init,
    loc_eng_start,
    loc_eng_stop,
    loc_eng_cleanup,
    loc_eng_inject_time,
    loc_eng_inject_location,
    loc_eng_delete_aiding_data,
    loc_eng_set_position_mode,
    loc_eng_get_extension,
  }; 

  JNI层为GpsLocationProvider.cpp中的sGpsInterface变量,
  前面已经讲过了一个操作,即将JNI层回调接口传递到HAL层,用到其中的loc_eng_init函数
  这里再分析一下loc_eng_start操作,其调用在GpsLocationProvider.cpp中第320行:
 
static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
  {
    if (sGpsInterface)
        return (sGpsInterface->start() == 0);
    else
        return false;
  }
  android_location_GpsLocationProvider_start对应JAVA函数native_start()在startNavigating()中被调用,
  此函数在好几个地方有被调用,其中有setRequest()函数,在Service被requestLocationUpdates函数间接调用,
  此函数应用层能通过进程间通讯调用,目的是注册位置通知的接收器,见LocationManager.java里的requestLocationUpdates函数

猜你喜欢

转载自danlov.iteye.com/blog/2294882
今日推荐