美文网首页
Android网络定位源码分析[上]

Android网络定位源码分析[上]

作者: 健身营养爱好者 | 来源:发表于2018-09-19 19:20 被阅读197次

    *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

    前言

    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网络定位源码分析[下]

    相关文章

      网友评论

          本文标题:Android网络定位源码分析[上]

          本文链接:https://www.haomeiwen.com/subject/qpeinftx.html