Android GPS学習ノート—LMS初期化

15100 ワード

LocationManagerService(LMSと略称する)とAndroid Java Frame eworkの他のServiceは同じSystemServerによって作成されて実行されます。processプロセス中です。LMSはシステムLocationモジュールの核心です。初期化を見てみます。
    カタログ:frame eworks/base/services/core/java/com/android/server
1.System Server.java
    SystemServer.javaファイルにおいて、startOther Service関数はLMSのコードを作成しました。まずLMSオブジェクトを作成し、LOCATION_を作成しました。SERVICEをServiceManagerに追加します。
if (!disableLocation) {
                try {
                    Slog.i(TAG, "Location Manager");
                    location = new LocationManagerService(context);
                    ServiceManager.addService(Context.LOCATION_SERVICE, location);
                } catch (Throwable e) {
                    reportWtf("starting Location Manager", e);
                }
同じくstartOtherService関数でLMSのsystem Running関数を呼び出しました。コードは以下の通りです。
           try {
                    if (locationF != null) locationF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying Location Service running", e);
                }
2.LMS(LocationManagerService)
LMSのsystem Running関数は以下のように実現される。
public void systemRunning() {
        synchronized (mLock) {
            if (D) Log.d(TAG, "systemReady()");

            // fetch package manager
            mPackageManager = mContext.getPackageManager();

            // fetch power manager
            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

            // prepare worker thread
            mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());

            // prepare mLocationHandler's dependents
            // Android               。  ,         LocationFudger        
            //                 。
            mLocationFudger = new LocationFudger(mContext, mLocationHandler);
            //                     LP,      ,LP     java    
            mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
            mBlacklist.init();
            //GeofenceManager       。            
            mGeofenceManager = new GeofenceManager(mContext, mBlacklist);

            // prepare providers     
            loadProvidersLocked();
            //           ,        LP。     , LP   LocationProviderInterface   enable/disable     
            updateProvidersLocked();
        }

        // listen for settings changes           ,  LOCATION_PROVIDERS_ALLOWED,            ,           
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
                new ContentObserver(mLocationHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        synchronized (mLock) {
                            updateProvidersLocked();
                        }
                    }
                }, UserHandle.USER_ALL);
        mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);

        //          ,APK  /          
        ... ...
    }
system Runningの中の内容はわりに多くて、その中の肝心な関数を見ます:loadProviderss Locked()、この関数はシステムの中のすべてのLPを創建してロードすることに用いて、そのコードは以下の通りです。
private void loadProvidersLocked() {
        
        //  PassiveProvider,  LP   enable 。passive    ,           ,     LP   
        //    ,PassiveProvider       LMS     LP        ,    PassiveProvider 
        //updateLocation      
        PassiveProvider passiveProvider = new PassiveProvider(this);
        //LMS      LP
        addProviderLocked(passiveProvider);
        //PassiveProvider        。mEnabledProviders          LP        
        mEnabledProviders.add(passiveProvider.getName());
        mPassiveProvider = passiveProvider;
        
        //  GPSLP   
        GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
                mLocationHandler.getLooper());

        if (GpsLocationProvider.isSupported()) {
            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
            //  GPSLP
            addProviderLocked(gpsProvider);
            //GPSLP         ,     mRealProviders            
            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
        }
        mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
        mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();

 
        Resources resources = mContext.getResources();
        ArrayList<String> providerPackageNames = new ArrayList<String>();
        //config_locationProviderPackageNames      LP java  。Android        
        //"com.android.location.fused"。FusedLP        frameworks/base/packages/FusedLocation
        String[] pkgs = resources.getStringArray(
                com.android.internal.R.array.config_locationProviderPackageNames);
        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
                Arrays.toString(pkgs));
        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
        //          LP   ,LMS                
        ensureFallbackFusedProviderPresentLocked(providerPackageNames);

        //   NetworkLP
        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
                mContext,
                LocationManager.NETWORK_PROVIDER,
                NETWORK_LOCATION_SERVICE_ACTION,
                com.android.internal.R.bool.config_enableNetworkLocationOverlay,
                com.android.internal.R.string.config_networkLocationProviderPackageName,
                com.android.internal.R.array.config_locationProviderPackageNames,
                mLocationHandler);
        if (networkProvider != null) {
            //NetworkLP     LP
            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
            //       LP   mProxyProviders 
            mProxyProviders.add(networkProvider);
            addProviderLocked(networkProvider);
        } else {
            Slog.w(TAG,  "no network location provider found");
        }

        //   FusedLP
        LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
                mContext,
                LocationManager.FUSED_PROVIDER,
                FUSED_LOCATION_SERVICE_ACTION,
                com.android.internal.R.bool.config_enableFusedLocationOverlay,
                com.android.internal.R.string.config_fusedLocationProviderPackageName,
                com.android.internal.R.array.config_locationProviderPackageNames,
                mLocationHandler);
        if (fusedLocationProvider != null) {
            addProviderLocked(fusedLocationProvider);
            mProxyProviders.add(fusedLocationProvider);
            //FusedLP         
            mEnabledProviders.add(fusedLocationProvider.getName());
            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
        } else {
            Slog.e(TAG, "no fused location provider found",
                    new IllegalStateException("Location service needs a fused location provider"));
        }

        //   Geocoder
        mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
                com.android.internal.R.bool.config_enableGeocoderOverlay,
                com.android.internal.R.string.config_geocoderProviderPackageName,
                com.android.internal.R.array.config_locationProviderPackageNames,
                mLocationHandler);
        if (mGeocodeProvider == null) {
            Slog.e(TAG,  "no geocoder provider found");
        }

        ... ...
        
    }
LMSの初期化関数において、loadProviders Lockedは、システム内のすべてのLPを作成してロードするために使用される。
1.Passive Provider:被動式の位置データ更新サービスを提供します。その位置データは他のLPから来ます。
2.GpslocationProvider:LMSによって作成されロードされ、LMSにあるプロセスsystem(u)を実行します。processでは、システムが提供するLPサービスに属します。
3.Network LocationProvider:このLPサービスはアプリケーションによって提供されます。
4.FussedLocationProvider:Fused Location.appkサービスで、システムが提供するアプリケーションに属します。その内部に他のLPが使用されます。
5.Geocode Provider:第三者のアプリケーションによって提供されます。一般的にはNetworkLPと同じアプリケーションにあります。
その中のGpspLocationProviderは重点で、次の文章の中でその初期化を紹介します。まずLMSがどのようにアプリケーションのLPと相互作用するかを見てみます。
3.LocationProvider Proxy.java
    loadProviders Proxy.javaコードにより、LMSはLocationProvider ProxyのcreateAndBind関数を通じてアプリケーションのLPをロードすることができます。
public static LocationProviderProxy createAndBind(
            Context context, String name, String action,
            int overlaySwitchResId, int defaultServicePackageNameResId,
            int initialPackageNamesResId, Handler handler) {
        LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
                overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId,
                handler);
        if (proxy.bind()) {
            return proxy;
        } else {
            return null;
        }
    }
上記の関数には二つの重要な関数があります。一つはLocationProvider Proxyの構造関数で、もう一つはbind関数です。まずその構造関数を見てみます。
private LocationProviderProxy(Context context, String name, String action,
            int overlaySwitchResId, int defaultServicePackageNameResId,
            int initialPackageNamesResId, Handler handler) {
        mContext = context;
        mName = name;
        mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId,
                defaultServicePackageNameResId, initialPackageNamesResId,
                mNewServiceWork, handler);
    }
その中でServiceWatchはLocationProvider Proxyの中で最も重要な対象です。Android LMSアーキテクチャでは、アプリケーションが実現するLPサービスはServiceを介して提供される。ServiceWatchは、LocationProvider Proxyにおいて、アプリケーションが実現するLPサービスを接続して監視するためのものです。
ビッド関数をもう一度見てみます。
private boolean bind () {
        return mServiceWatcher.start();
    }
bind関数は直接ServiceWatchのstart関数を呼び出しました。直接にstart関数を見にきます。
public boolean start() {
        synchronized (mLock) {
        //    bindBestPackageLocked
        if (!bindBestPackageLocked(mServicePackageName)) return false;
        }

        //       
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                    switchUser();
                }
            }
        }, UserHandle.ALL, intentFilter, null, mHandler);

        //          ,  ,       
        if (mServicePackageName == null) {
            mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
        }

        return true;
    }
その中の重要な関数はbindBestPackage Lockedで、その仕事は主に以下の内容があります。
1.目的のアプリケーションの署名を確認する
2.createAndBindの3番目のパラメータに基づいて、このターゲットアプリケーションが実現するServiceを検索します。NetworkLPを例にとると、ターゲットアプリケーションは「comp.android.locations.service.v.2.Network LocationProvider」というサービスを提供しなければなりません。
3.このサービスに接続し、ILocationProviderのタイプの例を取得する。この例により、LocationProvider Proxyは、アプリケーション内のLPサービスと対話することができる。
bindBestPackage Lockedの中で一番重要な関数はbindToPackage Lockedで、そのコードは以下の通りです。
private void bindToPackageLocked(String packageName, int version, boolean isMultiuser) {
        unbindLocked();
        Intent intent = new Intent(mAction);
        intent.setPackage(packageName);
        mPackageName = packageName;
        mVersion = version;
        mIsMultiuser = isMultiuser;
        if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ") ("
                + (isMultiuser ? "multi" : "single") + "-user)");
        mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                | Context.BIND_NOT_VISIBLE, mIsMultiuser ? UserHandle.OWNER : UserHandle.CURRENT);
    }
bindServiceAssUser関数は、サードパーティアプリケーションのLPサービスを結合しています。パラメータintentに入ってきたmActは、ServiceWatchの構造関数に値を割り当てたものです。LocationProvider Proxyのコードから、このactionは、createAndBind関数に入ってきたものであり、LMSでこのアクションを定義しました。
private static final String NETWORK_LOCATION_SERVICE_ACTION =
            "com.android.location.service.v3.NetworkLocationProvider"
バインディングが成功すると、ServiceWatchのoneServiceConneced関数が呼び出されます。
public void onServiceConnected(ComponentName name, IBinder binder) {
        synchronized (mLock) {
            String packageName = name.getPackageName();
            if (packageName.equals(mPackageName)) {
                if (D) Log.d(mTag, packageName + " connected");
                mBinder = binder;
                if (mHandler !=null && mNewServiceWork != null) {
                    mHandler.post(mNewServiceWork);
                }
            } else {
                Log.w(mTag, "unexpected onServiceConnected: " + packageName);
            }
        }
    }
mNewServiceWorkはLocationProvider Proxyによって提供され、Runnableの対象であり、そのコードは以下の通りである。
    private Runnable mNewServiceWork = new Runnable() {
        @Override
        public void run() {
            if (D) Log.d(TAG, "applying state to connected service");

            boolean enabled;
            ProviderProperties properties = null;
            ProviderRequest request;
            WorkSource source;
            ILocationProvider service;
            synchronized (mLock) {
                enabled = mEnabled;
                request = mRequest;
                source = mWorksource;
                service = getService();
            }

            if (service == null) return;

            try {
                //   LP     ,            ProviderProperties    
                properties = service.getProperties();
                if (properties == null) {
                    Log.e(TAG, mServiceWatcher.getBestPackageName() +
                            " has invalid locatino provider properties");
                }

                // apply current state to new service
                if (enabled) {
                    service.enable();//    LP
                    if (request != null) {//        ,        LP
                        service.setRequest(request, source);
                    }
                }
            } catch (RemoteException e) {
                Log.w(TAG, e);
            } catch (Exception e) {
                // never let remote service crash system server
                Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
            }

            synchronized (mLock) {
                mProperties = properties;
            }
        }
    };
参考文献:Android:WiFi、NFC、GPS巻を深く理解する