乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Android 系統(tǒng)中 Location Service 的實(shí)現(xiàn)與架構(gòu)

       老匹夫 2014-02-06

      Android 系統(tǒng)中 Location Service 的實(shí)現(xiàn)與架構(gòu)

      強(qiáng) 波, Java 軟件工程師, 富士通南大軟件技術(shù)有限公司

      簡(jiǎn)介: 定位服務(wù)是移動(dòng)設(shè)備上最常用的功能之一,本文以 Android 源碼為基礎(chǔ),詳細(xì)分析了 Android 系統(tǒng)中定位服務(wù)的架構(gòu)和實(shí)現(xiàn)。 在 Android 系統(tǒng)中,所有系統(tǒng)服務(wù)的實(shí)現(xiàn)都是類(lèi)似的。只要明白其中之一,然后舉一反三是很容易的。對(duì)于 Android 的應(yīng)用開(kāi)發(fā)人員來(lái)說(shuō),本文可以幫助他們了解他們所使用的 API 背后的實(shí)現(xiàn)。
      對(duì)于 Android 的系統(tǒng)開(kāi)發(fā)人員來(lái)說(shuō),本文可以幫助他們更好的了解 Android 系統(tǒng)架構(gòu)。

      發(fā)布日期: 2013 年 3 月 20 日
      級(jí)別: 初級(jí)
      訪問(wèn)情況 : 4356 次瀏覽
      評(píng)論: 1 (查看 | 添加評(píng)論 - 登錄)

      平均分 5 星 共 26 個(gè)評(píng)分 平均分 (26個(gè)評(píng)分)
      為本文評(píng)分

      前言

      定位服務(wù)是移動(dòng)設(shè)備上最常用的功能之一,下文以 Android 源碼為基礎(chǔ),詳細(xì)分析了 Android 系統(tǒng)中定位服務(wù)的架構(gòu)和實(shí)現(xiàn)。 定位服務(wù)是 Android 系統(tǒng)提供的一項(xiàng)系統(tǒng)服務(wù),在 Android 系統(tǒng)中,所有系統(tǒng)服務(wù)的架構(gòu)都是類(lèi)似的。只要明白其中一個(gè),然后再去理解其他是很容易的。 對(duì)于 Android 的應(yīng)用開(kāi)發(fā)人員來(lái)說(shuō),本文可以幫助他們了解他們所使用的 API 背后的實(shí)現(xiàn)。 對(duì)于 Android 的系統(tǒng)開(kāi)發(fā)人員來(lái)說(shuō),本文可以幫助他們更好的了解 Android 系統(tǒng)架構(gòu)。 關(guān)于如何獲取 Android 源碼,請(qǐng)參閱 Android Source 的官方網(wǎng)站:http://source./source/downloading.html Android 源碼中包含了大量的文件,有些源文件甚至是同名的。為了清楚的指明我們所討論的文件,本文在提到源碼文件的時(shí)候都會(huì)指明其在 Android 源碼樹(shù)中的路徑。

      回頁(yè)首

      android.location 包與 API 代碼示例

      定位服務(wù)提供給應(yīng)用層的 API 位于 android.location 包中,它其中包含的類(lèi)和接口如表 1 所示:


      表 1. android.location 包中的類(lèi)和接口
      名稱(chēng) 類(lèi)型 說(shuō)明
      GpsStatus.Listener 接口 用于接受 GPS 狀態(tài)改變時(shí)的通知。
      GpsStatus.NmeaListener 接口 用于接受 Nmea(為海用電子設(shè)備制定的格式)信息。
      LocationListener 接口 用于接受位置信息改變時(shí)的通知。
      Address 類(lèi) 用于描述地址信息。
      Criteria 類(lèi) 用于選擇 LocationProvider。
      Geocoder 類(lèi) 用于處理地理位置的編碼。
      GpsSatellite 類(lèi) 用于描述 GPS 衛(wèi)星的狀態(tài)。
      GpsStatus 類(lèi) 用于描述 GPS 設(shè)備的狀態(tài)。
      Location 類(lèi) 用于描述地理位置信息,包括經(jīng)度,緯度,海拔,方向等信息。
      LocationManager 類(lèi) 用于獲取和調(diào)用定位服務(wù)。
      LocationProvider 類(lèi) 描述 Location Provider 的超類(lèi),Location Provider 是真正用來(lái)獲取位置信息的組件。Location Provider 的實(shí)現(xiàn)主要可以分為兩類(lèi):一種依賴(lài)于 GPS 設(shè)備,另一種依賴(lài)網(wǎng)絡(luò)狀態(tài)。

      在表 1 中,最重要的類(lèi)是 LocationManager,這是整個(gè)定位服務(wù)的入口類(lèi)。 清單 1 是使用定位服務(wù) API 的代碼示例:


      清單 1. 使用定位服務(wù)提供的 API
      				
      	 public class MainActivity extends Activity { 
      	
      	  // 測(cè)試使用的日志 Tag 
      	  private static final String TAG = "LocationService API Demo"; 
      	  // 將在 onCreate 中被初始化
      	  private LocationManager locationManager; 
      	  // 接受位置更新的監(jiān)聽(tīng)器
      	  protected final LocationListener locationListener = 
      	                                  new 			 LocationListener() { 
      	
      	    // 當(dāng)位置發(fā)生變化時(shí),輸出位置信息
      	    public void onLocationChanged(Location location) { 
      	      Log.d(TAG, "Location changed to: " + getLocationInfo(location)); 
      	    } 
      	  
      	    public void onProviderDisabled(String provider) { 
      	      Log.d(TAG, provider + " disabled."); 
      	    } 
      	  
      	    public void onProviderEnabled(String provider) { 
      	      Log.d(TAG, provider + " enabled."); 
      	    } 
      	
      	    public void onStatusChanged(String provider, int status, 
      	 Bundle extras){ 
      	      Log.d(TAG, provider + " status changed."); 
      	    } 
      	  }; 
      	
      	  @Override 
      	  protected void onCreate(Bundle savedInstanceState) { 
      	    super.onCreate(savedInstanceState); 
      	    setContentView(R.layout.activity_main); 
      	    // 獲取 LocationManager 
      	    locationManager = (LocationManager)getSystemService(LOCATION_SERVICE); 
      	  } 
      	  
      	  @Override 
      	  protected void onResume() { 
      	    super.onResume(); 
      	    // 指定一個(gè) Provider 
      	    String currentProvider = LocationManager.NETWORK_PROVIDER; 
      	    Log.d(TAG, "CurrentProvider: " + currentProvider); 
      	    // 獲取 Provider 最后一個(gè)記錄的地址信息
      	    Location lastKnownLocation = locationManager 
      	 .getLastKnownLocation(currentProvider); 
      	    if (lastKnownLocation != null) { 
      	      Log.d(TAG, "LastKnownLocation: "
      	    + getLocationInfo(lastKnownLocation)); 
      	    } else { 
      	      Log.d(TAG, "Last Location Unkown!"); 
      	    } 
      	    // 注冊(cè)監(jiān)聽(tīng)器接受位置更新
      	    locationManager.requestLocationUpdates(currentProvider, 0, 0, 
      	 locationListener); 
      	  } 
      	  
      	  @Override 
      	  protected void onPause() { 
      	    super.onPause(); 
      	    // 移除監(jiān)聽(tīng)器
      	    locationManager.removeUpdates(locationListener); 
      	    Log.d(TAG, "LocationListener: " + locationListener + " removed."); 
      	  } 
      	
      	  /** 
      	   * 將 Location 對(duì)象轉(zhuǎn)換成字符串形式方便顯示
      	   * 
      	   * @param location 
      	   *            Location 對(duì)象
      	   * @return 字符串形式的表示
      	   */ 
      	  private String getLocationInfo(Location location) { 
      	    String info = ""; 
      	    info += "Longitude:" + location.getLongitude(); 
      	    info += ", Latitude:" + location.getLatitude(); 
      	    if (location.hasAltitude()) { 
      	      info += ", Altitude:" + location.getAltitude(); 
      	    } 
      	    if (location.hasBearing()) { 
      	      info += ", Bearing:" + location.getBearing(); 
      	    } 
      	    return info; 
      	  } 
      	 } 
      	

      這段代碼的說(shuō)明如下: 在 Activity 顯示的時(shí)候首先嘗試獲取通過(guò)網(wǎng)絡(luò)定位的 Location Provider 記錄的最后一次定位信息,然后在系統(tǒng)中注冊(cè)一個(gè)監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)位置信息的變更,這里的 API 都是使用定位服務(wù)最常用的。

      回頁(yè)首

      定位服務(wù)的實(shí)現(xiàn)架構(gòu)圖

      整個(gè)定位服務(wù)的架構(gòu)如圖 1 所示。該結(jié)構(gòu)共分為四層:

      • 最上面是應(yīng)用層,即 android.location 包中包含的內(nèi)容,是以 Java 語(yǔ)言提供的 API。
      • 第二層是框架層,這一層包含了系統(tǒng)服務(wù)的實(shí)現(xiàn),主要由 Java 語(yǔ)言來(lái)實(shí)現(xiàn)。
      • 第三層是共享庫(kù)層,本層由 C 以及 C++ 語(yǔ)言實(shí)現(xiàn) , 框架層與共享庫(kù)層使用 JNI 進(jìn)行銜接。
      • 最下面一層是 Linux 內(nèi)核層 , 整個(gè) Android 系統(tǒng)都是以 Linux 內(nèi)核為基礎(chǔ)的。

      從上至下它們是逐層依賴(lài)的關(guān)系,每層依賴(lài)下面一層完成其所需提供的服務(wù)。


      圖 1. 定位服務(wù)的實(shí)現(xiàn)架構(gòu)圖
      圖 1. 定位服務(wù)的實(shí)現(xiàn)架構(gòu)圖

      系統(tǒng)服務(wù)的啟動(dòng)與注冊(cè)

      從圖 1 中可以看出,在框架層,實(shí)現(xiàn)位置服務(wù)的類(lèi)是 LocationManagerService,這是一個(gè)系統(tǒng)服務(wù)。 那么 LocationManager 和 LocationManagerService 兩者是什么關(guān)系,它們是如何關(guān)聯(lián)起來(lái)的呢? 想要理解這一點(diǎn)就要先介紹一下 Android 中的 Binder 機(jī)制。 在 Android 系統(tǒng)中,系統(tǒng)服務(wù)運(yùn)行在一個(gè)專(zhuān)門(mén)的進(jìn)程中,這個(gè)進(jìn)程名稱(chēng)為 system_server。該進(jìn)程在系統(tǒng)啟動(dòng)的時(shí)候便被加載和啟動(dòng)。系統(tǒng)中有一個(gè)專(zhuān)門(mén)用來(lái)管理系統(tǒng)服務(wù)的類(lèi),它叫做 ServiceManager。這個(gè)類(lèi)負(fù)責(zé)注冊(cè)并管理所有的系統(tǒng)服務(wù)。 當(dāng)應(yīng)用程序想要使用系統(tǒng)服務(wù)時(shí),需要通過(guò)服務(wù)的代理來(lái)調(diào)用服務(wù)。由于客戶應(yīng)用程序運(yùn)行在自己的進(jìn)程中,這和 system_server 是兩個(gè)獨(dú)立的進(jìn)程,因此代理需要通過(guò)進(jìn)程間通訊將請(qǐng)求發(fā)送到 system_server 進(jìn)程,由該進(jìn)程來(lái)響應(yīng)服務(wù),然后再返回結(jié)果。整個(gè)這個(gè)機(jī)制稱(chēng)之為 Binder 機(jī)制。Binder 機(jī)制在 Android 系統(tǒng)中應(yīng)用非常之廣,幾乎所有的進(jìn)程間通訊都是使用該進(jìn)制完成的。 圖 2 描述了 Binder 機(jī)制的請(qǐng)求和響應(yīng)過(guò)程:


      圖 2. Binder 機(jī)制的請(qǐng)求和響應(yīng)過(guò)程
      圖 2. Binder 機(jī)制的請(qǐng)求和響應(yīng)過(guò)程

      Binder Driver 作為 Binder 機(jī)制的核心部分完成底層進(jìn)程間通訊的工作。被請(qǐng)求的進(jìn)程(這里是系統(tǒng)服務(wù)進(jìn)程)通常會(huì)緩存一些線程,當(dāng)有請(qǐng)求時(shí),在這些線程中完成請(qǐng)求。 了解了 Binder 機(jī)制之后,我們繼續(xù)來(lái)看 LocationManager,在 LocationManager.java( 位于:frameworks/base/location/java/android/location/) 中可以看到,LocationManager 類(lèi)中所有功能的實(shí)現(xiàn)都是依賴(lài)于一個(gè)名稱(chēng)為 mService 的字段來(lái)實(shí)現(xiàn)的,這個(gè)字段的類(lèi)型是 ILocationManager。而這個(gè)對(duì)象就是我們上面所說(shuō)的代理。mService 字段是在 LocationManager 的構(gòu)造函數(shù)中被初始化的,因此找到 LocationManager 構(gòu)造函數(shù)被調(diào)用的地方就可以知道這個(gè)代理對(duì)象是哪里來(lái)的了。 在 ContextImpl.java(frameworks/base/core/java/android/app) 中有這樣一段代碼,如清單 2 所示:


      清單 2. registerService 方法中的代碼片段
      				
       registerService(LOCATION_SERVICE, new StaticServiceFetcher() {                 
          public Object createStaticService() {                     
              IBinder b = ServiceManager.getService(LOCATION_SERVICE);                     
              return new LocationManager(ILocationManager.Stub.asInterface(b));                 
       }}); 
      	

      在這里,我們見(jiàn)到了 ServiceManager 這個(gè)類(lèi),上文說(shuō)了,這個(gè)類(lèi)是專(zhuān)門(mén)用來(lái)管理系統(tǒng)服務(wù)的。通過(guò)它,我們便可以獲取定位服務(wù)的實(shí)現(xiàn)類(lèi)對(duì)象,然后又通過(guò) ILocationManager.Stub.asInterface(b) 將其轉(zhuǎn)換成服務(wù)的代理存放到了 LocationManager 中。 好奇心重的讀者一定要問(wèn):那 ServiceManager 中所管理的系統(tǒng)服務(wù)對(duì)象又是從哪里來(lái)的呢?要弄清這個(gè)問(wèn)題,還需要比較多的調(diào)查。下面我們來(lái)詳細(xì)講解: 在 Android 系統(tǒng)啟動(dòng)過(guò)程中,需要完成一系列的初始化動(dòng)作。源碼中有一個(gè)專(zhuān)門(mén)的腳本來(lái)管理啟動(dòng)時(shí)需要完成的任務(wù),該腳本文件名稱(chēng)為 init.rc(位于:system/core/rootdir)。這個(gè)腳本文件由 init 進(jìn)程讀取。 在這個(gè)腳本文件中有這樣一段代碼(關(guān)于 init 進(jìn)程以及 init.rc 腳本的語(yǔ)法,請(qǐng)參見(jiàn)參考資料中的鏈接):


      清單 3. init.rc 中的代碼片段
      				
      				 service zygote /system/bin/app_process -Xzygote 
      				            /system/bin --zygote --start-system-server

      該行腳本的含義如下: “service”指明要啟動(dòng)一個(gè)系統(tǒng)服務(wù),“zygote”是該服務(wù)的名稱(chēng),“/system/bin/app_process”是該服務(wù)的可執(zhí)行文件路徑。“-Xzygote /system/bin”是可執(zhí)行文件的工作目錄,“--zygote – start-system-server”是提供給可執(zhí)行文件的參數(shù)。 想要弄清這里究竟發(fā)生了什么,我們還需要查看 app_process 的源碼。該源碼位于:frameworks/base/cmds/app_process/app_main.cpp 中。 在 app_main.cpp 中,判斷由于參數(shù)同時(shí)包含了“— zygote”和“--start-system-server”,因此啟動(dòng) com.android.internal.os.ZygoteInit 類(lèi),并傳遞“start-system-server”作為其 main 函數(shù)的參數(shù)。 而在 ZygoteInit.java(frameworks/base/core/java/com/android/internal/os)中,判斷如果參數(shù)為“start-system-server”則調(diào)用 startSystemServer 方法來(lái)啟動(dòng)系統(tǒng)服務(wù)。啟動(dòng)的方法是 fork 一個(gè)新的進(jìn)程,然后在其中加載 com.android.server.SystemServer 類(lèi)。 在 SystemServer 中,有一個(gè)名為 ServerThread 的類(lèi),這是一個(gè)線程類(lèi),在這個(gè)類(lèi)中真正執(zhí)行了系統(tǒng)服務(wù)的創(chuàng)建和注冊(cè) 。以 LocationManagerService 為例,在 ServerThread 的 run 方法中有以下代碼:


      清單 4. ServerThread 中 run 方法的代碼片段
      				
      	 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 的創(chuàng)建和注冊(cè)。 整個(gè)調(diào)用關(guān)系如圖 3 所示:


      圖 3. LocationManagerService 注冊(cè)過(guò)程
      圖 3. LocationManagerService 注冊(cè)過(guò)程

      查看大圖

      因此,在系統(tǒng)啟動(dòng)完成之后,這些系統(tǒng)服務(wù)也逐個(gè)的被啟動(dòng)并注冊(cè)在 ServiceManager 中了。 既然所有系統(tǒng)都是注冊(cè)在 ServiceManager 中的,有些讀者可能要問(wèn),可不可以不使用代理,直接通過(guò) ServiceManager 來(lái)獲取系統(tǒng)服務(wù)對(duì)象,然后調(diào)用呢?答案是否定的。 在 Android 中,將公開(kāi)的 API 和非公開(kāi)的 API 做了劃分。所有非公開(kāi)的 API 在開(kāi)發(fā)應(yīng)用程序的 SDK 中是無(wú)法使用的,而 ServiceManager 就是屬于非公開(kāi)的 API。所以對(duì)于應(yīng)用程序開(kāi)發(fā)人員,根本無(wú)法接觸到 ServiceManager 類(lèi)。

      回頁(yè)首

      LocationManagerService

      現(xiàn)在,我們終于可以來(lái)看看定位服務(wù)的真正實(shí)現(xiàn)類(lèi):LocationManagerService。 該類(lèi)位于 frameworks/base/services/java/com/android/server/LocationManagerService.java 中。 這個(gè)類(lèi)的文件有 2400 多行,第一次看到可能會(huì)覺(jué)得這個(gè)類(lèi)太大了,以至于無(wú)從下手。其實(shí),在 Android 的源碼,這個(gè)文件遠(yuǎn)不算大,WindowManagerService 源文件有 10000 多行,ActivityManagerService 源文件有 15000 多行。不管類(lèi)有多大,只要遵循一定的分析方法,總能逐步的將這個(gè)類(lèi)理解下來(lái)。 筆者認(rèn)為,要分析一個(gè)類(lèi)只要遵循以下幾個(gè)步驟即可:

      1. 理解該類(lèi)的主要作用
      2. 分析類(lèi)中的主要字段
      3. 理解類(lèi)的構(gòu)造方法以及初始化過(guò)程
      4. 理解類(lèi)中的主要業(yè)務(wù)邏輯方法
      5. 分析類(lèi)中的其他成員:例如內(nèi)部類(lèi)
      6. 分析與這個(gè)類(lèi)緊密相關(guān)的其他類(lèi)

      下面,我們就以這樣的方法來(lái)逐步剖析 LocationManagerService。 LocationManagerService 最主要的作用自然是提供定位服務(wù),在剛開(kāi)始的內(nèi)容中我們已經(jīng)看到,獲取位置信息可以選擇不同的 Location Provider,每個(gè) Location Provider 可能會(huì)記錄最近一次的定位信息。同時(shí),我們也可以使用監(jiān)聽(tīng)器來(lái)主動(dòng)獲取位置更新通知。所有的這些功能,都是在 LocationManagerService 中實(shí)現(xiàn)的。

      主要字段

      LocationManagerService 中包含主要字段如表 2 所示:


      表 2. LocationManagerService 中的主要字段
      類(lèi)型 名稱(chēng) 說(shuō)明
      HashMapmLastWriteTime記錄最后一次位置更新的時(shí)間,這是一個(gè)以 Location Provider 名稱(chēng)為鍵的映射。
      SetmEnabledProviders有效的 Location Provider。
      SetmDisabledProviders無(wú)效的 Location Provider。
      booleansProvidersLoadedLocation Provider 是否已經(jīng)被加載。
      StringmNetworkLocationProviderPackageName提供以網(wǎng)絡(luò)方式進(jìn)行定位服務(wù)的包名。
      StringmGeocodeProviderPackageName提供地理位置碼服務(wù)的包名。
      LocationWorkerHandlermLocationHandler這是一個(gè) Handler,用來(lái)處理位置信息更新和包更新兩種消息。
      LocationProviderProxymNetworkLocationProvider以網(wǎng)絡(luò)方式提供定位服務(wù)的 Location Provider 的代理。
      LocationProviderInterfacemGpsLocationProvider依賴(lài)于 GPS 模塊實(shí)現(xiàn)定位的 Location Provider。
      ArrayListmProviders所有的 Location Provider。
      HashMap mProvidersByName 所有的 Location Provider,以名字為鍵存儲(chǔ)在映射中。
      Object mLock 作為內(nèi)部實(shí)現(xiàn)的鎖使用。
      HashMap mLastKnownLocation 最近一次的定位信息,以 Location Provider 的名稱(chēng)為鍵的映射。
      PackageMonitor mPackageMonitor 監(jiān)測(cè)器,監(jiān)測(cè)服務(wù)包更新事件,并發(fā)送消息給 mLocationHandler。

      從這些字段中我們可以看出,LocationManagerService 中的主要內(nèi)容都是圍繞著 Location Provider 而實(shí)現(xiàn)的。

      構(gòu)造函數(shù)

      下面我們來(lái)看一下 LocationManagerService 的構(gòu)造方法:其代碼如清單 5 所示:


      清單 5. LocationManagerService 構(gòu)造方法
      				
       public LocationManagerService(Context context) { 
          super(); 
          mContext = context; 
          Resources resources = context.getResources(); 
      
          mNetworkLocationProviderPackageName = 
                                              resources.getString(    
           com.android.internal.R.string.config_networkLocationProviderPackageName); 
          mGeocodeProviderPackageName = resources.getString( 
       com.android.internal.R.string.config_geocodeProviderPackageName); 
      
          mPackageMonitor.register(context, null, true); 
      
          if (LOCAL_LOGV) { 
              Slog.v(TAG, "Constructed LocationManager Service"); 
          } 
       }

      這個(gè)構(gòu)造方法很簡(jiǎn)單,這里初始化了 mContext,mNetworkLocationProviderPackageName 和 mGeocodeProviderPackageName 三個(gè)字段,然后使用 mPackageMonitor 注冊(cè)包更新的 context。 其中,mNetworkLocationProviderPackageName,mGeocodeProviderPackageName 這兩個(gè)字段是通過(guò)讀取資源文件的內(nèi)容來(lái)初始化的。關(guān)于這兩個(gè)字段的說(shuō)明在表 2 中已經(jīng)提到過(guò)。

      這里之所以將這兩個(gè)包名放在外部資源文件中,同時(shí)通過(guò) LocationProviderProxy 以代理的形式來(lái)使用這個(gè)服務(wù),目的很顯然:這樣做可以在運(yùn)行的時(shí)候動(dòng)態(tài)的替換服務(wù)。而 PackageMonitor 以及 LocationWorkerHandler 便是相應(yīng)實(shí)現(xiàn)這一機(jī)制的類(lèi)。

      LocationProviderInterface

      上文中我們說(shuō)了,Location Provider 是真正獲取位置信息的模塊。在 android.location 包中,用 LocationProvider 這個(gè)接口來(lái)描述。而這一接口是提供給應(yīng)用層 API 使用的,在 LocationManagerService 中,Location Provider 使用另外一個(gè)接口來(lái)描述,這就是 com.android.location.provider. LocationProviderInterface,LocationManagerService 對(duì)于定位服務(wù)的實(shí)現(xiàn)均是通過(guò)調(diào)用 LocationProviderInterface 來(lái)完成的。

      LocationProviderInterface 對(duì)象存儲(chǔ)在名稱(chēng)為 mProviders 以及 mProvidersByName 的字段中(見(jiàn)表 2)。 LocationProviderInterface 接口的說(shuō)明如表 3 所示:


      表 3. LocationProviderInterface 接口說(shuō)明
      名稱(chēng) 說(shuō)明
      getName 獲取當(dāng)前 Location Provider 的名稱(chēng)
      requiresNetwork 該 Location Provider 是否需要網(wǎng)絡(luò)
      requiresSatellite 該 Location Provider 是否需要衛(wèi)星
      requiresCell 該 Location Provider 是否需要手機(jī)蜂窩信號(hào)
      hasMonetaryCost 該 Location Provider 是否需要耗費(fèi)金錢(qián)
      supportsAltitude 該 Location Provider 是否支持海拔高度信息
      supportsSpeed 該 Location Provider 是否支持速度信息
      supportsBearing 該 Location Provider 是否支持方位信息
      getPowerRequirement 獲取該 Location Provider 的耗電量級(jí)別
      meetsCriteria 該 Location Provider 是否能符合指定的 Criteria
      getAccuracy 獲取該 Location Provider 的精度級(jí)別
      isEnabled 查詢有效狀態(tài)
      enable 使該 Location Provider 有效
      disable 使該 Location Provider 無(wú)效
      getStatus 獲取該 Location Provider 的狀態(tài)
      getStatusUpdateTime 獲取該 Location Provider 的狀態(tài)更新時(shí)間
      enableLocationTracking 使該 Location Provider 位置追蹤有效
      requestSingleShotFix 請(qǐng)求 Single Shot Fix
      getInternalState 獲取該 Location Provider 的內(nèi)部狀態(tài)
      setMinTime 設(shè)置最小時(shí)間
      updateNetworkState 使該 Location Provider 更新網(wǎng)絡(luò)狀態(tài)
      updateLocation 使該 Location Provider 更新位置
      sendExtraCommand 使該 Location Provider 發(fā)送輔助的命令
      addListener 增加監(jiān)聽(tīng)器
      removeListener 移除監(jiān)聽(tīng)器

      在 Android 源碼中,實(shí)現(xiàn) LocationProviderInterface 接口的類(lèi)有四個(gè),它們?nèi)绫?4 所示:


      表 4. LocationProviderInterface 的實(shí)現(xiàn)類(lèi)
      名稱(chēng) 說(shuō)明
      GpsLocationProvider 使用 Gps 衛(wèi)星定位,最準(zhǔn)確的定位方式。
      PassiveProvider 該 Provider 并不真正觸發(fā)定位的更新,而是使用其他 Provider 來(lái)完成位置報(bào)告。
      LocationProviderProxy 使用網(wǎng)絡(luò)實(shí)現(xiàn)定位的服務(wù)的代理。網(wǎng)絡(luò)定位依賴(lài)于手機(jī)信號(hào)的基站或者 Wifi 接入點(diǎn)作為定位的基礎(chǔ)。注意該類(lèi)只是個(gè)代理,并不包含真正的實(shí)現(xiàn)邏輯。
      MockProvider 為了輔助測(cè)試的模擬實(shí)現(xiàn)類(lèi)。

      那么,在 LocationManagerService 中,對(duì)于 LocationProviderInterface 的加載是在什么時(shí)候完成的呢?上面我們已經(jīng)看過(guò) LocationManagerService 的構(gòu)造方法了,并沒(méi)有看到這部分內(nèi)容。 其實(shí),LocationManagerService 是一個(gè)線程類(lèi),除了構(gòu)造函數(shù)以外,在其 run 方法中又完成了另外一部分的初始化工作,主要是調(diào)用其 initialize 方法。 在 initialize 方法中調(diào)用了 loadProviders 方法,loadProviders 這個(gè)方法中完成了 Location Provider 的加載工作。 該方法又經(jīng)過(guò)同步加鎖以及異常的包裝,最終的實(shí)現(xiàn)方法是 _loadProvidersLocked。 _loadProvidersLocked 方法的代碼如清單 5 所示:


      清單 5. _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. 
      	        // The initial value of mNetworkLocationProviderPackageName and 
      	        // mGeocodeProviderPackageName is just used to determine what 
      	        // signatures future mNetworkLocationProviderPackageName and 
      	        // mGeocodeProviderPackageName packages must have. So alternate 
      	        // providers can be installed under a different package name 
      	        // so long as they have the same signature as the original 
      	        // provider packages. 
      	        if (mNetworkLocationProviderPackageName != null) { 
      	            String packageName = findBestPackage( 
      	                   LocationProviderProxy.SERVICE_ACTION, 
      	                    mNetworkLocationProviderPackageName); 
      	            if (packageName != null) { 
      	                mNetworkLocationProvider = new LocationProviderProxy( 
      	                        mContext, 
      	                        LocationManager.NETWORK_PROVIDER, 
      	                        packageName, mLocationHandler); 
      	                mNetworkLocationProviderPackageName = packageName; 
      	                addProvider(mNetworkLocationProvider); 
      	            } 
      	        } 
      	        if (mGeocodeProviderPackageName != null) { 
      	            String packageName = findBestPackage( 
      	                    GeocoderProxy.SERVICE_ACTION, 
      	                    mGeocodeProviderPackageName); 
      	            if (packageName != null) { 
      	                mGeocodeProvider = 
      	                      new GeocoderProxy(mContext, packageName); 
      	                mGeocodeProviderPackageName = packageName; 
      	            } 
      	        } 
      	
      	        updateProvidersLocked(); 
      	    } 
      	  

      這段代碼首先判斷當(dāng)前設(shè)備是否支持 Gps,如果支持,則會(huì)創(chuàng)建 GpsLocationProvider。 接著,創(chuàng)建了一個(gè) PassiveProvider 對(duì)象。 然后,根據(jù) mNetworkLocationProviderPackageName 字段創(chuàng)建 LocationProviderProxy 對(duì)象。(在創(chuàng)建 LocationProviderProxy 的時(shí)候,packageName 參數(shù)是依賴(lài)于 mNetworkLocationProviderPackageName 的。這個(gè)字段是在 LocationManagerService 的構(gòu)造函數(shù)中初始化的。) 最后,根據(jù) mGeocodeProviderPackageName 字段創(chuàng)建 GeocoderProxy 對(duì)象(mGeocodeProviderPackageName 同樣是在 LocationManagerService 的構(gòu)造函數(shù)中初始化的)。 這里需要注意的是,LocationProviderProxy 和 GeocoderProxy 兩個(gè)對(duì)象是否會(huì)創(chuàng)建,是依賴(lài)于系統(tǒng)環(huán)境的。在創(chuàng)建它們之前,都通過(guò) findBestPackage 去查看最合適的包,并且查找的過(guò)程指定了 Intent 的 Action。只有在系統(tǒng)中已有 Service 支持相應(yīng)的 Intent 的 Action 時(shí),才會(huì)找到合適的包,才會(huì)創(chuàng)建這兩個(gè)對(duì)象,否則,如果系統(tǒng)沒(méi)有找到合適的 Service 就不會(huì)創(chuàng)建這兩個(gè)對(duì)象,因?yàn)橄到y(tǒng)根本無(wú)法使用這兩項(xiàng)服務(wù)。 上文我們提到 LocationProviderInterface 有四個(gè)實(shí)現(xiàn)類(lèi)。而在 LocationManager 中,定義了三個(gè)常量來(lái)標(biāo)示定位服務(wù)的提供者:

      • public static final String NETWORK_PROVIDER = "network";
      • public static final String GPS_PROVIDER = "gps";
      • public static final String PASSIVE_PROVIDER = "passive";

      顯然,這三個(gè)常量分別對(duì)應(yīng)著三種 LocationProviderInterface 的實(shí)現(xiàn)類(lèi)(不包括 MockProvider,因?yàn)樵擃?lèi)僅僅是提供給測(cè)試用的)。

      內(nèi)部類(lèi)

      除此以外,LocationManagerService 中還包含了一些內(nèi)部類(lèi),它們的說(shuō)明如表 5 所示:


      表 5. LocationManagerService 中包含的內(nèi)部類(lèi)
      類(lèi)名 說(shuō)明
      LocationWorkerHandler 消息處理器,主要處理位置變更以及網(wǎng)絡(luò)定位的包更新兩種消息。例如,當(dāng)有 Provider 發(fā)現(xiàn)有位置更新時(shí),會(huì)首先發(fā)送消息到 LocationManagerService,而在 LocationManagerService 中該消息最終就是在 LocationWorkerHandler 被處理的。
      LpAccuracyComparator 對(duì)于 LocationProviderInterface 按精度排序的比較器。
      LpCapabilityComparator 對(duì)于 LocationProviderInterface 按能力排序的比較器。
      LpPowerComparator 對(duì)于 LocationProviderInterface 按耗電量排序的比較器。
      ProximityAlert 鄰近距離位置的警報(bào)器。
      ProximityListener 鄰近距離位置的警報(bào)監(jiān)聽(tīng)器。
      Receiver 包裝器,用來(lái)包含一個(gè) ILocationListener 或者 PendingIntent 來(lái)接受位置更新。其中,通知位置更新的方法為 callLocationChangedLocked。
      SettingsObserver 針對(duì)系統(tǒng)設(shè)置的監(jiān)聽(tīng)器。
      UpdateRecord 保存更新記錄的數(shù)據(jù)。

      回頁(yè)首

      GpsLocationProvider 的實(shí)現(xiàn)

      上文已經(jīng)提到,LocationProviderInterface 的實(shí)現(xiàn)類(lèi)有四個(gè)。而實(shí)際上,在移動(dòng)設(shè)備上我們可真正用于定位服務(wù)的實(shí)現(xiàn)通常只有兩種:一種是通過(guò) Gps 模塊,一種是通過(guò)網(wǎng)絡(luò)。 在分析 LocationManagerService 的代碼的時(shí)候我們已經(jīng)看到,對(duì)于通過(guò)網(wǎng)絡(luò)定位的實(shí)現(xiàn)其實(shí)是通過(guò)代理的方式來(lái)完成的,背后的實(shí)現(xiàn)是可以在運(yùn)行時(shí)動(dòng)態(tài)的替換的,是不確定的(在 Android 源碼中,通過(guò)網(wǎng)絡(luò)方式定位的默認(rèn)服務(wù)包名是:com.google.android.location, 很顯然,這是由 Google 提供實(shí)現(xiàn)的服務(wù),但這部分代碼是不包含在 Android 源碼中的,通過(guò)包名的配置,很容易的就做到了將實(shí)現(xiàn)與依賴(lài)進(jìn)行隔離了,這是一種非常好的軟件設(shè)計(jì))。 相反,Gps 模塊的定位實(shí)現(xiàn)是確定的,是我們可以參考的。 所以,下面我就來(lái)看看通過(guò) Gps 模塊來(lái)完成定位的實(shí)現(xiàn)類(lèi):GpsLocationProvider(位于:frameworks/base/services/java/com/android/server/location/GpsLocationProvider.java)。 GpsLocationProvider 類(lèi)包含了大量的常量定義,這些常量大部分是和 HAL 層(關(guān)于 HAL 層,我們稍后會(huì)講解)中的定義相對(duì)應(yīng)的,表 6 列出了比較重要的一些常量:


      表 6. GpsLocationProvider.java 中包含的重要的常量
      名稱(chēng) 說(shuō)明
      GPS_POSITION_MODE_STANDALONE 0 GPS 單獨(dú)運(yùn)行模式
      GPS_POSITION_MODE_MS_BASED 1 AGPS MS-Based 模式
      GPS_POSITION_MODE_MS_ASSISTED 2 AGPS MS-Assisted 模式
      GPS_POSITION_RECURRENCE_PERIODIC 0 以固定的間隔重復(fù)接受 GPS 調(diào)整
      GPS_POSITION_RECURRENCE_SINGLE 1 一次性接受 GPS 調(diào)整
      GPS_STATUS_NONE 0 GPS 狀態(tài)未知
      GPS_STATUS_SESSION_BEGIN 1 開(kāi)始導(dǎo)航
      GPS_STATUS_SESSION_END 2 導(dǎo)航結(jié)束
      GPS_STATUS_ENGINE_ON 3 GPS 引擎開(kāi)始工作
      GPS_STATUS_ENGINE_OFF 4 GPS 引擎關(guān)閉
      GPS_REQUEST_AGPS_DATA_CONN 1 GPS 模塊為 AGPS 請(qǐng)求數(shù)據(jù)連接
      GPS_RELEASE_AGPS_DATA_CONN 2 AGPS 數(shù)據(jù)連接關(guān)閉
      GPS_AGPS_DATA_CONNECTED 3 AGPS 數(shù)據(jù)連接開(kāi)始
      GPS_AGPS_DATA_CONN_DONE 4 AGPS 數(shù)據(jù)連接完成
      GPS_AGPS_DATA_CONN_FAILED 5 AGPS 數(shù)據(jù)連接
      LOCATION_INVALID 0 無(wú)效位置
      LOCATION_HAS_LAT_LONG 1 位置信息中包含了經(jīng)度和緯度信息
      LOCATION_HAS_ALTITUDE 2 位置信息中包含了海拔信息
      LOCATION_HAS_SPEED 4 位置信息中包含了速度信息
      LOCATION_HAS_BEARING 8 位置信息中包含了方位信息
      LOCATION_HAS_ACCURACY 16 位置信息中包含了準(zhǔn)確度信息
      GPS_CAPABILITY_SCHEDULING 0x0000001 GPS 支持計(jì)劃能力
      GPS_CAPABILITY_MSB 0x0000002 GPS 支持 MS-Based AGPS
      GPS_CAPABILITY_MSA 0x0000004 GPS 支持 MS-Assisted
      GPS_CAPABILITY_SINGLE_SHOT 0x0000008 GPS 支持 single-shot
      GPS_CAPABILITY_ON_DEMAND_TIME 0x0000010 GPS 支持 demand time injection

      GpsLocationProvider 調(diào)用 JNI 層為上層提供服務(wù)。它使用了 Android 提供的 Looper 和 Handler 機(jī)制,這使得它可以在一個(gè)獨(dú)立的線程中完成請(qǐng)求的處理,這些請(qǐng)求的響應(yīng)在 Looper 所在的線程,而不是請(qǐng)求所在的線程,因此不會(huì)阻塞請(qǐng)求的線程。 為了便于理解,我們將 GpsLocationProvider 中的方法分為幾類(lèi)來(lái)討論(某些方法可能不止屬于一類(lèi)):

      初始化方法

      GpsLocationProvider 的構(gòu)造函數(shù)代碼內(nèi)容較多,這里就不貼出了??偟膩?lái)說(shuō),構(gòu)造函數(shù)中主要完成了以下幾個(gè)事情:

      • 初始化了一系列的字段,包括獲取處理時(shí)間,電源,鬧鐘,網(wǎng)絡(luò)連接等功能的系統(tǒng)服務(wù)
      • 在系統(tǒng)中注冊(cè)了一個(gè) BroadcastReceiver,這個(gè) BroadcastReceiver 的作用是負(fù)責(zé)在使用 Gps 模塊時(shí)響應(yīng)對(duì)于鬧鐘以及短消息的事件處理。
      • 讀取 Gps 模塊的外部配置文件,這是一個(gè)屬性文件,該文件是用來(lái)配置 Gps 模塊擴(kuò)展功能的服務(wù)器信息,例如 XTRA 服務(wù)器,NTP 服務(wù)器等信息。該文件的位置記錄在 PROPERTIES_FILE 字段中,它的值是"/etc/gps.conf"。
      • 創(chuàng)建并啟動(dòng) GpsLocationProviderThread,這是一個(gè)線程類(lèi),對(duì)于 Gps 模塊功能的請(qǐng)求都是在這個(gè)線程中完成的。

      GpsLocationProviderThread 的 run 方法代碼如清單 7 所示:


      清單 7. GpsLocationProviderThread 類(lèi)中 run 方法代碼
      				
      	 public void run() { 
      	    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
      	    initialize(); 
      	    Looper.prepare(); 
      	    mHandler = new ProviderHandler(); 
      	    // signal when we are initialized and ready to go 
      	    mInitializedLatch.countDown(); 
      	    Looper.loop(); 
      	 } 
      	

      這個(gè)方法的處理邏輯如下: 首先,將當(dāng)前進(jìn)程級(jí)別設(shè)置為后臺(tái)級(jí)別,這是一個(gè)相對(duì)較低的級(jí)別。然后調(diào)用 initialize 方法,在這個(gè)方法中,將 mBroadcastReciever 注冊(cè)到 GpsLocationProviderThread 所在的線程中。 接著,使用 Looper.prepare(); 將當(dāng)前線程初始化為 Looper。然后,創(chuàng)建了一個(gè) ProviderHandler 對(duì)象。ProviderHandler 是 GpsLocationProvider 的內(nèi)部類(lèi),它繼承自 Handler,它負(fù)責(zé)處理通過(guò) Message 發(fā)送到當(dāng)前線程的請(qǐng)求。Looper 和 Handler 的配合使得當(dāng)前線程可以獨(dú)立于主線程完成請(qǐng)求和處理。ProviderHandler 是一個(gè)很重要的類(lèi),GpsLocationProvider 中很多請(qǐng)求都是依靠 Message 機(jī)制完成的,例如當(dāng)調(diào)用其 updateNetworkState,updateLocation 等方法時(shí),都是向 GpsLocationProviderThread 線程發(fā)送消息,這些消息的處理都是在 ProviderHandler 中完成的(即 GpsLocationProviderThread 所在線程)。 初始化的最后,為了通知主線程初始化已經(jīng)完成,調(diào)用了 mInitializedLatch.countDown(),這行代碼和 GpsLocationProvider 構(gòu)造函數(shù)中:mInitializedLatch.await() 是對(duì)應(yīng)的。調(diào)用 mInitializedLatch.await() 會(huì)導(dǎo)致線程阻塞,直到有另外一個(gè)線程調(diào)用 mInitializedLatch.countDown() 為止。這里這樣做的原因是因?yàn)橛胁糠殖跏蓟ぷ髟?GpsLocationProviderThread 線程中完成,這和主線程是互相獨(dú)立的。為了在保證只有在所有初始化工作完成之后 GpsLocationProvider 構(gòu)造函數(shù)才能返回,所以使用了 CountDownLatch 來(lái)保證。

      實(shí)現(xiàn) LocationProviderInterface 接口的方法

      這些方法是實(shí)現(xiàn) LocationProviderInterface 接口的方法,它們已經(jīng)在表 3 中說(shuō)明。

      向 GpsLocationProviderThread 發(fā)送請(qǐng)求的方法

      這些方法通過(guò) Message 機(jī)制發(fā)送請(qǐng)求到 GpsLocationProviderThread,它們?nèi)绫?7 所示:


      表 7. GpsLocationProviderThread 的主要方法
      名稱(chēng) 說(shuō)明
      enable 見(jiàn)表 2
      disable 見(jiàn)表 2
      enableLocationTracking 見(jiàn)表 2
      requestSingleShotFix 見(jiàn)表 2
      updateNetworkState 見(jiàn)表 2
      requestUtcTime 請(qǐng)求 Utc 時(shí)間信息
      xtraDownloadRequest XTRA 下載請(qǐng)求
      updateLocation 見(jiàn)表 2
      addListener 見(jiàn)表 2
      removeListener 見(jiàn)表 2

      ProviderHandler 調(diào)用的處理方法

      ProviderHandler 對(duì)于請(qǐng)求的處理邏輯并沒(méi)有直接寫(xiě)在 handleMessage 方法中,而是對(duì)于每一個(gè)請(qǐng)求專(zhuān)門(mén)用一個(gè)方法來(lái)處理,這些方法如表 8 所示。這些方法的實(shí)現(xiàn)通常都是依賴(lài)于表 9 的本地方法的。


      表 8. ProviderHandler 的方法
      名稱(chēng) 說(shuō)明
      handleEnable 使該 Provider 有效
      handleDisable 使該 Provider 無(wú)效
      handleEnableLocationTracking 使該 Provider 開(kāi)始記錄位置追蹤信息
      handleRequestSingleShot 使該 Provider 完成 singleShot 請(qǐng)求
      handleUpdateNetworkState 處理網(wǎng)絡(luò)狀態(tài)更新
      handleInjectNtpTime 處理 Ntp 時(shí)間注入
      handleDownloadXtraData 處理下載 Xtra 數(shù)據(jù)
      handleUpdateLocation 處理位置 更新
      handleAddListener 增加監(jiān)聽(tīng)器
      handleRemoveListener 刪除監(jiān)聽(tīng)器

      本地方法

      Gps 模塊的功能實(shí)現(xiàn)最終需要調(diào)用硬件來(lái)完成,這些實(shí)現(xiàn)必須通過(guò) C/C++ 語(yǔ)言才能完成。為了能在 GpsLocationProvider.java 中調(diào)用到這些功能,GpsLocationProvider 中包含了許多的 native 方法,這些方法如表 9 所示,這些方法都是以 JNI 的方式來(lái)實(shí)現(xiàn)的。這些 JNI 的實(shí)現(xiàn)方法位于 com_android_server_location_GpsLocationProvider.cpp(位于:frameworks/base/services/jni)中。


      表 9. GpsLocationProvider 中包含的 native 方法
      名稱(chēng) 說(shuō)明
      class_init_native 類(lèi)的初始化方法
      native_is_supported 是否支持 Gps 模塊
      native_init 初始化方法
      native_cleanup 負(fù)責(zé)清理工作
      native_set_position_mode 設(shè)置位置模式
      native_start 開(kāi)始導(dǎo)航
      native_stop 停止導(dǎo)航
      native_delete_aiding_data 刪除輔助信息
      native_read_sv_status 讀取 SV 狀態(tài)
      native_read_nmea 讀取 nmea 信息
      native_inject_location 注入位置信息
      native_inject_time 注入時(shí)間信息
      native_supports_xtra 是否支持 XTRA
      native_inject_xtra_data 注入 XTRA 數(shù)據(jù)
      native_get_internal_state 獲取內(nèi)部狀態(tài)
      native_agps_data_conn_open 打開(kāi) AGps 數(shù)據(jù)連接
      native_agps_data_conn_closed 關(guān)閉 AGps 數(shù)據(jù)連接
      native_agps_data_conn_failed AGps 數(shù)據(jù)連接失敗
      native_agps_ni_message AGps NI(Network-initiated)消息
      native_set_agps_server 設(shè)置 AGPS 服務(wù)器
      native_send_ni_response 發(fā)送 NI 響應(yīng)
      native_agps_set_ref_location_cellid AGPS 設(shè)置引用位置
      native_agps_set_id AGPS 設(shè)置 id
      native_update_network_state 更新網(wǎng)絡(luò)狀態(tài)

      被 JNI 方法回調(diào)的方法

      GpsLocationProvider 中最后一類(lèi)方法是被 JNI 方法回調(diào)的方法。在 JNI 的實(shí)現(xiàn)中,通過(guò)這些方法的回調(diào)來(lái)傳遞 JNI 層的執(zhí)行結(jié)果。它們?nèi)绫?10 所示:


      表 10. GpsLocationProvider 中被 JNI 回調(diào)的方法
      名稱(chēng) 說(shuō)明
      reportLocation 報(bào)告位置
      reportStatus 報(bào)告狀態(tài)
      reportSvStatus 報(bào)告 SV 狀態(tài)
      reportAGpsStatus 報(bào)告 AGps 狀態(tài)
      reportNmea 報(bào)告 Nmea
      setEngineCapabilities 設(shè)置引擎能力
      xtraDownloadRequest XTRA 下載請(qǐng)求
      reportNiNotification 報(bào)告 NI 通知
      requestRefLocation 請(qǐng)求引用位置
      requestSetID 請(qǐng)求設(shè)置 id
      requestUtcTime 請(qǐng)求 Utc 時(shí)間

      回頁(yè)首

      JNI 層與 HAL 層

      JNI(Java Native Interface) 層依賴(lài)于 HAL 層為上層提供服務(wù)。 HAL(Hardware Abstract Layer) 層是對(duì)硬件的抽象,這是整個(gè)模塊實(shí)現(xiàn)的最底層。

      JNI 層

      上文中我們已經(jīng)提到,Gps 模塊 JNI 層的實(shí)現(xiàn)在 com_android_server_location_GpsLocationProvider.cpp(位于:frameworks/base/services/jni)文件中。該層依賴(lài) HAL 層接口,提供對(duì)于 GpsLocationProvider.java 中本地方法的實(shí)現(xiàn)。這些本地方法和 JNI 方法是一一對(duì)應(yīng)(關(guān)于 GpsLocationProvider.java 中的本地方法請(qǐng)參閱表 9。)。 這種對(duì)應(yīng)關(guān)系是在 register_android_server_location_GpsLocationProvider 方法中,通過(guò) jniRegisterNativeMethods 函數(shù)建立的。 兩個(gè)文件中函數(shù)的對(duì)應(yīng)關(guān)系如表 11 所示:


      表 11. GpsLocationProvider 中的 native 方法及其 JNI 實(shí)現(xiàn)方法的對(duì)應(yīng)關(guān)系
      GpsLocationProvider.java 中的方法名 com_android_server_location_GpsLocationProvider.cpp 中對(duì)應(yīng)的實(shí)現(xiàn)方法
      class_init_native android_location_GpsLocationProvider_class_init_native
      native_is_supported android_location_GpsLocationProvider_is_supported
      native_init android_location_GpsLocationProvider_init
      native_cleanup android_location_GpsLocationProvider_cleanup
      native_set_position_mode android_location_GpsLocationProvider_set_position_mode
      native_start android_location_GpsLocationProvider_start
      native_stop android_location_GpsLocationProvider_stop
      native_delete_aiding_data android_location_GpsLocationProvider_delete_aiding_data
      native_read_sv_status android_location_GpsLocationProvider_read_sv_status
      native_read_nmea android_location_GpsLocationProvider_read_nmea
      native_inject_location android_location_GpsLocationProvider_inject_location
      native_inject_time android_location_GpsLocationProvider_inject_time
      native_supports_xtra android_location_GpsLocationProvider_supports_xtra
      native_inject_xtra_data android_location_GpsLocationProvider_inject_xtra_data
      native_get_internal_state android_location_GpsLocationProvider_get_internal_state
      native_agps_data_conn_open android_location_GpsLocationProvider_agps_data_conn_open
      native_agps_data_conn_closed android_location_GpsLocationProvider_agps_data_conn_closed
      native_agps_data_conn_failed android_location_GpsLocationProvider_agps_data_conn_failed
      native_agps_ni_message android_location_GpsLocationProvider_send_ni_response
      native_set_agps_server android_location_GpsLocationProvider_set_agps_server
      native_send_ni_response android_location_GpsLocationProvider_send_ni_response
      native_agps_set_ref_location_cellid android_location_GpsLocationProvider_agps_set_reference_location_cellid
      native_agps_set_id android_location_GpsLocationProvider_agps_set_id
      native_update_network_state android_location_GpsLocationProvider_update_network_state

      這其中,最為重要的是兩個(gè)初始化方法: 一個(gè)是 android_location_GpsLocationProvider_class_init_native 方法。這個(gè)方法在 GpsLocationProvider 類(lèi)中的靜態(tài)初始化塊中被調(diào)用,它的作用有三個(gè):

      • 在 JNI 層初始化對(duì)于 GpsLocationProvider.java 中回調(diào)方法的引用。
      • 嘗試打開(kāi) Gps 設(shè)備。
      • 如果 Gps 設(shè)備打開(kāi)成功,則獲取 Gps 擴(kuò)展接口的指針,它們一共有五種,分別是:GpsXtraInterface,AGpsInterface,GpsNiInterface,GpsDebugInterface,AGpsRilInterface。這些結(jié)構(gòu)的說(shuō)明見(jiàn)表 12。

      另一個(gè)是 android_location_GpsLocationProvider_init 方法。這個(gè)方法的作用是:

      • 嘗試初始化 Gps 設(shè)備模塊,如果初始化失敗,直接返回 false。
      • 嘗試初始化 XTRA 擴(kuò)展接口,如果初始化失敗,則使 sGpsXtraInterface 指向 NULL。
      • 嘗試初始化 AGpsInterface,GpsNiInterface,AGpsRilInterface 擴(kuò)展組件。

      HAL 層

      HAL 層是與硬件相接觸的一層,該層使用 C 語(yǔ)言實(shí)現(xiàn)。 Gps 模塊的 HAL 層的頭文件是 gps.h(位于:hardware/libhardware/include/hardware)。gps.h 中包含了很多的常量(這些常量是和 GpsLocationProvider 中的內(nèi)容相對(duì)應(yīng)的,請(qǐng)參見(jiàn)表 6)以及結(jié)構(gòu)體的定義。這其中,最重要的結(jié)構(gòu)體就是 GpsInterface,這是對(duì) Gps 模塊的抽象。它的內(nèi)容如清單 7 所示:


      清單 6. GpsInterface 結(jié)構(gòu)體定義
      				
       typedef struct { 
          // 設(shè)置為 sizeof(GpsInterface) 
          size_t          size; 
          // 打開(kāi) Gps 模塊,提供接口實(shí)現(xiàn)的回調(diào)函數(shù)
          int   (*init)( GpsCallbacks* callbacks ); 
          // 開(kāi)始導(dǎo)航
          int   (*start)( void ); 
          // 停止導(dǎo)航
          int   (*stop)( void ); 
          // 關(guān)閉 Gps 模塊
          void  (*cleanup)( void ); 
          // 注入當(dāng)前時(shí)間
          int   (*inject_time)(GpsUtcTime time, int64_t timeReference, 
              int uncertainty); 
          // 注入當(dāng)前位置
          int  (*inject_location)(double latitude, double longitude, 
              float accuracy); 
          // 指定下一次啟動(dòng)時(shí),不使用 flags 所定義的信息
          void  (*delete_aiding_data)(GpsAidingData flags); 
          // 設(shè)置位置模式
          int   (*set_position_mode)(GpsPositionMode mode, 
              GpsPositionRecurrence recurrence, 
              uint32_t min_interval, uint32_t preferred_accuracy, 
              uint32_t preferred_time); 
          // 獲取擴(kuò)展信息的指針
          const void* (*get_extension)(const char* name); 
       } GpsInterface; 
      

      除此以外,該頭文件中還定義了與 Gps 模塊相關(guān)的其他結(jié)構(gòu)體,它們?nèi)绫?12 所示:


      表 12. gps.h 中定義的其他結(jié)構(gòu)體
      名稱(chēng) 說(shuō)明
      GpsLocation 描述 Gps 位置,包括經(jīng)度,維度,海拔,速度,方位,精度等信息。
      GpsStatus 描述 Gps 狀態(tài)
      GpsSvInfo 描述 Gps SV 信息
      GpsSvStatus 描述 Gps SV 狀態(tài)
      AGpsRefLocationCellID 描述 AGps 引用位置單元 Id
      AGpsRefLocationMac 描述 AGps 引用位置 Mac
      AGpsRefLocation 描述 AGps 引用位置
      GpsCallbacks 描述 Gps 回調(diào)函數(shù)
      GpsXtraCallbacks 描述 XTRA 接口回調(diào)函數(shù)
      GpsXtraInterface 提供 XTRA 支持的擴(kuò)展接口
      GpsDebugInterface 提供 DEBUG 支持的擴(kuò)展接口
      AGpsStatus 描述 AGps 狀態(tài)
      AGpsCallbacks 描述 AGps 接口回調(diào)函數(shù)
      AGpsInterface 提供 AGps 支持的擴(kuò)展接口
      GpsNiNotification 描述一次 NI(Network-initiated)請(qǐng)求
      GpsNiCallbacks 描述 Gps NI 回調(diào)函數(shù)結(jié)構(gòu)體
      GpsNiInterface 提供 NI 支持的擴(kuò)展接口
      AGpsRilCallbacks 描述 AGps Ril 回調(diào)函數(shù)結(jié)構(gòu)體
      AGpsRilInterface 提供 AGPS-RIL 支持的擴(kuò)展接口

      由于篇幅所限,這里就不將這些內(nèi)容展開(kāi)講解,請(qǐng)讀者自行參閱 Android 源碼。 同時(shí),Android 源碼中包含了對(duì)于高通公司的 Gps 模塊的實(shí)現(xiàn),其代碼位于 hardware/qcom/gps 中。

      回頁(yè)首

      總結(jié)

      綜合以上知識(shí),我們來(lái)看一下當(dāng)硬件接受到位置更新之后,為了通知這個(gè)信息,整個(gè)調(diào)用關(guān)系是如何的 ( 為了描述方便,下文將 com_android_server_location_GpsLocationProvider.cpp 簡(jiǎn)稱(chēng)為 GpsLocationProvider.cpp)。

      1. 當(dāng)硬件檢測(cè)到有位置更新之后,最初調(diào)用的是 GpsLocationProvider.cpp 中的 location_callback 函數(shù)。
      2. location_callback 函數(shù)中對(duì)應(yīng)的是調(diào)用 GpsLocationProvider.java 中的 reportLocation 方法。
      3. GpsLocationProvider.java 中的 reportLocation 方法會(huì)調(diào)用 ILocationManager 的 reportLocation 方法,然后是調(diào)用 LocationManagerService 的 reportLocation 方法。
      4. LocationManagerService 的 reportLocation 方法中會(huì)對(duì) LocationWorkerHandler 發(fā)送消息 MESSAGE_LOCATION_CHANGED。該消息在 LocationWorkerHandler 的 handleMessage 方法中被處理。處理方法中會(huì)調(diào)用 LocationProviderInterface 的 updateLocation 方法和 LocationManagerService 的 handleLocationChangedLocked 的方法。前者對(duì)于 Gps 模塊來(lái)說(shuō)就是調(diào)用 GpsLocationProvider 的 updateLocation 方法。
      5. GpsLocationProvider 的 updateLocation 方法會(huì)對(duì) ProviderHandler 發(fā)送消息 UPDATE_LOCATION,該消息在 ProviderHandler 的 handler 方法中被處理,處理的方法是調(diào)用 handleUpdateLocation 方法,該方法中會(huì)調(diào)用 native_inject_location 方法以注入。
      6. 而 LocationManagerService 的 handleLocationChangedLocked 的方法會(huì)將最新的位置存放到 mLastKnownLocation 中。至此,便可以通過(guò) LocationManagerService 的 getLastKnownLocation 方法獲取到最新更新的位置信息了。

      下面是上述的邏輯順序圖。由于調(diào)用過(guò)程比較復(fù)雜,所以分成了兩部分。 圖 4 描述了上述步驟的 1 ~ 4,圖 5 描述了上述步驟的 4 ~ 6


      圖 4. 位置更新后的調(diào)用關(guān)系(前半部分)
      圖 4. 位置更新后的調(diào)用關(guān)系(前半部分)

      查看大圖


      圖 5. 位置更新后的調(diào)用關(guān)系(后半部分)
      圖 5. 位置更新后的調(diào)用關(guān)系(后半部分)

      查看大圖

      最后,我們來(lái)總結(jié)一下定位服務(wù)的實(shí)現(xiàn)牽涉到的文件及所處路徑,它們?nèi)绫?13 所示。


      表 13. 定位服務(wù)實(shí)現(xiàn)中牽涉到的文件一覽
      路徑 說(shuō)明
      frameworks/base/location/java/android 包含提供給應(yīng)用開(kāi)發(fā)的 API
      frameworks/base/services/java/com/android/server 包含 LocationManagerService.java
      frameworks/base/core/java/android/os 包含 ServiceManager.java
      frameworks/base/core/java/android/app 包含 ContextImpl.java
      system/core/rootdir 包含 init.rc
      frameworks/base/services/java/com/android/server/location 包含 LocationManagerService.java
      frameworks/base/services/jni 包含 com_android_server_location_GpsLocationProvider.cpp
      hardware/libhardware/include/hardware 包含了 HAL 層的接口
      hardware/qcom/gps 包含了對(duì)于高通公司的 Gps 模塊的實(shí)現(xiàn)

      前面我們說(shuō)了,在 Android 系統(tǒng)中,所有的系統(tǒng)服務(wù)的實(shí)現(xiàn)結(jié)構(gòu)都是類(lèi)似的。相信讀者在理解了定位服務(wù)的實(shí)現(xiàn)之后再去理解其他的系統(tǒng)服務(wù)是比較容易的。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多