前言
HI,欢迎来到《每周一博》。今天是九月第二周,我给大家分析一下Android网络定位源码。
App中基本都会用到定位服务,NLP即NetworkLocationProvider,是位置提供服务的一种,谷歌有提供自己的NLP,在国内厂商一般会集成百度或高德的NLP。
下面是我绘制的一张定位服务架构图,一共分为四层,每层都依赖下面一层完成其所需提供的服务:
1.应用层:是android.location包中包含的内容,主要通过LocationManager来进行方法调用;
2.框架层:这一层包含了系统服务的实现,LocationManager通过Binder机制来和LocationManagerService进行通讯,LocationManagerService会选择合适的provider来提供位置,其中LocationProviderProxy的一个实现就是NLP,可以理解为LocationProviderProxy和GeocoderProxy都是一个空壳,如果没有第三方实现他们,那么将不提供服务,如果使用了GpsLocationProvider则会去调用硬件来获取位置;
3.共享库层:GpsLocationProvider通过JNI来调用本层libgps.so中的C++代码;
4.Linux内核层:C++代码最终去调用GPS硬件来获取位置;
一. 为什么要分析源码
在做NLP的时候对于和系统交互这块一直都充满疑惑:
A. App调用请求是如何到了NLP的?
B. 不同的App同一时刻发起定位系统是如何处理的?
C. 为什么取消定位有的时候传off,有的时候传on,off是啥意思?
D. 为什么请求单次定位会回调2次onSetRequest方法?
E. NLP上抛的位置又是如何返给App的呢?
F. onSetRequest到底是该怎么用?
为了对NLP有一个更加深入的理解,我决定带着这些问题去看下安卓定位相关的源码,告别过去对系统行为的种种猜测。所以这篇文章不仅仅是源码解析,更是结合了日常开发NLP时候遇到的各种问题,各种测试现象,从源码里去找出答案。
二. LocationManager分析
App调用定位接口是通过LocationManager的API,那就先从LocationManager入手,我查看的是安卓8.0的源码,发现它的很多方法都是代理了service的一些方法,这个service的声明类型是ILocationManager,这个对象就是代理对象,很显然是AIDL的调用,具体实现类则是LocationManagerService,LocationManager和LocationManagerService就是通过Binder 机制来进行通讯的。
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper, PendingIntent intent) {
String packageName = mContext.getPackageName();
// wrap the listener class
ListenerTransport transport = wrapListener(listener, looper);
try {
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
LocationManager提供的主要方法有:
1.getLastKnownLocation:获取上一次缓存的位置,这个方法不会发起定位请求,返回的是上一次的位置信息,但此前如果没有位置更新的话,返回的位置信息可能是错误的;
2.requestSingleUpdate:只请求一次定位,会发起位置监听,该方法要在主线程上执行,可以传入Listener或广播来接收位置;
3.requestLocationUpdates:持续请求定位,根据传入的时间间隔和位置差进行回调,该方法要在主线程上执行,可以传入Listener或广播来接收位置;
4.removeUpdates:移除定位请求,传入Listener;
5.addProximityAlert:添加一个地理围栏,这是一个圆形的围栏;
6.getProvider:获取Provider,可以指定条件,也可以根据名字来获取;
7.sendExtraCommand:给系统发送辅助指令;
这些方法的最终都是由service来实现的,发起定位时传入的Listener经过包装成AIDL接口传给了服务端,因为它们是需要跨进程来进行通讯的。
这里分析一下requestSingleUpdate方法,这个方法主要是传一个Listener,然后内部创建了一个LocationRequest,最小时间和最小距离都是0,还给singleShot设置为了true,并最终调用requestLocationUpdates方法,所以requestLocationUpdates才是核心,而所有定制的参数都封装成了LocationRequest。
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
checkProvider(provider);
checkListener(listener);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, 0, 0, true);
requestLocationUpdates(request, listener, looper, null);
}
那么接下来看下LocationRequest的createFromDeprecatedProvider方法,这里把传来的最小时间频率,最小距离差值存下,设置了定位的精度类型,如果singleShot为true,会设置locationRequest.setNumUpdates(1),numUpdate这个变量的默认值是一个很大的数,Integer.MAX_VALUE = 0x7fffffff,而单次定位g该值就设为了1,这个点在分析service的代码时会用到。
/** @hide */
@SystemApi
public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,
float minDistance, boolean singleShot) {
if (minTime < 0) minTime = 0;
if (minDistance < 0) minDistance = 0;
int quality;
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
quality = POWER_NONE;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
quality = ACCURACY_FINE;
} else {
quality = POWER_LOW;
}
LocationRequest request = new LocationRequest()
.setProvider(provider)
.setQuality(quality)
.setInterval(minTime)
.setFastestInterval(minTime)
.setSmallestDisplacement(minDistance);
if (singleShot) request.setNumUpdates(1);
return request;
}
三. LocationManagerService的初始化
获取LocationManager是调用Activity的getSystemService(Context.LOCATION_SERVICE)方法来获得,那么它的初始化是在哪里呢?我们知道Activity是Context,那么这个方法的最终实现就是在ContextImpl类里面,所以我们看下ContextImpl的getSystemService方法,它调用了SystemServiceRegistry的getSystemService方法。
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
在SystemServiceRegistry类里,有LocationManager向ServiceManager注册的代码,这个类是6.0新加的,主要是用来缓存,注册,获取系统服务的,早期安卓版本直接在ComtextImpl里面实现了。
registerService(Context.LOCATION_SERVICE, LocationManager.class,
new CachedServiceFetcher<LocationManager>() {
@override
public LocationManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.LOCATION_SERVICE);
return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
}});
ServiceManager是安卓系统专门用来管理系统服务的,它负责注册并管理所有的系统服务。可以把ServiceManager当做一个容器,它里面存储了系统所有的服务,比如PackageManagerService,ActivityManagerService,AlarmManagerService等等,通过对应的Key就可以获得对应的服务。我们可以获取定位服务的实现类对象,然后再通过 ILocationManager.Stub.asInterface(b) 将其转换成服务的代理存放到 LocationManager中。
那 ServiceManager 中所管理的系统服务对象又是从哪里来的呢?在 Android 系统启动过程中,需要完成一系列的初始化动作。在Java层最终会调用到ZygoteInit类中,会调用startSystemServer 方法来启动系统服务。启动的方法是 fork一个新的进程,然后在其中加载SystemServer类。在SystemServer中执行了系统服务的创建和注册。以LocationManagerService为例,在SystemServer的startOtherService中有以下代码:
if (!disableLocation) {
traceBeginAndSlog("StartLocationManagerService");
try {
location = new LocationManagerService(context);
ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
reportWtf("starting Location Manager", e);
}
traceEnd();
traceBeginAndSlog("StartCountryDetectorService");
try {
countryDetector = new CountryDetectorService(context);
ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
} catch (Throwable e) {
reportWtf("starting Country Detector", e);
}
traceEnd();
}
在这个类里面new出了LocationManagerService对象,并把它加入到ServiceManager容器里面,当然还有其他的服务也会被加入到ServiceManager里面,然后走它的systemRunning方法;
traceBeginAndSlog("MakeLocationServiceReady");
try {
if (locationF != null) locationF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying Location Service running", e);
}
traceEnd();
那么接下来看LocationManagerService这个类,在systemRunning方法里,做了一系列初始化的操作,其中一个重要的方法就是loadProvidersLocked(),它就是来加载provider的;位置服务的提供者是LocationProvider,它包含3种:GPS_PROVIDER,NETWORK_PROVIDER,PASSIVE_PROVIDER,BaiduNLP就是NETWORK_PROVIDER的一种。大概看下这个类的成员变量,就知道这个类的很多工作就是来管理这些provider的,那么来看下loadProvidersLocked()这个方法;
PassiveProvider passiveProvider = new PassiveProvider(this);
addProviderLocked(passiveProvider);
mEnabledProviders.add(passiveProvider.getName());
mPassiveProvider = passiveProvider;
if (GnssLocationProvider.isSupported()) {
// Create a gps location provider
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
addProviderLocked(gnssProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
}
首先创建了一个PassiveProvider,并把它加到可用的provider里面,也就是PassiveProvider始终可用,然后根据GPS是否可用,增加一个GpsLocationProvider,这个代码在不同的系统版本上还是有许多差别的,原来是GpsLocationProvider,现在改成了GnssLocationProvider,另外PassiveProvider的创建顺序也发生了改变。
Resources resources = mContext.getResources();
ArrayList<String> providerPackageNames = new ArrayList<>();
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));
ensureFallbackFusedProviderPresentLocked(providerPackageNames);
// 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");
}
接下来就是加载NetworkLocationProvider了, LocationProviderProxy是对NetworkLocationProvider的代理,而第三方NLP才是NetworkLocationProvider的具体实现,这里会根据XML文件中配置的布尔值,包名和字符串数组去绑定指定action的服务,如果bind成功就把它加入到可用provider中。那么实现方必然要创建一个Service来实现LocationProviderProxy中使用的AIDL对象的接口,这个类名没有具体要求,但是Service必须要对指定的action进行绑定并返回binder对象才能被唤醒。所以有的时候会遇到第三方NLP没有被厂商bind上,后续就无法通过第三方NLP来获取位置。
这个action是"com.android.location.service.v3.NetworkLocationProvider",这个action在不同系统上可能会不同,所以需要适配v2,v3,否则可能会出现无法绑定的情况。
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;
}
}
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);
}
那么接下来继续看LocationProviderProxy的createAndBind方法,在这里创建了一个ServiceWatcher对象,然后执行了它的start方法。ServiceWatcher是用来连接和监视应用程序实现LocationProvider服务的,成功binder到服务后,会对该服务进行监控,包的卸载,加载、安装都会引起rebinder动作,它实现了ServiceConnection,在构造函数里,把xml中的配置项都传了过来,包括一个boolean值overlay(覆盖),一个字符串数组,一个默认的服务字符串,如果开启覆盖即overlay=true,则使用字符串数组中指定包名的provider,如果不覆盖,则使用包名字符串中的provider来提供服务。
106 public ServiceWatcher(Context context, String logTag, String action,
107 int overlaySwitchResId, int defaultServicePackageNameResId,
108 int initialPackageNamesResId, Runnable newServiceWork,
109 Handler handler) {
110 mContext = context;
111 mTag = logTag;
112 mAction = action;
113 mPm = mContext.getPackageManager();
114 mNewServiceWork = newServiceWork;
115 mHandler = handler;
116 Resources resources = context.getResources();
117
118 // Whether to enable service overlay.
119 boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
120 ArrayList<String> initialPackageNames = new ArrayList<String>();
121 if (enableOverlay) {
122 // A list of package names used to create the signatures.
123 String[] pkgs = resources.getStringArray(initialPackageNamesResId);
124 if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
125 mServicePackageName = null;
126 if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
127 } else {
128 // The default package name that is searched for service implementation when overlay is
129 // disabled.
130 String servicePackageName = resources.getString(defaultServicePackageNameResId);
131 if (servicePackageName != null) initialPackageNames.add(servicePackageName);
132 mServicePackageName = servicePackageName;
133 if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
134 }
135 mSignatureSets = getSignatureSets(context, initialPackageNames);
136 }
在ServiceWatcher的start方法里,执行了bindBestPackageLocked这个关键的方法,在这个方法里,先去给intent设置之前提到的Action,然后根据传来的包名去查询service,如果前面使用了字符串数组,那么包名就是空的,接着对遍历出来的service做签名效验。
201 private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
202 Intent intent = new Intent(mAction);
203 if (justCheckThisPackage != null) {
204 intent.setPackage(justCheckThisPackage);
205 }
206 final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
207 PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
208 mCurrentUserId);
209 int bestVersion = Integer.MIN_VALUE;
210 ComponentName bestComponent = null;
211 boolean bestIsMultiuser = false;
212 if (rInfos != null) {
213 for (ResolveInfo rInfo : rInfos) {
214 final ComponentName component = rInfo.serviceInfo.getComponentName();
215 final String packageName = component.getPackageName();
216
217 // check signature
218 try {
219 PackageInfo pInfo;
220 pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
221 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
222 if (!isSignatureMatch(pInfo.signatures)) {
223 Log.w(mTag, packageName + " resolves service " + mAction
224 + ", but has wrong signature, ignoring");
225 continue;
226 }
227 } catch (NameNotFoundException e) {
228 Log.wtf(mTag, e);
229 continue;
230 }
这里需要注意的是必须要在NLP的service里配置metadata属性,给service_version配置value。因为这段代码会去读这个字段,没有就赋值为Integer.MIN_VALUE,也就是-2147483648,而version的初始值也是-2147483648,所以version > bestVersion条件通不过,那bestComponent就是null,所以无法绑定。
// check metadata
233 int version = Integer.MIN_VALUE;
234 boolean isMultiuser = false;
235 if (rInfo.serviceInfo.metaData != null) {
236 version = rInfo.serviceInfo.metaData.getInt(
237 EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
238 isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
239 }
240
241 if (version > bestVersion) {
242 bestVersion = version;
243 bestComponent = component;
244 bestIsMultiuser = isMultiuser;
245 }
找到bestComponent后,就会调用bindToPackageLocked方法,在这里又调用了bindServiceAsUser方法,去绑定第三方NLP里的Service,随后就会回调自己的onServiceConnected方法,因为它本身是个ServiceConnection,在回调方法里会执行mNewServiceWork,它是由LocationProviderProxy提供的一个Runnable对象,在这个方法里执行的是;
93 /**
94 * Work to apply current state to a newly connected provider.
95 * Remember we can switch the service that implements a providers
96 * at run-time, so need to apply current state.
97 */
98 private Runnable mNewServiceWork = new Runnable() {
99 @Override
100 public void run() {
101 if (D) Log.d(TAG, "applying state to connected service");
102
103 boolean enabled;
104 ProviderProperties properties = null;
105 ProviderRequest request;
106 WorkSource source;
107 ILocationProvider service;
108 synchronized (mLock) {
109 enabled = mEnabled;
110 request = mRequest;
111 source = mWorksource;
112 service = getService();
113 }
114
115 if (service == null) return;
116
117 try {
118 // load properties from provider
119 properties = service.getProperties();
120 if (properties == null) {
121 Log.e(TAG, mServiceWatcher.getBestPackageName() +
122 " has invalid locatino provider properties");
123 }
124
125 // apply current state to new service
126 if (enabled) {
127 service.enable();
128 if (request != null) {
129 service.setRequest(request, source);
130 }
131 }
132 } catch (RemoteException e) {
133 Log.w(TAG, e);
134 } catch (Exception e) {
135 // never let remote service crash system server
136 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
137 }
138
139 synchronized (mLock) {
140 mProperties = properties;
141 }
142 }
143 };
获取属性信息,把这些属性统一封装在类型为ProviderProperties的对象中,并回调enable方法,如果客户端有请求,则回调setRequest方法,这里要注意的是这些回调方法的对象是ILocationProvider,而不是NLP提供商。把NLP添加到可用provider之后,又添加了融合定位的provider和GeocoderProvider,GeocoderProvider和NLP的代理过程类似,至此LocationManagerService的初始化流程就算是结束了,还是比较复杂的,我们可以看到目前的这个过程和NLP提供商还没有任何关联。
656 // bind to geocoder provider
657 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
658 com.android.internal.R.bool.config_enableGeocoderOverlay,
659 com.android.internal.R.string.config_geocoderProviderPackageName,
660 com.android.internal.R.array.config_locationProviderPackageNames,
661 mLocationHandler);
662 if (mGeocodeProvider == null) {
663 Slog.e(TAG, "no geocoder provider found");
664 }
665
666 // bind to fused hardware provider if supported
667 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
668 // exception, so make sure we only do that when supported
669 FlpHardwareProvider flpHardwareProvider;
670 if (FlpHardwareProvider.isSupported()) {
671 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
672 FusedProxy fusedProxy = FusedProxy.createAndBind(
673 mContext,
674 mLocationHandler,
675 flpHardwareProvider.getLocationHardware(),
676 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
677 com.android.internal.R.string.config_hardwareFlpPackageName,
678 com.android.internal.R.array.config_locationProviderPackageNames);
679 if (fusedProxy == null) {
680 Slog.d(TAG, "Unable to bind FusedProxy.");
681 }
682 } else {
683 flpHardwareProvider = null;
684 Slog.d(TAG, "FLP HAL not supported");
685 }
686
687 // bind to geofence provider
688 GeofenceProxy provider = GeofenceProxy.createAndBind(
689 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
690 com.android.internal.R.string.config_geofenceProviderPackageName,
691 com.android.internal.R.array.config_locationProviderPackageNames,
692 mLocationHandler,
693 mGpsGeofenceProxy,
694 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
695 if (provider == null) {
696 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
697 }
698
四. 双重Client-Server模型
那么LocationProviderProxy又是怎么和第三方NLP关联在一起的呢?
在回答这个问题前,我们可以从宏观上看下App是如何从NLP提供商得到位置的。App向OS发请求,OS里接收到请求后向NLP提供商发请求,NLP提供商把位置返给系统,系统再返给App。从Binder机制来看,App-OS是一组Client-Server模型,OS-BaiduNLP是一组Client-Server模型,App通过Binder请求OS的服务,然后OS通过Binder请求NLP提供商的服务,前者通过ILocationManager.aidl,后者通ILocationProvider.aidl,所以OS既是客户端,也是服务端,看你看的视角是哪个。这也是Binder机制一个优秀的点,我们以为系统是服务方,其实有时候它也是个客户端。
那么接下来我来分析下系统和NLP提供商交互的过程,系统有个类已经实现了ILocationProvider.aidl的接口,那就是LocationProviderBase,所以我们只需要继承LocationProviderBase并实现抽象接口就可以了,这里先看下LocationProviderBase里相关的方法;
78 private final class Service extends ILocationProvider.Stub {
79 @Override
80 public void enable() {
81 onEnable();
82 }
83 @Override
84 public void disable() {
85 onDisable();
86 }
87 @Override
88 public void setRequest(ProviderRequest request, WorkSource ws) {
89 onSetRequest(new ProviderRequestUnbundled(request), ws);
90 }
91 @Override
92 public ProviderProperties getProperties() {
93 return mProperties;
94 }
95 @Override
96 public int getStatus(Bundle extras) {
97 return onGetStatus(extras);
98 }
99 @Override
100 public long getStatusUpdateTime() {
101 return onGetStatusUpdateTime();
102 }
103 @Override
104 public boolean sendExtraCommand(String command, Bundle extras) {
105 return onSendExtraCommand(command, extras);
106 }
107 @Override
108 public void dump(FileDescriptor fd, String[] args) {
109 PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
110 onDump(fd, pw, args);
111 pw.flush();
112 }
113 }
是不是瞬间觉得熟悉了许多,比如onEnable,onDisable,onSetRequest。需要注意的是这个类系统是有的,但是android.jar里面没有,所以我们出APK的时候需要编译依赖,而不能打包进去,可以provided一个jar包,我们在制作jar包的时候不仅要把LocationProviderBase放进去,还要把相关联的类也放进去,既然系统选择了外包的方式来实现NLP,那么关联的类一定不会无限关联下去。
另外还需要注意的是早期ILocationProvider.aidl的实现类是com.android.location.provider.LocationProvider,也就是BaiduNetworkLocationProvider所继承的类,BaiduNetworkLocationProvider1继承的是LocationProviderBase,所以BaiduNetworkLocationProvider是兼容旧版本用的,这点从Action上也可以看出来,现在基本上已经不会被调用了。
五. LocationManagerService相关类梳理
那么至此我们就打通了从App到系统再到NLP提供商的路径,这里对和LocationManagerService相关的类做一个简单的梳理:
1.ILocationManager.aidl:LocationManagerService在客户端的代理;
2.ILocationProvider.aidl:NLP提供商如BaiduNLP在系统层的代理;
3.LocationManager:客户端调用位置服务的类;
4.LocationManagerService:真正实现LocationManager中方法的类;
5.LocationProvider:位置服务提供者;
6.LocationProviderInterface:位置服务提供者的抽象接口,它的实现类有PassiveProvider,GpsLocationProvider,LocationProviderProxy等;
7.LocationProviderProxy:它是NLP提供商的代理类,通过ILocationProvider.aidl来远程调用NLP提供商的服务;
8.ServiceWatcher:它是LocationProviderProxy用到的一个类,通过配置xml文件可以读取到指定的包名,然后去绑定对应的服务,并监听包的变更事件;
9.LocationProviderBase:它是NLP提供商需要继承并实现的抽象类;
10.GeocoderProxy:是Geocoder的代理类,实现方式和NetworkLocationProvider类似;
11.LocationRequest:客户端请求定位时传的参数会被封装成这个类传给服务端;
它们之间的简单关系图可以这样表示;
由于文章长度有限制,分为上下两篇,继续阅读请跳转到
Android网络定位源码分析[下]。