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 android.content.pm.PackageManagerInternal;
20 import com.android.internal.content.PackageMonitor;
21 import com.android.internal.location.ProviderProperties;
22 import com.android.internal.location.ProviderRequest;
23 import com.android.internal.os.BackgroundThread;
24 import com.android.server.location.ActivityRecognitionProxy;
25 import com.android.server.location.FlpHardwareProvider;
26 import com.android.server.location.FusedProxy;
27 import com.android.server.location.GeocoderProxy;
28 import com.android.server.location.GeofenceManager;
29 import com.android.server.location.GeofenceProxy;
30 import com.android.server.location.GpsLocationProvider;
31 import com.android.server.location.GpsMeasurementsProvider;
32 import com.android.server.location.GpsNavigationMessageProvider;
33 import com.android.server.location.LocationBlacklist;
34 import com.android.server.location.LocationFudger;
35 import com.android.server.location.LocationProviderInterface;
36 import com.android.server.location.LocationProviderProxy;
37 import com.android.server.location.LocationRequestStatistics;
38 import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
39 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
40 import com.android.server.location.MockProvider;
41 import com.android.server.location.PassiveProvider;
43 import android.app.AppOpsManager;
44 import android.app.PendingIntent;
45 import android.content.BroadcastReceiver;
46 import android.content.ContentResolver;
47 import android.content.Context;
48 import android.content.Intent;
49 import android.content.IntentFilter;
50 import android.content.pm.ApplicationInfo;
51 import android.content.pm.PackageInfo;
52 import android.content.pm.PackageManager;
53 import android.content.pm.PackageManager.NameNotFoundException;
54 import android.content.pm.ResolveInfo;
55 import android.content.pm.Signature;
56 import android.content.pm.UserInfo;
57 import android.content.res.Resources;
58 import android.database.ContentObserver;
59 import android.hardware.location.ActivityRecognitionHardware;
60 import android.location.Address;
61 import android.location.Criteria;
62 import android.location.GeocoderParams;
63 import android.location.Geofence;
64 import android.location.IGpsGeofenceHardware;
65 import android.location.IGpsMeasurementsListener;
66 import android.location.IGpsNavigationMessageListener;
67 import android.location.IGpsStatusListener;
68 import android.location.IGpsStatusProvider;
69 import android.location.ILocationListener;
70 import android.location.ILocationManager;
71 import android.location.INetInitiatedListener;
72 import android.location.Location;
73 import android.location.LocationManager;
74 import android.location.LocationProvider;
75 import android.location.LocationRequest;
76 import android.os.Binder;
77 import android.os.Bundle;
78 import android.os.Handler;
79 import android.os.IBinder;
80 import android.os.Looper;
81 import android.os.Message;
82 import android.os.PowerManager;
83 import android.os.Process;
84 import android.os.RemoteException;
85 import android.os.SystemClock;
86 import android.os.UserHandle;
87 import android.os.UserManager;
88 import android.os.WorkSource;
89 import android.provider.Settings;
90 import android.util.Log;
91 import android.util.Slog;
93 import java.io.FileDescriptor;
94 import java.io.PrintWriter;
95 import java.util.ArrayList;
96 import java.util.Arrays;
97 import java.util.HashMap;
98 import java.util.HashSet;
99 import java.util.List;
100 import java.util.Map;
101 import java.util.Set;
104 * The service class that manages LocationProviders and issues location
105 * updates and alerts.
107 public class LocationManagerService extends ILocationManager.Stub {
108 private static final String TAG = "LocationManagerService";
109 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
111 private static final String WAKELOCK_KEY = TAG;
113 // Location resolution level: no location data whatsoever
114 private static final int RESOLUTION_LEVEL_NONE = 0;
115 // Location resolution level: coarse location data only
116 private static final int RESOLUTION_LEVEL_COARSE = 1;
117 // Location resolution level: fine location data
118 private static final int RESOLUTION_LEVEL_FINE = 2;
120 private static final String ACCESS_MOCK_LOCATION =
121 android.Manifest.permission.ACCESS_MOCK_LOCATION;
122 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
123 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
124 private static final String INSTALL_LOCATION_PROVIDER =
125 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
127 private static final String NETWORK_LOCATION_SERVICE_ACTION =
128 "com.android.location.service.v3.NetworkLocationProvider";
129 private static final String FUSED_LOCATION_SERVICE_ACTION =
130 "com.android.location.service.FusedLocationProvider";
132 private static final int MSG_LOCATION_CHANGED = 1;
134 private static final long NANOS_PER_MILLI = 1000000L;
136 // The maximum interval a location request can have and still be considered "high power".
137 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
139 // Location Providers may sometimes deliver location updates
140 // slightly faster that requested - provide grace period so
141 // we don't unnecessarily filter events that are otherwise on
143 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
145 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
147 private final Context mContext;
148 private final AppOpsManager mAppOps;
150 // used internally for synchronization
151 private final Object mLock = new Object();
153 // --- fields below are final after systemReady() ---
154 private LocationFudger mLocationFudger;
155 private GeofenceManager mGeofenceManager;
156 private PackageManager mPackageManager;
157 private PowerManager mPowerManager;
158 private UserManager mUserManager;
159 private GeocoderProxy mGeocodeProvider;
160 private IGpsStatusProvider mGpsStatusProvider;
161 private INetInitiatedListener mNetInitiatedListener;
162 private LocationWorkerHandler mLocationHandler;
163 private PassiveProvider mPassiveProvider; // track passive provider for special cases
164 private LocationBlacklist mBlacklist;
165 private GpsMeasurementsProvider mGpsMeasurementsProvider;
166 private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
167 private IGpsGeofenceHardware mGpsGeofenceProxy;
169 // --- fields below are protected by mLock ---
170 // Set of providers that are explicitly enabled
171 private final Set<String> mEnabledProviders = new HashSet<String>();
173 // Set of providers that are explicitly disabled
174 private final Set<String> mDisabledProviders = new HashSet<String>();
176 // Mock (test) providers
177 private final HashMap<String, MockProvider> mMockProviders =
178 new HashMap<String, MockProvider>();
181 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
183 // currently installed providers (with mocks replacing real providers)
184 private final ArrayList<LocationProviderInterface> mProviders =
185 new ArrayList<LocationProviderInterface>();
187 // real providers, saved here when mocked out
188 private final HashMap<String, LocationProviderInterface> mRealProviders =
189 new HashMap<String, LocationProviderInterface>();
191 // mapping from provider name to provider
192 private final HashMap<String, LocationProviderInterface> mProvidersByName =
193 new HashMap<String, LocationProviderInterface>();
195 // mapping from provider name to all its UpdateRecords
196 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
197 new HashMap<String, ArrayList<UpdateRecord>>();
199 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
201 // mapping from provider name to last known location
202 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
204 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
205 // locations stored here are not fudged for coarse permissions.
206 private final HashMap<String, Location> mLastLocationCoarseInterval =
207 new HashMap<String, Location>();
209 // all providers that operate over proxy, for authorizing incoming location
210 private final ArrayList<LocationProviderProxy> mProxyProviders =
211 new ArrayList<LocationProviderProxy>();
213 // current active user on the device - other users are denied location data
214 private int mCurrentUserId = UserHandle.USER_OWNER;
215 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
217 public LocationManagerService(Context context) {
220 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
222 // Let the package manager query which are the default location
223 // providers as they get certain permissions granted by default.
224 PackageManagerInternal packageManagerInternal = LocalServices.getService(
225 PackageManagerInternal.class);
226 packageManagerInternal.setLocationPackagesProvider(
227 new PackageManagerInternal.PackagesProvider() {
229 public String[] getPackages(int userId) {
230 return mContext.getResources().getStringArray(
231 com.android.internal.R.array.config_locationProviderPackageNames);
235 if (D) Log.d(TAG, "Constructed");
237 // most startup is deferred until systemReady()
240 public void systemRunning() {
241 synchronized (mLock) {
242 if (D) Log.d(TAG, "systemReady()");
244 // fetch package manager
245 mPackageManager = mContext.getPackageManager();
247 // fetch power manager
248 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
250 // prepare worker thread
251 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
253 // prepare mLocationHandler's dependents
254 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
255 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
257 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
259 // Monitor for app ops mode changes.
260 AppOpsManager.OnOpChangedListener callback
261 = new AppOpsManager.OnOpChangedInternalListener() {
262 public void onOpChanged(int op, String packageName) {
263 synchronized (mLock) {
264 for (Receiver receiver : mReceivers.values()) {
265 receiver.updateMonitoring(true);
267 applyAllProviderRequirementsLocked();
271 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
273 PackageManager.OnPermissionsChangedListener permissionListener
274 = new PackageManager.OnPermissionsChangedListener() {
276 public void onPermissionsChanged(final int uid) {
277 synchronized (mLock) {
278 applyAllProviderRequirementsLocked();
282 mPackageManager.addOnPermissionsChangeListener(permissionListener);
284 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
285 updateUserProfiles(mCurrentUserId);
288 loadProvidersLocked();
289 updateProvidersLocked();
292 // listen for settings changes
293 mContext.getContentResolver().registerContentObserver(
294 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
295 new ContentObserver(mLocationHandler) {
297 public void onChange(boolean selfChange) {
298 synchronized (mLock) {
299 updateProvidersLocked();
302 }, UserHandle.USER_ALL);
303 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
305 // listen for user change
306 IntentFilter intentFilter = new IntentFilter();
307 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
308 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
309 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
311 mContext.registerReceiverAsUser(new BroadcastReceiver() {
313 public void onReceive(Context context, Intent intent) {
314 String action = intent.getAction();
315 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
316 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
317 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
318 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
319 updateUserProfiles(mCurrentUserId);
322 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
326 * Makes a list of userids that are related to the current user. This is
327 * relevant when using managed profiles. Otherwise the list only contains
330 * @param currentUserId the current user, who might have an alter-ego.
332 void updateUserProfiles(int currentUserId) {
333 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
334 synchronized (mLock) {
335 mCurrentUserProfiles = new int[profiles.size()];
336 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
337 mCurrentUserProfiles[i] = profiles.get(i).id;
343 * Checks if the specified userId matches any of the current foreground
344 * users stored in mCurrentUserProfiles.
346 private boolean isCurrentProfile(int userId) {
347 synchronized (mLock) {
348 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
349 if (mCurrentUserProfiles[i] == userId) {
357 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
358 PackageManager pm = mContext.getPackageManager();
359 String systemPackageName = mContext.getPackageName();
360 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
362 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
363 new Intent(FUSED_LOCATION_SERVICE_ACTION),
364 PackageManager.GET_META_DATA, mCurrentUserId);
365 for (ResolveInfo rInfo : rInfos) {
366 String packageName = rInfo.serviceInfo.packageName;
368 // Check that the signature is in the list of supported sigs. If it's not in
369 // this list the standard provider binding logic won't bind to it.
372 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
373 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
374 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
375 ", but has wrong signature, ignoring");
378 } catch (NameNotFoundException e) {
379 Log.e(TAG, "missing package: " + packageName);
383 // Get the version info
384 if (rInfo.serviceInfo.metaData == null) {
385 Log.w(TAG, "Found fused provider without metadata: " + packageName);
389 int version = rInfo.serviceInfo.metaData.getInt(
390 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
392 // This should be the fallback fused location provider.
394 // Make sure it's in the system partition.
395 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
396 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
400 // Check that the fallback is signed the same as the OS
401 // as a proxy for coreApp="true"
402 if (pm.checkSignatures(systemPackageName, packageName)
403 != PackageManager.SIGNATURE_MATCH) {
404 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
409 // Found a valid fallback.
410 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
413 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
417 throw new IllegalStateException("Unable to find a fused location provider that is in the "
418 + "system partition with version 0 and signed with the platform certificate. "
419 + "Such a package is needed to provide a default fused location provider in the "
420 + "event that no other fused location provider has been installed or is currently "
421 + "available. For example, coreOnly boot mode when decrypting the data "
422 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
425 private void loadProvidersLocked() {
426 // create a passive location provider, which is always enabled
427 PassiveProvider passiveProvider = new PassiveProvider(this);
428 addProviderLocked(passiveProvider);
429 mEnabledProviders.add(passiveProvider.getName());
430 mPassiveProvider = passiveProvider;
432 if (GpsLocationProvider.isSupported()) {
433 // Create a gps location provider
434 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
435 mLocationHandler.getLooper());
436 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
437 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
438 addProviderLocked(gpsProvider);
439 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
440 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
441 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
442 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
446 Load package name(s) containing location provider support.
447 These packages can contain services implementing location providers:
448 Geocoder Provider, Network Location Provider, and
449 Fused Location Provider. They will each be searched for
450 service components implementing these providers.
451 The location framework also has support for installation
452 of new location providers at run-time. The new package does not
453 have to be explicitly listed here, however it must have a signature
454 that matches the signature of at least one package on this list.
456 Resources resources = mContext.getResources();
457 ArrayList<String> providerPackageNames = new ArrayList<String>();
458 String[] pkgs = resources.getStringArray(
459 com.android.internal.R.array.config_locationProviderPackageNames);
460 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
461 Arrays.toString(pkgs));
462 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
464 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
466 // bind to network provider
467 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
469 LocationManager.NETWORK_PROVIDER,
470 NETWORK_LOCATION_SERVICE_ACTION,
471 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
472 com.android.internal.R.string.config_networkLocationProviderPackageName,
473 com.android.internal.R.array.config_locationProviderPackageNames,
475 if (networkProvider != null) {
476 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
477 mProxyProviders.add(networkProvider);
478 addProviderLocked(networkProvider);
480 Slog.w(TAG, "no network location provider found");
483 // bind to fused provider
484 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
486 LocationManager.FUSED_PROVIDER,
487 FUSED_LOCATION_SERVICE_ACTION,
488 com.android.internal.R.bool.config_enableFusedLocationOverlay,
489 com.android.internal.R.string.config_fusedLocationProviderPackageName,
490 com.android.internal.R.array.config_locationProviderPackageNames,
492 if (fusedLocationProvider != null) {
493 addProviderLocked(fusedLocationProvider);
494 mProxyProviders.add(fusedLocationProvider);
495 mEnabledProviders.add(fusedLocationProvider.getName());
496 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
498 Slog.e(TAG, "no fused location provider found",
499 new IllegalStateException("Location service needs a fused location provider"));
502 // bind to geocoder provider
503 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
504 com.android.internal.R.bool.config_enableGeocoderOverlay,
505 com.android.internal.R.string.config_geocoderProviderPackageName,
506 com.android.internal.R.array.config_locationProviderPackageNames,
508 if (mGeocodeProvider == null) {
509 Slog.e(TAG, "no geocoder provider found");
512 // bind to fused hardware provider if supported
513 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
514 // exception, so make sure we only do that when supported
515 FlpHardwareProvider flpHardwareProvider;
516 if (FlpHardwareProvider.isSupported()) {
517 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
518 FusedProxy fusedProxy = FusedProxy.createAndBind(
521 flpHardwareProvider.getLocationHardware(),
522 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
523 com.android.internal.R.string.config_hardwareFlpPackageName,
524 com.android.internal.R.array.config_locationProviderPackageNames);
525 if (fusedProxy == null) {
526 Slog.e(TAG, "Unable to bind FusedProxy.");
529 flpHardwareProvider = null;
530 Slog.e(TAG, "FLP HAL not supported");
533 // bind to geofence provider
534 GeofenceProxy provider = GeofenceProxy.createAndBind(
535 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
536 com.android.internal.R.string.config_geofenceProviderPackageName,
537 com.android.internal.R.array.config_locationProviderPackageNames,
540 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
541 if (provider == null) {
542 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
545 // bind to the hardware activity recognition if supported
546 if (ActivityRecognitionHardware.isSupported()) {
547 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
550 ActivityRecognitionHardware.getInstance(mContext),
551 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
552 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
553 com.android.internal.R.array.config_locationProviderPackageNames);
556 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
559 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
562 String[] testProviderStrings = resources.getStringArray(
563 com.android.internal.R.array.config_testLocationProviders);
564 for (String testProviderString : testProviderStrings) {
565 String fragments[] = testProviderString.split(",");
566 String name = fragments[0].trim();
567 if (mProvidersByName.get(name) != null) {
568 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
570 ProviderProperties properties = new ProviderProperties(
571 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
572 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
573 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
574 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
575 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
576 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
577 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
578 Integer.parseInt(fragments[8]) /* powerRequirement */,
579 Integer.parseInt(fragments[9]) /* accuracy */);
580 addTestProviderLocked(name, properties);
585 * Called when the device's active user changes.
586 * @param userId the new active user's UserId
588 private void switchUser(int userId) {
589 if (mCurrentUserId == userId) {
592 mBlacklist.switchUser(userId);
593 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
594 synchronized (mLock) {
595 mLastLocation.clear();
596 mLastLocationCoarseInterval.clear();
597 for (LocationProviderInterface p : mProviders) {
598 updateProviderListenersLocked(p.getName(), false);
600 mCurrentUserId = userId;
601 updateUserProfiles(userId);
602 updateProvidersLocked();
607 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
610 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
611 final int mUid; // uid of receiver
612 final int mPid; // pid of receiver
613 final String mPackageName; // package name of receiver
614 final int mAllowedResolutionLevel; // resolution level allowed to receiver
616 final ILocationListener mListener;
617 final PendingIntent mPendingIntent;
618 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
619 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
622 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
624 // True if app ops has started monitoring this receiver for locations.
625 boolean mOpMonitoring;
626 // True if app ops has started monitoring this receiver for high power (gps) locations.
627 boolean mOpHighPowerMonitoring;
628 int mPendingBroadcasts;
629 PowerManager.WakeLock mWakeLock;
631 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
632 String packageName, WorkSource workSource, boolean hideFromAppOps) {
633 mListener = listener;
634 mPendingIntent = intent;
635 if (listener != null) {
636 mKey = listener.asBinder();
640 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
643 mPackageName = packageName;
644 if (workSource != null && workSource.size() <= 0) {
647 mWorkSource = workSource;
648 mHideFromAppOps = hideFromAppOps;
650 updateMonitoring(true);
652 // construct/configure wakelock
653 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
654 if (workSource == null) {
655 workSource = new WorkSource(mUid, mPackageName);
657 mWakeLock.setWorkSource(workSource);
661 public boolean equals(Object otherObj) {
662 if (otherObj instanceof Receiver) {
663 return mKey.equals(((Receiver)otherObj).mKey);
669 public int hashCode() {
670 return mKey.hashCode();
674 public String toString() {
675 StringBuilder s = new StringBuilder();
676 s.append("Reciever[");
677 s.append(Integer.toHexString(System.identityHashCode(this)));
678 if (mListener != null) {
679 s.append(" listener");
683 for (String p : mUpdateRecords.keySet()) {
684 s.append(" ").append(mUpdateRecords.get(p).toString());
691 * Update AppOp monitoring for this receiver.
693 * @param allow If true receiver is currently active, if false it's been removed.
695 public void updateMonitoring(boolean allow) {
696 if (mHideFromAppOps) {
700 boolean requestingLocation = false;
701 boolean requestingHighPowerLocation = false;
703 // See if receiver has any enabled update records. Also note if any update records
704 // are high power (has a high power provider with an interval under a threshold).
705 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
706 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
707 requestingLocation = true;
708 LocationProviderInterface locationProvider
709 = mProvidersByName.get(updateRecord.mProvider);
710 ProviderProperties properties = locationProvider != null
711 ? locationProvider.getProperties() : null;
712 if (properties != null
713 && properties.mPowerRequirement == Criteria.POWER_HIGH
714 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
715 requestingHighPowerLocation = true;
722 // First update monitoring of any location request (including high power).
723 mOpMonitoring = updateMonitoring(
726 AppOpsManager.OP_MONITOR_LOCATION);
728 // Now update monitoring of high power requests only.
729 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
730 mOpHighPowerMonitoring = updateMonitoring(
731 requestingHighPowerLocation,
732 mOpHighPowerMonitoring,
733 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
734 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
735 // Send an intent to notify that a high power request has been added/removed.
736 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
737 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
742 * Update AppOps monitoring for a single location request and op type.
744 * @param allowMonitoring True if monitoring is allowed for this request/op.
745 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
746 * @param op AppOps code for the op to update.
747 * @return True if monitoring is on for this request/op after updating.
749 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
751 if (!currentlyMonitoring) {
752 if (allowMonitoring) {
753 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
754 == AppOpsManager.MODE_ALLOWED;
757 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
758 != AppOpsManager.MODE_ALLOWED) {
759 mAppOps.finishOp(op, mUid, mPackageName);
764 return currentlyMonitoring;
767 public boolean isListener() {
768 return mListener != null;
771 public boolean isPendingIntent() {
772 return mPendingIntent != null;
775 public ILocationListener getListener() {
776 if (mListener != null) {
779 throw new IllegalStateException("Request for non-existent listener");
782 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
783 if (mListener != null) {
785 synchronized (this) {
786 // synchronize to ensure incrementPendingBroadcastsLocked()
787 // is called before decrementPendingBroadcasts()
788 mListener.onStatusChanged(provider, status, extras);
789 // call this after broadcasting so we do not increment
790 // if we throw an exeption.
791 incrementPendingBroadcastsLocked();
793 } catch (RemoteException e) {
797 Intent statusChanged = new Intent();
798 statusChanged.putExtras(new Bundle(extras));
799 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
801 synchronized (this) {
802 // synchronize to ensure incrementPendingBroadcastsLocked()
803 // is called before decrementPendingBroadcasts()
804 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
805 getResolutionPermission(mAllowedResolutionLevel));
806 // call this after broadcasting so we do not increment
807 // if we throw an exeption.
808 incrementPendingBroadcastsLocked();
810 } catch (PendingIntent.CanceledException e) {
817 public boolean callLocationChangedLocked(Location location) {
818 if (mListener != null) {
820 synchronized (this) {
821 // synchronize to ensure incrementPendingBroadcastsLocked()
822 // is called before decrementPendingBroadcasts()
823 mListener.onLocationChanged(new Location(location));
824 // call this after broadcasting so we do not increment
825 // if we throw an exeption.
826 incrementPendingBroadcastsLocked();
828 } catch (RemoteException e) {
832 Intent locationChanged = new Intent();
833 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
835 synchronized (this) {
836 // synchronize to ensure incrementPendingBroadcastsLocked()
837 // is called before decrementPendingBroadcasts()
838 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
839 getResolutionPermission(mAllowedResolutionLevel));
840 // call this after broadcasting so we do not increment
841 // if we throw an exeption.
842 incrementPendingBroadcastsLocked();
844 } catch (PendingIntent.CanceledException e) {
851 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
852 // First update AppOp monitoring.
853 // An app may get/lose location access as providers are enabled/disabled.
854 updateMonitoring(true);
856 if (mListener != null) {
858 synchronized (this) {
859 // synchronize to ensure incrementPendingBroadcastsLocked()
860 // is called before decrementPendingBroadcasts()
862 mListener.onProviderEnabled(provider);
864 mListener.onProviderDisabled(provider);
866 // call this after broadcasting so we do not increment
867 // if we throw an exeption.
868 incrementPendingBroadcastsLocked();
870 } catch (RemoteException e) {
874 Intent providerIntent = new Intent();
875 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
877 synchronized (this) {
878 // synchronize to ensure incrementPendingBroadcastsLocked()
879 // is called before decrementPendingBroadcasts()
880 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
881 getResolutionPermission(mAllowedResolutionLevel));
882 // call this after broadcasting so we do not increment
883 // if we throw an exeption.
884 incrementPendingBroadcastsLocked();
886 } catch (PendingIntent.CanceledException e) {
894 public void binderDied() {
895 if (D) Log.d(TAG, "Location listener died");
897 synchronized (mLock) {
898 removeUpdatesLocked(this);
900 synchronized (this) {
901 clearPendingBroadcastsLocked();
906 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
907 int resultCode, String resultData, Bundle resultExtras) {
908 synchronized (this) {
909 decrementPendingBroadcastsLocked();
913 // this must be called while synchronized by caller in a synchronized block
914 // containing the sending of the broadcaset
915 private void incrementPendingBroadcastsLocked() {
916 if (mPendingBroadcasts++ == 0) {
921 private void decrementPendingBroadcastsLocked() {
922 if (--mPendingBroadcasts == 0) {
923 if (mWakeLock.isHeld()) {
929 public void clearPendingBroadcastsLocked() {
930 if (mPendingBroadcasts > 0) {
931 mPendingBroadcasts = 0;
932 if (mWakeLock.isHeld()) {
940 public void locationCallbackFinished(ILocationListener listener) {
941 //Do not use getReceiverLocked here as that will add the ILocationListener to
942 //the receiver list if it is not found. If it is not found then the
943 //LocationListener was removed when it had a pending broadcast and should
945 synchronized (mLock) {
946 IBinder binder = listener.asBinder();
947 Receiver receiver = mReceivers.get(binder);
948 if (receiver != null) {
949 synchronized (receiver) {
950 // so wakelock calls will succeed
951 long identity = Binder.clearCallingIdentity();
952 receiver.decrementPendingBroadcastsLocked();
953 Binder.restoreCallingIdentity(identity);
959 private void addProviderLocked(LocationProviderInterface provider) {
960 mProviders.add(provider);
961 mProvidersByName.put(provider.getName(), provider);
964 private void removeProviderLocked(LocationProviderInterface provider) {
966 mProviders.remove(provider);
967 mProvidersByName.remove(provider.getName());
971 * Returns "true" if access to the specified location provider is allowed by the current
972 * user's settings. Access to all location providers is forbidden to non-location-provider
973 * processes belonging to background users.
975 * @param provider the name of the location provider
978 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
979 if (mEnabledProviders.contains(provider)) {
982 if (mDisabledProviders.contains(provider)) {
985 // Use system settings
986 ContentResolver resolver = mContext.getContentResolver();
988 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
992 * Returns "true" if access to the specified location provider is allowed by the specified
993 * user's settings. Access to all location providers is forbidden to non-location-provider
994 * processes belonging to background users.
996 * @param provider the name of the location provider
997 * @param uid the requestor's UID
1000 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
1001 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
1004 return isAllowedByCurrentUserSettingsLocked(provider);
1008 * Returns the permission string associated with the specified resolution level.
1010 * @param resolutionLevel the resolution level
1011 * @return the permission string
1013 private String getResolutionPermission(int resolutionLevel) {
1014 switch (resolutionLevel) {
1015 case RESOLUTION_LEVEL_FINE:
1016 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1017 case RESOLUTION_LEVEL_COARSE:
1018 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1025 * Returns the resolution level allowed to the given PID/UID pair.
1027 * @param pid the PID
1028 * @param uid the UID
1029 * @return resolution level allowed to the pid/uid pair
1031 private int getAllowedResolutionLevel(int pid, int uid) {
1032 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1033 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1034 return RESOLUTION_LEVEL_FINE;
1035 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1036 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1037 return RESOLUTION_LEVEL_COARSE;
1039 return RESOLUTION_LEVEL_NONE;
1044 * Returns the resolution level allowed to the caller
1046 * @return resolution level allowed to caller
1048 private int getCallerAllowedResolutionLevel() {
1049 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1053 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1055 * @param allowedResolutionLevel resolution level allowed to caller
1057 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1058 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1059 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1064 * Return the minimum resolution level required to use the specified location provider.
1066 * @param provider the name of the location provider
1067 * @return minimum resolution level required for provider
1069 private int getMinimumResolutionLevelForProviderUse(String provider) {
1070 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1071 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1072 // gps and passive providers require FINE permission
1073 return RESOLUTION_LEVEL_FINE;
1074 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1075 LocationManager.FUSED_PROVIDER.equals(provider)) {
1076 // network and fused providers are ok with COARSE or FINE
1077 return RESOLUTION_LEVEL_COARSE;
1080 LocationProviderInterface lp = mMockProviders.get(provider);
1082 ProviderProperties properties = lp.getProperties();
1083 if (properties != null) {
1084 if (properties.mRequiresSatellite) {
1085 // provider requiring satellites require FINE permission
1086 return RESOLUTION_LEVEL_FINE;
1087 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1088 // provider requiring network and or cell require COARSE or FINE
1089 return RESOLUTION_LEVEL_COARSE;
1094 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
1098 * Throw SecurityException if specified resolution level is insufficient to use the named
1099 * location provider.
1101 * @param allowedResolutionLevel resolution level allowed to caller
1102 * @param providerName the name of the location provider
1104 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1105 String providerName) {
1106 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1107 if (allowedResolutionLevel < requiredResolutionLevel) {
1108 switch (requiredResolutionLevel) {
1109 case RESOLUTION_LEVEL_FINE:
1110 throw new SecurityException("\"" + providerName + "\" location provider " +
1111 "requires ACCESS_FINE_LOCATION permission.");
1112 case RESOLUTION_LEVEL_COARSE:
1113 throw new SecurityException("\"" + providerName + "\" location provider " +
1114 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1116 throw new SecurityException("Insufficient permission for \"" + providerName +
1117 "\" location provider.");
1123 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1126 private void checkDeviceStatsAllowed() {
1127 mContext.enforceCallingOrSelfPermission(
1128 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1131 private void checkUpdateAppOpsAllowed() {
1132 mContext.enforceCallingOrSelfPermission(
1133 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1136 public static int resolutionLevelToOp(int allowedResolutionLevel) {
1137 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1138 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
1139 return AppOpsManager.OP_COARSE_LOCATION;
1141 return AppOpsManager.OP_FINE_LOCATION;
1147 boolean reportLocationAccessNoThrow(
1148 int pid, int uid, String packageName, int allowedResolutionLevel) {
1149 int op = resolutionLevelToOp(allowedResolutionLevel);
1151 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1156 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1163 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
1164 int op = resolutionLevelToOp(allowedResolutionLevel);
1166 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1171 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1179 * Returns all providers by name, including passive, but excluding
1180 * fused, also including ones that are not permitted to
1181 * be accessed by the calling activity or are currently disabled.
1184 public List<String> getAllProviders() {
1185 ArrayList<String> out;
1186 synchronized (mLock) {
1187 out = new ArrayList<String>(mProviders.size());
1188 for (LocationProviderInterface provider : mProviders) {
1189 String name = provider.getName();
1190 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1197 if (D) Log.d(TAG, "getAllProviders()=" + out);
1202 * Return all providers by name, that match criteria and are optionally
1204 * Can return passive provider, but never returns fused provider.
1207 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
1208 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1209 ArrayList<String> out;
1210 int uid = Binder.getCallingUid();;
1211 long identity = Binder.clearCallingIdentity();
1213 synchronized (mLock) {
1214 out = new ArrayList<String>(mProviders.size());
1215 for (LocationProviderInterface provider : mProviders) {
1216 String name = provider.getName();
1217 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1220 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1221 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
1224 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1225 name, provider.getProperties(), criteria)) {
1233 Binder.restoreCallingIdentity(identity);
1236 if (D) Log.d(TAG, "getProviders()=" + out);
1241 * Return the name of the best provider given a Criteria object.
1242 * This method has been deprecated from the public API,
1243 * and the whole LocationProvider (including #meetsCriteria)
1244 * has been deprecated as well. So this method now uses
1245 * some simplified logic.
1248 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1249 String result = null;
1251 List<String> providers = getProviders(criteria, enabledOnly);
1252 if (!providers.isEmpty()) {
1253 result = pickBest(providers);
1254 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1257 providers = getProviders(null, enabledOnly);
1258 if (!providers.isEmpty()) {
1259 result = pickBest(providers);
1260 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1264 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1268 private String pickBest(List<String> providers) {
1269 if (providers.contains(LocationManager.GPS_PROVIDER)) {
1270 return LocationManager.GPS_PROVIDER;
1271 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1272 return LocationManager.NETWORK_PROVIDER;
1274 return providers.get(0);
1279 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1280 LocationProviderInterface p = mProvidersByName.get(provider);
1282 throw new IllegalArgumentException("provider=" + provider);
1285 boolean result = LocationProvider.propertiesMeetCriteria(
1286 p.getName(), p.getProperties(), criteria);
1287 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1291 private void updateProvidersLocked() {
1292 boolean changesMade = false;
1293 for (int i = mProviders.size() - 1; i >= 0; i--) {
1294 LocationProviderInterface p = mProviders.get(i);
1295 boolean isEnabled = p.isEnabled();
1296 String name = p.getName();
1297 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
1298 if (isEnabled && !shouldBeEnabled) {
1299 updateProviderListenersLocked(name, false);
1300 // If any provider has been disabled, clear all last locations for all providers.
1301 // This is to be on the safe side in case a provider has location derived from
1302 // this disabled provider.
1303 mLastLocation.clear();
1304 mLastLocationCoarseInterval.clear();
1306 } else if (!isEnabled && shouldBeEnabled) {
1307 updateProviderListenersLocked(name, true);
1312 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1314 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1319 private void updateProviderListenersLocked(String provider, boolean enabled) {
1322 LocationProviderInterface p = mProvidersByName.get(provider);
1323 if (p == null) return;
1325 ArrayList<Receiver> deadReceivers = null;
1327 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1328 if (records != null) {
1329 final int N = records.size();
1330 for (int i = 0; i < N; i++) {
1331 UpdateRecord record = records.get(i);
1332 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1333 // Sends a notification message to the receiver
1334 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1335 if (deadReceivers == null) {
1336 deadReceivers = new ArrayList<Receiver>();
1338 deadReceivers.add(record.mReceiver);
1345 if (deadReceivers != null) {
1346 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1347 removeUpdatesLocked(deadReceivers.get(i));
1353 if (listeners > 0) {
1354 applyRequirementsLocked(provider);
1361 private void applyRequirementsLocked(String provider) {
1362 LocationProviderInterface p = mProvidersByName.get(provider);
1363 if (p == null) return;
1365 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1366 WorkSource worksource = new WorkSource();
1367 ProviderRequest providerRequest = new ProviderRequest();
1369 if (records != null) {
1370 for (UpdateRecord record : records) {
1371 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1372 if (checkLocationAccess(
1373 record.mReceiver.mPid,
1374 record.mReceiver.mUid,
1375 record.mReceiver.mPackageName,
1376 record.mReceiver.mAllowedResolutionLevel)) {
1377 LocationRequest locationRequest = record.mRequest;
1378 providerRequest.locationRequests.add(locationRequest);
1379 if (locationRequest.getInterval() < providerRequest.interval) {
1380 providerRequest.reportLocation = true;
1381 providerRequest.interval = locationRequest.getInterval();
1387 if (providerRequest.reportLocation) {
1388 // calculate who to blame for power
1389 // This is somewhat arbitrary. We pick a threshold interval
1390 // that is slightly higher that the minimum interval, and
1391 // spread the blame across all applications with a request
1392 // under that threshold.
1393 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1394 for (UpdateRecord record : records) {
1395 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1396 LocationRequest locationRequest = record.mRequest;
1397 if (locationRequest.getInterval() <= thresholdInterval) {
1398 if (record.mReceiver.mWorkSource != null
1399 && record.mReceiver.mWorkSource.size() > 0
1400 && record.mReceiver.mWorkSource.getName(0) != null) {
1401 // Assign blame to another work source.
1402 // Can only assign blame if the WorkSource contains names.
1403 worksource.add(record.mReceiver.mWorkSource);
1405 // Assign blame to caller.
1407 record.mReceiver.mUid,
1408 record.mReceiver.mPackageName);
1416 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1417 p.setRequest(providerRequest, worksource);
1420 private class UpdateRecord {
1421 final String mProvider;
1422 final LocationRequest mRequest;
1423 final Receiver mReceiver;
1424 Location mLastFixBroadcast;
1425 long mLastStatusBroadcast;
1428 * Note: must be constructed with lock held.
1430 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1431 mProvider = provider;
1433 mReceiver = receiver;
1435 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1436 if (records == null) {
1437 records = new ArrayList<UpdateRecord>();
1438 mRecordsByProvider.put(provider, records);
1440 if (!records.contains(this)) {
1444 // Update statistics for historical location requests by package/provider
1445 mRequestStatistics.startRequesting(
1446 mReceiver.mPackageName, provider, request.getInterval());
1450 * Method to be called when a record will no longer be used.
1452 void disposeLocked(boolean removeReceiver) {
1453 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1455 // remove from mRecordsByProvider
1456 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1457 if (globalRecords != null) {
1458 globalRecords.remove(this);
1461 if (!removeReceiver) return; // the caller will handle the rest
1463 // remove from Receiver#mUpdateRecords
1464 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1465 if (receiverRecords != null) {
1466 receiverRecords.remove(this.mProvider);
1468 // and also remove the Receiver if it has no more update records
1469 if (removeReceiver && receiverRecords.size() == 0) {
1470 removeUpdatesLocked(mReceiver);
1476 public String toString() {
1477 StringBuilder s = new StringBuilder();
1478 s.append("UpdateRecord[");
1479 s.append(mProvider);
1480 s.append(' ').append(mReceiver.mPackageName).append('(');
1481 s.append(mReceiver.mUid).append(')');
1482 s.append(' ').append(mRequest);
1484 return s.toString();
1488 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1489 String packageName, WorkSource workSource, boolean hideFromAppOps) {
1490 IBinder binder = listener.asBinder();
1491 Receiver receiver = mReceivers.get(binder);
1492 if (receiver == null) {
1493 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1496 receiver.getListener().asBinder().linkToDeath(receiver, 0);
1497 } catch (RemoteException e) {
1498 Slog.e(TAG, "linkToDeath failed:", e);
1501 mReceivers.put(binder, receiver);
1506 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1507 WorkSource workSource, boolean hideFromAppOps) {
1508 Receiver receiver = mReceivers.get(intent);
1509 if (receiver == null) {
1510 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1512 mReceivers.put(intent, receiver);
1518 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1519 * and consistency requirements.
1521 * @param request the LocationRequest from which to create a sanitized version
1522 * @return a version of request that meets the given resolution and consistency requirements
1525 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1526 LocationRequest sanitizedRequest = new LocationRequest(request);
1527 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1528 switch (sanitizedRequest.getQuality()) {
1529 case LocationRequest.ACCURACY_FINE:
1530 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1532 case LocationRequest.POWER_HIGH:
1533 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1537 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1538 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1540 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1541 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1544 // make getFastestInterval() the minimum of interval and fastest interval
1545 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1546 request.setFastestInterval(request.getInterval());
1548 return sanitizedRequest;
1551 private void checkPackageName(String packageName) {
1552 if (packageName == null) {
1553 throw new SecurityException("invalid package name: " + packageName);
1555 int uid = Binder.getCallingUid();
1556 String[] packages = mPackageManager.getPackagesForUid(uid);
1557 if (packages == null) {
1558 throw new SecurityException("invalid UID " + uid);
1560 for (String pkg : packages) {
1561 if (packageName.equals(pkg)) return;
1563 throw new SecurityException("invalid package name: " + packageName);
1566 private void checkPendingIntent(PendingIntent intent) {
1567 if (intent == null) {
1568 throw new IllegalArgumentException("invalid pending intent: " + intent);
1572 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1573 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1574 if (intent == null && listener == null) {
1575 throw new IllegalArgumentException("need either listener or intent");
1576 } else if (intent != null && listener != null) {
1577 throw new IllegalArgumentException("cannot register both listener and intent");
1578 } else if (intent != null) {
1579 checkPendingIntent(intent);
1580 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1582 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1587 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1588 PendingIntent intent, String packageName) {
1589 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1590 checkPackageName(packageName);
1591 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1592 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1593 request.getProvider());
1594 WorkSource workSource = request.getWorkSource();
1595 if (workSource != null && workSource.size() > 0) {
1596 checkDeviceStatsAllowed();
1598 boolean hideFromAppOps = request.getHideFromAppOps();
1599 if (hideFromAppOps) {
1600 checkUpdateAppOpsAllowed();
1602 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1604 final int pid = Binder.getCallingPid();
1605 final int uid = Binder.getCallingUid();
1606 // providers may use public location API's, need to clear identity
1607 long identity = Binder.clearCallingIdentity();
1609 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1611 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1613 synchronized (mLock) {
1614 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1615 packageName, workSource, hideFromAppOps);
1616 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
1619 Binder.restoreCallingIdentity(identity);
1623 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1624 int pid, int uid, String packageName) {
1625 // Figure out the provider. Either its explicitly request (legacy use cases), or
1626 // use the fused provider
1627 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1628 String name = request.getProvider();
1630 throw new IllegalArgumentException("provider name must not be null");
1633 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1634 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
1635 LocationProviderInterface provider = mProvidersByName.get(name);
1636 if (provider == null) {
1637 throw new IllegalArgumentException("provider doesn't exist: " + name);
1640 UpdateRecord record = new UpdateRecord(name, request, receiver);
1641 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1642 if (oldRecord != null) {
1643 oldRecord.disposeLocked(false);
1646 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
1647 if (isProviderEnabled) {
1648 applyRequirementsLocked(name);
1650 // Notify the listener that updates are currently disabled
1651 receiver.callProviderEnabledLocked(name, false);
1653 // Update the monitoring here just in case multiple location requests were added to the
1654 // same receiver (this request may be high power and the initial might not have been).
1655 receiver.updateMonitoring(true);
1659 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1660 String packageName) {
1661 checkPackageName(packageName);
1663 final int pid = Binder.getCallingPid();
1664 final int uid = Binder.getCallingUid();
1666 synchronized (mLock) {
1667 WorkSource workSource = null;
1668 boolean hideFromAppOps = false;
1669 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1670 packageName, workSource, hideFromAppOps);
1672 // providers may use public location API's, need to clear identity
1673 long identity = Binder.clearCallingIdentity();
1675 removeUpdatesLocked(receiver);
1677 Binder.restoreCallingIdentity(identity);
1682 private void removeUpdatesLocked(Receiver receiver) {
1683 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1685 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1686 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1687 synchronized (receiver) {
1688 receiver.clearPendingBroadcastsLocked();
1692 receiver.updateMonitoring(false);
1694 // Record which providers were associated with this listener
1695 HashSet<String> providers = new HashSet<String>();
1696 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1697 if (oldRecords != null) {
1698 // Call dispose() on the obsolete update records.
1699 for (UpdateRecord record : oldRecords.values()) {
1700 // Update statistics for historical location requests by package/provider
1701 record.disposeLocked(false);
1703 // Accumulate providers
1704 providers.addAll(oldRecords.keySet());
1708 for (String provider : providers) {
1709 // If provider is already disabled, don't need to do anything
1710 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
1714 applyRequirementsLocked(provider);
1718 private void applyAllProviderRequirementsLocked() {
1719 for (LocationProviderInterface p : mProviders) {
1720 // If provider is already disabled, don't need to do anything
1721 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
1725 applyRequirementsLocked(p.getName());
1730 public Location getLastLocation(LocationRequest request, String packageName) {
1731 if (D) Log.d(TAG, "getLastLocation: " + request);
1732 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1733 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1734 checkPackageName(packageName);
1735 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1736 request.getProvider());
1737 // no need to sanitize this request, as only the provider name is used
1739 final int pid = Binder.getCallingPid();
1740 final int uid = Binder.getCallingUid();
1741 final long identity = Binder.clearCallingIdentity();
1743 if (mBlacklist.isBlacklisted(packageName)) {
1744 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1749 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
1750 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1755 synchronized (mLock) {
1756 // Figure out the provider. Either its explicitly request (deprecated API's),
1757 // or use the fused provider
1758 String name = request.getProvider();
1759 if (name == null) name = LocationManager.FUSED_PROVIDER;
1760 LocationProviderInterface provider = mProvidersByName.get(name);
1761 if (provider == null) return null;
1763 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
1766 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1767 // Make sure that an app with coarse permissions can't get frequent location
1768 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1769 location = mLastLocationCoarseInterval.get(name);
1771 location = mLastLocation.get(name);
1773 if (location == null) {
1776 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1777 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1778 if (noGPSLocation != null) {
1779 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
1782 return new Location(location);
1787 Binder.restoreCallingIdentity(identity);
1792 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1793 String packageName) {
1794 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1795 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1796 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
1797 checkPendingIntent(intent);
1798 checkPackageName(packageName);
1799 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1800 request.getProvider());
1801 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1803 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
1805 // geo-fence manager uses the public location API, need to clear identity
1806 int uid = Binder.getCallingUid();
1807 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1808 // temporary measure until geofences work for secondary users
1809 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1812 long identity = Binder.clearCallingIdentity();
1814 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1817 Binder.restoreCallingIdentity(identity);
1822 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1823 checkPendingIntent(intent);
1824 checkPackageName(packageName);
1826 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1828 // geo-fence manager uses the public location API, need to clear identity
1829 long identity = Binder.clearCallingIdentity();
1831 mGeofenceManager.removeFence(geofence, intent);
1833 Binder.restoreCallingIdentity(identity);
1839 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
1840 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1841 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1842 LocationManager.GPS_PROVIDER);
1844 final int pid = Binder.getCallingPid();
1845 final int uid = Binder.getCallingUid();
1846 final long ident = Binder.clearCallingIdentity();
1848 if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
1852 Binder.restoreCallingIdentity(ident);
1855 if (mGpsStatusProvider == null) {
1860 mGpsStatusProvider.addGpsStatusListener(listener);
1861 } catch (RemoteException e) {
1862 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1869 public void removeGpsStatusListener(IGpsStatusListener listener) {
1870 synchronized (mLock) {
1872 mGpsStatusProvider.removeGpsStatusListener(listener);
1873 } catch (Exception e) {
1874 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1880 public boolean addGpsMeasurementsListener(
1881 IGpsMeasurementsListener listener,
1882 String packageName) {
1883 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1884 checkResolutionLevelIsSufficientForProviderUse(
1885 allowedResolutionLevel,
1886 LocationManager.GPS_PROVIDER);
1888 int pid = Binder.getCallingPid();
1889 int uid = Binder.getCallingUid();
1890 long identity = Binder.clearCallingIdentity();
1891 boolean hasLocationAccess;
1893 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1895 Binder.restoreCallingIdentity(identity);
1898 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
1901 return mGpsMeasurementsProvider.addListener(listener);
1905 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
1906 if (mGpsMeasurementsProvider != null) {
1907 mGpsMeasurementsProvider.removeListener(listener);
1912 public boolean addGpsNavigationMessageListener(
1913 IGpsNavigationMessageListener listener,
1914 String packageName) {
1915 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1916 checkResolutionLevelIsSufficientForProviderUse(
1917 allowedResolutionLevel,
1918 LocationManager.GPS_PROVIDER);
1920 int pid = Binder.getCallingPid();
1921 int uid = Binder.getCallingUid();
1922 long identity = Binder.clearCallingIdentity();
1923 boolean hasLocationAccess;
1925 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1927 Binder.restoreCallingIdentity(identity);
1930 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
1933 return mGpsNavigationMessageProvider.addListener(listener);
1937 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
1938 if (mGpsNavigationMessageProvider != null) {
1939 mGpsNavigationMessageProvider.removeListener(listener);
1944 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1945 if (provider == null) {
1946 // throw NullPointerException to remain compatible with previous implementation
1947 throw new NullPointerException();
1949 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1952 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1953 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1954 != PackageManager.PERMISSION_GRANTED)) {
1955 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1958 synchronized (mLock) {
1959 LocationProviderInterface p = mProvidersByName.get(provider);
1960 if (p == null) return false;
1962 return p.sendExtraCommand(command, extras);
1967 public boolean sendNiResponse(int notifId, int userResponse) {
1968 if (Binder.getCallingUid() != Process.myUid()) {
1969 throw new SecurityException(
1970 "calling sendNiResponse from outside of the system is not allowed");
1973 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1974 } catch (RemoteException e) {
1975 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1981 * @return null if the provider does not exist
1982 * @throws SecurityException if the provider is not allowed to be
1983 * accessed by the caller
1986 public ProviderProperties getProviderProperties(String provider) {
1987 if (mProvidersByName.get(provider) == null) {
1991 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1994 LocationProviderInterface p;
1995 synchronized (mLock) {
1996 p = mProvidersByName.get(provider);
1999 if (p == null) return null;
2000 return p.getProperties();
2004 * @return null if the provider does not exist
2005 * @throws SecurityException if the provider is not allowed to be
2006 * accessed by the caller
2009 public String getNetworkProviderPackage() {
2010 LocationProviderInterface p;
2011 synchronized (mLock) {
2012 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2015 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2018 if (p instanceof LocationProviderProxy) {
2019 return ((LocationProviderProxy) p).getConnectedPackageName();
2025 public boolean isProviderEnabled(String provider) {
2026 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2027 // so we discourage its use
2028 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2030 int uid = Binder.getCallingUid();
2031 long identity = Binder.clearCallingIdentity();
2033 synchronized (mLock) {
2034 LocationProviderInterface p = mProvidersByName.get(provider);
2035 if (p == null) return false;
2037 return isAllowedByUserSettingsLocked(provider, uid);
2040 Binder.restoreCallingIdentity(identity);
2045 * Returns "true" if the UID belongs to a bound location provider.
2047 * @param uid the uid
2048 * @return true if uid belongs to a bound location provider
2050 private boolean isUidALocationProvider(int uid) {
2051 if (uid == Process.SYSTEM_UID) {
2054 if (mGeocodeProvider != null) {
2055 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
2057 for (LocationProviderProxy proxy : mProxyProviders) {
2058 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
2063 private void checkCallerIsProvider() {
2064 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2065 == PackageManager.PERMISSION_GRANTED) {
2069 // Previously we only used the INSTALL_LOCATION_PROVIDER
2070 // check. But that is system or signature
2071 // protection level which is not flexible enough for
2072 // providers installed oustide the system image. So
2073 // also allow providers with a UID matching the
2074 // currently bound package name
2076 if (isUidALocationProvider(Binder.getCallingUid())) {
2080 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2081 "or UID of a currently bound location provider");
2085 * Returns true if the given package belongs to the given uid.
2087 private boolean doesUidHavePackage(int uid, String packageName) {
2088 if (packageName == null) {
2091 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2092 if (packageNames == null) {
2095 for (String name : packageNames) {
2096 if (packageName.equals(name)) {
2104 public void reportLocation(Location location, boolean passive) {
2105 checkCallerIsProvider();
2107 if (!location.isComplete()) {
2108 Log.w(TAG, "Dropping incomplete location: " + location);
2112 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2113 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2114 m.arg1 = (passive ? 1 : 0);
2115 mLocationHandler.sendMessageAtFrontOfQueue(m);
2119 private static boolean shouldBroadcastSafe(
2120 Location loc, Location lastLoc, UpdateRecord record, long now) {
2121 // Always broadcast the first update
2122 if (lastLoc == null) {
2126 // Check whether sufficient time has passed
2127 long minTime = record.mRequest.getFastestInterval();
2128 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2130 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2134 // Check whether sufficient distance has been traveled
2135 double minDistance = record.mRequest.getSmallestDisplacement();
2136 if (minDistance > 0.0) {
2137 if (loc.distanceTo(lastLoc) <= minDistance) {
2142 // Check whether sufficient number of udpates is left
2143 if (record.mRequest.getNumUpdates() <= 0) {
2147 // Check whether the expiry date has passed
2148 if (record.mRequest.getExpireAt() < now) {
2155 private void handleLocationChangedLocked(Location location, boolean passive) {
2156 if (D) Log.d(TAG, "incoming location: " + location);
2158 long now = SystemClock.elapsedRealtime();
2159 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2161 // Skip if the provider is unknown.
2162 LocationProviderInterface p = mProvidersByName.get(provider);
2163 if (p == null) return;
2165 // Update last known locations
2166 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2167 Location lastNoGPSLocation = null;
2168 Location lastLocation = mLastLocation.get(provider);
2169 if (lastLocation == null) {
2170 lastLocation = new Location(provider);
2171 mLastLocation.put(provider, lastLocation);
2173 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2174 if (noGPSLocation == null && lastNoGPSLocation != null) {
2175 // New location has no no-GPS location: adopt last no-GPS location. This is set
2176 // directly into location because we do not want to notify COARSE clients.
2177 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2180 lastLocation.set(location);
2182 // Update last known coarse interval location if enough time has passed.
2183 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2184 if (lastLocationCoarseInterval == null) {
2185 lastLocationCoarseInterval = new Location(location);
2186 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2188 long timeDiffNanos = location.getElapsedRealtimeNanos()
2189 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2190 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2191 lastLocationCoarseInterval.set(location);
2193 // Don't ever return a coarse location that is more recent than the allowed update
2194 // interval (i.e. don't allow an app to keep registering and unregistering for
2195 // location updates to overcome the minimum interval).
2197 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2199 // Skip if there are no UpdateRecords for this provider.
2200 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2201 if (records == null || records.size() == 0) return;
2203 // Fetch coarse location
2204 Location coarseLocation = null;
2205 if (noGPSLocation != null) {
2206 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2209 // Fetch latest status update time
2210 long newStatusUpdateTime = p.getStatusUpdateTime();
2212 // Get latest status
2213 Bundle extras = new Bundle();
2214 int status = p.getStatus(extras);
2216 ArrayList<Receiver> deadReceivers = null;
2217 ArrayList<UpdateRecord> deadUpdateRecords = null;
2219 // Broadcast location or status to all listeners
2220 for (UpdateRecord r : records) {
2221 Receiver receiver = r.mReceiver;
2222 boolean receiverDead = false;
2224 int receiverUserId = UserHandle.getUserId(receiver.mUid);
2225 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2227 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2228 " (current user: " + mCurrentUserId + ", app: " +
2229 receiver.mPackageName + ")");
2234 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2235 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2236 receiver.mPackageName);
2240 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
2241 receiver.mAllowedResolutionLevel)) {
2242 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2243 receiver.mPackageName);
2247 Location notifyLocation = null;
2248 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2249 notifyLocation = coarseLocation; // use coarse location
2251 notifyLocation = lastLocation; // use fine location
2253 if (notifyLocation != null) {
2254 Location lastLoc = r.mLastFixBroadcast;
2255 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2256 if (lastLoc == null) {
2257 lastLoc = new Location(notifyLocation);
2258 r.mLastFixBroadcast = lastLoc;
2260 lastLoc.set(notifyLocation);
2262 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2263 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2264 receiverDead = true;
2266 r.mRequest.decrementNumUpdates();
2270 long prevStatusUpdateTime = r.mLastStatusBroadcast;
2271 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2272 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2274 r.mLastStatusBroadcast = newStatusUpdateTime;
2275 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2276 receiverDead = true;
2277 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2281 // track expired records
2282 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2283 if (deadUpdateRecords == null) {
2284 deadUpdateRecords = new ArrayList<UpdateRecord>();
2286 deadUpdateRecords.add(r);
2288 // track dead receivers
2290 if (deadReceivers == null) {
2291 deadReceivers = new ArrayList<Receiver>();
2293 if (!deadReceivers.contains(receiver)) {
2294 deadReceivers.add(receiver);
2299 // remove dead records and receivers outside the loop
2300 if (deadReceivers != null) {
2301 for (Receiver receiver : deadReceivers) {
2302 removeUpdatesLocked(receiver);
2305 if (deadUpdateRecords != null) {
2306 for (UpdateRecord r : deadUpdateRecords) {
2307 r.disposeLocked(true);
2309 applyRequirementsLocked(provider);
2313 private class LocationWorkerHandler extends Handler {
2314 public LocationWorkerHandler(Looper looper) {
2315 super(looper, null, true);
2319 public void handleMessage(Message msg) {
2321 case MSG_LOCATION_CHANGED:
2322 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2328 private boolean isMockProvider(String provider) {
2329 synchronized (mLock) {
2330 return mMockProviders.containsKey(provider);
2334 private void handleLocationChanged(Location location, boolean passive) {
2335 // create a working copy of the incoming Location so that the service can modify it without
2336 // disturbing the caller's copy
2337 Location myLocation = new Location(location);
2338 String provider = myLocation.getProvider();
2340 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2341 // bit if location did not come from a mock provider because passive/fused providers can
2342 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2343 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2344 myLocation.setIsFromMockProvider(true);
2347 synchronized (mLock) {
2348 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2350 // notify passive provider of the new location
2351 mPassiveProvider.updateLocation(myLocation);
2353 handleLocationChangedLocked(myLocation, passive);
2358 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2360 public void onPackageDisappeared(String packageName, int reason) {
2361 // remove all receivers associated with this package name
2362 synchronized (mLock) {
2363 ArrayList<Receiver> deadReceivers = null;
2365 for (Receiver receiver : mReceivers.values()) {
2366 if (receiver.mPackageName.equals(packageName)) {
2367 if (deadReceivers == null) {
2368 deadReceivers = new ArrayList<Receiver>();
2370 deadReceivers.add(receiver);
2374 // perform removal outside of mReceivers loop
2375 if (deadReceivers != null) {
2376 for (Receiver receiver : deadReceivers) {
2377 removeUpdatesLocked(receiver);
2387 public boolean geocoderIsPresent() {
2388 return mGeocodeProvider != null;
2392 public String getFromLocation(double latitude, double longitude, int maxResults,
2393 GeocoderParams params, List<Address> addrs) {
2394 if (mGeocodeProvider != null) {
2395 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2403 public String getFromLocationName(String locationName,
2404 double lowerLeftLatitude, double lowerLeftLongitude,
2405 double upperRightLatitude, double upperRightLongitude, int maxResults,
2406 GeocoderParams params, List<Address> addrs) {
2408 if (mGeocodeProvider != null) {
2409 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2410 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2411 maxResults, params, addrs);
2418 private boolean canCallerAccessMockLocation(String opPackageName) {
2419 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2420 opPackageName) == AppOpsManager.MODE_ALLOWED;
2424 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2425 if (!canCallerAccessMockLocation(opPackageName)) {
2429 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2430 throw new IllegalArgumentException("Cannot mock the passive location provider");
2433 long identity = Binder.clearCallingIdentity();
2434 synchronized (mLock) {
2435 // remove the real provider if we are replacing GPS or network provider
2436 if (LocationManager.GPS_PROVIDER.equals(name)
2437 || LocationManager.NETWORK_PROVIDER.equals(name)
2438 || LocationManager.FUSED_PROVIDER.equals(name)) {
2439 LocationProviderInterface p = mProvidersByName.get(name);
2441 removeProviderLocked(p);
2444 addTestProviderLocked(name, properties);
2445 updateProvidersLocked();
2447 Binder.restoreCallingIdentity(identity);
2450 private void addTestProviderLocked(String name, ProviderProperties properties) {
2451 if (mProvidersByName.get(name) != null) {
2452 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2454 MockProvider provider = new MockProvider(name, this, properties);
2455 addProviderLocked(provider);
2456 mMockProviders.put(name, provider);
2457 mLastLocation.put(name, null);
2458 mLastLocationCoarseInterval.put(name, null);
2462 public void removeTestProvider(String provider, String opPackageName) {
2463 if (!canCallerAccessMockLocation(opPackageName)) {
2467 synchronized (mLock) {
2469 // These methods can't be called after removing the test provider, so first make sure
2470 // we don't leave anything dangling.
2471 clearTestProviderEnabled(provider, opPackageName);
2472 clearTestProviderLocation(provider, opPackageName);
2473 clearTestProviderStatus(provider, opPackageName);
2475 MockProvider mockProvider = mMockProviders.remove(provider);
2476 if (mockProvider == null) {
2477 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2479 long identity = Binder.clearCallingIdentity();
2480 removeProviderLocked(mProvidersByName.get(provider));
2482 // reinstate real provider if available
2483 LocationProviderInterface realProvider = mRealProviders.get(provider);
2484 if (realProvider != null) {
2485 addProviderLocked(realProvider);
2487 mLastLocation.put(provider, null);
2488 mLastLocationCoarseInterval.put(provider, null);
2489 updateProvidersLocked();
2490 Binder.restoreCallingIdentity(identity);
2495 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2496 if (!canCallerAccessMockLocation(opPackageName)) {
2500 synchronized (mLock) {
2501 MockProvider mockProvider = mMockProviders.get(provider);
2502 if (mockProvider == null) {
2503 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2505 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2506 long identity = Binder.clearCallingIdentity();
2507 mockProvider.setLocation(loc);
2508 Binder.restoreCallingIdentity(identity);
2513 public void clearTestProviderLocation(String provider, String opPackageName) {
2514 if (!canCallerAccessMockLocation(opPackageName)) {
2518 synchronized (mLock) {
2519 MockProvider mockProvider = mMockProviders.get(provider);
2520 if (mockProvider == null) {
2521 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2523 mockProvider.clearLocation();
2528 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2529 if (!canCallerAccessMockLocation(opPackageName)) {
2533 synchronized (mLock) {
2534 MockProvider mockProvider = mMockProviders.get(provider);
2535 if (mockProvider == null) {
2536 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2538 long identity = Binder.clearCallingIdentity();
2540 mockProvider.enable();
2541 mEnabledProviders.add(provider);
2542 mDisabledProviders.remove(provider);
2544 mockProvider.disable();
2545 mEnabledProviders.remove(provider);
2546 mDisabledProviders.add(provider);
2548 updateProvidersLocked();
2549 Binder.restoreCallingIdentity(identity);
2554 public void clearTestProviderEnabled(String provider, String opPackageName) {
2555 if (!canCallerAccessMockLocation(opPackageName)) {
2559 synchronized (mLock) {
2560 MockProvider mockProvider = mMockProviders.get(provider);
2561 if (mockProvider == null) {
2562 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2564 long identity = Binder.clearCallingIdentity();
2565 mEnabledProviders.remove(provider);
2566 mDisabledProviders.remove(provider);
2567 updateProvidersLocked();
2568 Binder.restoreCallingIdentity(identity);
2573 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2574 String opPackageName) {
2575 if (!canCallerAccessMockLocation(opPackageName)) {
2579 synchronized (mLock) {
2580 MockProvider mockProvider = mMockProviders.get(provider);
2581 if (mockProvider == null) {
2582 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2584 mockProvider.setStatus(status, extras, updateTime);
2589 public void clearTestProviderStatus(String provider, String opPackageName) {
2590 if (!canCallerAccessMockLocation(opPackageName)) {
2594 synchronized (mLock) {
2595 MockProvider mockProvider = mMockProviders.get(provider);
2596 if (mockProvider == null) {
2597 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2599 mockProvider.clearStatus();
2603 private void log(String log) {
2604 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2610 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2611 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2612 != PackageManager.PERMISSION_GRANTED) {
2613 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2614 + Binder.getCallingPid()
2615 + ", uid=" + Binder.getCallingUid());
2619 synchronized (mLock) {
2620 pw.println("Current Location Manager state:");
2621 pw.println(" Location Listeners:");
2622 for (Receiver receiver : mReceivers.values()) {
2623 pw.println(" " + receiver);
2625 pw.println(" Active Records by Provider:");
2626 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2627 pw.println(" " + entry.getKey() + ":");
2628 for (UpdateRecord record : entry.getValue()) {
2629 pw.println(" " + record);
2632 pw.println(" Historical Records by Provider:");
2633 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2634 : mRequestStatistics.statistics.entrySet()) {
2635 PackageProviderKey key = entry.getKey();
2636 PackageStatistics stats = entry.getValue();
2637 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2639 pw.println(" Last Known Locations:");
2640 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2641 String provider = entry.getKey();
2642 Location location = entry.getValue();
2643 pw.println(" " + provider + ": " + location);
2646 pw.println(" Last Known Locations Coarse Intervals:");
2647 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2648 String provider = entry.getKey();
2649 Location location = entry.getValue();
2650 pw.println(" " + provider + ": " + location);
2653 mGeofenceManager.dump(pw);
2655 if (mEnabledProviders.size() > 0) {
2656 pw.println(" Enabled Providers:");
2657 for (String i : mEnabledProviders) {
2658 pw.println(" " + i);
2662 if (mDisabledProviders.size() > 0) {
2663 pw.println(" Disabled Providers:");
2664 for (String i : mDisabledProviders) {
2665 pw.println(" " + i);
2669 mBlacklist.dump(pw);
2670 if (mMockProviders.size() > 0) {
2671 pw.println(" Mock Providers:");
2672 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2673 i.getValue().dump(pw, " ");
2677 pw.append(" fudger: ");
2678 mLocationFudger.dump(fd, pw, args);
2680 if (args.length > 0 && "short".equals(args[0])) {
2683 for (LocationProviderInterface provider: mProviders) {
2684 pw.print(provider.getName() + " Internal State");
2685 if (provider instanceof LocationProviderProxy) {
2686 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2687 pw.print(" (" + proxy.getConnectedPackageName() + ")");
2690 provider.dump(fd, pw, args);