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