LocationManagerService.java revision a4fa3b5aa53cf677b623fe346c585cb8a0c1ce26
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package com.android.server; 18 19import com.android.internal.content.PackageMonitor; 20import com.android.internal.location.ProviderProperties; 21import com.android.internal.location.ProviderRequest; 22import com.android.internal.os.BackgroundThread; 23import com.android.server.location.ActivityRecognitionProxy; 24import com.android.server.location.FlpHardwareProvider; 25import com.android.server.location.FusedProxy; 26import com.android.server.location.GeocoderProxy; 27import com.android.server.location.GeofenceManager; 28import com.android.server.location.GeofenceProxy; 29import com.android.server.location.GpsLocationProvider; 30import com.android.server.location.GpsMeasurementsProvider; 31import com.android.server.location.LocationBlacklist; 32import com.android.server.location.LocationFudger; 33import com.android.server.location.LocationProviderInterface; 34import com.android.server.location.LocationProviderProxy; 35import com.android.server.location.LocationRequestStatistics; 36import com.android.server.location.LocationRequestStatistics.PackageProviderKey; 37import com.android.server.location.LocationRequestStatistics.PackageStatistics; 38import com.android.server.location.MockProvider; 39import com.android.server.location.PassiveProvider; 40 41import android.app.AppOpsManager; 42import android.app.PendingIntent; 43import android.content.BroadcastReceiver; 44import android.content.ContentResolver; 45import android.content.Context; 46import android.content.Intent; 47import android.content.IntentFilter; 48import android.content.pm.ApplicationInfo; 49import android.content.pm.PackageInfo; 50import android.content.pm.PackageManager; 51import android.content.pm.PackageManager.NameNotFoundException; 52import android.content.pm.ResolveInfo; 53import android.content.pm.Signature; 54import android.content.pm.UserInfo; 55import android.content.res.Resources; 56import android.database.ContentObserver; 57import android.hardware.location.ActivityRecognitionHardware; 58import android.location.Address; 59import android.location.Criteria; 60import android.location.GeocoderParams; 61import android.location.Geofence; 62import android.location.IGpsMeasurementsListener; 63import android.location.IGpsStatusListener; 64import android.location.IGpsStatusProvider; 65import android.location.ILocationListener; 66import android.location.ILocationManager; 67import android.location.INetInitiatedListener; 68import android.location.Location; 69import android.location.LocationManager; 70import android.location.LocationProvider; 71import android.location.LocationRequest; 72import android.os.Binder; 73import android.os.Bundle; 74import android.os.Handler; 75import android.os.IBinder; 76import android.os.Looper; 77import android.os.Message; 78import android.os.PowerManager; 79import android.os.Process; 80import android.os.RemoteException; 81import android.os.SystemClock; 82import android.os.UserHandle; 83import android.os.UserManager; 84import android.os.WorkSource; 85import android.provider.Settings; 86import android.util.Log; 87import android.util.Slog; 88 89import java.io.FileDescriptor; 90import java.io.PrintWriter; 91import java.util.ArrayList; 92import java.util.Arrays; 93import java.util.HashMap; 94import java.util.HashSet; 95import java.util.List; 96import java.util.Map; 97import java.util.Set; 98 99/** 100 * The service class that manages LocationProviders and issues location 101 * updates and alerts. 102 */ 103public class LocationManagerService extends ILocationManager.Stub { 104 private static final String TAG = "LocationManagerService"; 105 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); 106 107 private static final String WAKELOCK_KEY = TAG; 108 109 // Location resolution level: no location data whatsoever 110 private static final int RESOLUTION_LEVEL_NONE = 0; 111 // Location resolution level: coarse location data only 112 private static final int RESOLUTION_LEVEL_COARSE = 1; 113 // Location resolution level: fine location data 114 private static final int RESOLUTION_LEVEL_FINE = 2; 115 116 private static final String ACCESS_MOCK_LOCATION = 117 android.Manifest.permission.ACCESS_MOCK_LOCATION; 118 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 119 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 120 private static final String INSTALL_LOCATION_PROVIDER = 121 android.Manifest.permission.INSTALL_LOCATION_PROVIDER; 122 123 private static final String NETWORK_LOCATION_SERVICE_ACTION = 124 "com.android.location.service.v3.NetworkLocationProvider"; 125 private static final String FUSED_LOCATION_SERVICE_ACTION = 126 "com.android.location.service.FusedLocationProvider"; 127 128 private static final int MSG_LOCATION_CHANGED = 1; 129 130 private static final long NANOS_PER_MILLI = 1000000L; 131 132 // The maximum interval a location request can have and still be considered "high power". 133 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000; 134 135 // Location Providers may sometimes deliver location updates 136 // slightly faster that requested - provide grace period so 137 // we don't unnecessarily filter events that are otherwise on 138 // time 139 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100; 140 141 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest(); 142 143 private final Context mContext; 144 private final AppOpsManager mAppOps; 145 146 // used internally for synchronization 147 private final Object mLock = new Object(); 148 149 // --- fields below are final after systemReady() --- 150 private LocationFudger mLocationFudger; 151 private GeofenceManager mGeofenceManager; 152 private PackageManager mPackageManager; 153 private PowerManager mPowerManager; 154 private UserManager mUserManager; 155 private GeocoderProxy mGeocodeProvider; 156 private IGpsStatusProvider mGpsStatusProvider; 157 private INetInitiatedListener mNetInitiatedListener; 158 private LocationWorkerHandler mLocationHandler; 159 private PassiveProvider mPassiveProvider; // track passive provider for special cases 160 private LocationBlacklist mBlacklist; 161 private GpsMeasurementsProvider mGpsMeasurementsProvider; 162 163 // --- fields below are protected by mLock --- 164 // Set of providers that are explicitly enabled 165 private final Set<String> mEnabledProviders = new HashSet<String>(); 166 167 // Set of providers that are explicitly disabled 168 private final Set<String> mDisabledProviders = new HashSet<String>(); 169 170 // Mock (test) providers 171 private final HashMap<String, MockProvider> mMockProviders = 172 new HashMap<String, MockProvider>(); 173 174 // all receivers 175 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 176 177 // currently installed providers (with mocks replacing real providers) 178 private final ArrayList<LocationProviderInterface> mProviders = 179 new ArrayList<LocationProviderInterface>(); 180 181 // real providers, saved here when mocked out 182 private final HashMap<String, LocationProviderInterface> mRealProviders = 183 new HashMap<String, LocationProviderInterface>(); 184 185 // mapping from provider name to provider 186 private final HashMap<String, LocationProviderInterface> mProvidersByName = 187 new HashMap<String, LocationProviderInterface>(); 188 189 // mapping from provider name to all its UpdateRecords 190 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider = 191 new HashMap<String, ArrayList<UpdateRecord>>(); 192 193 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics(); 194 195 // mapping from provider name to last known location 196 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>(); 197 198 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS. 199 // locations stored here are not fudged for coarse permissions. 200 private final HashMap<String, Location> mLastLocationCoarseInterval = 201 new HashMap<String, Location>(); 202 203 // all providers that operate over proxy, for authorizing incoming location 204 private final ArrayList<LocationProviderProxy> mProxyProviders = 205 new ArrayList<LocationProviderProxy>(); 206 207 // current active user on the device - other users are denied location data 208 private int mCurrentUserId = UserHandle.USER_OWNER; 209 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER }; 210 211 public LocationManagerService(Context context) { 212 super(); 213 mContext = context; 214 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 215 216 if (D) Log.d(TAG, "Constructed"); 217 218 // most startup is deferred until systemReady() 219 } 220 221 public void systemRunning() { 222 synchronized (mLock) { 223 if (D) Log.d(TAG, "systemReady()"); 224 225 // fetch package manager 226 mPackageManager = mContext.getPackageManager(); 227 228 // fetch power manager 229 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 230 231 // prepare worker thread 232 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper()); 233 234 // prepare mLocationHandler's dependents 235 mLocationFudger = new LocationFudger(mContext, mLocationHandler); 236 mBlacklist = new LocationBlacklist(mContext, mLocationHandler); 237 mBlacklist.init(); 238 mGeofenceManager = new GeofenceManager(mContext, mBlacklist); 239 240 // Monitor for app ops mode changes. 241 AppOpsManager.OnOpChangedListener callback 242 = new AppOpsManager.OnOpChangedInternalListener() { 243 public void onOpChanged(int op, String packageName) { 244 synchronized (mLock) { 245 for (Receiver receiver : mReceivers.values()) { 246 receiver.updateMonitoring(true); 247 } 248 applyAllProviderRequirementsLocked(); 249 } 250 } 251 }; 252 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback); 253 254 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 255 updateUserProfiles(mCurrentUserId); 256 257 // prepare providers 258 loadProvidersLocked(); 259 updateProvidersLocked(); 260 } 261 262 // listen for settings changes 263 mContext.getContentResolver().registerContentObserver( 264 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true, 265 new ContentObserver(mLocationHandler) { 266 @Override 267 public void onChange(boolean selfChange) { 268 synchronized (mLock) { 269 updateProvidersLocked(); 270 } 271 } 272 }, UserHandle.USER_ALL); 273 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true); 274 275 // listen for user change 276 IntentFilter intentFilter = new IntentFilter(); 277 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 278 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 279 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 280 281 mContext.registerReceiverAsUser(new BroadcastReceiver() { 282 @Override 283 public void onReceive(Context context, Intent intent) { 284 String action = intent.getAction(); 285 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 286 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 287 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action) 288 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { 289 updateUserProfiles(mCurrentUserId); 290 } 291 } 292 }, UserHandle.ALL, intentFilter, null, mLocationHandler); 293 } 294 295 /** 296 * Makes a list of userids that are related to the current user. This is 297 * relevant when using managed profiles. Otherwise the list only contains 298 * the current user. 299 * 300 * @param currentUserId the current user, who might have an alter-ego. 301 */ 302 void updateUserProfiles(int currentUserId) { 303 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId); 304 synchronized (mLock) { 305 mCurrentUserProfiles = new int[profiles.size()]; 306 for (int i = 0; i < mCurrentUserProfiles.length; i++) { 307 mCurrentUserProfiles[i] = profiles.get(i).id; 308 } 309 } 310 } 311 312 /** 313 * Checks if the specified userId matches any of the current foreground 314 * users stored in mCurrentUserProfiles. 315 */ 316 private boolean isCurrentProfile(int userId) { 317 synchronized (mLock) { 318 for (int i = 0; i < mCurrentUserProfiles.length; i++) { 319 if (mCurrentUserProfiles[i] == userId) { 320 return true; 321 } 322 } 323 return false; 324 } 325 } 326 327 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) { 328 PackageManager pm = mContext.getPackageManager(); 329 String systemPackageName = mContext.getPackageName(); 330 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); 331 332 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser( 333 new Intent(FUSED_LOCATION_SERVICE_ACTION), 334 PackageManager.GET_META_DATA, mCurrentUserId); 335 for (ResolveInfo rInfo : rInfos) { 336 String packageName = rInfo.serviceInfo.packageName; 337 338 // Check that the signature is in the list of supported sigs. If it's not in 339 // this list the standard provider binding logic won't bind to it. 340 try { 341 PackageInfo pInfo; 342 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); 343 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) { 344 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION + 345 ", but has wrong signature, ignoring"); 346 continue; 347 } 348 } catch (NameNotFoundException e) { 349 Log.e(TAG, "missing package: " + packageName); 350 continue; 351 } 352 353 // Get the version info 354 if (rInfo.serviceInfo.metaData == null) { 355 Log.w(TAG, "Found fused provider without metadata: " + packageName); 356 continue; 357 } 358 359 int version = rInfo.serviceInfo.metaData.getInt( 360 ServiceWatcher.EXTRA_SERVICE_VERSION, -1); 361 if (version == 0) { 362 // This should be the fallback fused location provider. 363 364 // Make sure it's in the system partition. 365 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 366 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName); 367 continue; 368 } 369 370 // Check that the fallback is signed the same as the OS 371 // as a proxy for coreApp="true" 372 if (pm.checkSignatures(systemPackageName, packageName) 373 != PackageManager.SIGNATURE_MATCH) { 374 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: " 375 + packageName); 376 continue; 377 } 378 379 // Found a valid fallback. 380 if (D) Log.d(TAG, "Found fallback provider: " + packageName); 381 return; 382 } else { 383 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName); 384 } 385 } 386 387 throw new IllegalStateException("Unable to find a fused location provider that is in the " 388 + "system partition with version 0 and signed with the platform certificate. " 389 + "Such a package is needed to provide a default fused location provider in the " 390 + "event that no other fused location provider has been installed or is currently " 391 + "available. For example, coreOnly boot mode when decrypting the data " 392 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest"); 393 } 394 395 private void loadProvidersLocked() { 396 // create a passive location provider, which is always enabled 397 PassiveProvider passiveProvider = new PassiveProvider(this); 398 addProviderLocked(passiveProvider); 399 mEnabledProviders.add(passiveProvider.getName()); 400 mPassiveProvider = passiveProvider; 401 // Create a gps location provider 402 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this, 403 mLocationHandler.getLooper()); 404 405 if (GpsLocationProvider.isSupported()) { 406 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 407 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 408 addProviderLocked(gpsProvider); 409 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); 410 } 411 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider(); 412 413 /* 414 Load package name(s) containing location provider support. 415 These packages can contain services implementing location providers: 416 Geocoder Provider, Network Location Provider, and 417 Fused Location Provider. They will each be searched for 418 service components implementing these providers. 419 The location framework also has support for installation 420 of new location providers at run-time. The new package does not 421 have to be explicitly listed here, however it must have a signature 422 that matches the signature of at least one package on this list. 423 */ 424 Resources resources = mContext.getResources(); 425 ArrayList<String> providerPackageNames = new ArrayList<String>(); 426 String[] pkgs = resources.getStringArray( 427 com.android.internal.R.array.config_locationProviderPackageNames); 428 if (D) Log.d(TAG, "certificates for location providers pulled from: " + 429 Arrays.toString(pkgs)); 430 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs)); 431 432 ensureFallbackFusedProviderPresentLocked(providerPackageNames); 433 434 // bind to network provider 435 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( 436 mContext, 437 LocationManager.NETWORK_PROVIDER, 438 NETWORK_LOCATION_SERVICE_ACTION, 439 com.android.internal.R.bool.config_enableNetworkLocationOverlay, 440 com.android.internal.R.string.config_networkLocationProviderPackageName, 441 com.android.internal.R.array.config_locationProviderPackageNames, 442 mLocationHandler); 443 if (networkProvider != null) { 444 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); 445 mProxyProviders.add(networkProvider); 446 addProviderLocked(networkProvider); 447 } else { 448 Slog.w(TAG, "no network location provider found"); 449 } 450 451 // bind to fused provider 452 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind( 453 mContext, 454 LocationManager.FUSED_PROVIDER, 455 FUSED_LOCATION_SERVICE_ACTION, 456 com.android.internal.R.bool.config_enableFusedLocationOverlay, 457 com.android.internal.R.string.config_fusedLocationProviderPackageName, 458 com.android.internal.R.array.config_locationProviderPackageNames, 459 mLocationHandler); 460 if (fusedLocationProvider != null) { 461 addProviderLocked(fusedLocationProvider); 462 mProxyProviders.add(fusedLocationProvider); 463 mEnabledProviders.add(fusedLocationProvider.getName()); 464 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider); 465 } else { 466 Slog.e(TAG, "no fused location provider found", 467 new IllegalStateException("Location service needs a fused location provider")); 468 } 469 470 // bind to geocoder provider 471 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, 472 com.android.internal.R.bool.config_enableGeocoderOverlay, 473 com.android.internal.R.string.config_geocoderProviderPackageName, 474 com.android.internal.R.array.config_locationProviderPackageNames, 475 mLocationHandler); 476 if (mGeocodeProvider == null) { 477 Slog.e(TAG, "no geocoder provider found"); 478 } 479 480 // bind to fused hardware provider if supported 481 if (FlpHardwareProvider.isSupported()) { 482 FlpHardwareProvider flpHardwareProvider = 483 FlpHardwareProvider.getInstance(mContext); 484 FusedProxy fusedProxy = FusedProxy.createAndBind( 485 mContext, 486 mLocationHandler, 487 flpHardwareProvider.getLocationHardware(), 488 com.android.internal.R.bool.config_enableHardwareFlpOverlay, 489 com.android.internal.R.string.config_hardwareFlpPackageName, 490 com.android.internal.R.array.config_locationProviderPackageNames); 491 if(fusedProxy == null) { 492 Slog.e(TAG, "Unable to bind FusedProxy."); 493 } 494 495 // bind to geofence provider 496 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, 497 com.android.internal.R.bool.config_enableGeofenceOverlay, 498 com.android.internal.R.string.config_geofenceProviderPackageName, 499 com.android.internal.R.array.config_locationProviderPackageNames, 500 mLocationHandler, 501 gpsProvider.getGpsGeofenceProxy(), 502 flpHardwareProvider.getGeofenceHardware()); 503 if (provider == null) { 504 Slog.e(TAG, "Unable to bind FLP Geofence proxy."); 505 } 506 } else { 507 Slog.e(TAG, "FLP HAL not supported."); 508 } 509 510 // bind to the hardware activity recognition if supported 511 if (ActivityRecognitionHardware.isSupported()) { 512 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind( 513 mContext, 514 mLocationHandler, 515 ActivityRecognitionHardware.getInstance(mContext), 516 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay, 517 com.android.internal.R.string.config_activityRecognitionHardwarePackageName, 518 com.android.internal.R.array.config_locationProviderPackageNames); 519 520 if (proxy == null) { 521 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy."); 522 } 523 } else { 524 Slog.e(TAG, "Hardware Activity-Recognition not supported."); 525 } 526 527 String[] testProviderStrings = resources.getStringArray( 528 com.android.internal.R.array.config_testLocationProviders); 529 for (String testProviderString : testProviderStrings) { 530 String fragments[] = testProviderString.split(","); 531 String name = fragments[0].trim(); 532 if (mProvidersByName.get(name) != null) { 533 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 534 } 535 ProviderProperties properties = new ProviderProperties( 536 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */, 537 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */, 538 Boolean.parseBoolean(fragments[3]) /* requiresCell */, 539 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */, 540 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */, 541 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */, 542 Boolean.parseBoolean(fragments[7]) /* supportsBearing */, 543 Integer.parseInt(fragments[8]) /* powerRequirement */, 544 Integer.parseInt(fragments[9]) /* accuracy */); 545 addTestProviderLocked(name, properties); 546 } 547 } 548 549 /** 550 * Called when the device's active user changes. 551 * @param userId the new active user's UserId 552 */ 553 private void switchUser(int userId) { 554 if (mCurrentUserId == userId) { 555 return; 556 } 557 mBlacklist.switchUser(userId); 558 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED); 559 synchronized (mLock) { 560 mLastLocation.clear(); 561 mLastLocationCoarseInterval.clear(); 562 for (LocationProviderInterface p : mProviders) { 563 updateProviderListenersLocked(p.getName(), false); 564 } 565 mCurrentUserId = userId; 566 updateUserProfiles(userId); 567 updateProvidersLocked(); 568 } 569 } 570 571 /** 572 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 573 * location updates. 574 */ 575 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 576 final int mUid; // uid of receiver 577 final int mPid; // pid of receiver 578 final String mPackageName; // package name of receiver 579 final int mAllowedResolutionLevel; // resolution level allowed to receiver 580 581 final ILocationListener mListener; 582 final PendingIntent mPendingIntent; 583 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller. 584 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver. 585 final Object mKey; 586 587 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 588 589 // True if app ops has started monitoring this receiver for locations. 590 boolean mOpMonitoring; 591 // True if app ops has started monitoring this receiver for high power (gps) locations. 592 boolean mOpHighPowerMonitoring; 593 int mPendingBroadcasts; 594 PowerManager.WakeLock mWakeLock; 595 596 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, 597 String packageName, WorkSource workSource, boolean hideFromAppOps) { 598 mListener = listener; 599 mPendingIntent = intent; 600 if (listener != null) { 601 mKey = listener.asBinder(); 602 } else { 603 mKey = intent; 604 } 605 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid); 606 mUid = uid; 607 mPid = pid; 608 mPackageName = packageName; 609 if (workSource != null && workSource.size() <= 0) { 610 workSource = null; 611 } 612 mWorkSource = workSource; 613 mHideFromAppOps = hideFromAppOps; 614 615 updateMonitoring(true); 616 617 // construct/configure wakelock 618 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 619 if (workSource == null) { 620 workSource = new WorkSource(mUid, mPackageName); 621 } 622 mWakeLock.setWorkSource(workSource); 623 } 624 625 @Override 626 public boolean equals(Object otherObj) { 627 if (otherObj instanceof Receiver) { 628 return mKey.equals(((Receiver)otherObj).mKey); 629 } 630 return false; 631 } 632 633 @Override 634 public int hashCode() { 635 return mKey.hashCode(); 636 } 637 638 @Override 639 public String toString() { 640 StringBuilder s = new StringBuilder(); 641 s.append("Reciever["); 642 s.append(Integer.toHexString(System.identityHashCode(this))); 643 if (mListener != null) { 644 s.append(" listener"); 645 } else { 646 s.append(" intent"); 647 } 648 for (String p : mUpdateRecords.keySet()) { 649 s.append(" ").append(mUpdateRecords.get(p).toString()); 650 } 651 s.append("]"); 652 return s.toString(); 653 } 654 655 /** 656 * Update AppOp monitoring for this receiver. 657 * 658 * @param allow If true receiver is currently active, if false it's been removed. 659 */ 660 public void updateMonitoring(boolean allow) { 661 if (mHideFromAppOps) { 662 return; 663 } 664 665 boolean requestingLocation = false; 666 boolean requestingHighPowerLocation = false; 667 if (allow) { 668 // See if receiver has any enabled update records. Also note if any update records 669 // are high power (has a high power provider with an interval under a threshold). 670 for (UpdateRecord updateRecord : mUpdateRecords.values()) { 671 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) { 672 requestingLocation = true; 673 LocationProviderInterface locationProvider 674 = mProvidersByName.get(updateRecord.mProvider); 675 ProviderProperties properties = locationProvider != null 676 ? locationProvider.getProperties() : null; 677 if (properties != null 678 && properties.mPowerRequirement == Criteria.POWER_HIGH 679 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) { 680 requestingHighPowerLocation = true; 681 break; 682 } 683 } 684 } 685 } 686 687 // First update monitoring of any location request (including high power). 688 mOpMonitoring = updateMonitoring( 689 requestingLocation, 690 mOpMonitoring, 691 AppOpsManager.OP_MONITOR_LOCATION); 692 693 // Now update monitoring of high power requests only. 694 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring; 695 mOpHighPowerMonitoring = updateMonitoring( 696 requestingHighPowerLocation, 697 mOpHighPowerMonitoring, 698 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION); 699 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) { 700 // Send an intent to notify that a high power request has been added/removed. 701 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); 702 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 703 } 704 } 705 706 /** 707 * Update AppOps monitoring for a single location request and op type. 708 * 709 * @param allowMonitoring True if monitoring is allowed for this request/op. 710 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op. 711 * @param op AppOps code for the op to update. 712 * @return True if monitoring is on for this request/op after updating. 713 */ 714 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring, 715 int op) { 716 if (!currentlyMonitoring) { 717 if (allowMonitoring) { 718 return mAppOps.startOpNoThrow(op, mUid, mPackageName) 719 == AppOpsManager.MODE_ALLOWED; 720 } 721 } else { 722 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName) 723 != AppOpsManager.MODE_ALLOWED) { 724 mAppOps.finishOp(op, mUid, mPackageName); 725 return false; 726 } 727 } 728 729 return currentlyMonitoring; 730 } 731 732 public boolean isListener() { 733 return mListener != null; 734 } 735 736 public boolean isPendingIntent() { 737 return mPendingIntent != null; 738 } 739 740 public ILocationListener getListener() { 741 if (mListener != null) { 742 return mListener; 743 } 744 throw new IllegalStateException("Request for non-existent listener"); 745 } 746 747 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 748 if (mListener != null) { 749 try { 750 synchronized (this) { 751 // synchronize to ensure incrementPendingBroadcastsLocked() 752 // is called before decrementPendingBroadcasts() 753 mListener.onStatusChanged(provider, status, extras); 754 // call this after broadcasting so we do not increment 755 // if we throw an exeption. 756 incrementPendingBroadcastsLocked(); 757 } 758 } catch (RemoteException e) { 759 return false; 760 } 761 } else { 762 Intent statusChanged = new Intent(); 763 statusChanged.putExtras(new Bundle(extras)); 764 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 765 try { 766 synchronized (this) { 767 // synchronize to ensure incrementPendingBroadcastsLocked() 768 // is called before decrementPendingBroadcasts() 769 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, 770 getResolutionPermission(mAllowedResolutionLevel)); 771 // call this after broadcasting so we do not increment 772 // if we throw an exeption. 773 incrementPendingBroadcastsLocked(); 774 } 775 } catch (PendingIntent.CanceledException e) { 776 return false; 777 } 778 } 779 return true; 780 } 781 782 public boolean callLocationChangedLocked(Location location) { 783 if (mListener != null) { 784 try { 785 synchronized (this) { 786 // synchronize to ensure incrementPendingBroadcastsLocked() 787 // is called before decrementPendingBroadcasts() 788 mListener.onLocationChanged(new Location(location)); 789 // call this after broadcasting so we do not increment 790 // if we throw an exeption. 791 incrementPendingBroadcastsLocked(); 792 } 793 } catch (RemoteException e) { 794 return false; 795 } 796 } else { 797 Intent locationChanged = new Intent(); 798 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location)); 799 try { 800 synchronized (this) { 801 // synchronize to ensure incrementPendingBroadcastsLocked() 802 // is called before decrementPendingBroadcasts() 803 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, 804 getResolutionPermission(mAllowedResolutionLevel)); 805 // call this after broadcasting so we do not increment 806 // if we throw an exeption. 807 incrementPendingBroadcastsLocked(); 808 } 809 } catch (PendingIntent.CanceledException e) { 810 return false; 811 } 812 } 813 return true; 814 } 815 816 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 817 // First update AppOp monitoring. 818 // An app may get/lose location access as providers are enabled/disabled. 819 updateMonitoring(true); 820 821 if (mListener != null) { 822 try { 823 synchronized (this) { 824 // synchronize to ensure incrementPendingBroadcastsLocked() 825 // is called before decrementPendingBroadcasts() 826 if (enabled) { 827 mListener.onProviderEnabled(provider); 828 } else { 829 mListener.onProviderDisabled(provider); 830 } 831 // call this after broadcasting so we do not increment 832 // if we throw an exeption. 833 incrementPendingBroadcastsLocked(); 834 } 835 } catch (RemoteException e) { 836 return false; 837 } 838 } else { 839 Intent providerIntent = new Intent(); 840 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 841 try { 842 synchronized (this) { 843 // synchronize to ensure incrementPendingBroadcastsLocked() 844 // is called before decrementPendingBroadcasts() 845 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, 846 getResolutionPermission(mAllowedResolutionLevel)); 847 // call this after broadcasting so we do not increment 848 // if we throw an exeption. 849 incrementPendingBroadcastsLocked(); 850 } 851 } catch (PendingIntent.CanceledException e) { 852 return false; 853 } 854 } 855 return true; 856 } 857 858 @Override 859 public void binderDied() { 860 if (D) Log.d(TAG, "Location listener died"); 861 862 synchronized (mLock) { 863 removeUpdatesLocked(this); 864 } 865 synchronized (this) { 866 clearPendingBroadcastsLocked(); 867 } 868 } 869 870 @Override 871 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 872 int resultCode, String resultData, Bundle resultExtras) { 873 synchronized (this) { 874 decrementPendingBroadcastsLocked(); 875 } 876 } 877 878 // this must be called while synchronized by caller in a synchronized block 879 // containing the sending of the broadcaset 880 private void incrementPendingBroadcastsLocked() { 881 if (mPendingBroadcasts++ == 0) { 882 mWakeLock.acquire(); 883 } 884 } 885 886 private void decrementPendingBroadcastsLocked() { 887 if (--mPendingBroadcasts == 0) { 888 if (mWakeLock.isHeld()) { 889 mWakeLock.release(); 890 } 891 } 892 } 893 894 public void clearPendingBroadcastsLocked() { 895 if (mPendingBroadcasts > 0) { 896 mPendingBroadcasts = 0; 897 if (mWakeLock.isHeld()) { 898 mWakeLock.release(); 899 } 900 } 901 } 902 } 903 904 @Override 905 public void locationCallbackFinished(ILocationListener listener) { 906 //Do not use getReceiverLocked here as that will add the ILocationListener to 907 //the receiver list if it is not found. If it is not found then the 908 //LocationListener was removed when it had a pending broadcast and should 909 //not be added back. 910 synchronized (mLock) { 911 IBinder binder = listener.asBinder(); 912 Receiver receiver = mReceivers.get(binder); 913 if (receiver != null) { 914 synchronized (receiver) { 915 // so wakelock calls will succeed 916 long identity = Binder.clearCallingIdentity(); 917 receiver.decrementPendingBroadcastsLocked(); 918 Binder.restoreCallingIdentity(identity); 919 } 920 } 921 } 922 } 923 924 private void addProviderLocked(LocationProviderInterface provider) { 925 mProviders.add(provider); 926 mProvidersByName.put(provider.getName(), provider); 927 } 928 929 private void removeProviderLocked(LocationProviderInterface provider) { 930 provider.disable(); 931 mProviders.remove(provider); 932 mProvidersByName.remove(provider.getName()); 933 } 934 935 /** 936 * Returns "true" if access to the specified location provider is allowed by the current 937 * user's settings. Access to all location providers is forbidden to non-location-provider 938 * processes belonging to background users. 939 * 940 * @param provider the name of the location provider 941 * @return 942 */ 943 private boolean isAllowedByCurrentUserSettingsLocked(String provider) { 944 if (mEnabledProviders.contains(provider)) { 945 return true; 946 } 947 if (mDisabledProviders.contains(provider)) { 948 return false; 949 } 950 // Use system settings 951 ContentResolver resolver = mContext.getContentResolver(); 952 953 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId); 954 } 955 956 /** 957 * Returns "true" if access to the specified location provider is allowed by the specified 958 * user's settings. Access to all location providers is forbidden to non-location-provider 959 * processes belonging to background users. 960 * 961 * @param provider the name of the location provider 962 * @param uid the requestor's UID 963 * @return 964 */ 965 private boolean isAllowedByUserSettingsLocked(String provider, int uid) { 966 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) { 967 return false; 968 } 969 return isAllowedByCurrentUserSettingsLocked(provider); 970 } 971 972 /** 973 * Returns the permission string associated with the specified resolution level. 974 * 975 * @param resolutionLevel the resolution level 976 * @return the permission string 977 */ 978 private String getResolutionPermission(int resolutionLevel) { 979 switch (resolutionLevel) { 980 case RESOLUTION_LEVEL_FINE: 981 return android.Manifest.permission.ACCESS_FINE_LOCATION; 982 case RESOLUTION_LEVEL_COARSE: 983 return android.Manifest.permission.ACCESS_COARSE_LOCATION; 984 default: 985 return null; 986 } 987 } 988 989 /** 990 * Returns the resolution level allowed to the given PID/UID pair. 991 * 992 * @param pid the PID 993 * @param uid the UID 994 * @return resolution level allowed to the pid/uid pair 995 */ 996 private int getAllowedResolutionLevel(int pid, int uid) { 997 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, 998 pid, uid) == PackageManager.PERMISSION_GRANTED) { 999 return RESOLUTION_LEVEL_FINE; 1000 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, 1001 pid, uid) == PackageManager.PERMISSION_GRANTED) { 1002 return RESOLUTION_LEVEL_COARSE; 1003 } else { 1004 return RESOLUTION_LEVEL_NONE; 1005 } 1006 } 1007 1008 /** 1009 * Returns the resolution level allowed to the caller 1010 * 1011 * @return resolution level allowed to caller 1012 */ 1013 private int getCallerAllowedResolutionLevel() { 1014 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid()); 1015 } 1016 1017 /** 1018 * Throw SecurityException if specified resolution level is insufficient to use geofences. 1019 * 1020 * @param allowedResolutionLevel resolution level allowed to caller 1021 */ 1022 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) { 1023 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1024 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission"); 1025 } 1026 } 1027 1028 /** 1029 * Return the minimum resolution level required to use the specified location provider. 1030 * 1031 * @param provider the name of the location provider 1032 * @return minimum resolution level required for provider 1033 */ 1034 private int getMinimumResolutionLevelForProviderUse(String provider) { 1035 if (LocationManager.GPS_PROVIDER.equals(provider) || 1036 LocationManager.PASSIVE_PROVIDER.equals(provider)) { 1037 // gps and passive providers require FINE permission 1038 return RESOLUTION_LEVEL_FINE; 1039 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) || 1040 LocationManager.FUSED_PROVIDER.equals(provider)) { 1041 // network and fused providers are ok with COARSE or FINE 1042 return RESOLUTION_LEVEL_COARSE; 1043 } else { 1044 // mock providers 1045 LocationProviderInterface lp = mMockProviders.get(provider); 1046 if (lp != null) { 1047 ProviderProperties properties = lp.getProperties(); 1048 if (properties != null) { 1049 if (properties.mRequiresSatellite) { 1050 // provider requiring satellites require FINE permission 1051 return RESOLUTION_LEVEL_FINE; 1052 } else if (properties.mRequiresNetwork || properties.mRequiresCell) { 1053 // provider requiring network and or cell require COARSE or FINE 1054 return RESOLUTION_LEVEL_COARSE; 1055 } 1056 } 1057 } 1058 } 1059 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE 1060 } 1061 1062 /** 1063 * Throw SecurityException if specified resolution level is insufficient to use the named 1064 * location provider. 1065 * 1066 * @param allowedResolutionLevel resolution level allowed to caller 1067 * @param providerName the name of the location provider 1068 */ 1069 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel, 1070 String providerName) { 1071 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName); 1072 if (allowedResolutionLevel < requiredResolutionLevel) { 1073 switch (requiredResolutionLevel) { 1074 case RESOLUTION_LEVEL_FINE: 1075 throw new SecurityException("\"" + providerName + "\" location provider " + 1076 "requires ACCESS_FINE_LOCATION permission."); 1077 case RESOLUTION_LEVEL_COARSE: 1078 throw new SecurityException("\"" + providerName + "\" location provider " + 1079 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); 1080 default: 1081 throw new SecurityException("Insufficient permission for \"" + providerName + 1082 "\" location provider."); 1083 } 1084 } 1085 } 1086 1087 /** 1088 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages 1089 * for battery). 1090 */ 1091 private void checkDeviceStatsAllowed() { 1092 mContext.enforceCallingOrSelfPermission( 1093 android.Manifest.permission.UPDATE_DEVICE_STATS, null); 1094 } 1095 1096 private void checkUpdateAppOpsAllowed() { 1097 mContext.enforceCallingOrSelfPermission( 1098 android.Manifest.permission.UPDATE_APP_OPS_STATS, null); 1099 } 1100 1101 public static int resolutionLevelToOp(int allowedResolutionLevel) { 1102 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) { 1103 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) { 1104 return AppOpsManager.OP_COARSE_LOCATION; 1105 } else { 1106 return AppOpsManager.OP_FINE_LOCATION; 1107 } 1108 } 1109 return -1; 1110 } 1111 1112 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) { 1113 int op = resolutionLevelToOp(allowedResolutionLevel); 1114 if (op >= 0) { 1115 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) { 1116 return false; 1117 } 1118 } 1119 return true; 1120 } 1121 1122 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) { 1123 int op = resolutionLevelToOp(allowedResolutionLevel); 1124 if (op >= 0) { 1125 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) { 1126 return false; 1127 } 1128 } 1129 return true; 1130 } 1131 1132 /** 1133 * Returns all providers by name, including passive, but excluding 1134 * fused, also including ones that are not permitted to 1135 * be accessed by the calling activity or are currently disabled. 1136 */ 1137 @Override 1138 public List<String> getAllProviders() { 1139 ArrayList<String> out; 1140 synchronized (mLock) { 1141 out = new ArrayList<String>(mProviders.size()); 1142 for (LocationProviderInterface provider : mProviders) { 1143 String name = provider.getName(); 1144 if (LocationManager.FUSED_PROVIDER.equals(name)) { 1145 continue; 1146 } 1147 out.add(name); 1148 } 1149 } 1150 1151 if (D) Log.d(TAG, "getAllProviders()=" + out); 1152 return out; 1153 } 1154 1155 /** 1156 * Return all providers by name, that match criteria and are optionally 1157 * enabled. 1158 * Can return passive provider, but never returns fused provider. 1159 */ 1160 @Override 1161 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 1162 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1163 ArrayList<String> out; 1164 int uid = Binder.getCallingUid();; 1165 long identity = Binder.clearCallingIdentity(); 1166 try { 1167 synchronized (mLock) { 1168 out = new ArrayList<String>(mProviders.size()); 1169 for (LocationProviderInterface provider : mProviders) { 1170 String name = provider.getName(); 1171 if (LocationManager.FUSED_PROVIDER.equals(name)) { 1172 continue; 1173 } 1174 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) { 1175 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) { 1176 continue; 1177 } 1178 if (criteria != null && !LocationProvider.propertiesMeetCriteria( 1179 name, provider.getProperties(), criteria)) { 1180 continue; 1181 } 1182 out.add(name); 1183 } 1184 } 1185 } 1186 } finally { 1187 Binder.restoreCallingIdentity(identity); 1188 } 1189 1190 if (D) Log.d(TAG, "getProviders()=" + out); 1191 return out; 1192 } 1193 1194 /** 1195 * Return the name of the best provider given a Criteria object. 1196 * This method has been deprecated from the public API, 1197 * and the whole LocationProvider (including #meetsCriteria) 1198 * has been deprecated as well. So this method now uses 1199 * some simplified logic. 1200 */ 1201 @Override 1202 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 1203 String result = null; 1204 1205 List<String> providers = getProviders(criteria, enabledOnly); 1206 if (!providers.isEmpty()) { 1207 result = pickBest(providers); 1208 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 1209 return result; 1210 } 1211 providers = getProviders(null, enabledOnly); 1212 if (!providers.isEmpty()) { 1213 result = pickBest(providers); 1214 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 1215 return result; 1216 } 1217 1218 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 1219 return null; 1220 } 1221 1222 private String pickBest(List<String> providers) { 1223 if (providers.contains(LocationManager.GPS_PROVIDER)) { 1224 return LocationManager.GPS_PROVIDER; 1225 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) { 1226 return LocationManager.NETWORK_PROVIDER; 1227 } else { 1228 return providers.get(0); 1229 } 1230 } 1231 1232 @Override 1233 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 1234 LocationProviderInterface p = mProvidersByName.get(provider); 1235 if (p == null) { 1236 throw new IllegalArgumentException("provider=" + provider); 1237 } 1238 1239 boolean result = LocationProvider.propertiesMeetCriteria( 1240 p.getName(), p.getProperties(), criteria); 1241 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result); 1242 return result; 1243 } 1244 1245 private void updateProvidersLocked() { 1246 boolean changesMade = false; 1247 for (int i = mProviders.size() - 1; i >= 0; i--) { 1248 LocationProviderInterface p = mProviders.get(i); 1249 boolean isEnabled = p.isEnabled(); 1250 String name = p.getName(); 1251 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name); 1252 if (isEnabled && !shouldBeEnabled) { 1253 updateProviderListenersLocked(name, false); 1254 // If any provider has been disabled, clear all last locations for all providers. 1255 // This is to be on the safe side in case a provider has location derived from 1256 // this disabled provider. 1257 mLastLocation.clear(); 1258 mLastLocationCoarseInterval.clear(); 1259 changesMade = true; 1260 } else if (!isEnabled && shouldBeEnabled) { 1261 updateProviderListenersLocked(name, true); 1262 changesMade = true; 1263 } 1264 } 1265 if (changesMade) { 1266 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION), 1267 UserHandle.ALL); 1268 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION), 1269 UserHandle.ALL); 1270 } 1271 } 1272 1273 private void updateProviderListenersLocked(String provider, boolean enabled) { 1274 int listeners = 0; 1275 1276 LocationProviderInterface p = mProvidersByName.get(provider); 1277 if (p == null) return; 1278 1279 ArrayList<Receiver> deadReceivers = null; 1280 1281 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1282 if (records != null) { 1283 final int N = records.size(); 1284 for (int i = 0; i < N; i++) { 1285 UpdateRecord record = records.get(i); 1286 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { 1287 // Sends a notification message to the receiver 1288 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 1289 if (deadReceivers == null) { 1290 deadReceivers = new ArrayList<Receiver>(); 1291 } 1292 deadReceivers.add(record.mReceiver); 1293 } 1294 listeners++; 1295 } 1296 } 1297 } 1298 1299 if (deadReceivers != null) { 1300 for (int i = deadReceivers.size() - 1; i >= 0; i--) { 1301 removeUpdatesLocked(deadReceivers.get(i)); 1302 } 1303 } 1304 1305 if (enabled) { 1306 p.enable(); 1307 if (listeners > 0) { 1308 applyRequirementsLocked(provider); 1309 } 1310 } else { 1311 p.disable(); 1312 } 1313 } 1314 1315 private void applyRequirementsLocked(String provider) { 1316 LocationProviderInterface p = mProvidersByName.get(provider); 1317 if (p == null) return; 1318 1319 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1320 WorkSource worksource = new WorkSource(); 1321 ProviderRequest providerRequest = new ProviderRequest(); 1322 1323 if (records != null) { 1324 for (UpdateRecord record : records) { 1325 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { 1326 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName, 1327 record.mReceiver.mAllowedResolutionLevel)) { 1328 LocationRequest locationRequest = record.mRequest; 1329 providerRequest.locationRequests.add(locationRequest); 1330 if (locationRequest.getInterval() < providerRequest.interval) { 1331 providerRequest.reportLocation = true; 1332 providerRequest.interval = locationRequest.getInterval(); 1333 } 1334 } 1335 } 1336 } 1337 1338 if (providerRequest.reportLocation) { 1339 // calculate who to blame for power 1340 // This is somewhat arbitrary. We pick a threshold interval 1341 // that is slightly higher that the minimum interval, and 1342 // spread the blame across all applications with a request 1343 // under that threshold. 1344 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2; 1345 for (UpdateRecord record : records) { 1346 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { 1347 LocationRequest locationRequest = record.mRequest; 1348 if (locationRequest.getInterval() <= thresholdInterval) { 1349 if (record.mReceiver.mWorkSource != null 1350 && record.mReceiver.mWorkSource.size() > 0 1351 && record.mReceiver.mWorkSource.getName(0) != null) { 1352 // Assign blame to another work source. 1353 // Can only assign blame if the WorkSource contains names. 1354 worksource.add(record.mReceiver.mWorkSource); 1355 } else { 1356 // Assign blame to caller. 1357 worksource.add( 1358 record.mReceiver.mUid, 1359 record.mReceiver.mPackageName); 1360 } 1361 } 1362 } 1363 } 1364 } 1365 } 1366 1367 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest); 1368 p.setRequest(providerRequest, worksource); 1369 } 1370 1371 private class UpdateRecord { 1372 final String mProvider; 1373 final LocationRequest mRequest; 1374 final Receiver mReceiver; 1375 Location mLastFixBroadcast; 1376 long mLastStatusBroadcast; 1377 1378 /** 1379 * Note: must be constructed with lock held. 1380 */ 1381 UpdateRecord(String provider, LocationRequest request, Receiver receiver) { 1382 mProvider = provider; 1383 mRequest = request; 1384 mReceiver = receiver; 1385 1386 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1387 if (records == null) { 1388 records = new ArrayList<UpdateRecord>(); 1389 mRecordsByProvider.put(provider, records); 1390 } 1391 if (!records.contains(this)) { 1392 records.add(this); 1393 } 1394 1395 // Update statistics for historical location requests by package/provider 1396 mRequestStatistics.startRequesting( 1397 mReceiver.mPackageName, provider, request.getInterval()); 1398 } 1399 1400 /** 1401 * Method to be called when a record will no longer be used. 1402 */ 1403 void disposeLocked(boolean removeReceiver) { 1404 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider); 1405 1406 // remove from mRecordsByProvider 1407 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider); 1408 if (globalRecords != null) { 1409 globalRecords.remove(this); 1410 } 1411 1412 if (!removeReceiver) return; // the caller will handle the rest 1413 1414 // remove from Receiver#mUpdateRecords 1415 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords; 1416 if (receiverRecords != null) { 1417 receiverRecords.remove(this.mProvider); 1418 1419 // and also remove the Receiver if it has no more update records 1420 if (removeReceiver && receiverRecords.size() == 0) { 1421 removeUpdatesLocked(mReceiver); 1422 } 1423 } 1424 } 1425 1426 @Override 1427 public String toString() { 1428 StringBuilder s = new StringBuilder(); 1429 s.append("UpdateRecord["); 1430 s.append(mProvider); 1431 s.append(' ').append(mReceiver.mPackageName).append('('); 1432 s.append(mReceiver.mUid).append(')'); 1433 s.append(' ').append(mRequest); 1434 s.append(']'); 1435 return s.toString(); 1436 } 1437 } 1438 1439 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid, 1440 String packageName, WorkSource workSource, boolean hideFromAppOps) { 1441 IBinder binder = listener.asBinder(); 1442 Receiver receiver = mReceivers.get(binder); 1443 if (receiver == null) { 1444 receiver = new Receiver(listener, null, pid, uid, packageName, workSource, 1445 hideFromAppOps); 1446 mReceivers.put(binder, receiver); 1447 1448 try { 1449 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1450 } catch (RemoteException e) { 1451 Slog.e(TAG, "linkToDeath failed:", e); 1452 return null; 1453 } 1454 } 1455 return receiver; 1456 } 1457 1458 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName, 1459 WorkSource workSource, boolean hideFromAppOps) { 1460 Receiver receiver = mReceivers.get(intent); 1461 if (receiver == null) { 1462 receiver = new Receiver(null, intent, pid, uid, packageName, workSource, 1463 hideFromAppOps); 1464 mReceivers.put(intent, receiver); 1465 } 1466 return receiver; 1467 } 1468 1469 /** 1470 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution 1471 * and consistency requirements. 1472 * 1473 * @param request the LocationRequest from which to create a sanitized version 1474 * @return a version of request that meets the given resolution and consistency requirements 1475 * @hide 1476 */ 1477 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) { 1478 LocationRequest sanitizedRequest = new LocationRequest(request); 1479 if (resolutionLevel < RESOLUTION_LEVEL_FINE) { 1480 switch (sanitizedRequest.getQuality()) { 1481 case LocationRequest.ACCURACY_FINE: 1482 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK); 1483 break; 1484 case LocationRequest.POWER_HIGH: 1485 sanitizedRequest.setQuality(LocationRequest.POWER_LOW); 1486 break; 1487 } 1488 // throttle 1489 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1490 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 1491 } 1492 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1493 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 1494 } 1495 } 1496 // make getFastestInterval() the minimum of interval and fastest interval 1497 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) { 1498 request.setFastestInterval(request.getInterval()); 1499 } 1500 return sanitizedRequest; 1501 } 1502 1503 private void checkPackageName(String packageName) { 1504 if (packageName == null) { 1505 throw new SecurityException("invalid package name: " + packageName); 1506 } 1507 int uid = Binder.getCallingUid(); 1508 String[] packages = mPackageManager.getPackagesForUid(uid); 1509 if (packages == null) { 1510 throw new SecurityException("invalid UID " + uid); 1511 } 1512 for (String pkg : packages) { 1513 if (packageName.equals(pkg)) return; 1514 } 1515 throw new SecurityException("invalid package name: " + packageName); 1516 } 1517 1518 private void checkPendingIntent(PendingIntent intent) { 1519 if (intent == null) { 1520 throw new IllegalArgumentException("invalid pending intent: " + intent); 1521 } 1522 } 1523 1524 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent, 1525 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) { 1526 if (intent == null && listener == null) { 1527 throw new IllegalArgumentException("need either listener or intent"); 1528 } else if (intent != null && listener != null) { 1529 throw new IllegalArgumentException("cannot register both listener and intent"); 1530 } else if (intent != null) { 1531 checkPendingIntent(intent); 1532 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps); 1533 } else { 1534 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps); 1535 } 1536 } 1537 1538 @Override 1539 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 1540 PendingIntent intent, String packageName) { 1541 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1542 checkPackageName(packageName); 1543 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1544 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1545 request.getProvider()); 1546 WorkSource workSource = request.getWorkSource(); 1547 if (workSource != null && workSource.size() > 0) { 1548 checkDeviceStatsAllowed(); 1549 } 1550 boolean hideFromAppOps = request.getHideFromAppOps(); 1551 if (hideFromAppOps) { 1552 checkUpdateAppOpsAllowed(); 1553 } 1554 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1555 1556 final int pid = Binder.getCallingPid(); 1557 final int uid = Binder.getCallingUid(); 1558 // providers may use public location API's, need to clear identity 1559 long identity = Binder.clearCallingIdentity(); 1560 try { 1561 // We don't check for MODE_IGNORED here; we will do that when we go to deliver 1562 // a location. 1563 checkLocationAccess(uid, packageName, allowedResolutionLevel); 1564 1565 synchronized (mLock) { 1566 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid, 1567 packageName, workSource, hideFromAppOps); 1568 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); 1569 } 1570 } finally { 1571 Binder.restoreCallingIdentity(identity); 1572 } 1573 } 1574 1575 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 1576 int pid, int uid, String packageName) { 1577 // Figure out the provider. Either its explicitly request (legacy use cases), or 1578 // use the fused provider 1579 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1580 String name = request.getProvider(); 1581 if (name == null) { 1582 throw new IllegalArgumentException("provider name must not be null"); 1583 } 1584 1585 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) 1586 + " " + name + " " + request + " from " + packageName + "(" + uid + ")"); 1587 LocationProviderInterface provider = mProvidersByName.get(name); 1588 if (provider == null) { 1589 throw new IllegalArgumentException("provider doesn't exist: " + name); 1590 } 1591 1592 UpdateRecord record = new UpdateRecord(name, request, receiver); 1593 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 1594 if (oldRecord != null) { 1595 oldRecord.disposeLocked(false); 1596 } 1597 1598 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid); 1599 if (isProviderEnabled) { 1600 applyRequirementsLocked(name); 1601 } else { 1602 // Notify the listener that updates are currently disabled 1603 receiver.callProviderEnabledLocked(name, false); 1604 } 1605 // Update the monitoring here just in case multiple location requests were added to the 1606 // same receiver (this request may be high power and the initial might not have been). 1607 receiver.updateMonitoring(true); 1608 } 1609 1610 @Override 1611 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1612 String packageName) { 1613 checkPackageName(packageName); 1614 1615 final int pid = Binder.getCallingPid(); 1616 final int uid = Binder.getCallingUid(); 1617 1618 synchronized (mLock) { 1619 WorkSource workSource = null; 1620 boolean hideFromAppOps = false; 1621 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, 1622 packageName, workSource, hideFromAppOps); 1623 1624 // providers may use public location API's, need to clear identity 1625 long identity = Binder.clearCallingIdentity(); 1626 try { 1627 removeUpdatesLocked(receiver); 1628 } finally { 1629 Binder.restoreCallingIdentity(identity); 1630 } 1631 } 1632 } 1633 1634 private void removeUpdatesLocked(Receiver receiver) { 1635 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1636 1637 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1638 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1639 synchronized (receiver) { 1640 receiver.clearPendingBroadcastsLocked(); 1641 } 1642 } 1643 1644 receiver.updateMonitoring(false); 1645 1646 // Record which providers were associated with this listener 1647 HashSet<String> providers = new HashSet<String>(); 1648 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1649 if (oldRecords != null) { 1650 // Call dispose() on the obsolete update records. 1651 for (UpdateRecord record : oldRecords.values()) { 1652 // Update statistics for historical location requests by package/provider 1653 record.disposeLocked(false); 1654 } 1655 // Accumulate providers 1656 providers.addAll(oldRecords.keySet()); 1657 } 1658 1659 // update provider 1660 for (String provider : providers) { 1661 // If provider is already disabled, don't need to do anything 1662 if (!isAllowedByCurrentUserSettingsLocked(provider)) { 1663 continue; 1664 } 1665 1666 applyRequirementsLocked(provider); 1667 } 1668 } 1669 1670 private void applyAllProviderRequirementsLocked() { 1671 for (LocationProviderInterface p : mProviders) { 1672 // If provider is already disabled, don't need to do anything 1673 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) { 1674 continue; 1675 } 1676 1677 applyRequirementsLocked(p.getName()); 1678 } 1679 } 1680 1681 @Override 1682 public Location getLastLocation(LocationRequest request, String packageName) { 1683 if (D) Log.d(TAG, "getLastLocation: " + request); 1684 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1685 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1686 checkPackageName(packageName); 1687 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1688 request.getProvider()); 1689 // no need to sanitize this request, as only the provider name is used 1690 1691 final int uid = Binder.getCallingUid(); 1692 final long identity = Binder.clearCallingIdentity(); 1693 try { 1694 if (mBlacklist.isBlacklisted(packageName)) { 1695 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1696 packageName); 1697 return null; 1698 } 1699 1700 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) { 1701 if (D) Log.d(TAG, "not returning last loc for no op app: " + 1702 packageName); 1703 return null; 1704 } 1705 1706 synchronized (mLock) { 1707 // Figure out the provider. Either its explicitly request (deprecated API's), 1708 // or use the fused provider 1709 String name = request.getProvider(); 1710 if (name == null) name = LocationManager.FUSED_PROVIDER; 1711 LocationProviderInterface provider = mProvidersByName.get(name); 1712 if (provider == null) return null; 1713 1714 if (!isAllowedByUserSettingsLocked(name, uid)) return null; 1715 1716 Location location; 1717 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1718 // Make sure that an app with coarse permissions can't get frequent location 1719 // updates by calling LocationManager.getLastKnownLocation repeatedly. 1720 location = mLastLocationCoarseInterval.get(name); 1721 } else { 1722 location = mLastLocation.get(name); 1723 } 1724 if (location == null) { 1725 return null; 1726 } 1727 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1728 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 1729 if (noGPSLocation != null) { 1730 return new Location(mLocationFudger.getOrCreate(noGPSLocation)); 1731 } 1732 } else { 1733 return new Location(location); 1734 } 1735 } 1736 return null; 1737 } finally { 1738 Binder.restoreCallingIdentity(identity); 1739 } 1740 } 1741 1742 @Override 1743 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1744 String packageName) { 1745 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1746 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1747 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel); 1748 checkPendingIntent(intent); 1749 checkPackageName(packageName); 1750 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1751 request.getProvider()); 1752 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1753 1754 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent); 1755 1756 // geo-fence manager uses the public location API, need to clear identity 1757 int uid = Binder.getCallingUid(); 1758 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) { 1759 // temporary measure until geofences work for secondary users 1760 Log.w(TAG, "proximity alerts are currently available only to the primary user"); 1761 return; 1762 } 1763 long identity = Binder.clearCallingIdentity(); 1764 try { 1765 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel, 1766 uid, packageName); 1767 } finally { 1768 Binder.restoreCallingIdentity(identity); 1769 } 1770 } 1771 1772 @Override 1773 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1774 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel()); 1775 checkPendingIntent(intent); 1776 checkPackageName(packageName); 1777 1778 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1779 1780 // geo-fence manager uses the public location API, need to clear identity 1781 long identity = Binder.clearCallingIdentity(); 1782 try { 1783 mGeofenceManager.removeFence(geofence, intent); 1784 } finally { 1785 Binder.restoreCallingIdentity(identity); 1786 } 1787 } 1788 1789 1790 @Override 1791 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) { 1792 if (mGpsStatusProvider == null) { 1793 return false; 1794 } 1795 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1796 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1797 LocationManager.GPS_PROVIDER); 1798 1799 final int uid = Binder.getCallingUid(); 1800 final long ident = Binder.clearCallingIdentity(); 1801 try { 1802 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) { 1803 return false; 1804 } 1805 } finally { 1806 Binder.restoreCallingIdentity(ident); 1807 } 1808 1809 try { 1810 mGpsStatusProvider.addGpsStatusListener(listener); 1811 } catch (RemoteException e) { 1812 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1813 return false; 1814 } 1815 return true; 1816 } 1817 1818 @Override 1819 public void removeGpsStatusListener(IGpsStatusListener listener) { 1820 synchronized (mLock) { 1821 try { 1822 mGpsStatusProvider.removeGpsStatusListener(listener); 1823 } catch (Exception e) { 1824 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1825 } 1826 } 1827 } 1828 1829 @Override 1830 public boolean addGpsMeasurementsListener( 1831 IGpsMeasurementsListener listener, 1832 String packageName) { 1833 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1834 checkResolutionLevelIsSufficientForProviderUse( 1835 allowedResolutionLevel, 1836 LocationManager.GPS_PROVIDER); 1837 1838 int uid = Binder.getCallingUid(); 1839 long identity = Binder.clearCallingIdentity(); 1840 boolean hasLocationAccess; 1841 try { 1842 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel); 1843 } finally { 1844 Binder.restoreCallingIdentity(identity); 1845 } 1846 1847 if (!hasLocationAccess) { 1848 return false; 1849 } 1850 1851 return mGpsMeasurementsProvider.addListener(listener); 1852 } 1853 1854 @Override 1855 public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) { 1856 return mGpsMeasurementsProvider.removeListener(listener); 1857 } 1858 1859 @Override 1860 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1861 if (provider == null) { 1862 // throw NullPointerException to remain compatible with previous implementation 1863 throw new NullPointerException(); 1864 } 1865 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1866 provider); 1867 1868 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1869 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1870 != PackageManager.PERMISSION_GRANTED)) { 1871 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1872 } 1873 1874 synchronized (mLock) { 1875 LocationProviderInterface p = mProvidersByName.get(provider); 1876 if (p == null) return false; 1877 1878 return p.sendExtraCommand(command, extras); 1879 } 1880 } 1881 1882 @Override 1883 public boolean sendNiResponse(int notifId, int userResponse) { 1884 if (Binder.getCallingUid() != Process.myUid()) { 1885 throw new SecurityException( 1886 "calling sendNiResponse from outside of the system is not allowed"); 1887 } 1888 try { 1889 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1890 } catch (RemoteException e) { 1891 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1892 return false; 1893 } 1894 } 1895 1896 /** 1897 * @return null if the provider does not exist 1898 * @throws SecurityException if the provider is not allowed to be 1899 * accessed by the caller 1900 */ 1901 @Override 1902 public ProviderProperties getProviderProperties(String provider) { 1903 if (mProvidersByName.get(provider) == null) { 1904 return null; 1905 } 1906 1907 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1908 provider); 1909 1910 LocationProviderInterface p; 1911 synchronized (mLock) { 1912 p = mProvidersByName.get(provider); 1913 } 1914 1915 if (p == null) return null; 1916 return p.getProperties(); 1917 } 1918 1919 @Override 1920 public boolean isProviderEnabled(String provider) { 1921 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs, 1922 // so we discourage its use 1923 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1924 1925 int uid = Binder.getCallingUid(); 1926 long identity = Binder.clearCallingIdentity(); 1927 try { 1928 synchronized (mLock) { 1929 LocationProviderInterface p = mProvidersByName.get(provider); 1930 if (p == null) return false; 1931 1932 return isAllowedByUserSettingsLocked(provider, uid); 1933 } 1934 } finally { 1935 Binder.restoreCallingIdentity(identity); 1936 } 1937 } 1938 1939 /** 1940 * Returns "true" if the UID belongs to a bound location provider. 1941 * 1942 * @param uid the uid 1943 * @return true if uid belongs to a bound location provider 1944 */ 1945 private boolean isUidALocationProvider(int uid) { 1946 if (uid == Process.SYSTEM_UID) { 1947 return true; 1948 } 1949 if (mGeocodeProvider != null) { 1950 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true; 1951 } 1952 for (LocationProviderProxy proxy : mProxyProviders) { 1953 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true; 1954 } 1955 return false; 1956 } 1957 1958 private void checkCallerIsProvider() { 1959 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1960 == PackageManager.PERMISSION_GRANTED) { 1961 return; 1962 } 1963 1964 // Previously we only used the INSTALL_LOCATION_PROVIDER 1965 // check. But that is system or signature 1966 // protection level which is not flexible enough for 1967 // providers installed oustide the system image. So 1968 // also allow providers with a UID matching the 1969 // currently bound package name 1970 1971 if (isUidALocationProvider(Binder.getCallingUid())) { 1972 return; 1973 } 1974 1975 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1976 "or UID of a currently bound location provider"); 1977 } 1978 1979 /** 1980 * Returns true if the given package belongs to the given uid. 1981 */ 1982 private boolean doesUidHavePackage(int uid, String packageName) { 1983 if (packageName == null) { 1984 return false; 1985 } 1986 String[] packageNames = mPackageManager.getPackagesForUid(uid); 1987 if (packageNames == null) { 1988 return false; 1989 } 1990 for (String name : packageNames) { 1991 if (packageName.equals(name)) { 1992 return true; 1993 } 1994 } 1995 return false; 1996 } 1997 1998 @Override 1999 public void reportLocation(Location location, boolean passive) { 2000 checkCallerIsProvider(); 2001 2002 if (!location.isComplete()) { 2003 Log.w(TAG, "Dropping incomplete location: " + location); 2004 return; 2005 } 2006 2007 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 2008 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 2009 m.arg1 = (passive ? 1 : 0); 2010 mLocationHandler.sendMessageAtFrontOfQueue(m); 2011 } 2012 2013 2014 private static boolean shouldBroadcastSafe( 2015 Location loc, Location lastLoc, UpdateRecord record, long now) { 2016 // Always broadcast the first update 2017 if (lastLoc == null) { 2018 return true; 2019 } 2020 2021 // Check whether sufficient time has passed 2022 long minTime = record.mRequest.getFastestInterval(); 2023 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) 2024 / NANOS_PER_MILLI; 2025 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 2026 return false; 2027 } 2028 2029 // Check whether sufficient distance has been traveled 2030 double minDistance = record.mRequest.getSmallestDisplacement(); 2031 if (minDistance > 0.0) { 2032 if (loc.distanceTo(lastLoc) <= minDistance) { 2033 return false; 2034 } 2035 } 2036 2037 // Check whether sufficient number of udpates is left 2038 if (record.mRequest.getNumUpdates() <= 0) { 2039 return false; 2040 } 2041 2042 // Check whether the expiry date has passed 2043 if (record.mRequest.getExpireAt() < now) { 2044 return false; 2045 } 2046 2047 return true; 2048 } 2049 2050 private void handleLocationChangedLocked(Location location, boolean passive) { 2051 if (D) Log.d(TAG, "incoming location: " + location); 2052 2053 long now = SystemClock.elapsedRealtime(); 2054 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 2055 2056 // Skip if the provider is unknown. 2057 LocationProviderInterface p = mProvidersByName.get(provider); 2058 if (p == null) return; 2059 2060 // Update last known locations 2061 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2062 Location lastNoGPSLocation = null; 2063 Location lastLocation = mLastLocation.get(provider); 2064 if (lastLocation == null) { 2065 lastLocation = new Location(provider); 2066 mLastLocation.put(provider, lastLocation); 2067 } else { 2068 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2069 if (noGPSLocation == null && lastNoGPSLocation != null) { 2070 // New location has no no-GPS location: adopt last no-GPS location. This is set 2071 // directly into location because we do not want to notify COARSE clients. 2072 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); 2073 } 2074 } 2075 lastLocation.set(location); 2076 2077 // Update last known coarse interval location if enough time has passed. 2078 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider); 2079 if (lastLocationCoarseInterval == null) { 2080 lastLocationCoarseInterval = new Location(location); 2081 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval); 2082 } 2083 long timeDiffNanos = location.getElapsedRealtimeNanos() 2084 - lastLocationCoarseInterval.getElapsedRealtimeNanos(); 2085 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) { 2086 lastLocationCoarseInterval.set(location); 2087 } 2088 // Don't ever return a coarse location that is more recent than the allowed update 2089 // interval (i.e. don't allow an app to keep registering and unregistering for 2090 // location updates to overcome the minimum interval). 2091 noGPSLocation = 2092 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2093 2094 // Skip if there are no UpdateRecords for this provider. 2095 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 2096 if (records == null || records.size() == 0) return; 2097 2098 // Fetch coarse location 2099 Location coarseLocation = null; 2100 if (noGPSLocation != null) { 2101 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation); 2102 } 2103 2104 // Fetch latest status update time 2105 long newStatusUpdateTime = p.getStatusUpdateTime(); 2106 2107 // Get latest status 2108 Bundle extras = new Bundle(); 2109 int status = p.getStatus(extras); 2110 2111 ArrayList<Receiver> deadReceivers = null; 2112 ArrayList<UpdateRecord> deadUpdateRecords = null; 2113 2114 // Broadcast location or status to all listeners 2115 for (UpdateRecord r : records) { 2116 Receiver receiver = r.mReceiver; 2117 boolean receiverDead = false; 2118 2119 int receiverUserId = UserHandle.getUserId(receiver.mUid); 2120 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) { 2121 if (D) { 2122 Log.d(TAG, "skipping loc update for background user " + receiverUserId + 2123 " (current user: " + mCurrentUserId + ", app: " + 2124 receiver.mPackageName + ")"); 2125 } 2126 continue; 2127 } 2128 2129 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 2130 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 2131 receiver.mPackageName); 2132 continue; 2133 } 2134 2135 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName, 2136 receiver.mAllowedResolutionLevel)) { 2137 if (D) Log.d(TAG, "skipping loc update for no op app: " + 2138 receiver.mPackageName); 2139 continue; 2140 } 2141 2142 Location notifyLocation = null; 2143 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 2144 notifyLocation = coarseLocation; // use coarse location 2145 } else { 2146 notifyLocation = lastLocation; // use fine location 2147 } 2148 if (notifyLocation != null) { 2149 Location lastLoc = r.mLastFixBroadcast; 2150 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) { 2151 if (lastLoc == null) { 2152 lastLoc = new Location(notifyLocation); 2153 r.mLastFixBroadcast = lastLoc; 2154 } else { 2155 lastLoc.set(notifyLocation); 2156 } 2157 if (!receiver.callLocationChangedLocked(notifyLocation)) { 2158 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 2159 receiverDead = true; 2160 } 2161 r.mRequest.decrementNumUpdates(); 2162 } 2163 } 2164 2165 long prevStatusUpdateTime = r.mLastStatusBroadcast; 2166 if ((newStatusUpdateTime > prevStatusUpdateTime) && 2167 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 2168 2169 r.mLastStatusBroadcast = newStatusUpdateTime; 2170 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 2171 receiverDead = true; 2172 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 2173 } 2174 } 2175 2176 // track expired records 2177 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) { 2178 if (deadUpdateRecords == null) { 2179 deadUpdateRecords = new ArrayList<UpdateRecord>(); 2180 } 2181 deadUpdateRecords.add(r); 2182 } 2183 // track dead receivers 2184 if (receiverDead) { 2185 if (deadReceivers == null) { 2186 deadReceivers = new ArrayList<Receiver>(); 2187 } 2188 if (!deadReceivers.contains(receiver)) { 2189 deadReceivers.add(receiver); 2190 } 2191 } 2192 } 2193 2194 // remove dead records and receivers outside the loop 2195 if (deadReceivers != null) { 2196 for (Receiver receiver : deadReceivers) { 2197 removeUpdatesLocked(receiver); 2198 } 2199 } 2200 if (deadUpdateRecords != null) { 2201 for (UpdateRecord r : deadUpdateRecords) { 2202 r.disposeLocked(true); 2203 } 2204 applyRequirementsLocked(provider); 2205 } 2206 } 2207 2208 private class LocationWorkerHandler extends Handler { 2209 public LocationWorkerHandler(Looper looper) { 2210 super(looper, null, true); 2211 } 2212 2213 @Override 2214 public void handleMessage(Message msg) { 2215 switch (msg.what) { 2216 case MSG_LOCATION_CHANGED: 2217 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 2218 break; 2219 } 2220 } 2221 } 2222 2223 private boolean isMockProvider(String provider) { 2224 synchronized (mLock) { 2225 return mMockProviders.containsKey(provider); 2226 } 2227 } 2228 2229 private void handleLocationChanged(Location location, boolean passive) { 2230 // create a working copy of the incoming Location so that the service can modify it without 2231 // disturbing the caller's copy 2232 Location myLocation = new Location(location); 2233 String provider = myLocation.getProvider(); 2234 2235 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this 2236 // bit if location did not come from a mock provider because passive/fused providers can 2237 // forward locations from mock providers, and should not grant them legitimacy in doing so. 2238 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) { 2239 myLocation.setIsFromMockProvider(true); 2240 } 2241 2242 synchronized (mLock) { 2243 if (isAllowedByCurrentUserSettingsLocked(provider)) { 2244 if (!passive) { 2245 // notify passive provider of the new location 2246 mPassiveProvider.updateLocation(myLocation); 2247 } 2248 handleLocationChangedLocked(myLocation, passive); 2249 } 2250 } 2251 } 2252 2253 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 2254 @Override 2255 public void onPackageDisappeared(String packageName, int reason) { 2256 // remove all receivers associated with this package name 2257 synchronized (mLock) { 2258 ArrayList<Receiver> deadReceivers = null; 2259 2260 for (Receiver receiver : mReceivers.values()) { 2261 if (receiver.mPackageName.equals(packageName)) { 2262 if (deadReceivers == null) { 2263 deadReceivers = new ArrayList<Receiver>(); 2264 } 2265 deadReceivers.add(receiver); 2266 } 2267 } 2268 2269 // perform removal outside of mReceivers loop 2270 if (deadReceivers != null) { 2271 for (Receiver receiver : deadReceivers) { 2272 removeUpdatesLocked(receiver); 2273 } 2274 } 2275 } 2276 } 2277 }; 2278 2279 // Geocoder 2280 2281 @Override 2282 public boolean geocoderIsPresent() { 2283 return mGeocodeProvider != null; 2284 } 2285 2286 @Override 2287 public String getFromLocation(double latitude, double longitude, int maxResults, 2288 GeocoderParams params, List<Address> addrs) { 2289 if (mGeocodeProvider != null) { 2290 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 2291 params, addrs); 2292 } 2293 return null; 2294 } 2295 2296 2297 @Override 2298 public String getFromLocationName(String locationName, 2299 double lowerLeftLatitude, double lowerLeftLongitude, 2300 double upperRightLatitude, double upperRightLongitude, int maxResults, 2301 GeocoderParams params, List<Address> addrs) { 2302 2303 if (mGeocodeProvider != null) { 2304 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 2305 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 2306 maxResults, params, addrs); 2307 } 2308 return null; 2309 } 2310 2311 // Mock Providers 2312 2313 private void checkMockPermissionsSafe() { 2314 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2315 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 2316 if (!allowMocks) { 2317 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2318 } 2319 2320 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2321 PackageManager.PERMISSION_GRANTED) { 2322 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2323 } 2324 } 2325 2326 @Override 2327 public void addTestProvider(String name, ProviderProperties properties) { 2328 checkMockPermissionsSafe(); 2329 2330 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 2331 throw new IllegalArgumentException("Cannot mock the passive location provider"); 2332 } 2333 2334 long identity = Binder.clearCallingIdentity(); 2335 synchronized (mLock) { 2336 // remove the real provider if we are replacing GPS or network provider 2337 if (LocationManager.GPS_PROVIDER.equals(name) 2338 || LocationManager.NETWORK_PROVIDER.equals(name) 2339 || LocationManager.FUSED_PROVIDER.equals(name)) { 2340 LocationProviderInterface p = mProvidersByName.get(name); 2341 if (p != null) { 2342 removeProviderLocked(p); 2343 } 2344 } 2345 addTestProviderLocked(name, properties); 2346 updateProvidersLocked(); 2347 } 2348 Binder.restoreCallingIdentity(identity); 2349 } 2350 2351 private void addTestProviderLocked(String name, ProviderProperties properties) { 2352 if (mProvidersByName.get(name) != null) { 2353 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2354 } 2355 MockProvider provider = new MockProvider(name, this, properties); 2356 addProviderLocked(provider); 2357 mMockProviders.put(name, provider); 2358 mLastLocation.put(name, null); 2359 mLastLocationCoarseInterval.put(name, null); 2360 } 2361 2362 @Override 2363 public void removeTestProvider(String provider) { 2364 checkMockPermissionsSafe(); 2365 synchronized (mLock) { 2366 2367 // These methods can't be called after removing the test provider, so first make sure 2368 // we don't leave anything dangling. 2369 clearTestProviderEnabled(provider); 2370 clearTestProviderLocation(provider); 2371 clearTestProviderStatus(provider); 2372 2373 MockProvider mockProvider = mMockProviders.remove(provider); 2374 if (mockProvider == null) { 2375 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2376 } 2377 long identity = Binder.clearCallingIdentity(); 2378 removeProviderLocked(mProvidersByName.get(provider)); 2379 2380 // reinstate real provider if available 2381 LocationProviderInterface realProvider = mRealProviders.get(provider); 2382 if (realProvider != null) { 2383 addProviderLocked(realProvider); 2384 } 2385 mLastLocation.put(provider, null); 2386 mLastLocationCoarseInterval.put(provider, null); 2387 updateProvidersLocked(); 2388 Binder.restoreCallingIdentity(identity); 2389 } 2390 } 2391 2392 @Override 2393 public void setTestProviderLocation(String provider, Location loc) { 2394 checkMockPermissionsSafe(); 2395 synchronized (mLock) { 2396 MockProvider mockProvider = mMockProviders.get(provider); 2397 if (mockProvider == null) { 2398 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2399 } 2400 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 2401 long identity = Binder.clearCallingIdentity(); 2402 mockProvider.setLocation(loc); 2403 Binder.restoreCallingIdentity(identity); 2404 } 2405 } 2406 2407 @Override 2408 public void clearTestProviderLocation(String provider) { 2409 checkMockPermissionsSafe(); 2410 synchronized (mLock) { 2411 MockProvider mockProvider = mMockProviders.get(provider); 2412 if (mockProvider == null) { 2413 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2414 } 2415 mockProvider.clearLocation(); 2416 } 2417 } 2418 2419 @Override 2420 public void setTestProviderEnabled(String provider, boolean enabled) { 2421 checkMockPermissionsSafe(); 2422 synchronized (mLock) { 2423 MockProvider mockProvider = mMockProviders.get(provider); 2424 if (mockProvider == null) { 2425 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2426 } 2427 long identity = Binder.clearCallingIdentity(); 2428 if (enabled) { 2429 mockProvider.enable(); 2430 mEnabledProviders.add(provider); 2431 mDisabledProviders.remove(provider); 2432 } else { 2433 mockProvider.disable(); 2434 mEnabledProviders.remove(provider); 2435 mDisabledProviders.add(provider); 2436 } 2437 updateProvidersLocked(); 2438 Binder.restoreCallingIdentity(identity); 2439 } 2440 } 2441 2442 @Override 2443 public void clearTestProviderEnabled(String provider) { 2444 checkMockPermissionsSafe(); 2445 synchronized (mLock) { 2446 MockProvider mockProvider = mMockProviders.get(provider); 2447 if (mockProvider == null) { 2448 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2449 } 2450 long identity = Binder.clearCallingIdentity(); 2451 mEnabledProviders.remove(provider); 2452 mDisabledProviders.remove(provider); 2453 updateProvidersLocked(); 2454 Binder.restoreCallingIdentity(identity); 2455 } 2456 } 2457 2458 @Override 2459 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2460 checkMockPermissionsSafe(); 2461 synchronized (mLock) { 2462 MockProvider mockProvider = mMockProviders.get(provider); 2463 if (mockProvider == null) { 2464 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2465 } 2466 mockProvider.setStatus(status, extras, updateTime); 2467 } 2468 } 2469 2470 @Override 2471 public void clearTestProviderStatus(String provider) { 2472 checkMockPermissionsSafe(); 2473 synchronized (mLock) { 2474 MockProvider mockProvider = mMockProviders.get(provider); 2475 if (mockProvider == null) { 2476 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2477 } 2478 mockProvider.clearStatus(); 2479 } 2480 } 2481 2482 private void log(String log) { 2483 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2484 Slog.d(TAG, log); 2485 } 2486 } 2487 2488 @Override 2489 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2490 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2491 != PackageManager.PERMISSION_GRANTED) { 2492 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2493 + Binder.getCallingPid() 2494 + ", uid=" + Binder.getCallingUid()); 2495 return; 2496 } 2497 2498 synchronized (mLock) { 2499 pw.println("Current Location Manager state:"); 2500 pw.println(" Location Listeners:"); 2501 for (Receiver receiver : mReceivers.values()) { 2502 pw.println(" " + receiver); 2503 } 2504 pw.println(" Active Records by Provider:"); 2505 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 2506 pw.println(" " + entry.getKey() + ":"); 2507 for (UpdateRecord record : entry.getValue()) { 2508 pw.println(" " + record); 2509 } 2510 } 2511 pw.println(" Historical Records by Provider:"); 2512 for (Map.Entry<PackageProviderKey, PackageStatistics> entry 2513 : mRequestStatistics.statistics.entrySet()) { 2514 PackageProviderKey key = entry.getKey(); 2515 PackageStatistics stats = entry.getValue(); 2516 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats); 2517 } 2518 pw.println(" Last Known Locations:"); 2519 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 2520 String provider = entry.getKey(); 2521 Location location = entry.getValue(); 2522 pw.println(" " + provider + ": " + location); 2523 } 2524 2525 pw.println(" Last Known Locations Coarse Intervals:"); 2526 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) { 2527 String provider = entry.getKey(); 2528 Location location = entry.getValue(); 2529 pw.println(" " + provider + ": " + location); 2530 } 2531 2532 mGeofenceManager.dump(pw); 2533 2534 if (mEnabledProviders.size() > 0) { 2535 pw.println(" Enabled Providers:"); 2536 for (String i : mEnabledProviders) { 2537 pw.println(" " + i); 2538 } 2539 2540 } 2541 if (mDisabledProviders.size() > 0) { 2542 pw.println(" Disabled Providers:"); 2543 for (String i : mDisabledProviders) { 2544 pw.println(" " + i); 2545 } 2546 } 2547 pw.append(" "); 2548 mBlacklist.dump(pw); 2549 if (mMockProviders.size() > 0) { 2550 pw.println(" Mock Providers:"); 2551 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2552 i.getValue().dump(pw, " "); 2553 } 2554 } 2555 2556 pw.append(" fudger: "); 2557 mLocationFudger.dump(fd, pw, args); 2558 2559 if (args.length > 0 && "short".equals(args[0])) { 2560 return; 2561 } 2562 for (LocationProviderInterface provider: mProviders) { 2563 pw.print(provider.getName() + " Internal State"); 2564 if (provider instanceof LocationProviderProxy) { 2565 LocationProviderProxy proxy = (LocationProviderProxy) provider; 2566 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 2567 } 2568 pw.println(":"); 2569 provider.dump(fd, pw, args); 2570 } 2571 } 2572 } 2573} 2574