Android GPS学習ノート—LMS初期化
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に追加します。
LMSのsystem Running関数は以下のように実現される。
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をロードすることができます。
ビッド関数をもう一度見てみます。
1.目的のアプリケーションの署名を確認する
2.createAndBindの3番目のパラメータに基づいて、このターゲットアプリケーションが実現するServiceを検索します。NetworkLPを例にとると、ターゲットアプリケーションは「comp.android.locations.service.v.2.Network LocationProvider」というサービスを提供しなければなりません。
3.このサービスに接続し、ILocationProviderのタイプの例を取得する。この例により、LocationProvider Proxyは、アプリケーション内のLPサービスと対話することができる。
bindBestPackage Lockedの中で一番重要な関数はbindToPackage Lockedで、そのコードは以下の通りです。
カタログ: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巻を深く理解する