2012年1月2日月曜日

位置情報取得について調べてみた(その2)

さて、昨日は位置情報の取得技術と、Androidのアプリからの利用方法について軽く調べてみました。というわけで、続きの調査メモです。

前回のエントリで見た位置情報関連クラスは以下の通りです。
  • Address
  • Criteria
  • Geocoder
  • GpsSatelite
  • GpsStatus
  • Location
  • LocationManager
  • LocationProvider
さて、この中で真っ先に取得するのは、LocationManager [ frameworks/base/location/java/android/location/LocationManager.java ]
でした。LocationManagerは、Binderを使ってSystem Location Service(LocationManagerService)へアクセスするためのクラスのようです。

実体は、ContextImplクラスのstaticブロックで生成・登録されています。
[src] frameworks/base/core/java/android/app/ContextImpl.java
        registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
                    return new LocationManager(ILocationManager.Stub.asInterface(b));
                }});

というわけで、ここでPF部として目を付けなくてはならないのは、LocationManagerServiceですね。で、このLocationManagerServiceが生成されているのは何処か?というと、いつか何処かでみた場所なんですね。この辺りはPF部でも発表してますし、さらっと呼び出しだけ見ておきましょう。

SystemServer::init2()
  ServerThread::start()
    ServerThread::run() [frameworks/base/services/java/com/android/server/SystemServer.java]
        location = new LocationManagerService(context);
        ServiceManager.addService(Context.LOCATION_SERVICE, location);
        final LocationManagerService locationF = location;
        locationF.systemReady(); [frameworks/base/services/java/com/android/server/LocationManagerService.java]
            Thread thread = new Thread(null, this, "LocationManagerService");
            thread.start();

注: 例によって上記はC++チックなメソッド名の表記をしているだけです。

init周りを追いかけた時にでてきたSystemServerのServerThread中で生成され、LocationManagerServiceスレッドがstartされています。

public void LocationManagerService::run()
{
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    Looper.prepare();
    mLocationHandler = new LocationWorkerHandler();
    initialize();
    Looper.loop();
}

Runされると、initialize処理を行った後、Looperでまわしています。このLocationManagerService::initialize()の中で、呼んでいるLocationManagerSerivce::loadProviders()でAndroid共通のProviderの生成と登録、Geocoderの生成が行われています。

LocationManagerService::loadProviders()
    LocationManagerService::loadProvidersLocked()
        LocationManagerService::_loadProvidersLocked()
        {
                if (GpsLocationProvider.isSupported()) {
                    GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
                    mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
                    mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
                    addProvider(gpsProvider);
                    mGpsLocationProvider = gpsProvider;
                }
                PassiveProvider passiveProvider = new PassiveProvider(this);
                addProvider(passiveProvider);
                mEnabledProviders.add(passiveProvider.getName());

                PackageManager pm = mContext.getPackageManager();
                if (mNetworkLocationProviderPackageName != null &&
                    pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) {
                    mNetworkLocationProvider =
                        new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
                                mNetworkLocationProviderPackageName, mLocationHandler);
                    addProvider(mNetworkLocationProvider);
                }

                if (mGeocodeProviderPackageName != null &&
                         pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) {
                    mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
                }
                updateProvidersLocked();
        }

生成/AddされているProviderは、3つ
  • public class GpsLocationProvider implements LocationProviderInterface
  • public class PassiveProvider implements LocationProviderInterface
  • public class LocationProviderProxy implements LocationProviderInterface
GeocodeProviderとしては
  • public class GeocoderProxy
が生成されています。

またこのうちPassiveProviderは、mNetworkLocationProviderPackageNameのパッケージがある場合に生成されています。これは、リソース中のcom.android.internal.R.string.config_networkLocationProvider の文字列になります。
また、GeocodeProxyについても、mGeocodeProviderPackageNameのパッケージがある場合にのみ生成されており、こちらは、com.android.internal.R.string.config_geocodeProvider の文字列になります。

4.0のソースコードに含まれるtunaのconfig設定 [
device/samsung/tuna/overlay/frameworks/base/core/res/res/values/config.xml]  ですと

<string name="config_networkLocationProvider">com.google.android.location.NetworkLocationProvider</string>
<string name="config_geocodeProvider">com.google.android.location.GeocodeProvider</string>

となっています。
ちなみに、GplLocationProvider classには

    static { class_init_native(); }

となっています。ですので、最初のif文の時にこの関数が呼び出されます。
こちらは、nativeコードで実装されており、実際には

android_location_GpsLocationProvider_class_init_native()

で、その中でhw_get_module("gps",....)が呼び出されます。この辺りはHALの実装の周りの部分でして、必要になるライブラリを探して行きます。4.0のコードでは以下の順にライブラリを探し見つかったものをdlopenを使ってZygoteとリンクします。


  1. /vendor/lib/hw/gps.<ro.hardware>.so
  2. /system/lib/hw/gps.<ro.hardware>.so
  3. /vendor/lib/hw/gps.<ro.product.board>.so
  4. /system/lib/hw/gps.<ro.product.board>.so
  5. /vendor/lib/hw/gps.<ro.board.platform>.so
  6. /system/lib/hw/gps.<ro.board.platform>.so
  7. /vendor/lib/hw/gps.<ro.arch>.so
  8. /system/lib/hw/gps.<ro.arch>.so
  9. /system/lib/hw/gps.default.so

以前は、libがついていた気がするんですけどね。最近はlibがつかないのかな。

ついでにいうと、implements LocationProviderInterfaceなclassは他にもあって
  • public class MockProvider implements LocationProviderInterface
というのがあります。こちらは、LocationManager::addTestProviderを行った時に内部でaddProviderされるProviderのようです。CTS等のテスト時に使われるようですね。


さて、とりあえずここまでで見た限りは、LocationManagerはLocation情報を管理しているわけではなく、LocationProviderの管理をしていると見るのが自然なようです。
というわけで、次回は、LocationProviderについて、Gpsを中心にもう少し調べてみたいなと思います。

0 件のコメント:

コメントを投稿