【Android】GPS啟動流程及資料流向分析(基於2.3.5)

來源:互聯網
上載者:User

GPS啟動流程及資料流向分析:

 首先在系統init階段,會通過ServiceManager addService添加很多的Service,這其中就包含LocationService。
代碼在SystemServer.java中:

             try {
                  Slog.i(TAG, "Location Manager");
                  location = new LocationManagerService(context);
                  ServiceManager.addService(Context.LOCATION_SERVICE, location);
             } catch (Throwable e) {
                  reportWtf("starting Location Manager", e);
             } 隨後調用LocationManagerService的systemReady函數開啟一個線程。            final LocationManagerService locationF = location;
            try {
                     if (locationF != null) locationF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Location Service ready", e);
            }--LocationManagerService.java     void systemReady() {
          // we defer starting up the service until the system is ready 
          Thread thread = new Thread(null, this, "LocationManagerService");
          thread.start();
     }在 Thread的run函數中為接收訊息做好了準備,並且調用了一個initialize函數:     public void run()
     {
          Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
          Looper.prepare();
          mLocationHandler = new LocationWorkerHandler();
          initialize();
          Looper.loop();
     }接著看initialize():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();

          // Register for Network (Wifi or Mobile) updates
          IntentFilter intentFilter = new IntentFilter();
          intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
          // Register for Package Manager updates
          intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
          intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
          intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
          mContext.registerReceiver(mBroadcastReceiver, intentFilter);
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
          mContext.registerReceiver(mBroadcastReceiver, sdFilter);

          // listen for settings changes
          ContentResolver resolver = mContext.getContentResolver();
          Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
                  "(" + Settings.System.NAME + "=?)",
                  new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
                 null);
          mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
          SettingsObserver settingsObserver = new SettingsObserver();
          mSettings.addObserver(settingsObserver);
     }其中有兩個重要的地方:
 1) loadProviders(),會new一個GpsLocationProvider,並將本GpsLocationProvider添加一個ArrayList<LocationProviderInterface>的鏈 表中。
 2) new 一個 SettingsObserver對象,該對象應該是負責在Settings中有資料變化時通知本地程式進行相應處理的功能。其中 SettingsObserver類中實現 了Observer介面,該介面中的update函數應該就是一個回呼函數,當Settings中有資料變化時會回調進這個函數:private final class SettingsObserver implements Observer {
          public void update(Observable o, Object arg) {
              synchronized (mLock) {
                   updateProvidersLocked();
              }
          }
     }

 private void updateProvidersLocked() {
          boolean changesMade = false;
          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);
                    changesMade = true;
               } else if (!isEnabled && shouldBeEnabled) {
                    updateProviderListenersLocked(name, true);
                    changesMade = true;
               }
          }
          if (changesMade) {
               mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
          }
     }

 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) {
              p.enable();
              if (listeners > 0) {
                   p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
                   p.enableLocationTracking(true);
              }
         } else {
              p.enableLocationTracking(false);
              p.disable();
         }
     }可知是在 updateProviderListenersLocked函數中,通過 LocationProviderInterface p調用enable或者disable來開關位置服務。這裡會調用到 LocationProviderInterface的子類GpsLocationProvider中的enable或者disable中:
 
 GpsLocationProvider.java public void enable() {
          synchronized (mHandler) {
             sendMessage(ENABLE, 1, null);
          }
       }handlenable就是ENABLE的訊息處理函數: private void handleEnable() {
          if (DEBUG) Log.d(TAG, "handleEnable");
          if (mEnabled) return;
          mEnabled = native_init();
        
          Intent intent = new Intent(LocationManager.GPS_SETTING_ENABLED_CHANGE_ACTION);
          intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mEnabled);
          mContext.sendBroadcast(intent);

          if (mEnabled) {
              mSupportsXtra = native_supports_xtra();
              if (mSuplServerHost != null) {
                   native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
              }
              if (mC2KServerHost != null) {
                   native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
              }
          } else {
              Log.w(TAG, "Failed to enable location provider");
          }
     }可見這裡就開始與native層通訊了。
 native_init對應jni中的android_location_GpsLocationProvider_init函數,在該函數中調用了
 sGpsInterface->init(&sGpsCallbacks),
 而 sGpsCallbacks定義如下: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,
 }; 這是將jni的一些函數作為參數傳遞到native c 空間中去,這樣在native c中如果有可用資料將通過回調的方式調用到jni中的函數。簡單的看一下 location_callback的定義:static void location_callback(GpsLocation* location)
 {
      JNIEnv* env = AndroidRuntime::getJNIEnv();
      env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
             (jdouble)location->latitude, (jdouble)location->longitude,
             (jdouble)location->altitude,
             (jfloat)location->speed, (jfloat)location->bearing,
             (jfloat)location->accuracy, (jlong)location->timestamp);
      checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }

其中有定義:
 static jmethodID method_reportLocation;並且:
 method_reportLocation = env->GetMethodID(clazz, "reportLocation","(IDDDFFFJ)V"); 
 可見jni中的callback函數其實又回調掉了java空間(Framework)中的  reportLocation函數,這便是整個GPS架構的資料流向結構了。所有的資料都是通過回調的方式通知上層:
 nativeC通過回調通知JNI,JNI通過回調通知Framework。這應該是gps整個架構最重要的部分吧,理解了資料流向,其他的應該都簡單了。
 我們的native c中並沒有實現 native_set_agps_server的功能,所以使用agps的資料服務器不在上層指定,而是在c檔案中直接指定的。 native_set_agps_server只是一個空函數。

 上面介紹了 sGpsInterface->init(&sGpsCallbacks)中sGpsCallbacks的作用,但是init函數調用還未進行剖析:
  sGpsInterface定義如下:
 static const GpsInterface* sGpsInterface = NULL;
 它是在android_location_GpsLocationProvider_class_init_native函數初始化的,該函數在GpsLocationProvider中通過static方式預先載入:

 err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
     if (err == 0) {
         hw_device_t* device;
 //通過open調用,在native層分配了一個 gps_device_t的空間,並傳遞迴來。
         err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
         if (err == 0) {
  //這個強制轉換是因為 gps_device_t中第一個item是一個 hw_device_t。
  //並且在native中確實是分配的gps_device_t空間
            gps_device_t* gps_device = (gps_device_t *)device;
            sGpsInterface = gps_device->get_gps_interface(gps_device);
         }
     }

 

可見這個 sGpsInterface是從hwModule中擷取的。來看看get_gps_interface函數: 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));    
      if (dev == NULL) { 
          LOGE("gps device can not malloc memery!"); 
          return -ENOMEM; 
     } 
    
     memset(dev, 0, sizeof(*dev));    
     dev->common.tag = HARDWARE_DEVICE_TAG;    
     dev->common.version = 0;    
     dev->common.module = (struct hw_module_t*)module;  
     dev->common.close = close_gps; 
 //注意一個有參 一個無參   
     dev->get_gps_interface = gps_get_hardware_interface;    
     *device = (struct hw_device_t *)dev;    
    
     return 0; 
 }

 const GpsInterface *gps_get_hardware_interface() 
 { 
      return &ubloxGpsInterface; 
 }

 /*gps interface struct*/ 
 static const GpsInterface  ubloxGpsInterface = 
 { 
      .size = sizeof(GpsInterface), 
      .init = ublox_gps_init, 
      .start = ublox_gps_start, 
      .stop = ublox_gps_stop, 
      .cleanup = ublox_gps_cleanup, 
      .inject_location = ublox_gps_inject_location, 
      .delete_aiding_data = ublox_gps_delete_aiding_data, 
      .set_position_mode = ublox_gps_set_position_mode, 
      .get_extension = ublox_gps_get_extension, 
 };

 static int ublox_gps_init(GpsCallbacks* callbacks) 
 { 
      UbloxGpsData *gps_data = &ublox_gps_data; 

      //ublox gps support MS-based A-GPS, fix in the gps terminal 
      callbacks->set_capabilities_cb(GPS_CAPABILITY_SCHEDULING | GPS_CAPABILITY_MSB);

      pthread_mutex_init(&gps_data->deferred_action_mutex, NULL); 
      pthread_cond_init(&gps_data->deferred_action_cond, NULL); 
      agps_state->used_proxy = 0; 

      gps_data->gps_callbacks = *callbacks; 
      gps_data->thread_start = 0; 

      LOGD("gps finishes initialization"); 
   
      return 0; 
 } 所以 sGpsInterface實際上指向了native層的 ubloxGpsInterface。調用其init函數,將JNI空間的回呼函數傳遞到了native空間。
應用程式層通過調用 Settings.Secure.setLocationProviderEnabled(
                        resolver,
                        LocationManager.GPS_PROVIDER,
                        desiredState);來enable或者Disable位置服務。

url:http://greatverve.cnblogs.com/archive/2012/01/31/android-gps.html

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.