2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server;
19 import com.android.internal.content.PackageMonitor;
20 import com.android.internal.location.ProviderProperties;
21 import com.android.internal.location.ProviderRequest;
22 import com.android.internal.os.BackgroundThread;
23 import com.android.server.location.ActivityRecognitionProxy;
24 import com.android.server.location.FlpHardwareProvider;
25 import com.android.server.location.FusedProxy;
26 import com.android.server.location.GeocoderProxy;
27 import com.android.server.location.GeofenceManager;
28 import com.android.server.location.GeofenceProxy;
29 import com.android.server.location.GpsLocationProvider;
30 import com.android.server.location.GpsMeasurementsProvider;
31 import com.android.server.location.GpsNavigationMessageProvider;
32 import com.android.server.location.LocationBlacklist;
33 import com.android.server.location.LocationFudger;
34 import com.android.server.location.LocationProviderInterface;
35 import com.android.server.location.LocationProviderProxy;
36 import com.android.server.location.LocationRequestStatistics;
37 import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
38 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
39 import com.android.server.location.MockProvider;
40 import com.android.server.location.PassiveProvider;
42 import android.app.AppOpsManager;
43 import android.app.PendingIntent;
44 import android.content.BroadcastReceiver;
45 import android.content.ContentResolver;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.IntentFilter;
49 import android.content.pm.ApplicationInfo;
50 import android.content.pm.PackageInfo;
51 import android.content.pm.PackageManager;
52 import android.content.pm.PackageManager.NameNotFoundException;
53 import android.content.pm.ResolveInfo;
54 import android.content.pm.Signature;
55 import android.content.pm.UserInfo;
56 import android.content.res.Resources;
57 import android.database.ContentObserver;
58 import android.hardware.location.ActivityRecognitionHardware;
59 import android.location.Address;
60 import android.location.Criteria;
61 import android.location.GeocoderParams;
62 import android.location.Geofence;
63 import android.location.IGpsGeofenceHardware;
64 import android.location.IGpsMeasurementsListener;
65 import android.location.IGpsNavigationMessageListener;
66 import android.location.IGpsStatusListener;
67 import android.location.IGpsStatusProvider;
68 import android.location.ILocationListener;
69 import android.location.ILocationManager;
70 import android.location.INetInitiatedListener;
71 import android.location.Location;
72 import android.location.LocationManager;
73 import android.location.LocationProvider;
74 import android.location.LocationRequest;
75 import android.os.Binder;
76 import android.os.Bundle;
77 import android.os.Handler;
78 import android.os.IBinder;
79 import android.os.Looper;
80 import android.os.Message;
81 import android.os.PowerManager;
82 import android.os.Process;
83 import android.os.RemoteException;
84 import android.os.SystemClock;
85 import android.os.UserHandle;
86 import android.os.UserManager;
87 import android.os.WorkSource;
88 import android.provider.Settings;
89 import android.util.Log;
90 import android.util.Slog;
92 import java.io.FileDescriptor;
93 import java.io.PrintWriter;
94 import java.util.ArrayList;
95 import java.util.Arrays;
96 import java.util.HashMap;
97 import java.util.HashSet;
98 import java.util.List;
100 import java.util.Set;
103 * The service class that manages LocationProviders and issues location
104 * updates and alerts.
106 public class LocationManagerService extends ILocationManager.Stub {
107 private static final String TAG = "LocationManagerService";
108 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
110 private static final String WAKELOCK_KEY = TAG;
112 // Location resolution level: no location data whatsoever
113 private static final int RESOLUTION_LEVEL_NONE = 0;
114 // Location resolution level: coarse location data only
115 private static final int RESOLUTION_LEVEL_COARSE = 1;
116 // Location resolution level: fine location data
117 private static final int RESOLUTION_LEVEL_FINE = 2;
119 private static final String ACCESS_MOCK_LOCATION =
120 android.Manifest.permission.ACCESS_MOCK_LOCATION;
121 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
122 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
123 private static final String INSTALL_LOCATION_PROVIDER =
124 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
126 private static final String NETWORK_LOCATION_SERVICE_ACTION =
127 "com.android.location.service.v3.NetworkLocationProvider";
128 private static final String FUSED_LOCATION_SERVICE_ACTION =
129 "com.android.location.service.FusedLocationProvider";
131 private static final int MSG_LOCATION_CHANGED = 1;
133 private static final long NANOS_PER_MILLI = 1000000L;
135 // The maximum interval a location request can have and still be considered "high power".
136 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
138 // Location Providers may sometimes deliver location updates
139 // slightly faster that requested - provide grace period so
140 // we don't unnecessarily filter events that are otherwise on
142 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
144 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
146 private final Context mContext;
147 private final AppOpsManager mAppOps;
149 // used internally for synchronization
150 private final Object mLock = new Object();
152 // --- fields below are final after systemReady() ---
153 private LocationFudger mLocationFudger;
154 private GeofenceManager mGeofenceManager;
155 private PackageManager mPackageManager;
156 private PowerManager mPowerManager;
157 private UserManager mUserManager;
158 private GeocoderProxy mGeocodeProvider;
159 private IGpsStatusProvider mGpsStatusProvider;
160 private INetInitiatedListener mNetInitiatedListener;
161 private LocationWorkerHandler mLocationHandler;
162 private PassiveProvider mPassiveProvider; // track passive provider for special cases
163 private LocationBlacklist mBlacklist;
164 private GpsMeasurementsProvider mGpsMeasurementsProvider;
165 private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
166 private IGpsGeofenceHardware mGpsGeofenceProxy;
168 // --- fields below are protected by mLock ---
169 // Set of providers that are explicitly enabled
170 private final Set<String> mEnabledProviders = new HashSet<String>();
172 // Set of providers that are explicitly disabled
173 private final Set<String> mDisabledProviders = new HashSet<String>();
175 // Mock (test) providers
176 private final HashMap<String, MockProvider> mMockProviders =
177 new HashMap<String, MockProvider>();
180 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
182 // currently installed providers (with mocks replacing real providers)
183 private final ArrayList<LocationProviderInterface> mProviders =
184 new ArrayList<LocationProviderInterface>();
186 // real providers, saved here when mocked out
187 private final HashMap<String, LocationProviderInterface> mRealProviders =
188 new HashMap<String, LocationProviderInterface>();
190 // mapping from provider name to provider
191 private final HashMap<String, LocationProviderInterface> mProvidersByName =
192 new HashMap<String, LocationProviderInterface>();
194 // mapping from provider name to all its UpdateRecords
195 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
196 new HashMap<String, ArrayList<UpdateRecord>>();
198 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
200 // mapping from provider name to last known location
201 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
203 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
204 // locations stored here are not fudged for coarse permissions.
205 private final HashMap<String, Location> mLastLocationCoarseInterval =
206 new HashMap<String, Location>();
208 // all providers that operate over proxy, for authorizing incoming location
209 private final ArrayList<LocationProviderProxy> mProxyProviders =
210 new ArrayList<LocationProviderProxy>();
212 // current active user on the device - other users are denied location data
213 private int mCurrentUserId = UserHandle.USER_OWNER;
214 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
216 public LocationManagerService(Context context) {
219 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
221 if (D) Log.d(TAG, "Constructed");
223 // most startup is deferred until systemReady()
226 public void systemRunning() {
227 synchronized (mLock) {
228 if (D) Log.d(TAG, "systemReady()");
230 // fetch package manager
231 mPackageManager = mContext.getPackageManager();
233 // fetch power manager
234 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
236 // prepare worker thread
237 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
239 // prepare mLocationHandler's dependents
240 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
241 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
243 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
245 // Monitor for app ops mode changes.
246 AppOpsManager.OnOpChangedListener callback
247 = new AppOpsManager.OnOpChangedInternalListener() {
248 public void onOpChanged(int op, String packageName) {
249 synchronized (mLock) {
250 for (Receiver receiver : mReceivers.values()) {
251 receiver.updateMonitoring(true);
253 applyAllProviderRequirementsLocked();
257 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
259 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
260 updateUserProfiles(mCurrentUserId);
263 loadProvidersLocked();
264 updateProvidersLocked();
267 // listen for settings changes
268 mContext.getContentResolver().registerContentObserver(
269 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
270 new ContentObserver(mLocationHandler) {
272 public void onChange(boolean selfChange) {
273 synchronized (mLock) {
274 updateProvidersLocked();
277 }, UserHandle.USER_ALL);
278 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
280 // listen for user change
281 IntentFilter intentFilter = new IntentFilter();
282 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
283 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
284 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
286 mContext.registerReceiverAsUser(new BroadcastReceiver() {
288 public void onReceive(Context context, Intent intent) {
289 String action = intent.getAction();
290 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
291 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
292 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
293 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
294 updateUserProfiles(mCurrentUserId);
297 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
301 * Makes a list of userids that are related to the current user. This is
302 * relevant when using managed profiles. Otherwise the list only contains
305 * @param currentUserId the current user, who might have an alter-ego.
307 void updateUserProfiles(int currentUserId) {
308 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
309 synchronized (mLock) {
310 mCurrentUserProfiles = new int[profiles.size()];
311 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
312 mCurrentUserProfiles[i] = profiles.get(i).id;
318 * Checks if the specified userId matches any of the current foreground
319 * users stored in mCurrentUserProfiles.
321 private boolean isCurrentProfile(int userId) {
322 synchronized (mLock) {
323 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
324 if (mCurrentUserProfiles[i] == userId) {
332 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
333 PackageManager pm = mContext.getPackageManager();
334 String systemPackageName = mContext.getPackageName();
335 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
337 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
338 new Intent(FUSED_LOCATION_SERVICE_ACTION),
339 PackageManager.GET_META_DATA, mCurrentUserId);
340 for (ResolveInfo rInfo : rInfos) {
341 String packageName = rInfo.serviceInfo.packageName;
343 // Check that the signature is in the list of supported sigs. If it's not in
344 // this list the standard provider binding logic won't bind to it.
347 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
348 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
349 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
350 ", but has wrong signature, ignoring");
353 } catch (NameNotFoundException e) {
354 Log.e(TAG, "missing package: " + packageName);
358 // Get the version info
359 if (rInfo.serviceInfo.metaData == null) {
360 Log.w(TAG, "Found fused provider without metadata: " + packageName);
364 int version = rInfo.serviceInfo.metaData.getInt(
365 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
367 // This should be the fallback fused location provider.
369 // Make sure it's in the system partition.
370 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
371 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
375 // Check that the fallback is signed the same as the OS
376 // as a proxy for coreApp="true"
377 if (pm.checkSignatures(systemPackageName, packageName)
378 != PackageManager.SIGNATURE_MATCH) {
379 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
384 // Found a valid fallback.
385 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
388 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
392 throw new IllegalStateException("Unable to find a fused location provider that is in the "
393 + "system partition with version 0 and signed with the platform certificate. "
394 + "Such a package is needed to provide a default fused location provider in the "
395 + "event that no other fused location provider has been installed or is currently "
396 + "available. For example, coreOnly boot mode when decrypting the data "
397 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
400 private void loadProvidersLocked() {
401 // create a passive location provider, which is always enabled
402 PassiveProvider passiveProvider = new PassiveProvider(this);
403 addProviderLocked(passiveProvider);
404 mEnabledProviders.add(passiveProvider.getName());
405 mPassiveProvider = passiveProvider;
407 if (GpsLocationProvider.isSupported()) {
408 // Create a gps location provider
409 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
410 mLocationHandler.getLooper());
411 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
412 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
413 addProviderLocked(gpsProvider);
414 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
415 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
416 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
417 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
421 Load package name(s) containing location provider support.
422 These packages can contain services implementing location providers:
423 Geocoder Provider, Network Location Provider, and
424 Fused Location Provider. They will each be searched for
425 service components implementing these providers.
426 The location framework also has support for installation
427 of new location providers at run-time. The new package does not
428 have to be explicitly listed here, however it must have a signature
429 that matches the signature of at least one package on this list.
431 Resources resources = mContext.getResources();
432 ArrayList<String> providerPackageNames = new ArrayList<String>();
433 String[] pkgs = resources.getStringArray(
434 com.android.internal.R.array.config_locationProviderPackageNames);
435 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
436 Arrays.toString(pkgs));
437 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
439 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
441 // bind to network provider
442 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
444 LocationManager.NETWORK_PROVIDER,
445 NETWORK_LOCATION_SERVICE_ACTION,
446 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
447 com.android.internal.R.string.config_networkLocationProviderPackageName,
448 com.android.internal.R.array.config_locationProviderPackageNames,
450 if (networkProvider != null) {
451 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
452 mProxyProviders.add(networkProvider);
453 addProviderLocked(networkProvider);
455 Slog.w(TAG, "no network location provider found");
458 // bind to fused provider
459 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
461 LocationManager.FUSED_PROVIDER,
462 FUSED_LOCATION_SERVICE_ACTION,
463 com.android.internal.R.bool.config_enableFusedLocationOverlay,
464 com.android.internal.R.string.config_fusedLocationProviderPackageName,
465 com.android.internal.R.array.config_locationProviderPackageNames,
467 if (fusedLocationProvider != null) {
468 addProviderLocked(fusedLocationProvider);
469 mProxyProviders.add(fusedLocationProvider);
470 mEnabledProviders.add(fusedLocationProvider.getName());
471 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
473 Slog.e(TAG, "no fused location provider found",
474 new IllegalStateException("Location service needs a fused location provider"));
477 // bind to geocoder provider
478 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
479 com.android.internal.R.bool.config_enableGeocoderOverlay,
480 com.android.internal.R.string.config_geocoderProviderPackageName,
481 com.android.internal.R.array.config_locationProviderPackageNames,
483 if (mGeocodeProvider == null) {
484 Slog.e(TAG, "no geocoder provider found");
487 // bind to fused hardware provider if supported
488 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
489 // exception, so make sure we only do that when supported
490 FlpHardwareProvider flpHardwareProvider;
491 if (FlpHardwareProvider.isSupported()) {
492 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
493 FusedProxy fusedProxy = FusedProxy.createAndBind(
496 flpHardwareProvider.getLocationHardware(),
497 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
498 com.android.internal.R.string.config_hardwareFlpPackageName,
499 com.android.internal.R.array.config_locationProviderPackageNames);
500 if (fusedProxy == null) {
501 Slog.e(TAG, "Unable to bind FusedProxy.");
504 flpHardwareProvider = null;
505 Slog.e(TAG, "FLP HAL not supported");
508 // bind to geofence provider
509 GeofenceProxy provider = GeofenceProxy.createAndBind(
510 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
511 com.android.internal.R.string.config_geofenceProviderPackageName,
512 com.android.internal.R.array.config_locationProviderPackageNames,
515 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
516 if (provider == null) {
517 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
520 // bind to the hardware activity recognition if supported
521 if (ActivityRecognitionHardware.isSupported()) {
522 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
525 ActivityRecognitionHardware.getInstance(mContext),
526 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
527 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
528 com.android.internal.R.array.config_locationProviderPackageNames);
531 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
534 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
537 String[] testProviderStrings = resources.getStringArray(
538 com.android.internal.R.array.config_testLocationProviders);
539 for (String testProviderString : testProviderStrings) {
540 String fragments[] = testProviderString.split(",");
541 String name = fragments[0].trim();
542 if (mProvidersByName.get(name) != null) {
543 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
545 ProviderProperties properties = new ProviderProperties(
546 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
547 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
548 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
549 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
550 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
551 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
552 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
553 Integer.parseInt(fragments[8]) /* powerRequirement */,
554 Integer.parseInt(fragments[9]) /* accuracy */);
555 addTestProviderLocked(name, properties);
560 * Called when the device's active user changes.
561 * @param userId the new active user's UserId
563 private void switchUser(int userId) {
564 if (mCurrentUserId == userId) {
567 mBlacklist.switchUser(userId);
568 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
569 synchronized (mLock) {
570 mLastLocation.clear();
571 mLastLocationCoarseInterval.clear();
572 for (LocationProviderInterface p : mProviders) {
573 updateProviderListenersLocked(p.getName(), false);
575 mCurrentUserId = userId;
576 updateUserProfiles(userId);
577 updateProvidersLocked();
582 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
585 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
586 final int mUid; // uid of receiver
587 final int mPid; // pid of receiver
588 final String mPackageName; // package name of receiver
589 final int mAllowedResolutionLevel; // resolution level allowed to receiver
591 final ILocationListener mListener;
592 final PendingIntent mPendingIntent;
593 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
594 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
597 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
599 // True if app ops has started monitoring this receiver for locations.
600 boolean mOpMonitoring;
601 // True if app ops has started monitoring this receiver for high power (gps) locations.
602 boolean mOpHighPowerMonitoring;
603 int mPendingBroadcasts;
604 PowerManager.WakeLock mWakeLock;
606 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
607 String packageName, WorkSource workSource, boolean hideFromAppOps) {
608 mListener = listener;
609 mPendingIntent = intent;
610 if (listener != null) {
611 mKey = listener.asBinder();
615 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
618 mPackageName = packageName;
619 if (workSource != null && workSource.size() <= 0) {
622 mWorkSource = workSource;
623 mHideFromAppOps = hideFromAppOps;
625 updateMonitoring(true);
627 // construct/configure wakelock
628 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
629 if (workSource == null) {
630 workSource = new WorkSource(mUid, mPackageName);
632 mWakeLock.setWorkSource(workSource);
636 public boolean equals(Object otherObj) {
637 if (otherObj instanceof Receiver) {
638 return mKey.equals(((Receiver)otherObj).mKey);
644 public int hashCode() {
645 return mKey.hashCode();
649 public String toString() {
650 StringBuilder s = new StringBuilder();
651 s.append("Reciever[");
652 s.append(Integer.toHexString(System.identityHashCode(this)));
653 if (mListener != null) {
654 s.append(" listener");
658 for (String p : mUpdateRecords.keySet()) {
659 s.append(" ").append(mUpdateRecords.get(p).toString());
666 * Update AppOp monitoring for this receiver.
668 * @param allow If true receiver is currently active, if false it's been removed.
670 public void updateMonitoring(boolean allow) {
671 if (mHideFromAppOps) {
675 boolean requestingLocation = false;
676 boolean requestingHighPowerLocation = false;
678 // See if receiver has any enabled update records. Also note if any update records
679 // are high power (has a high power provider with an interval under a threshold).
680 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
681 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
682 requestingLocation = true;
683 LocationProviderInterface locationProvider
684 = mProvidersByName.get(updateRecord.mProvider);
685 ProviderProperties properties = locationProvider != null
686 ? locationProvider.getProperties() : null;
687 if (properties != null
688 && properties.mPowerRequirement == Criteria.POWER_HIGH
689 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
690 requestingHighPowerLocation = true;
697 // First update monitoring of any location request (including high power).
698 mOpMonitoring = updateMonitoring(
701 AppOpsManager.OP_MONITOR_LOCATION);
703 // Now update monitoring of high power requests only.
704 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
705 mOpHighPowerMonitoring = updateMonitoring(
706 requestingHighPowerLocation,
707 mOpHighPowerMonitoring,
708 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
709 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
710 // Send an intent to notify that a high power request has been added/removed.
711 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
712 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
717 * Update AppOps monitoring for a single location request and op type.
719 * @param allowMonitoring True if monitoring is allowed for this request/op.
720 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
721 * @param op AppOps code for the op to update.
722 * @return True if monitoring is on for this request/op after updating.
724 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
726 if (!currentlyMonitoring) {
727 if (allowMonitoring) {
728 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
729 == AppOpsManager.MODE_ALLOWED;
732 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
733 != AppOpsManager.MODE_ALLOWED) {
734 mAppOps.finishOp(op, mUid, mPackageName);
739 return currentlyMonitoring;
742 public boolean isListener() {
743 return mListener != null;
746 public boolean isPendingIntent() {
747 return mPendingIntent != null;
750 public ILocationListener getListener() {
751 if (mListener != null) {
754 throw new IllegalStateException("Request for non-existent listener");
757 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
758 if (mListener != null) {
760 synchronized (this) {
761 // synchronize to ensure incrementPendingBroadcastsLocked()
762 // is called before decrementPendingBroadcasts()
763 mListener.onStatusChanged(provider, status, extras);
764 // call this after broadcasting so we do not increment
765 // if we throw an exeption.
766 incrementPendingBroadcastsLocked();
768 } catch (RemoteException e) {
772 Intent statusChanged = new Intent();
773 statusChanged.putExtras(new Bundle(extras));
774 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
776 synchronized (this) {
777 // synchronize to ensure incrementPendingBroadcastsLocked()
778 // is called before decrementPendingBroadcasts()
779 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
780 getResolutionPermission(mAllowedResolutionLevel));
781 // call this after broadcasting so we do not increment
782 // if we throw an exeption.
783 incrementPendingBroadcastsLocked();
785 } catch (PendingIntent.CanceledException e) {
792 public boolean callLocationChangedLocked(Location location) {
793 if (mListener != null) {
795 synchronized (this) {
796 // synchronize to ensure incrementPendingBroadcastsLocked()
797 // is called before decrementPendingBroadcasts()
798 mListener.onLocationChanged(new Location(location));
799 // call this after broadcasting so we do not increment
800 // if we throw an exeption.
801 incrementPendingBroadcastsLocked();
803 } catch (RemoteException e) {
807 Intent locationChanged = new Intent();
808 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
810 synchronized (this) {
811 // synchronize to ensure incrementPendingBroadcastsLocked()
812 // is called before decrementPendingBroadcasts()
813 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
814 getResolutionPermission(mAllowedResolutionLevel));
815 // call this after broadcasting so we do not increment
816 // if we throw an exeption.
817 incrementPendingBroadcastsLocked();
819 } catch (PendingIntent.CanceledException e) {
826 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
827 // First update AppOp monitoring.
828 // An app may get/lose location access as providers are enabled/disabled.
829 updateMonitoring(true);
831 if (mListener != null) {
833 synchronized (this) {
834 // synchronize to ensure incrementPendingBroadcastsLocked()
835 // is called before decrementPendingBroadcasts()
837 mListener.onProviderEnabled(provider);
839 mListener.onProviderDisabled(provider);
841 // call this after broadcasting so we do not increment
842 // if we throw an exeption.
843 incrementPendingBroadcastsLocked();
845 } catch (RemoteException e) {
849 Intent providerIntent = new Intent();
850 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
852 synchronized (this) {
853 // synchronize to ensure incrementPendingBroadcastsLocked()
854 // is called before decrementPendingBroadcasts()
855 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
856 getResolutionPermission(mAllowedResolutionLevel));
857 // call this after broadcasting so we do not increment
858 // if we throw an exeption.
859 incrementPendingBroadcastsLocked();
861 } catch (PendingIntent.CanceledException e) {
869 public void binderDied() {
870 if (D) Log.d(TAG, "Location listener died");
872 synchronized (mLock) {
873 removeUpdatesLocked(this);
875 synchronized (this) {
876 clearPendingBroadcastsLocked();
881 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
882 int resultCode, String resultData, Bundle resultExtras) {
883 synchronized (this) {
884 decrementPendingBroadcastsLocked();
888 // this must be called while synchronized by caller in a synchronized block
889 // containing the sending of the broadcaset
890 private void incrementPendingBroadcastsLocked() {
891 if (mPendingBroadcasts++ == 0) {
896 private void decrementPendingBroadcastsLocked() {
897 if (--mPendingBroadcasts == 0) {
898 if (mWakeLock.isHeld()) {
904 public void clearPendingBroadcastsLocked() {
905 if (mPendingBroadcasts > 0) {
906 mPendingBroadcasts = 0;
907 if (mWakeLock.isHeld()) {
915 public void locationCallbackFinished(ILocationListener listener) {
916 //Do not use getReceiverLocked here as that will add the ILocationListener to
917 //the receiver list if it is not found. If it is not found then the
918 //LocationListener was removed when it had a pending broadcast and should
920 synchronized (mLock) {
921 IBinder binder = listener.asBinder();
922 Receiver receiver = mReceivers.get(binder);
923 if (receiver != null) {
924 synchronized (receiver) {
925 // so wakelock calls will succeed
926 long identity = Binder.clearCallingIdentity();
927 receiver.decrementPendingBroadcastsLocked();
928 Binder.restoreCallingIdentity(identity);
934 private void addProviderLocked(LocationProviderInterface provider) {
935 mProviders.add(provider);
936 mProvidersByName.put(provider.getName(), provider);
939 private void removeProviderLocked(LocationProviderInterface provider) {
941 mProviders.remove(provider);
942 mProvidersByName.remove(provider.getName());
946 * Returns "true" if access to the specified location provider is allowed by the current
947 * user's settings. Access to all location providers is forbidden to non-location-provider
948 * processes belonging to background users.
950 * @param provider the name of the location provider
953 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
954 if (mEnabledProviders.contains(provider)) {
957 if (mDisabledProviders.contains(provider)) {
960 // Use system settings
961 ContentResolver resolver = mContext.getContentResolver();
963 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
967 * Returns "true" if access to the specified location provider is allowed by the specified
968 * user's settings. Access to all location providers is forbidden to non-location-provider
969 * processes belonging to background users.
971 * @param provider the name of the location provider
972 * @param uid the requestor's UID
975 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
976 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
979 return isAllowedByCurrentUserSettingsLocked(provider);
983 * Returns the permission string associated with the specified resolution level.
985 * @param resolutionLevel the resolution level
986 * @return the permission string
988 private String getResolutionPermission(int resolutionLevel) {
989 switch (resolutionLevel) {
990 case RESOLUTION_LEVEL_FINE:
991 return android.Manifest.permission.ACCESS_FINE_LOCATION;
992 case RESOLUTION_LEVEL_COARSE:
993 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1000 * Returns the resolution level allowed to the given PID/UID pair.
1002 * @param pid the PID
1003 * @param uid the UID
1004 * @return resolution level allowed to the pid/uid pair
1006 private int getAllowedResolutionLevel(int pid, int uid) {
1007 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1008 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1009 return RESOLUTION_LEVEL_FINE;
1010 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1011 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1012 return RESOLUTION_LEVEL_COARSE;
1014 return RESOLUTION_LEVEL_NONE;
1019 * Returns the resolution level allowed to the caller
1021 * @return resolution level allowed to caller
1023 private int getCallerAllowedResolutionLevel() {
1024 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1028 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1030 * @param allowedResolutionLevel resolution level allowed to caller
1032 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1033 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1034 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1039 * Return the minimum resolution level required to use the specified location provider.
1041 * @param provider the name of the location provider
1042 * @return minimum resolution level required for provider
1044 private int getMinimumResolutionLevelForProviderUse(String provider) {
1045 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1046 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1047 // gps and passive providers require FINE permission
1048 return RESOLUTION_LEVEL_FINE;
1049 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1050 LocationManager.FUSED_PROVIDER.equals(provider)) {
1051 // network and fused providers are ok with COARSE or FINE
1052 return RESOLUTION_LEVEL_COARSE;
1055 LocationProviderInterface lp = mMockProviders.get(provider);
1057 ProviderProperties properties = lp.getProperties();
1058 if (properties != null) {
1059 if (properties.mRequiresSatellite) {
1060 // provider requiring satellites require FINE permission
1061 return RESOLUTION_LEVEL_FINE;
1062 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1063 // provider requiring network and or cell require COARSE or FINE
1064 return RESOLUTION_LEVEL_COARSE;
1069 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
1073 * Throw SecurityException if specified resolution level is insufficient to use the named
1074 * location provider.
1076 * @param allowedResolutionLevel resolution level allowed to caller
1077 * @param providerName the name of the location provider
1079 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1080 String providerName) {
1081 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1082 if (allowedResolutionLevel < requiredResolutionLevel) {
1083 switch (requiredResolutionLevel) {
1084 case RESOLUTION_LEVEL_FINE:
1085 throw new SecurityException("\"" + providerName + "\" location provider " +
1086 "requires ACCESS_FINE_LOCATION permission.");
1087 case RESOLUTION_LEVEL_COARSE:
1088 throw new SecurityException("\"" + providerName + "\" location provider " +
1089 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1091 throw new SecurityException("Insufficient permission for \"" + providerName +
1092 "\" location provider.");
1098 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1101 private void checkDeviceStatsAllowed() {
1102 mContext.enforceCallingOrSelfPermission(
1103 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1106 private void checkUpdateAppOpsAllowed() {
1107 mContext.enforceCallingOrSelfPermission(
1108 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1111 public static int resolutionLevelToOp(int allowedResolutionLevel) {
1112 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1113 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
1114 return AppOpsManager.OP_COARSE_LOCATION;
1116 return AppOpsManager.OP_FINE_LOCATION;
1122 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1123 int op = resolutionLevelToOp(allowedResolutionLevel);
1125 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1132 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
1133 int op = resolutionLevelToOp(allowedResolutionLevel);
1135 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1143 * Returns all providers by name, including passive, but excluding
1144 * fused, also including ones that are not permitted to
1145 * be accessed by the calling activity or are currently disabled.
1148 public List<String> getAllProviders() {
1149 ArrayList<String> out;
1150 synchronized (mLock) {
1151 out = new ArrayList<String>(mProviders.size());
1152 for (LocationProviderInterface provider : mProviders) {
1153 String name = provider.getName();
1154 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1161 if (D) Log.d(TAG, "getAllProviders()=" + out);
1166 * Return all providers by name, that match criteria and are optionally
1168 * Can return passive provider, but never returns fused provider.
1171 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
1172 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1173 ArrayList<String> out;
1174 int uid = Binder.getCallingUid();;
1175 long identity = Binder.clearCallingIdentity();
1177 synchronized (mLock) {
1178 out = new ArrayList<String>(mProviders.size());
1179 for (LocationProviderInterface provider : mProviders) {
1180 String name = provider.getName();
1181 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1184 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1185 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
1188 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1189 name, provider.getProperties(), criteria)) {
1197 Binder.restoreCallingIdentity(identity);
1200 if (D) Log.d(TAG, "getProviders()=" + out);
1205 * Return the name of the best provider given a Criteria object.
1206 * This method has been deprecated from the public API,
1207 * and the whole LocationProvider (including #meetsCriteria)
1208 * has been deprecated as well. So this method now uses
1209 * some simplified logic.
1212 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1213 String result = null;
1215 List<String> providers = getProviders(criteria, enabledOnly);
1216 if (!providers.isEmpty()) {
1217 result = pickBest(providers);
1218 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1221 providers = getProviders(null, enabledOnly);
1222 if (!providers.isEmpty()) {
1223 result = pickBest(providers);
1224 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1228 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1232 private String pickBest(List<String> providers) {
1233 if (providers.contains(LocationManager.GPS_PROVIDER)) {
1234 return LocationManager.GPS_PROVIDER;
1235 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1236 return LocationManager.NETWORK_PROVIDER;
1238 return providers.get(0);
1243 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1244 LocationProviderInterface p = mProvidersByName.get(provider);
1246 throw new IllegalArgumentException("provider=" + provider);
1249 boolean result = LocationProvider.propertiesMeetCriteria(
1250 p.getName(), p.getProperties(), criteria);
1251 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1255 private void updateProvidersLocked() {
1256 boolean changesMade = false;
1257 for (int i = mProviders.size() - 1; i >= 0; i--) {
1258 LocationProviderInterface p = mProviders.get(i);
1259 boolean isEnabled = p.isEnabled();
1260 String name = p.getName();
1261 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
1262 if (isEnabled && !shouldBeEnabled) {
1263 updateProviderListenersLocked(name, false);
1264 // If any provider has been disabled, clear all last locations for all providers.
1265 // This is to be on the safe side in case a provider has location derived from
1266 // this disabled provider.
1267 mLastLocation.clear();
1268 mLastLocationCoarseInterval.clear();
1270 } else if (!isEnabled && shouldBeEnabled) {
1271 updateProviderListenersLocked(name, true);
1276 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1278 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1283 private void updateProviderListenersLocked(String provider, boolean enabled) {
1286 LocationProviderInterface p = mProvidersByName.get(provider);
1287 if (p == null) return;
1289 ArrayList<Receiver> deadReceivers = null;
1291 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1292 if (records != null) {
1293 final int N = records.size();
1294 for (int i = 0; i < N; i++) {
1295 UpdateRecord record = records.get(i);
1296 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1297 // Sends a notification message to the receiver
1298 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1299 if (deadReceivers == null) {
1300 deadReceivers = new ArrayList<Receiver>();
1302 deadReceivers.add(record.mReceiver);
1309 if (deadReceivers != null) {
1310 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1311 removeUpdatesLocked(deadReceivers.get(i));
1317 if (listeners > 0) {
1318 applyRequirementsLocked(provider);
1325 private void applyRequirementsLocked(String provider) {
1326 LocationProviderInterface p = mProvidersByName.get(provider);
1327 if (p == null) return;
1329 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1330 WorkSource worksource = new WorkSource();
1331 ProviderRequest providerRequest = new ProviderRequest();
1333 if (records != null) {
1334 for (UpdateRecord record : records) {
1335 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1336 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1337 record.mReceiver.mAllowedResolutionLevel)) {
1338 LocationRequest locationRequest = record.mRequest;
1339 providerRequest.locationRequests.add(locationRequest);
1340 if (locationRequest.getInterval() < providerRequest.interval) {
1341 providerRequest.reportLocation = true;
1342 providerRequest.interval = locationRequest.getInterval();
1348 if (providerRequest.reportLocation) {
1349 // calculate who to blame for power
1350 // This is somewhat arbitrary. We pick a threshold interval
1351 // that is slightly higher that the minimum interval, and
1352 // spread the blame across all applications with a request
1353 // under that threshold.
1354 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1355 for (UpdateRecord record : records) {
1356 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1357 LocationRequest locationRequest = record.mRequest;
1358 if (locationRequest.getInterval() <= thresholdInterval) {
1359 if (record.mReceiver.mWorkSource != null
1360 && record.mReceiver.mWorkSource.size() > 0
1361 && record.mReceiver.mWorkSource.getName(0) != null) {
1362 // Assign blame to another work source.
1363 // Can only assign blame if the WorkSource contains names.
1364 worksource.add(record.mReceiver.mWorkSource);
1366 // Assign blame to caller.
1368 record.mReceiver.mUid,
1369 record.mReceiver.mPackageName);
1377 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1378 p.setRequest(providerRequest, worksource);
1381 private class UpdateRecord {
1382 final String mProvider;
1383 final LocationRequest mRequest;
1384 final Receiver mReceiver;
1385 Location mLastFixBroadcast;
1386 long mLastStatusBroadcast;
1389 * Note: must be constructed with lock held.
1391 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1392 mProvider = provider;
1394 mReceiver = receiver;
1396 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1397 if (records == null) {
1398 records = new ArrayList<UpdateRecord>();
1399 mRecordsByProvider.put(provider, records);
1401 if (!records.contains(this)) {
1405 // Update statistics for historical location requests by package/provider
1406 mRequestStatistics.startRequesting(
1407 mReceiver.mPackageName, provider, request.getInterval());
1411 * Method to be called when a record will no longer be used.
1413 void disposeLocked(boolean removeReceiver) {
1414 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1416 // remove from mRecordsByProvider
1417 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1418 if (globalRecords != null) {
1419 globalRecords.remove(this);
1422 if (!removeReceiver) return; // the caller will handle the rest
1424 // remove from Receiver#mUpdateRecords
1425 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1426 if (receiverRecords != null) {
1427 receiverRecords.remove(this.mProvider);
1429 // and also remove the Receiver if it has no more update records
1430 if (removeReceiver && receiverRecords.size() == 0) {
1431 removeUpdatesLocked(mReceiver);
1437 public String toString() {
1438 StringBuilder s = new StringBuilder();
1439 s.append("UpdateRecord[");
1440 s.append(mProvider);
1441 s.append(' ').append(mReceiver.mPackageName).append('(');
1442 s.append(mReceiver.mUid).append(')');
1443 s.append(' ').append(mRequest);
1445 return s.toString();
1449 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1450 String packageName, WorkSource workSource, boolean hideFromAppOps) {
1451 IBinder binder = listener.asBinder();
1452 Receiver receiver = mReceivers.get(binder);
1453 if (receiver == null) {
1454 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1457 receiver.getListener().asBinder().linkToDeath(receiver, 0);
1458 } catch (RemoteException e) {
1459 Slog.e(TAG, "linkToDeath failed:", e);
1462 mReceivers.put(binder, receiver);
1467 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1468 WorkSource workSource, boolean hideFromAppOps) {
1469 Receiver receiver = mReceivers.get(intent);
1470 if (receiver == null) {
1471 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1473 mReceivers.put(intent, receiver);
1479 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1480 * and consistency requirements.
1482 * @param request the LocationRequest from which to create a sanitized version
1483 * @return a version of request that meets the given resolution and consistency requirements
1486 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1487 LocationRequest sanitizedRequest = new LocationRequest(request);
1488 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1489 switch (sanitizedRequest.getQuality()) {
1490 case LocationRequest.ACCURACY_FINE:
1491 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1493 case LocationRequest.POWER_HIGH:
1494 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1498 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1499 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1501 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1502 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1505 // make getFastestInterval() the minimum of interval and fastest interval
1506 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1507 request.setFastestInterval(request.getInterval());
1509 return sanitizedRequest;
1512 private void checkPackageName(String packageName) {
1513 if (packageName == null) {
1514 throw new SecurityException("invalid package name: " + packageName);
1516 int uid = Binder.getCallingUid();
1517 String[] packages = mPackageManager.getPackagesForUid(uid);
1518 if (packages == null) {
1519 throw new SecurityException("invalid UID " + uid);
1521 for (String pkg : packages) {
1522 if (packageName.equals(pkg)) return;
1524 throw new SecurityException("invalid package name: " + packageName);
1527 private void checkPendingIntent(PendingIntent intent) {
1528 if (intent == null) {
1529 throw new IllegalArgumentException("invalid pending intent: " + intent);
1533 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1534 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1535 if (intent == null && listener == null) {
1536 throw new IllegalArgumentException("need either listener or intent");
1537 } else if (intent != null && listener != null) {
1538 throw new IllegalArgumentException("cannot register both listener and intent");
1539 } else if (intent != null) {
1540 checkPendingIntent(intent);
1541 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1543 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1548 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1549 PendingIntent intent, String packageName) {
1550 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1551 checkPackageName(packageName);
1552 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1553 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1554 request.getProvider());
1555 WorkSource workSource = request.getWorkSource();
1556 if (workSource != null && workSource.size() > 0) {
1557 checkDeviceStatsAllowed();
1559 boolean hideFromAppOps = request.getHideFromAppOps();
1560 if (hideFromAppOps) {
1561 checkUpdateAppOpsAllowed();
1563 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1565 final int pid = Binder.getCallingPid();
1566 final int uid = Binder.getCallingUid();
1567 // providers may use public location API's, need to clear identity
1568 long identity = Binder.clearCallingIdentity();
1570 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1572 checkLocationAccess(uid, packageName, allowedResolutionLevel);
1574 synchronized (mLock) {
1575 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1576 packageName, workSource, hideFromAppOps);
1577 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
1580 Binder.restoreCallingIdentity(identity);
1584 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1585 int pid, int uid, String packageName) {
1586 // Figure out the provider. Either its explicitly request (legacy use cases), or
1587 // use the fused provider
1588 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1589 String name = request.getProvider();
1591 throw new IllegalArgumentException("provider name must not be null");
1594 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1595 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
1596 LocationProviderInterface provider = mProvidersByName.get(name);
1597 if (provider == null) {
1598 throw new IllegalArgumentException("provider doesn't exist: " + name);
1601 UpdateRecord record = new UpdateRecord(name, request, receiver);
1602 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1603 if (oldRecord != null) {
1604 oldRecord.disposeLocked(false);
1607 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
1608 if (isProviderEnabled) {
1609 applyRequirementsLocked(name);
1611 // Notify the listener that updates are currently disabled
1612 receiver.callProviderEnabledLocked(name, false);
1614 // Update the monitoring here just in case multiple location requests were added to the
1615 // same receiver (this request may be high power and the initial might not have been).
1616 receiver.updateMonitoring(true);
1620 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1621 String packageName) {
1622 checkPackageName(packageName);
1624 final int pid = Binder.getCallingPid();
1625 final int uid = Binder.getCallingUid();
1627 synchronized (mLock) {
1628 WorkSource workSource = null;
1629 boolean hideFromAppOps = false;
1630 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1631 packageName, workSource, hideFromAppOps);
1633 // providers may use public location API's, need to clear identity
1634 long identity = Binder.clearCallingIdentity();
1636 removeUpdatesLocked(receiver);
1638 Binder.restoreCallingIdentity(identity);
1643 private void removeUpdatesLocked(Receiver receiver) {
1644 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1646 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1647 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1648 synchronized (receiver) {
1649 receiver.clearPendingBroadcastsLocked();
1653 receiver.updateMonitoring(false);
1655 // Record which providers were associated with this listener
1656 HashSet<String> providers = new HashSet<String>();
1657 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1658 if (oldRecords != null) {
1659 // Call dispose() on the obsolete update records.
1660 for (UpdateRecord record : oldRecords.values()) {
1661 // Update statistics for historical location requests by package/provider
1662 record.disposeLocked(false);
1664 // Accumulate providers
1665 providers.addAll(oldRecords.keySet());
1669 for (String provider : providers) {
1670 // If provider is already disabled, don't need to do anything
1671 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
1675 applyRequirementsLocked(provider);
1679 private void applyAllProviderRequirementsLocked() {
1680 for (LocationProviderInterface p : mProviders) {
1681 // If provider is already disabled, don't need to do anything
1682 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
1686 applyRequirementsLocked(p.getName());
1691 public Location getLastLocation(LocationRequest request, String packageName) {
1692 if (D) Log.d(TAG, "getLastLocation: " + request);
1693 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1694 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1695 checkPackageName(packageName);
1696 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1697 request.getProvider());
1698 // no need to sanitize this request, as only the provider name is used
1700 final int uid = Binder.getCallingUid();
1701 final long identity = Binder.clearCallingIdentity();
1703 if (mBlacklist.isBlacklisted(packageName)) {
1704 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1709 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1710 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1715 synchronized (mLock) {
1716 // Figure out the provider. Either its explicitly request (deprecated API's),
1717 // or use the fused provider
1718 String name = request.getProvider();
1719 if (name == null) name = LocationManager.FUSED_PROVIDER;
1720 LocationProviderInterface provider = mProvidersByName.get(name);
1721 if (provider == null) return null;
1723 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
1726 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1727 // Make sure that an app with coarse permissions can't get frequent location
1728 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1729 location = mLastLocationCoarseInterval.get(name);
1731 location = mLastLocation.get(name);
1733 if (location == null) {
1736 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1737 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1738 if (noGPSLocation != null) {
1739 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
1742 return new Location(location);
1747 Binder.restoreCallingIdentity(identity);
1752 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1753 String packageName) {
1754 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1755 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1756 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
1757 checkPendingIntent(intent);
1758 checkPackageName(packageName);
1759 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1760 request.getProvider());
1761 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1763 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
1765 // geo-fence manager uses the public location API, need to clear identity
1766 int uid = Binder.getCallingUid();
1767 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1768 // temporary measure until geofences work for secondary users
1769 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1772 long identity = Binder.clearCallingIdentity();
1774 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1777 Binder.restoreCallingIdentity(identity);
1782 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1783 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
1784 checkPendingIntent(intent);
1785 checkPackageName(packageName);
1787 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1789 // geo-fence manager uses the public location API, need to clear identity
1790 long identity = Binder.clearCallingIdentity();
1792 mGeofenceManager.removeFence(geofence, intent);
1794 Binder.restoreCallingIdentity(identity);
1800 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
1801 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1802 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1803 LocationManager.GPS_PROVIDER);
1805 final int uid = Binder.getCallingUid();
1806 final long ident = Binder.clearCallingIdentity();
1808 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
1812 Binder.restoreCallingIdentity(ident);
1815 if (mGpsStatusProvider == null) {
1820 mGpsStatusProvider.addGpsStatusListener(listener);
1821 } catch (RemoteException e) {
1822 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1829 public void removeGpsStatusListener(IGpsStatusListener listener) {
1830 synchronized (mLock) {
1832 mGpsStatusProvider.removeGpsStatusListener(listener);
1833 } catch (Exception e) {
1834 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1840 public boolean addGpsMeasurementsListener(
1841 IGpsMeasurementsListener listener,
1842 String packageName) {
1843 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1844 checkResolutionLevelIsSufficientForProviderUse(
1845 allowedResolutionLevel,
1846 LocationManager.GPS_PROVIDER);
1848 int uid = Binder.getCallingUid();
1849 long identity = Binder.clearCallingIdentity();
1850 boolean hasLocationAccess;
1852 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1854 Binder.restoreCallingIdentity(identity);
1857 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
1860 return mGpsMeasurementsProvider.addListener(listener);
1864 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
1865 if (mGpsMeasurementsProvider != null) {
1866 mGpsMeasurementsProvider.removeListener(listener);
1871 public boolean addGpsNavigationMessageListener(
1872 IGpsNavigationMessageListener listener,
1873 String packageName) {
1874 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1875 checkResolutionLevelIsSufficientForProviderUse(
1876 allowedResolutionLevel,
1877 LocationManager.GPS_PROVIDER);
1879 int uid = Binder.getCallingUid();
1880 long identity = Binder.clearCallingIdentity();
1881 boolean hasLocationAccess;
1883 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1885 Binder.restoreCallingIdentity(identity);
1888 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
1891 return mGpsNavigationMessageProvider.addListener(listener);
1895 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
1896 if (mGpsNavigationMessageProvider != null) {
1897 mGpsNavigationMessageProvider.removeListener(listener);
1902 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1903 if (provider == null) {
1904 // throw NullPointerException to remain compatible with previous implementation
1905 throw new NullPointerException();
1907 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1910 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1911 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1912 != PackageManager.PERMISSION_GRANTED)) {
1913 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1916 synchronized (mLock) {
1917 LocationProviderInterface p = mProvidersByName.get(provider);
1918 if (p == null) return false;
1920 return p.sendExtraCommand(command, extras);
1925 public boolean sendNiResponse(int notifId, int userResponse) {
1926 if (Binder.getCallingUid() != Process.myUid()) {
1927 throw new SecurityException(
1928 "calling sendNiResponse from outside of the system is not allowed");
1931 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1932 } catch (RemoteException e) {
1933 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1939 * @return null if the provider does not exist
1940 * @throws SecurityException if the provider is not allowed to be
1941 * accessed by the caller
1944 public ProviderProperties getProviderProperties(String provider) {
1945 if (mProvidersByName.get(provider) == null) {
1949 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1952 LocationProviderInterface p;
1953 synchronized (mLock) {
1954 p = mProvidersByName.get(provider);
1957 if (p == null) return null;
1958 return p.getProperties();
1962 public boolean isProviderEnabled(String provider) {
1963 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1964 // so we discourage its use
1965 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1967 int uid = Binder.getCallingUid();
1968 long identity = Binder.clearCallingIdentity();
1970 synchronized (mLock) {
1971 LocationProviderInterface p = mProvidersByName.get(provider);
1972 if (p == null) return false;
1974 return isAllowedByUserSettingsLocked(provider, uid);
1977 Binder.restoreCallingIdentity(identity);
1982 * Returns "true" if the UID belongs to a bound location provider.
1984 * @param uid the uid
1985 * @return true if uid belongs to a bound location provider
1987 private boolean isUidALocationProvider(int uid) {
1988 if (uid == Process.SYSTEM_UID) {
1991 if (mGeocodeProvider != null) {
1992 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1994 for (LocationProviderProxy proxy : mProxyProviders) {
1995 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
2000 private void checkCallerIsProvider() {
2001 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2002 == PackageManager.PERMISSION_GRANTED) {
2006 // Previously we only used the INSTALL_LOCATION_PROVIDER
2007 // check. But that is system or signature
2008 // protection level which is not flexible enough for
2009 // providers installed oustide the system image. So
2010 // also allow providers with a UID matching the
2011 // currently bound package name
2013 if (isUidALocationProvider(Binder.getCallingUid())) {
2017 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2018 "or UID of a currently bound location provider");
2022 * Returns true if the given package belongs to the given uid.
2024 private boolean doesUidHavePackage(int uid, String packageName) {
2025 if (packageName == null) {
2028 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2029 if (packageNames == null) {
2032 for (String name : packageNames) {
2033 if (packageName.equals(name)) {
2041 public void reportLocation(Location location, boolean passive) {
2042 checkCallerIsProvider();
2044 if (!location.isComplete()) {
2045 Log.w(TAG, "Dropping incomplete location: " + location);
2049 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2050 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2051 m.arg1 = (passive ? 1 : 0);
2052 mLocationHandler.sendMessageAtFrontOfQueue(m);
2056 private static boolean shouldBroadcastSafe(
2057 Location loc, Location lastLoc, UpdateRecord record, long now) {
2058 // Always broadcast the first update
2059 if (lastLoc == null) {
2063 // Check whether sufficient time has passed
2064 long minTime = record.mRequest.getFastestInterval();
2065 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2067 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2071 // Check whether sufficient distance has been traveled
2072 double minDistance = record.mRequest.getSmallestDisplacement();
2073 if (minDistance > 0.0) {
2074 if (loc.distanceTo(lastLoc) <= minDistance) {
2079 // Check whether sufficient number of udpates is left
2080 if (record.mRequest.getNumUpdates() <= 0) {
2084 // Check whether the expiry date has passed
2085 if (record.mRequest.getExpireAt() < now) {
2092 private void handleLocationChangedLocked(Location location, boolean passive) {
2093 if (D) Log.d(TAG, "incoming location: " + location);
2095 long now = SystemClock.elapsedRealtime();
2096 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2098 // Skip if the provider is unknown.
2099 LocationProviderInterface p = mProvidersByName.get(provider);
2100 if (p == null) return;
2102 // Update last known locations
2103 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2104 Location lastNoGPSLocation = null;
2105 Location lastLocation = mLastLocation.get(provider);
2106 if (lastLocation == null) {
2107 lastLocation = new Location(provider);
2108 mLastLocation.put(provider, lastLocation);
2110 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2111 if (noGPSLocation == null && lastNoGPSLocation != null) {
2112 // New location has no no-GPS location: adopt last no-GPS location. This is set
2113 // directly into location because we do not want to notify COARSE clients.
2114 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2117 lastLocation.set(location);
2119 // Update last known coarse interval location if enough time has passed.
2120 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2121 if (lastLocationCoarseInterval == null) {
2122 lastLocationCoarseInterval = new Location(location);
2123 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2125 long timeDiffNanos = location.getElapsedRealtimeNanos()
2126 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2127 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2128 lastLocationCoarseInterval.set(location);
2130 // Don't ever return a coarse location that is more recent than the allowed update
2131 // interval (i.e. don't allow an app to keep registering and unregistering for
2132 // location updates to overcome the minimum interval).
2134 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2136 // Skip if there are no UpdateRecords for this provider.
2137 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2138 if (records == null || records.size() == 0) return;
2140 // Fetch coarse location
2141 Location coarseLocation = null;
2142 if (noGPSLocation != null) {
2143 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2146 // Fetch latest status update time
2147 long newStatusUpdateTime = p.getStatusUpdateTime();
2149 // Get latest status
2150 Bundle extras = new Bundle();
2151 int status = p.getStatus(extras);
2153 ArrayList<Receiver> deadReceivers = null;
2154 ArrayList<UpdateRecord> deadUpdateRecords = null;
2156 // Broadcast location or status to all listeners
2157 for (UpdateRecord r : records) {
2158 Receiver receiver = r.mReceiver;
2159 boolean receiverDead = false;
2161 int receiverUserId = UserHandle.getUserId(receiver.mUid);
2162 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2164 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2165 " (current user: " + mCurrentUserId + ", app: " +
2166 receiver.mPackageName + ")");
2171 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2172 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2173 receiver.mPackageName);
2177 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2178 receiver.mAllowedResolutionLevel)) {
2179 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2180 receiver.mPackageName);
2184 Location notifyLocation = null;
2185 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2186 notifyLocation = coarseLocation; // use coarse location
2188 notifyLocation = lastLocation; // use fine location
2190 if (notifyLocation != null) {
2191 Location lastLoc = r.mLastFixBroadcast;
2192 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2193 if (lastLoc == null) {
2194 lastLoc = new Location(notifyLocation);
2195 r.mLastFixBroadcast = lastLoc;
2197 lastLoc.set(notifyLocation);
2199 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2200 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2201 receiverDead = true;
2203 r.mRequest.decrementNumUpdates();
2207 long prevStatusUpdateTime = r.mLastStatusBroadcast;
2208 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2209 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2211 r.mLastStatusBroadcast = newStatusUpdateTime;
2212 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2213 receiverDead = true;
2214 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2218 // track expired records
2219 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2220 if (deadUpdateRecords == null) {
2221 deadUpdateRecords = new ArrayList<UpdateRecord>();
2223 deadUpdateRecords.add(r);
2225 // track dead receivers
2227 if (deadReceivers == null) {
2228 deadReceivers = new ArrayList<Receiver>();
2230 if (!deadReceivers.contains(receiver)) {
2231 deadReceivers.add(receiver);
2236 // remove dead records and receivers outside the loop
2237 if (deadReceivers != null) {
2238 for (Receiver receiver : deadReceivers) {
2239 removeUpdatesLocked(receiver);
2242 if (deadUpdateRecords != null) {
2243 for (UpdateRecord r : deadUpdateRecords) {
2244 r.disposeLocked(true);
2246 applyRequirementsLocked(provider);
2250 private class LocationWorkerHandler extends Handler {
2251 public LocationWorkerHandler(Looper looper) {
2252 super(looper, null, true);
2256 public void handleMessage(Message msg) {
2258 case MSG_LOCATION_CHANGED:
2259 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2265 private boolean isMockProvider(String provider) {
2266 synchronized (mLock) {
2267 return mMockProviders.containsKey(provider);
2271 private void handleLocationChanged(Location location, boolean passive) {
2272 // create a working copy of the incoming Location so that the service can modify it without
2273 // disturbing the caller's copy
2274 Location myLocation = new Location(location);
2275 String provider = myLocation.getProvider();
2277 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2278 // bit if location did not come from a mock provider because passive/fused providers can
2279 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2280 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2281 myLocation.setIsFromMockProvider(true);
2284 synchronized (mLock) {
2285 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2287 // notify passive provider of the new location
2288 mPassiveProvider.updateLocation(myLocation);
2290 handleLocationChangedLocked(myLocation, passive);
2295 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2297 public void onPackageDisappeared(String packageName, int reason) {
2298 // remove all receivers associated with this package name
2299 synchronized (mLock) {
2300 ArrayList<Receiver> deadReceivers = null;
2302 for (Receiver receiver : mReceivers.values()) {
2303 if (receiver.mPackageName.equals(packageName)) {
2304 if (deadReceivers == null) {
2305 deadReceivers = new ArrayList<Receiver>();
2307 deadReceivers.add(receiver);
2311 // perform removal outside of mReceivers loop
2312 if (deadReceivers != null) {
2313 for (Receiver receiver : deadReceivers) {
2314 removeUpdatesLocked(receiver);
2324 public boolean geocoderIsPresent() {
2325 return mGeocodeProvider != null;
2329 public String getFromLocation(double latitude, double longitude, int maxResults,
2330 GeocoderParams params, List<Address> addrs) {
2331 if (mGeocodeProvider != null) {
2332 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2340 public String getFromLocationName(String locationName,
2341 double lowerLeftLatitude, double lowerLeftLongitude,
2342 double upperRightLatitude, double upperRightLongitude, int maxResults,
2343 GeocoderParams params, List<Address> addrs) {
2345 if (mGeocodeProvider != null) {
2346 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2347 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2348 maxResults, params, addrs);
2355 private void checkMockPermissionsSafe() {
2356 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2357 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2359 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2362 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2363 PackageManager.PERMISSION_GRANTED) {
2364 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2369 public void addTestProvider(String name, ProviderProperties properties) {
2370 checkMockPermissionsSafe();
2372 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2373 throw new IllegalArgumentException("Cannot mock the passive location provider");
2376 long identity = Binder.clearCallingIdentity();
2377 synchronized (mLock) {
2378 // remove the real provider if we are replacing GPS or network provider
2379 if (LocationManager.GPS_PROVIDER.equals(name)
2380 || LocationManager.NETWORK_PROVIDER.equals(name)
2381 || LocationManager.FUSED_PROVIDER.equals(name)) {
2382 LocationProviderInterface p = mProvidersByName.get(name);
2384 removeProviderLocked(p);
2387 addTestProviderLocked(name, properties);
2388 updateProvidersLocked();
2390 Binder.restoreCallingIdentity(identity);
2393 private void addTestProviderLocked(String name, ProviderProperties properties) {
2394 if (mProvidersByName.get(name) != null) {
2395 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2397 MockProvider provider = new MockProvider(name, this, properties);
2398 addProviderLocked(provider);
2399 mMockProviders.put(name, provider);
2400 mLastLocation.put(name, null);
2401 mLastLocationCoarseInterval.put(name, null);
2405 public void removeTestProvider(String provider) {
2406 checkMockPermissionsSafe();
2407 synchronized (mLock) {
2409 // These methods can't be called after removing the test provider, so first make sure
2410 // we don't leave anything dangling.
2411 clearTestProviderEnabled(provider);
2412 clearTestProviderLocation(provider);
2413 clearTestProviderStatus(provider);
2415 MockProvider mockProvider = mMockProviders.remove(provider);
2416 if (mockProvider == null) {
2417 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2419 long identity = Binder.clearCallingIdentity();
2420 removeProviderLocked(mProvidersByName.get(provider));
2422 // reinstate real provider if available
2423 LocationProviderInterface realProvider = mRealProviders.get(provider);
2424 if (realProvider != null) {
2425 addProviderLocked(realProvider);
2427 mLastLocation.put(provider, null);
2428 mLastLocationCoarseInterval.put(provider, null);
2429 updateProvidersLocked();
2430 Binder.restoreCallingIdentity(identity);
2435 public void setTestProviderLocation(String provider, Location loc) {
2436 checkMockPermissionsSafe();
2437 synchronized (mLock) {
2438 MockProvider mockProvider = mMockProviders.get(provider);
2439 if (mockProvider == null) {
2440 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2442 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2443 long identity = Binder.clearCallingIdentity();
2444 mockProvider.setLocation(loc);
2445 Binder.restoreCallingIdentity(identity);
2450 public void clearTestProviderLocation(String provider) {
2451 checkMockPermissionsSafe();
2452 synchronized (mLock) {
2453 MockProvider mockProvider = mMockProviders.get(provider);
2454 if (mockProvider == null) {
2455 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2457 mockProvider.clearLocation();
2462 public void setTestProviderEnabled(String provider, boolean enabled) {
2463 checkMockPermissionsSafe();
2464 synchronized (mLock) {
2465 MockProvider mockProvider = mMockProviders.get(provider);
2466 if (mockProvider == null) {
2467 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2469 long identity = Binder.clearCallingIdentity();
2471 mockProvider.enable();
2472 mEnabledProviders.add(provider);
2473 mDisabledProviders.remove(provider);
2475 mockProvider.disable();
2476 mEnabledProviders.remove(provider);
2477 mDisabledProviders.add(provider);
2479 updateProvidersLocked();
2480 Binder.restoreCallingIdentity(identity);
2485 public void clearTestProviderEnabled(String provider) {
2486 checkMockPermissionsSafe();
2487 synchronized (mLock) {
2488 MockProvider mockProvider = mMockProviders.get(provider);
2489 if (mockProvider == null) {
2490 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2492 long identity = Binder.clearCallingIdentity();
2493 mEnabledProviders.remove(provider);
2494 mDisabledProviders.remove(provider);
2495 updateProvidersLocked();
2496 Binder.restoreCallingIdentity(identity);
2501 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2502 checkMockPermissionsSafe();
2503 synchronized (mLock) {
2504 MockProvider mockProvider = mMockProviders.get(provider);
2505 if (mockProvider == null) {
2506 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2508 mockProvider.setStatus(status, extras, updateTime);
2513 public void clearTestProviderStatus(String provider) {
2514 checkMockPermissionsSafe();
2515 synchronized (mLock) {
2516 MockProvider mockProvider = mMockProviders.get(provider);
2517 if (mockProvider == null) {
2518 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2520 mockProvider.clearStatus();
2524 private void log(String log) {
2525 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2531 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2532 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2533 != PackageManager.PERMISSION_GRANTED) {
2534 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2535 + Binder.getCallingPid()
2536 + ", uid=" + Binder.getCallingUid());
2540 synchronized (mLock) {
2541 pw.println("Current Location Manager state:");
2542 pw.println(" Location Listeners:");
2543 for (Receiver receiver : mReceivers.values()) {
2544 pw.println(" " + receiver);
2546 pw.println(" Active Records by Provider:");
2547 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2548 pw.println(" " + entry.getKey() + ":");
2549 for (UpdateRecord record : entry.getValue()) {
2550 pw.println(" " + record);
2553 pw.println(" Historical Records by Provider:");
2554 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2555 : mRequestStatistics.statistics.entrySet()) {
2556 PackageProviderKey key = entry.getKey();
2557 PackageStatistics stats = entry.getValue();
2558 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2560 pw.println(" Last Known Locations:");
2561 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2562 String provider = entry.getKey();
2563 Location location = entry.getValue();
2564 pw.println(" " + provider + ": " + location);
2567 pw.println(" Last Known Locations Coarse Intervals:");
2568 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2569 String provider = entry.getKey();
2570 Location location = entry.getValue();
2571 pw.println(" " + provider + ": " + location);
2574 mGeofenceManager.dump(pw);
2576 if (mEnabledProviders.size() > 0) {
2577 pw.println(" Enabled Providers:");
2578 for (String i : mEnabledProviders) {
2579 pw.println(" " + i);
2583 if (mDisabledProviders.size() > 0) {
2584 pw.println(" Disabled Providers:");
2585 for (String i : mDisabledProviders) {
2586 pw.println(" " + i);
2590 mBlacklist.dump(pw);
2591 if (mMockProviders.size() > 0) {
2592 pw.println(" Mock Providers:");
2593 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2594 i.getValue().dump(pw, " ");
2598 pw.append(" fudger: ");
2599 mLocationFudger.dump(fd, pw, args);
2601 if (args.length > 0 && "short".equals(args[0])) {
2604 for (LocationProviderInterface provider: mProviders) {
2605 pw.print(provider.getName() + " Internal State");
2606 if (provider instanceof LocationProviderProxy) {
2607 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2608 pw.print(" (" + proxy.getConnectedPackageName() + ")");
2611 provider.dump(fd, pw, args);