LocationManagerService简单分析

与Android 位置信息相关的分析

1. Android 从GPS中获取位置信息流程分析
2. Android 从NetWork获取位置信息流程分析
3. Android 从PassiveProvider获取位置信息


frameworks/base/location/java/android/location/LocationManager.java

public void requestLocationUpdates(String provider, long minTime, float minDistance,
        LocationListener listener) {
    checkProvider(provider);  // 检查provider是否为空
    checkListener(listener);  // 检查listener是否为空

    LocationRequest request = LocationRequest.createFromDeprecatedProvider(
            provider, minTime, minDistance, false);
    requestLocationUpdates(request, listener, null, null); // 调用下方的requestLocationUpdates方法
}

provider 是可以使用的定位提供器,可以使network,可以是GPS,可以是三方应用,比如百度,高德等。
minTime 每经过minTime时间后会调用listener方法
minDistance 每移动minDistance距离后会调用listener方法


frameworks/base/location/java/android/location/LocationRequest.java

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;
}

private void requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper, PendingIntent intent) {
    String packageName = mContext.getPackageName();
    ListenerTransport transport = wrapListener(listener, looper);
    try {
        mService.requestLocationUpdates(request, transport, intent, packageName);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

封装listener,调用 LocationManagerService 服务中的 requestLocationUpdates 方法。



private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
        if (listener == null) return null;
        synchronized (mListeners) {
            ListenerTransport transport = mListeners.get(listener);
            if (transport == null) {
                transport = new ListenerTransport(listener, looper);
            }
            mListeners.put(listener, transport);
            return transport;
        }
    }

private class ListenerTransport extends ILocationListener.Stub

封装是为了能够与 Service 进行通信。要与服务器通信需要是基本数据类型和aidl和可序列化的类。
从mListeners中获取与该listener相关的 ListenerTransport ,如果没有则重新创建并放入mListeners中。


frameworks/base/services/core/java/com/android/server/LocationManagerService.java

public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
        PendingIntent intent, String packageName) {
    if (request == null) request = DEFAULT_LOCATION_REQUEST;
    checkPackageName(packageName); //检查调用的package与传入的package是否一致
    int allowedResolutionLevel = getCallerAllowedResolutionLevel(); //检查调用app的权限级别RESOLUTION_LEVEL_FINE、RESOLUTION_LEVEL_COARSE 或者是 RESOLUTION_LEVEL_NONE
    checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
            request.getProvider()); // 检查当前的权限级别是否满足请求的provider的级别,如果不满足则抛出异常
    WorkSource workSource = request.getWorkSource();  // workSource 为null
    if (workSource != null && !workSource.isEmpty()) {
        checkDeviceStatsAllowed(); // 判断是否需要赋予调用者 UPDATE_DEVICE_STATS 权限
    }
    boolean hideFromAppOps = request.getHideFromAppOps();
    if (hideFromAppOps) {
        checkUpdateAppOpsAllowed(); //判断是否需要赋予调用者 UPDATE_APP_OPS_STATS 权限
    }
    boolean callerHasLocationHardwarePermission =
            mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
                    == PERMISSION_GRANTED;
    LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
            callerHasLocationHardwarePermission); // 通过调用者权限级别和是否有hardware权限重新设置请求精度和格式化重复数据

    final int pid = Binder.getCallingPid();
    final int uid = Binder.getCallingUid();
    // providers may use public location API's, need to clear identity
    long identity = Binder.clearCallingIdentity(); //清除调用端的UID和PID,使用当前服务的UID和PID
    try {
        checkLocationAccess(pid, uid, packageName, allowedResolutionLevel); //使用AppOpsManager进行判断

        synchronized (mLock) {
            Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
                    packageName, workSource, hideFromAppOps);
            requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
        }
    } finally {
        Binder.restoreCallingIdentity(identity); // 恢复为调用端的UID和PID
    }
}

checkListenerOrIntentLocked -> getReceiverLocked


private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
        String packageName, WorkSource workSource, boolean hideFromAppOps) {
    IBinder binder = listener.asBinder();
    Receiver receiver = mReceivers.get(binder);
    if (receiver == null) {
        receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
                hideFromAppOps);
        try {
            receiver.getListener().asBinder().linkToDeath(receiver, 0); // 设置当listener 中断时的一些操作
        } catch (RemoteException e) {
            Slog.e(TAG, "linkToDeath failed:", e);
            return null;
        }
        mReceivers.put(binder, receiver); //将receiver与binder进行绑定然后放在mReceivers hashMap中。
    }
    return receiver;
}
private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
        int pid, int uid, String packageName) {
    if (request == null) request = DEFAULT_LOCATION_REQUEST;
    String name = request.getProvider(); // 获取Provider 名字
    if (name == null) {
        throw new IllegalArgumentException("provider name must not be null");
    }
    // 通过name 获取location provider
    LocationProviderInterface provider = mProvidersByName.get(name);
    if (provider == null) {
        throw new IllegalArgumentException("provider doesn't exist: " + name);
    }

    UpdateRecord record = new UpdateRecord(name, request, receiver);

    UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
    if (oldRecord != null) {
        oldRecord.disposeLocked(false); // 将当前update record 从名字为name 的provider的 record表中移除
    }

    boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
    if (isProviderEnabled) {
        applyRequirementsLocked(name);
    } else {
        // Notify the listener that updates are currently disabled
        receiver.callProviderEnabledLocked(name, false);
    }
    receiver.updateMonitoring(true);
}

private void applyRequirementsLocked(String provider) {
    LocationProviderInterface p = mProvidersByName.get(provider);
    if (p == null) return;

    ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
    WorkSource worksource = new WorkSource();
    ProviderRequest providerRequest = new ProviderRequest();

    ContentResolver resolver = mContext.getContentResolver();

    // 后台定位频率
    long backgroundThrottleInterval = Settings.Global.getLong(
            resolver,
            Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
            DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
    // initialize the low power mode to true and set to false if any of the records requires

    // 循环遍历所有的UpdateRecord, 找出最小的定位频率进行更新定位信息
    providerRequest.lowPowerMode = true;
    if (records != null) {
        for (UpdateRecord record : records) {
            if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                if (checkLocationAccess(
                        record.mReceiver.mIdentity.mPid,
                        record.mReceiver.mIdentity.mUid,
                        record.mReceiver.mIdentity.mPackageName,
                        record.mReceiver.mAllowedResolutionLevel)) {
                    LocationRequest locationRequest = record.mRealRequest;
                    long interval = locationRequest.getInterval();
                    // 如果调用端不是系统应用同时没有在白名单中,那么会使用自定义的更新频率和系统默认的后台更新频率取最大值作为该应用的后台更新频率。
                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
                        if (!record.mIsForegroundUid) {
                            interval = Math.max(interval, backgroundThrottleInterval);
                        }
                        if (interval != locationRequest.getInterval()) {
                            locationRequest = new LocationRequest(locationRequest);
                            locationRequest.setInterval(interval);
                        }
                    }

                    record.mRequest = locationRequest;
                    providerRequest.locationRequests.add(locationRequest);
                    if (!locationRequest.isLowPowerMode()) {
                        providerRequest.lowPowerMode = false;
                    }
                    if (interval < providerRequest.interval) {
                        providerRequest.reportLocation = true;
                        providerRequest.interval = interval;
                    }
                }
            }
        }
        // 如果需要上报位置,就把worksource记录下,以便于追查耗电的应用
        if (providerRequest.reportLocation) {
            long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
            for (UpdateRecord record : records) {
                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                    LocationRequest locationRequest = record.mRequest;

                    // Don't assign battery blame for update records whose
                    // client has no permission to receive location data.
                    if (!providerRequest.locationRequests.contains(locationRequest)) {
                        continue;
                    }

                    if (locationRequest.getInterval() <= thresholdInterval) {
                        if (record.mReceiver.mWorkSource != null
                                && isValidWorkSource(record.mReceiver.mWorkSource)) {
                            worksource.add(record.mReceiver.mWorkSource);
                        } else {
                            // Assign blame to caller if there's no WorkSource associated with
                            // the request or if it's invalid.
                            worksource.add(
                                    record.mReceiver.mIdentity.mUid,
                                    record.mReceiver.mIdentity.mPackageName);
                        }
                    }
                }
            }
        }
    }
    p.setRequest(providerRequest, worksource);
}

如果是network provider,p.setRequest()方法会调用以下方法

LocationProviderProxy.java

ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
    service.setRequest(request, source); // ILocationProvider的实现是 LocationProviderBase.java,所以会调用到onSetRequest 方法,onSetRequest 方法需要三方应用实现,比如百度、高德,此方法会获取到Location 信息,然后使用reportLocation方法回调给LocationProviderBase.java。
} 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);
}

LocationProviderBase.java

...
mLocationManager = ILocationManager.Stub.asInterface
...

public final void reportLocation(Location location) {
    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);
    }
}

ILocationManager 的实现在LocationManagerService 中实现

LocationManagerService.java

public void reportLocation(Location location, boolean passive) {
    checkCallerIsProvider();

    if (!location.isComplete()) {
        Log.w(TAG, "Dropping incomplete location: " + location);
        return;
    }

    mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
    Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
    m.arg1 = (passive ? 1 : 0);
    mLocationHandler.sendMessageAtFrontOfQueue(m);
}

收到mLocationHandler 对MSG_LOCATION_CHANGED的处理直接调用 handleLocationChanged() 方法

LocationManagerService.java

private void handleLocationChanged(Location location, boolean passive) {
    Location myLocation = new Location(location);
    String provider = myLocation.getProvider();

    if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
        myLocation.setIsFromMockProvider(true);
    }

    synchronized (mLock) {
        if (isAllowedByCurrentUserSettingsLocked(provider)) {
            if (!passive) {
                location = screenLocationLocked(location, provider);
                if (location == null) {
                    return;
                }
                // notify passive provider of the new location
                mPassiveProvider.updateLocation(myLocation);
            }
            handleLocationChangedLocked(myLocation, passive);
        }
    }
}


private void handleLocationChangedLocked(Location location, boolean passive) {
    if (D) Log.d(TAG, "incoming location: " + location);
    long now = SystemClock.elapsedRealtime();
    String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
    // Skip if the provider is unknown.
    LocationProviderInterface p = mProvidersByName.get(provider);
    if (p == null) return;
    updateLastLocationLocked(location, provider); // 更新最新的Location 信息
    // mLastLocation should have been updated from the updateLastLocationLocked call above.
    Location lastLocation = mLastLocation.get(provider);
    if (lastLocation == null) {
        Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
        return;
    }

    // Update last known coarse interval location if enough time has passed.
    Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
    if (lastLocationCoarseInterval == null) {
        lastLocationCoarseInterval = new Location(location);
        mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
    }
    // 如果经过了很长时间,更新粗略精度
    long timeDiffNanos = location.getElapsedRealtimeNanos()
            - lastLocationCoarseInterval.getElapsedRealtimeNanos();
    if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
        lastLocationCoarseInterval.set(location);
    }
    Location noGPSLocation =
            lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);

    // Skip if there are no UpdateRecords for this provider.
    ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
    if (records == null || records.size() == 0) return;

    // Fetch coarse location
    Location coarseLocation = null;
    if (noGPSLocation != null) {
        coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
    }

    // Fetch latest status update time
    long newStatusUpdateTime = p.getStatusUpdateTime();

    // Get latest status
    Bundle extras = new Bundle();
    int status = p.getStatus(extras);

    ArrayList<Receiver> deadReceivers = null;
    ArrayList<UpdateRecord> deadUpdateRecords = null;

    // Broadcast location or status to all listeners
    // 遍历所有UpdateRecord,根据LocationRequest请求的精度来确定返回粗略位置还是精确位置。
    for (UpdateRecord r : records) {
        Receiver receiver = r.mReceiver;
        boolean receiverDead = false;

        int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
        if (!isCurrentProfile(receiverUserId)
                && !isUidALocationProvider(receiver.mIdentity.mUid)) {
            if (D) {
                Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                        " (current user: " + mCurrentUserId + ", app: " +
                        receiver.mIdentity.mPackageName + ")");
            }
            continue;
        }

        if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
            if (D) {
                Log.d(TAG, "skipping loc update for blacklisted app: " +
                        receiver.mIdentity.mPackageName);
            }
            continue;
        }

        if (!reportLocationAccessNoThrow(
                receiver.mIdentity.mPid,
                receiver.mIdentity.mUid,
                receiver.mIdentity.mPackageName,
                receiver.mAllowedResolutionLevel)) {
            if (D) {
                Log.d(TAG, "skipping loc update for no op app: " +
                        receiver.mIdentity.mPackageName);
            }
            continue;
        }

        Location notifyLocation;
        if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
            // 返回粗略位置信息
            notifyLocation = coarseLocation;  // use coarse location
        } else {
            // 返回精准位置信息
            notifyLocation = lastLocation;  // use fine location
        }
        if (notifyLocation != null) {
            Location lastLoc = r.mLastFixBroadcast;
            // shouldBroadcastSafe方法判断是否需要发送Location变化消息,通过client传入的定位频率和距离与前后两次Location之间的时间差和距离差作比较。
            if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
                if (lastLoc == null) {
                    lastLoc = new Location(notifyLocation);
                    r.mLastFixBroadcast = lastLoc;
                } else {
                    lastLoc.set(notifyLocation);
                }
                // 远程调用,如果断开了连接,则会抛出remote异常,返回值为false。
                if (!receiver.callLocationChangedLocked(notifyLocation)) {
                    Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
                    receiverDead = true;
                    // 抛出了remote异常,说明client与service已经断开连接,可以释放service为此client开辟的资源。
                }
                r.mRealRequest.decrementNumUpdates();
            }
        }

        long prevStatusUpdateTime = r.mLastStatusBroadcast;
        if ((newStatusUpdateTime > prevStatusUpdateTime) &&
                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {

            r.mLastStatusBroadcast = newStatusUpdateTime;
            if (!receiver.callStatusChangedLocked(provider, status, extras)) {
                receiverDead = true;
                Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
            }
        }

        // track expired records
        if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
            if (deadUpdateRecords == null) {
                deadUpdateRecords = new ArrayList<>();
            }
            deadUpdateRecords.add(r);
        }
        // track dead receivers
        if (receiverDead) {
            if (deadReceivers == null) {
                deadReceivers = new ArrayList<>();
            }
            if (!deadReceivers.contains(receiver)) {
                deadReceivers.add(receiver);
            }
        }
    }

    // remove dead records and receivers outside the loop
    if (deadReceivers != null) {
        for (Receiver receiver : deadReceivers) {
            removeUpdatesLocked(receiver);
        }
    }
    if (deadUpdateRecords != null) {
        for (UpdateRecord r : deadUpdateRecords) {
            r.disposeLocked(true);
        }
        applyRequirementsLocked(provider);
    }
}


通过判断listener 是否为空来判断是使用回调还是广播的方式来发送localtion 变化信息。

public boolean callLocationChangedLocked(Location location) {
    if (mListener != null) {
        try {
            synchronized (this) {
                mListener.onLocationChanged(new Location(location));
                incrementPendingBroadcastsLocked();
            }
        } catch (RemoteException e) {
            return false;
        }
    } else {
        Intent locationChanged = new Intent();
        locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
                new Location(location));
        try {
            synchronized (this) {
                mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
                        getResolutionPermission(mAllowedResolutionLevel),
                        PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                incrementPendingBroadcastsLocked();
            }
        } catch (PendingIntent.CanceledException e) {
            return false;
        }
    }
    return true;
}

applyRequirementsLocked这是个关键方法,不论是初始化,还是requestUpdate,removeUpdates,reportLocation都会调用它,它就是一个应用参数标准,每当有变动就去检查,变更一下定位频率,并回调onSetRequest方法。所以onSetRequest方法就是参数(主要就是定位频率)发生了变更后的回调,而不是定一次位就回调一次,每当定位频率发生改变这个方法就会回调。


LocationProvider 初始化

frameworks/base/services/core/java/com/android/server/LocationManagerService.java

private void loadProvidersLocked() {
    // 创建 PassiveProvider, name 为"passive"
    PassiveProvider passiveProvider = new PassiveProvider(this);
    addProviderLocked(passiveProvider);
....

    // 添加GPS provider, name 为 "gps"
    if (GnssLocationProvider.isSupported()) {
        GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
            mLocationHandler.getLooper());
        addProviderLocked(gnssProvider);
    }
....
    // 添加networkProvider, name 为 "network"
    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);
}

ProviderRequest类是对LocationRequest集合的一个封装,可以理解为是现在所有发起的定位的请求集合,比如5个应用向系统要位置,那么ProviderRequest里就有5个LocationRequest。它有2个变量,最小时间间隔默认值是9223372036854775807L,是否需要上报位置默认值是flase。


1.明确类的主要作用:顾名思义,LocationManagerService主要是用来提供定位服务的;

2.分析类的主要字段:LocationManagerService的很多字段都是围绕provider来展开的,所以它主要是用来管理provider的;

(1) mEnabledProviders:可用的Provider集合;
(2) mRecordsByProvider:定位请求Update的集合;
(3) mLastLocation:最近一次的定位信息,以 Location Provider 的名称为键的映射

3.理解类的初始化过程:LocationManagerService的初始化主要就是加载各种Provider,其中NetworkLocationPrivider和GeocoderProvider是通过ServiceWatcher去配置中读取绑定的;

4.理解类的主要业务逻辑方法:

(1) requestLocationUpdatesLocked:请求定位的方法,插入一条记录;
(2) removeUpdatesLocked:移除定位请求的方法,移除一条记录;
(3) applyRequirementsLocked:各种配置变更都会走该方法,它会回调setRequest方法;
(4) handleLocationChanged:上报位置时会触发该方法,这里会把结果回调给App;

参考文档:
LocationManagerService : https://www.jianshu.com/p/071722bd9f1c
linkToDeath机制 : https://www.jianshu.com/p/e38f08e34686
clearCallingIdentity : https://blog.csdn.net/fchyang/article/details/82345927

你可能感兴趣的:(android开发,android,java,开发语言,Location)