与Android 位置信息相关的分析
1. Android LocationManagerService流程分析
2. Android 从GPS中获取位置信息流程分析
3. Android 从PassiveProvider获取位置信息
在LocationManagerService文章中介绍了各个LocationProvider和从各个LocationProvider中获取位置信息和大致流程。
在这篇文章中将会介绍networkProvider怎么获取位置信息。
network:通过网络来获取位置信息的,主要利用手机的基站,和WiFi节点的位置来大致定位。在国内基本使用第三方应用的sdk来实现的。(百度、高德等)
LocationManagerService与networkProvider通信主要是通过LocationProviderProxy 代理类来与networkProvider通信
LocationManagerService.java
private void loadProvidersLocked() {
...
// bind to network provider
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) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mProxyProviders.add(networkProvider);
addProviderLocked(networkProvider);
} else {
Slog.w(TAG, "no network location provider found");
}
...
}
使用LocationProviderProxy 的createAndBind方法创建和绑定networkProvider
LocationProviderProxy.java
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()) { // 绑定服务 ,会调用ServiceWatcher.start方法
return proxy;
} else {
return null;
}
}
LocationProviderProxy.java
// action 通过PMS可以找到这个此service,启动并绑定, 该action 为 “com.android.location.service.v3.NetworkLocationProvider”
// mServiceWatcher 会启动这个服务
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);
}
private boolean bind () {
return mServiceWatcher.start();
}
ServiceWatcher.java
public class ServiceWatcher implements ServiceConnection {
public boolean start() {
if (isServiceMissing()) return false;
synchronized (mLock) {
bindBestPackageLocked(mServicePackageName, false); // 启动服务并绑定
}
...略
}
private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
Intent intent = new Intent(mAction);
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
// 通过intent 查找对应的service
final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
mCurrentUserId);
int bestVersion = Integer.MIN_VALUE;
ComponentName bestComponent = null;
boolean bestIsMultiuser = false;
if (rInfos != null) {
for (ResolveInfo rInfo : rInfos) {
final ComponentName component = rInfo.serviceInfo.getComponentName();
final String packageName = component.getPackageName();
// check signature
try {
PackageInfo pInfo;
pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
if (!isSignatureMatch(pInfo.signatures)) { // 判断签名
Log.w(mTag, packageName + " resolves service " + mAction
+ ", but has wrong signature, ignoring");
continue;
}
} catch (NameNotFoundException e) {
Log.wtf(mTag, e);
continue;
}
// check metadata
int version = Integer.MIN_VALUE;
boolean isMultiuser = false;
if (rInfo.serviceInfo.metaData != null) {
version = rInfo.serviceInfo.metaData.getInt(
EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
}
// 判断该service的serviceVersion 是否大于Integer.MIN_VALUE,是则表示有效
if (version > bestVersion) {
bestVersion = version;
bestComponent = component;
bestIsMultiuser = isMultiuser;
}
}
}
if (bestComponent == null) {
Slog.w(mTag, "Odd, no component found for service " + mAction);
unbindLocked();
return false;
}
final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
&& bestVersion == mBoundVersion && userId == mBoundUserId;
if (forceRebind || !alreadyBound) {
unbindLocked();
bindToPackageLocked(bestComponent, bestVersion, userId); //通过compoent绑定服务
}
return true;
}
// 绑定服务
private void bindToPackageLocked(ComponentName component, int version, int userId) {
Intent intent = new Intent(mAction);
intent.setComponent(component);
mBoundComponent = component;
mBoundPackageName = component.getPackageName();
mBoundVersion = version;
mBoundUserId = userId;
if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
new UserHandle(userId));
}
// 由于当前ServiceWatcher 继承 ServiceConnection,所以当通过bindServiceAsUser 方法绑定成功后会调用onServiceConnected
public void onServiceConnected(ComponentName component, IBinder binder) {
synchronized (mLock) {
if (component.equals(mBoundComponent)) {
if (D) Log.d(mTag, component + " connected");
mBoundService = binder; // 保存连接上的service
if (mHandler !=null && mNewServiceWork != null) {
mHandler.post(mNewServiceWork); // 执行mNewServiceWork Runnable方法,此方法在LocationProviderProxy:mNewServiceWork
}
} else {
Log.w(mTag, "unexpected onServiceConnected: " + component);
}
}
}
}
LocationProviderProxy.java
// 当成功获取到第三方应用的LocationProvider 服务会调用此线程
private Runnable mNewServiceWork = new Runnable() {
@Override
public void run() {
boolean enabled;
final ProviderProperties[] properties = new ProviderProperties[1];
ProviderRequest request;
WorkSource source;
synchronized (mLock) {
enabled = mEnabled;
request = mRequest;
source = mWorksource;
}
// 调用runOnBinder 方法会再次调用BinderRunner.run 方法,并且将上一步保存的service通过参数回调过来即binder
mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
@Override
public void run(IBinder binder) {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
// load properties from provider
properties[0] = service.getProperties();
if (properties[0] == null) {
Log.e(TAG, mServiceWatcher.getBestPackageName() +
" has invalid location provider properties");
}
// apply current state to new service
if (enabled) { // 如果需要获取位置信息,则调用enable 方法启动第三方应用的locationProvider。并且通过setRequest设置LocationRequest
service.enable();
if (request != null) {
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[0];
}
}
};
到现在,mServiceWatcher中已经存放了三方应用的LocationProvider,本地应用调用requestLocationUpdates方法后的流程(使用network获取位置信息):
LocationManager.requestLocationUpdates() -> LocationManagerService.requestLocationUpdates() -> LocationManagerService.requestLocationUpdatesLocked() -> LocationManagerService.applyRequirementsLocked() ->
LocationProviderProxy.setRequest() -> mServiceWatcher.runOnBinder() -> ServiceWatcher.BinderRunner.run() -> 第三方service的setRequest(request, source)方法。
由于三方LocationProvider会继承 LocationProviderBase 方法。最后在计算出Location信息后会调用LocationProviderBase类的reportLocation()方法将数据传给请求数据的应用。
LocationProviderBase.java
public final void reportLocation(Location location) {
// mLocationManager 为 LocationManagerService 实例对象
try {
mLocationManager.reportLocation(location, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
} catch (Exception e) {
// never crash provider, might be running in a system process
Log.e(TAG, "Exception", e);
}
}
总结:
1.通过LocationManager.NETWORK_PROVIDER来获取位置信息,LocationManagerService会使用 LocationProviderProxy 与三方SDK的LocationProvide通信获取位置信息。
2.LocationProviderProxy 中通过 ServiceWatcher 来绑定三方SDK的LocationProvide 服务,并且内部会保存此服务
3.LocationProviderProxy 会通过 ServiceWatcher 来调用服务的接口与服务通信。