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