LocationManagerService.java revision cb3ab221f72fa10a3c72142dd7567161fb9af878
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 try { 1454 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1455 } catch (RemoteException e) { 1456 Slog.e(TAG, "linkToDeath failed:", e); 1457 return null; 1458 } 1459 mReceivers.put(binder, receiver); 1460 } 1461 return receiver; 1462 } 1463 1464 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName, 1465 WorkSource workSource, boolean hideFromAppOps) { 1466 Receiver receiver = mReceivers.get(intent); 1467 if (receiver == null) { 1468 receiver = new Receiver(null, intent, pid, uid, packageName, workSource, 1469 hideFromAppOps); 1470 mReceivers.put(intent, receiver); 1471 } 1472 return receiver; 1473 } 1474 1475 /** 1476 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution 1477 * and consistency requirements. 1478 * 1479 * @param request the LocationRequest from which to create a sanitized version 1480 * @return a version of request that meets the given resolution and consistency requirements 1481 * @hide 1482 */ 1483 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) { 1484 LocationRequest sanitizedRequest = new LocationRequest(request); 1485 if (resolutionLevel < RESOLUTION_LEVEL_FINE) { 1486 switch (sanitizedRequest.getQuality()) { 1487 case LocationRequest.ACCURACY_FINE: 1488 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK); 1489 break; 1490 case LocationRequest.POWER_HIGH: 1491 sanitizedRequest.setQuality(LocationRequest.POWER_LOW); 1492 break; 1493 } 1494 // throttle 1495 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1496 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 1497 } 1498 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1499 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 1500 } 1501 } 1502 // make getFastestInterval() the minimum of interval and fastest interval 1503 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) { 1504 request.setFastestInterval(request.getInterval()); 1505 } 1506 return sanitizedRequest; 1507 } 1508 1509 private void checkPackageName(String packageName) { 1510 if (packageName == null) { 1511 throw new SecurityException("invalid package name: " + packageName); 1512 } 1513 int uid = Binder.getCallingUid(); 1514 String[] packages = mPackageManager.getPackagesForUid(uid); 1515 if (packages == null) { 1516 throw new SecurityException("invalid UID " + uid); 1517 } 1518 for (String pkg : packages) { 1519 if (packageName.equals(pkg)) return; 1520 } 1521 throw new SecurityException("invalid package name: " + packageName); 1522 } 1523 1524 private void checkPendingIntent(PendingIntent intent) { 1525 if (intent == null) { 1526 throw new IllegalArgumentException("invalid pending intent: " + intent); 1527 } 1528 } 1529 1530 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent, 1531 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) { 1532 if (intent == null && listener == null) { 1533 throw new IllegalArgumentException("need either listener or intent"); 1534 } else if (intent != null && listener != null) { 1535 throw new IllegalArgumentException("cannot register both listener and intent"); 1536 } else if (intent != null) { 1537 checkPendingIntent(intent); 1538 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps); 1539 } else { 1540 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps); 1541 } 1542 } 1543 1544 @Override 1545 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 1546 PendingIntent intent, String packageName) { 1547 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1548 checkPackageName(packageName); 1549 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1550 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1551 request.getProvider()); 1552 WorkSource workSource = request.getWorkSource(); 1553 if (workSource != null && workSource.size() > 0) { 1554 checkDeviceStatsAllowed(); 1555 } 1556 boolean hideFromAppOps = request.getHideFromAppOps(); 1557 if (hideFromAppOps) { 1558 checkUpdateAppOpsAllowed(); 1559 } 1560 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1561 1562 final int pid = Binder.getCallingPid(); 1563 final int uid = Binder.getCallingUid(); 1564 // providers may use public location API's, need to clear identity 1565 long identity = Binder.clearCallingIdentity(); 1566 try { 1567 // We don't check for MODE_IGNORED here; we will do that when we go to deliver 1568 // a location. 1569 checkLocationAccess(uid, packageName, allowedResolutionLevel); 1570 1571 synchronized (mLock) { 1572 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid, 1573 packageName, workSource, hideFromAppOps); 1574 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); 1575 } 1576 } finally { 1577 Binder.restoreCallingIdentity(identity); 1578 } 1579 } 1580 1581 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 1582 int pid, int uid, String packageName) { 1583 // Figure out the provider. Either its explicitly request (legacy use cases), or 1584 // use the fused provider 1585 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1586 String name = request.getProvider(); 1587 if (name == null) { 1588 throw new IllegalArgumentException("provider name must not be null"); 1589 } 1590 1591 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) 1592 + " " + name + " " + request + " from " + packageName + "(" + uid + ")"); 1593 LocationProviderInterface provider = mProvidersByName.get(name); 1594 if (provider == null) { 1595 throw new IllegalArgumentException("provider doesn't exist: " + name); 1596 } 1597 1598 UpdateRecord record = new UpdateRecord(name, request, receiver); 1599 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 1600 if (oldRecord != null) { 1601 oldRecord.disposeLocked(false); 1602 } 1603 1604 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid); 1605 if (isProviderEnabled) { 1606 applyRequirementsLocked(name); 1607 } else { 1608 // Notify the listener that updates are currently disabled 1609 receiver.callProviderEnabledLocked(name, false); 1610 } 1611 // Update the monitoring here just in case multiple location requests were added to the 1612 // same receiver (this request may be high power and the initial might not have been). 1613 receiver.updateMonitoring(true); 1614 } 1615 1616 @Override 1617 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1618 String packageName) { 1619 checkPackageName(packageName); 1620 1621 final int pid = Binder.getCallingPid(); 1622 final int uid = Binder.getCallingUid(); 1623 1624 synchronized (mLock) { 1625 WorkSource workSource = null; 1626 boolean hideFromAppOps = false; 1627 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, 1628 packageName, workSource, hideFromAppOps); 1629 1630 // providers may use public location API's, need to clear identity 1631 long identity = Binder.clearCallingIdentity(); 1632 try { 1633 removeUpdatesLocked(receiver); 1634 } finally { 1635 Binder.restoreCallingIdentity(identity); 1636 } 1637 } 1638 } 1639 1640 private void removeUpdatesLocked(Receiver receiver) { 1641 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1642 1643 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1644 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1645 synchronized (receiver) { 1646 receiver.clearPendingBroadcastsLocked(); 1647 } 1648 } 1649 1650 receiver.updateMonitoring(false); 1651 1652 // Record which providers were associated with this listener 1653 HashSet<String> providers = new HashSet<String>(); 1654 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1655 if (oldRecords != null) { 1656 // Call dispose() on the obsolete update records. 1657 for (UpdateRecord record : oldRecords.values()) { 1658 // Update statistics for historical location requests by package/provider 1659 record.disposeLocked(false); 1660 } 1661 // Accumulate providers 1662 providers.addAll(oldRecords.keySet()); 1663 } 1664 1665 // update provider 1666 for (String provider : providers) { 1667 // If provider is already disabled, don't need to do anything 1668 if (!isAllowedByCurrentUserSettingsLocked(provider)) { 1669 continue; 1670 } 1671 1672 applyRequirementsLocked(provider); 1673 } 1674 } 1675 1676 private void applyAllProviderRequirementsLocked() { 1677 for (LocationProviderInterface p : mProviders) { 1678 // If provider is already disabled, don't need to do anything 1679 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) { 1680 continue; 1681 } 1682 1683 applyRequirementsLocked(p.getName()); 1684 } 1685 } 1686 1687 @Override 1688 public Location getLastLocation(LocationRequest request, String packageName) { 1689 if (D) Log.d(TAG, "getLastLocation: " + request); 1690 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1691 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1692 checkPackageName(packageName); 1693 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1694 request.getProvider()); 1695 // no need to sanitize this request, as only the provider name is used 1696 1697 final int uid = Binder.getCallingUid(); 1698 final long identity = Binder.clearCallingIdentity(); 1699 try { 1700 if (mBlacklist.isBlacklisted(packageName)) { 1701 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1702 packageName); 1703 return null; 1704 } 1705 1706 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) { 1707 if (D) Log.d(TAG, "not returning last loc for no op app: " + 1708 packageName); 1709 return null; 1710 } 1711 1712 synchronized (mLock) { 1713 // Figure out the provider. Either its explicitly request (deprecated API's), 1714 // or use the fused provider 1715 String name = request.getProvider(); 1716 if (name == null) name = LocationManager.FUSED_PROVIDER; 1717 LocationProviderInterface provider = mProvidersByName.get(name); 1718 if (provider == null) return null; 1719 1720 if (!isAllowedByUserSettingsLocked(name, uid)) return null; 1721 1722 Location location; 1723 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1724 // Make sure that an app with coarse permissions can't get frequent location 1725 // updates by calling LocationManager.getLastKnownLocation repeatedly. 1726 location = mLastLocationCoarseInterval.get(name); 1727 } else { 1728 location = mLastLocation.get(name); 1729 } 1730 if (location == null) { 1731 return null; 1732 } 1733 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1734 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 1735 if (noGPSLocation != null) { 1736 return new Location(mLocationFudger.getOrCreate(noGPSLocation)); 1737 } 1738 } else { 1739 return new Location(location); 1740 } 1741 } 1742 return null; 1743 } finally { 1744 Binder.restoreCallingIdentity(identity); 1745 } 1746 } 1747 1748 @Override 1749 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1750 String packageName) { 1751 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1752 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1753 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel); 1754 checkPendingIntent(intent); 1755 checkPackageName(packageName); 1756 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1757 request.getProvider()); 1758 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1759 1760 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent); 1761 1762 // geo-fence manager uses the public location API, need to clear identity 1763 int uid = Binder.getCallingUid(); 1764 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) { 1765 // temporary measure until geofences work for secondary users 1766 Log.w(TAG, "proximity alerts are currently available only to the primary user"); 1767 return; 1768 } 1769 long identity = Binder.clearCallingIdentity(); 1770 try { 1771 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel, 1772 uid, packageName); 1773 } finally { 1774 Binder.restoreCallingIdentity(identity); 1775 } 1776 } 1777 1778 @Override 1779 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1780 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel()); 1781 checkPendingIntent(intent); 1782 checkPackageName(packageName); 1783 1784 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1785 1786 // geo-fence manager uses the public location API, need to clear identity 1787 long identity = Binder.clearCallingIdentity(); 1788 try { 1789 mGeofenceManager.removeFence(geofence, intent); 1790 } finally { 1791 Binder.restoreCallingIdentity(identity); 1792 } 1793 } 1794 1795 1796 @Override 1797 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) { 1798 if (mGpsStatusProvider == null) { 1799 return false; 1800 } 1801 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1802 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1803 LocationManager.GPS_PROVIDER); 1804 1805 final int uid = Binder.getCallingUid(); 1806 final long ident = Binder.clearCallingIdentity(); 1807 try { 1808 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) { 1809 return false; 1810 } 1811 } finally { 1812 Binder.restoreCallingIdentity(ident); 1813 } 1814 1815 try { 1816 mGpsStatusProvider.addGpsStatusListener(listener); 1817 } catch (RemoteException e) { 1818 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1819 return false; 1820 } 1821 return true; 1822 } 1823 1824 @Override 1825 public void removeGpsStatusListener(IGpsStatusListener listener) { 1826 synchronized (mLock) { 1827 try { 1828 mGpsStatusProvider.removeGpsStatusListener(listener); 1829 } catch (Exception e) { 1830 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1831 } 1832 } 1833 } 1834 1835 @Override 1836 public boolean addGpsMeasurementsListener( 1837 IGpsMeasurementsListener listener, 1838 String packageName) { 1839 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1840 checkResolutionLevelIsSufficientForProviderUse( 1841 allowedResolutionLevel, 1842 LocationManager.GPS_PROVIDER); 1843 1844 int uid = Binder.getCallingUid(); 1845 long identity = Binder.clearCallingIdentity(); 1846 boolean hasLocationAccess; 1847 try { 1848 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel); 1849 } finally { 1850 Binder.restoreCallingIdentity(identity); 1851 } 1852 1853 if (!hasLocationAccess) { 1854 return false; 1855 } 1856 return mGpsMeasurementsProvider.addListener(listener); 1857 } 1858 1859 @Override 1860 public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) { 1861 return mGpsMeasurementsProvider.removeListener(listener); 1862 } 1863 1864 @Override 1865 public boolean addGpsNavigationMessageListener( 1866 IGpsNavigationMessageListener listener, 1867 String packageName) { 1868 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1869 checkResolutionLevelIsSufficientForProviderUse( 1870 allowedResolutionLevel, 1871 LocationManager.GPS_PROVIDER); 1872 1873 int uid = Binder.getCallingUid(); 1874 long identity = Binder.clearCallingIdentity(); 1875 boolean hasLocationAccess; 1876 try { 1877 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel); 1878 } finally { 1879 Binder.restoreCallingIdentity(identity); 1880 } 1881 1882 if (!hasLocationAccess) { 1883 return false; 1884 } 1885 return mGpsNavigationMessageProvider.addListener(listener); 1886 } 1887 1888 @Override 1889 public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) { 1890 return mGpsNavigationMessageProvider.removeListener(listener); 1891 } 1892 1893 @Override 1894 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1895 if (provider == null) { 1896 // throw NullPointerException to remain compatible with previous implementation 1897 throw new NullPointerException(); 1898 } 1899 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1900 provider); 1901 1902 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1903 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1904 != PackageManager.PERMISSION_GRANTED)) { 1905 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1906 } 1907 1908 synchronized (mLock) { 1909 LocationProviderInterface p = mProvidersByName.get(provider); 1910 if (p == null) return false; 1911 1912 return p.sendExtraCommand(command, extras); 1913 } 1914 } 1915 1916 @Override 1917 public boolean sendNiResponse(int notifId, int userResponse) { 1918 if (Binder.getCallingUid() != Process.myUid()) { 1919 throw new SecurityException( 1920 "calling sendNiResponse from outside of the system is not allowed"); 1921 } 1922 try { 1923 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1924 } catch (RemoteException e) { 1925 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1926 return false; 1927 } 1928 } 1929 1930 /** 1931 * @return null if the provider does not exist 1932 * @throws SecurityException if the provider is not allowed to be 1933 * accessed by the caller 1934 */ 1935 @Override 1936 public ProviderProperties getProviderProperties(String provider) { 1937 if (mProvidersByName.get(provider) == null) { 1938 return null; 1939 } 1940 1941 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1942 provider); 1943 1944 LocationProviderInterface p; 1945 synchronized (mLock) { 1946 p = mProvidersByName.get(provider); 1947 } 1948 1949 if (p == null) return null; 1950 return p.getProperties(); 1951 } 1952 1953 @Override 1954 public boolean isProviderEnabled(String provider) { 1955 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs, 1956 // so we discourage its use 1957 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1958 1959 int uid = Binder.getCallingUid(); 1960 long identity = Binder.clearCallingIdentity(); 1961 try { 1962 synchronized (mLock) { 1963 LocationProviderInterface p = mProvidersByName.get(provider); 1964 if (p == null) return false; 1965 1966 return isAllowedByUserSettingsLocked(provider, uid); 1967 } 1968 } finally { 1969 Binder.restoreCallingIdentity(identity); 1970 } 1971 } 1972 1973 /** 1974 * Returns "true" if the UID belongs to a bound location provider. 1975 * 1976 * @param uid the uid 1977 * @return true if uid belongs to a bound location provider 1978 */ 1979 private boolean isUidALocationProvider(int uid) { 1980 if (uid == Process.SYSTEM_UID) { 1981 return true; 1982 } 1983 if (mGeocodeProvider != null) { 1984 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true; 1985 } 1986 for (LocationProviderProxy proxy : mProxyProviders) { 1987 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true; 1988 } 1989 return false; 1990 } 1991 1992 private void checkCallerIsProvider() { 1993 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1994 == PackageManager.PERMISSION_GRANTED) { 1995 return; 1996 } 1997 1998 // Previously we only used the INSTALL_LOCATION_PROVIDER 1999 // check. But that is system or signature 2000 // protection level which is not flexible enough for 2001 // providers installed oustide the system image. So 2002 // also allow providers with a UID matching the 2003 // currently bound package name 2004 2005 if (isUidALocationProvider(Binder.getCallingUid())) { 2006 return; 2007 } 2008 2009 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 2010 "or UID of a currently bound location provider"); 2011 } 2012 2013 /** 2014 * Returns true if the given package belongs to the given uid. 2015 */ 2016 private boolean doesUidHavePackage(int uid, String packageName) { 2017 if (packageName == null) { 2018 return false; 2019 } 2020 String[] packageNames = mPackageManager.getPackagesForUid(uid); 2021 if (packageNames == null) { 2022 return false; 2023 } 2024 for (String name : packageNames) { 2025 if (packageName.equals(name)) { 2026 return true; 2027 } 2028 } 2029 return false; 2030 } 2031 2032 @Override 2033 public void reportLocation(Location location, boolean passive) { 2034 checkCallerIsProvider(); 2035 2036 if (!location.isComplete()) { 2037 Log.w(TAG, "Dropping incomplete location: " + location); 2038 return; 2039 } 2040 2041 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 2042 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 2043 m.arg1 = (passive ? 1 : 0); 2044 mLocationHandler.sendMessageAtFrontOfQueue(m); 2045 } 2046 2047 2048 private static boolean shouldBroadcastSafe( 2049 Location loc, Location lastLoc, UpdateRecord record, long now) { 2050 // Always broadcast the first update 2051 if (lastLoc == null) { 2052 return true; 2053 } 2054 2055 // Check whether sufficient time has passed 2056 long minTime = record.mRequest.getFastestInterval(); 2057 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) 2058 / NANOS_PER_MILLI; 2059 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 2060 return false; 2061 } 2062 2063 // Check whether sufficient distance has been traveled 2064 double minDistance = record.mRequest.getSmallestDisplacement(); 2065 if (minDistance > 0.0) { 2066 if (loc.distanceTo(lastLoc) <= minDistance) { 2067 return false; 2068 } 2069 } 2070 2071 // Check whether sufficient number of udpates is left 2072 if (record.mRequest.getNumUpdates() <= 0) { 2073 return false; 2074 } 2075 2076 // Check whether the expiry date has passed 2077 if (record.mRequest.getExpireAt() < now) { 2078 return false; 2079 } 2080 2081 return true; 2082 } 2083 2084 private void handleLocationChangedLocked(Location location, boolean passive) { 2085 if (D) Log.d(TAG, "incoming location: " + location); 2086 2087 long now = SystemClock.elapsedRealtime(); 2088 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 2089 2090 // Skip if the provider is unknown. 2091 LocationProviderInterface p = mProvidersByName.get(provider); 2092 if (p == null) return; 2093 2094 // Update last known locations 2095 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2096 Location lastNoGPSLocation = null; 2097 Location lastLocation = mLastLocation.get(provider); 2098 if (lastLocation == null) { 2099 lastLocation = new Location(provider); 2100 mLastLocation.put(provider, lastLocation); 2101 } else { 2102 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2103 if (noGPSLocation == null && lastNoGPSLocation != null) { 2104 // New location has no no-GPS location: adopt last no-GPS location. This is set 2105 // directly into location because we do not want to notify COARSE clients. 2106 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); 2107 } 2108 } 2109 lastLocation.set(location); 2110 2111 // Update last known coarse interval location if enough time has passed. 2112 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider); 2113 if (lastLocationCoarseInterval == null) { 2114 lastLocationCoarseInterval = new Location(location); 2115 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval); 2116 } 2117 long timeDiffNanos = location.getElapsedRealtimeNanos() 2118 - lastLocationCoarseInterval.getElapsedRealtimeNanos(); 2119 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) { 2120 lastLocationCoarseInterval.set(location); 2121 } 2122 // Don't ever return a coarse location that is more recent than the allowed update 2123 // interval (i.e. don't allow an app to keep registering and unregistering for 2124 // location updates to overcome the minimum interval). 2125 noGPSLocation = 2126 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 2127 2128 // Skip if there are no UpdateRecords for this provider. 2129 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 2130 if (records == null || records.size() == 0) return; 2131 2132 // Fetch coarse location 2133 Location coarseLocation = null; 2134 if (noGPSLocation != null) { 2135 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation); 2136 } 2137 2138 // Fetch latest status update time 2139 long newStatusUpdateTime = p.getStatusUpdateTime(); 2140 2141 // Get latest status 2142 Bundle extras = new Bundle(); 2143 int status = p.getStatus(extras); 2144 2145 ArrayList<Receiver> deadReceivers = null; 2146 ArrayList<UpdateRecord> deadUpdateRecords = null; 2147 2148 // Broadcast location or status to all listeners 2149 for (UpdateRecord r : records) { 2150 Receiver receiver = r.mReceiver; 2151 boolean receiverDead = false; 2152 2153 int receiverUserId = UserHandle.getUserId(receiver.mUid); 2154 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) { 2155 if (D) { 2156 Log.d(TAG, "skipping loc update for background user " + receiverUserId + 2157 " (current user: " + mCurrentUserId + ", app: " + 2158 receiver.mPackageName + ")"); 2159 } 2160 continue; 2161 } 2162 2163 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 2164 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 2165 receiver.mPackageName); 2166 continue; 2167 } 2168 2169 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName, 2170 receiver.mAllowedResolutionLevel)) { 2171 if (D) Log.d(TAG, "skipping loc update for no op app: " + 2172 receiver.mPackageName); 2173 continue; 2174 } 2175 2176 Location notifyLocation = null; 2177 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 2178 notifyLocation = coarseLocation; // use coarse location 2179 } else { 2180 notifyLocation = lastLocation; // use fine location 2181 } 2182 if (notifyLocation != null) { 2183 Location lastLoc = r.mLastFixBroadcast; 2184 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) { 2185 if (lastLoc == null) { 2186 lastLoc = new Location(notifyLocation); 2187 r.mLastFixBroadcast = lastLoc; 2188 } else { 2189 lastLoc.set(notifyLocation); 2190 } 2191 if (!receiver.callLocationChangedLocked(notifyLocation)) { 2192 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 2193 receiverDead = true; 2194 } 2195 r.mRequest.decrementNumUpdates(); 2196 } 2197 } 2198 2199 long prevStatusUpdateTime = r.mLastStatusBroadcast; 2200 if ((newStatusUpdateTime > prevStatusUpdateTime) && 2201 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 2202 2203 r.mLastStatusBroadcast = newStatusUpdateTime; 2204 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 2205 receiverDead = true; 2206 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 2207 } 2208 } 2209 2210 // track expired records 2211 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) { 2212 if (deadUpdateRecords == null) { 2213 deadUpdateRecords = new ArrayList<UpdateRecord>(); 2214 } 2215 deadUpdateRecords.add(r); 2216 } 2217 // track dead receivers 2218 if (receiverDead) { 2219 if (deadReceivers == null) { 2220 deadReceivers = new ArrayList<Receiver>(); 2221 } 2222 if (!deadReceivers.contains(receiver)) { 2223 deadReceivers.add(receiver); 2224 } 2225 } 2226 } 2227 2228 // remove dead records and receivers outside the loop 2229 if (deadReceivers != null) { 2230 for (Receiver receiver : deadReceivers) { 2231 removeUpdatesLocked(receiver); 2232 } 2233 } 2234 if (deadUpdateRecords != null) { 2235 for (UpdateRecord r : deadUpdateRecords) { 2236 r.disposeLocked(true); 2237 } 2238 applyRequirementsLocked(provider); 2239 } 2240 } 2241 2242 private class LocationWorkerHandler extends Handler { 2243 public LocationWorkerHandler(Looper looper) { 2244 super(looper, null, true); 2245 } 2246 2247 @Override 2248 public void handleMessage(Message msg) { 2249 switch (msg.what) { 2250 case MSG_LOCATION_CHANGED: 2251 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 2252 break; 2253 } 2254 } 2255 } 2256 2257 private boolean isMockProvider(String provider) { 2258 synchronized (mLock) { 2259 return mMockProviders.containsKey(provider); 2260 } 2261 } 2262 2263 private void handleLocationChanged(Location location, boolean passive) { 2264 // create a working copy of the incoming Location so that the service can modify it without 2265 // disturbing the caller's copy 2266 Location myLocation = new Location(location); 2267 String provider = myLocation.getProvider(); 2268 2269 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this 2270 // bit if location did not come from a mock provider because passive/fused providers can 2271 // forward locations from mock providers, and should not grant them legitimacy in doing so. 2272 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) { 2273 myLocation.setIsFromMockProvider(true); 2274 } 2275 2276 synchronized (mLock) { 2277 if (isAllowedByCurrentUserSettingsLocked(provider)) { 2278 if (!passive) { 2279 // notify passive provider of the new location 2280 mPassiveProvider.updateLocation(myLocation); 2281 } 2282 handleLocationChangedLocked(myLocation, passive); 2283 } 2284 } 2285 } 2286 2287 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 2288 @Override 2289 public void onPackageDisappeared(String packageName, int reason) { 2290 // remove all receivers associated with this package name 2291 synchronized (mLock) { 2292 ArrayList<Receiver> deadReceivers = null; 2293 2294 for (Receiver receiver : mReceivers.values()) { 2295 if (receiver.mPackageName.equals(packageName)) { 2296 if (deadReceivers == null) { 2297 deadReceivers = new ArrayList<Receiver>(); 2298 } 2299 deadReceivers.add(receiver); 2300 } 2301 } 2302 2303 // perform removal outside of mReceivers loop 2304 if (deadReceivers != null) { 2305 for (Receiver receiver : deadReceivers) { 2306 removeUpdatesLocked(receiver); 2307 } 2308 } 2309 } 2310 } 2311 }; 2312 2313 // Geocoder 2314 2315 @Override 2316 public boolean geocoderIsPresent() { 2317 return mGeocodeProvider != null; 2318 } 2319 2320 @Override 2321 public String getFromLocation(double latitude, double longitude, int maxResults, 2322 GeocoderParams params, List<Address> addrs) { 2323 if (mGeocodeProvider != null) { 2324 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 2325 params, addrs); 2326 } 2327 return null; 2328 } 2329 2330 2331 @Override 2332 public String getFromLocationName(String locationName, 2333 double lowerLeftLatitude, double lowerLeftLongitude, 2334 double upperRightLatitude, double upperRightLongitude, int maxResults, 2335 GeocoderParams params, List<Address> addrs) { 2336 2337 if (mGeocodeProvider != null) { 2338 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 2339 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 2340 maxResults, params, addrs); 2341 } 2342 return null; 2343 } 2344 2345 // Mock Providers 2346 2347 private void checkMockPermissionsSafe() { 2348 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2349 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 2350 if (!allowMocks) { 2351 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2352 } 2353 2354 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2355 PackageManager.PERMISSION_GRANTED) { 2356 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2357 } 2358 } 2359 2360 @Override 2361 public void addTestProvider(String name, ProviderProperties properties) { 2362 checkMockPermissionsSafe(); 2363 2364 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 2365 throw new IllegalArgumentException("Cannot mock the passive location provider"); 2366 } 2367 2368 long identity = Binder.clearCallingIdentity(); 2369 synchronized (mLock) { 2370 // remove the real provider if we are replacing GPS or network provider 2371 if (LocationManager.GPS_PROVIDER.equals(name) 2372 || LocationManager.NETWORK_PROVIDER.equals(name) 2373 || LocationManager.FUSED_PROVIDER.equals(name)) { 2374 LocationProviderInterface p = mProvidersByName.get(name); 2375 if (p != null) { 2376 removeProviderLocked(p); 2377 } 2378 } 2379 addTestProviderLocked(name, properties); 2380 updateProvidersLocked(); 2381 } 2382 Binder.restoreCallingIdentity(identity); 2383 } 2384 2385 private void addTestProviderLocked(String name, ProviderProperties properties) { 2386 if (mProvidersByName.get(name) != null) { 2387 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2388 } 2389 MockProvider provider = new MockProvider(name, this, properties); 2390 addProviderLocked(provider); 2391 mMockProviders.put(name, provider); 2392 mLastLocation.put(name, null); 2393 mLastLocationCoarseInterval.put(name, null); 2394 } 2395 2396 @Override 2397 public void removeTestProvider(String provider) { 2398 checkMockPermissionsSafe(); 2399 synchronized (mLock) { 2400 2401 // These methods can't be called after removing the test provider, so first make sure 2402 // we don't leave anything dangling. 2403 clearTestProviderEnabled(provider); 2404 clearTestProviderLocation(provider); 2405 clearTestProviderStatus(provider); 2406 2407 MockProvider mockProvider = mMockProviders.remove(provider); 2408 if (mockProvider == null) { 2409 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2410 } 2411 long identity = Binder.clearCallingIdentity(); 2412 removeProviderLocked(mProvidersByName.get(provider)); 2413 2414 // reinstate real provider if available 2415 LocationProviderInterface realProvider = mRealProviders.get(provider); 2416 if (realProvider != null) { 2417 addProviderLocked(realProvider); 2418 } 2419 mLastLocation.put(provider, null); 2420 mLastLocationCoarseInterval.put(provider, null); 2421 updateProvidersLocked(); 2422 Binder.restoreCallingIdentity(identity); 2423 } 2424 } 2425 2426 @Override 2427 public void setTestProviderLocation(String provider, Location loc) { 2428 checkMockPermissionsSafe(); 2429 synchronized (mLock) { 2430 MockProvider mockProvider = mMockProviders.get(provider); 2431 if (mockProvider == null) { 2432 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2433 } 2434 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 2435 long identity = Binder.clearCallingIdentity(); 2436 mockProvider.setLocation(loc); 2437 Binder.restoreCallingIdentity(identity); 2438 } 2439 } 2440 2441 @Override 2442 public void clearTestProviderLocation(String provider) { 2443 checkMockPermissionsSafe(); 2444 synchronized (mLock) { 2445 MockProvider mockProvider = mMockProviders.get(provider); 2446 if (mockProvider == null) { 2447 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2448 } 2449 mockProvider.clearLocation(); 2450 } 2451 } 2452 2453 @Override 2454 public void setTestProviderEnabled(String provider, boolean enabled) { 2455 checkMockPermissionsSafe(); 2456 synchronized (mLock) { 2457 MockProvider mockProvider = mMockProviders.get(provider); 2458 if (mockProvider == null) { 2459 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2460 } 2461 long identity = Binder.clearCallingIdentity(); 2462 if (enabled) { 2463 mockProvider.enable(); 2464 mEnabledProviders.add(provider); 2465 mDisabledProviders.remove(provider); 2466 } else { 2467 mockProvider.disable(); 2468 mEnabledProviders.remove(provider); 2469 mDisabledProviders.add(provider); 2470 } 2471 updateProvidersLocked(); 2472 Binder.restoreCallingIdentity(identity); 2473 } 2474 } 2475 2476 @Override 2477 public void clearTestProviderEnabled(String provider) { 2478 checkMockPermissionsSafe(); 2479 synchronized (mLock) { 2480 MockProvider mockProvider = mMockProviders.get(provider); 2481 if (mockProvider == null) { 2482 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2483 } 2484 long identity = Binder.clearCallingIdentity(); 2485 mEnabledProviders.remove(provider); 2486 mDisabledProviders.remove(provider); 2487 updateProvidersLocked(); 2488 Binder.restoreCallingIdentity(identity); 2489 } 2490 } 2491 2492 @Override 2493 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2494 checkMockPermissionsSafe(); 2495 synchronized (mLock) { 2496 MockProvider mockProvider = mMockProviders.get(provider); 2497 if (mockProvider == null) { 2498 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2499 } 2500 mockProvider.setStatus(status, extras, updateTime); 2501 } 2502 } 2503 2504 @Override 2505 public void clearTestProviderStatus(String provider) { 2506 checkMockPermissionsSafe(); 2507 synchronized (mLock) { 2508 MockProvider mockProvider = mMockProviders.get(provider); 2509 if (mockProvider == null) { 2510 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2511 } 2512 mockProvider.clearStatus(); 2513 } 2514 } 2515 2516 private void log(String log) { 2517 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2518 Slog.d(TAG, log); 2519 } 2520 } 2521 2522 @Override 2523 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2524 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2525 != PackageManager.PERMISSION_GRANTED) { 2526 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2527 + Binder.getCallingPid() 2528 + ", uid=" + Binder.getCallingUid()); 2529 return; 2530 } 2531 2532 synchronized (mLock) { 2533 pw.println("Current Location Manager state:"); 2534 pw.println(" Location Listeners:"); 2535 for (Receiver receiver : mReceivers.values()) { 2536 pw.println(" " + receiver); 2537 } 2538 pw.println(" Active Records by Provider:"); 2539 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 2540 pw.println(" " + entry.getKey() + ":"); 2541 for (UpdateRecord record : entry.getValue()) { 2542 pw.println(" " + record); 2543 } 2544 } 2545 pw.println(" Historical Records by Provider:"); 2546 for (Map.Entry<PackageProviderKey, PackageStatistics> entry 2547 : mRequestStatistics.statistics.entrySet()) { 2548 PackageProviderKey key = entry.getKey(); 2549 PackageStatistics stats = entry.getValue(); 2550 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats); 2551 } 2552 pw.println(" Last Known Locations:"); 2553 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 2554 String provider = entry.getKey(); 2555 Location location = entry.getValue(); 2556 pw.println(" " + provider + ": " + location); 2557 } 2558 2559 pw.println(" Last Known Locations Coarse Intervals:"); 2560 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) { 2561 String provider = entry.getKey(); 2562 Location location = entry.getValue(); 2563 pw.println(" " + provider + ": " + location); 2564 } 2565 2566 mGeofenceManager.dump(pw); 2567 2568 if (mEnabledProviders.size() > 0) { 2569 pw.println(" Enabled Providers:"); 2570 for (String i : mEnabledProviders) { 2571 pw.println(" " + i); 2572 } 2573 2574 } 2575 if (mDisabledProviders.size() > 0) { 2576 pw.println(" Disabled Providers:"); 2577 for (String i : mDisabledProviders) { 2578 pw.println(" " + i); 2579 } 2580 } 2581 pw.append(" "); 2582 mBlacklist.dump(pw); 2583 if (mMockProviders.size() > 0) { 2584 pw.println(" Mock Providers:"); 2585 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2586 i.getValue().dump(pw, " "); 2587 } 2588 } 2589 2590 pw.append(" fudger: "); 2591 mLocationFudger.dump(fd, pw, args); 2592 2593 if (args.length > 0 && "short".equals(args[0])) { 2594 return; 2595 } 2596 for (LocationProviderInterface provider: mProviders) { 2597 pw.print(provider.getName() + " Internal State"); 2598 if (provider instanceof LocationProviderProxy) { 2599 LocationProviderProxy proxy = (LocationProviderProxy) provider; 2600 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 2601 } 2602 pw.println(":"); 2603 provider.dump(fd, pw, args); 2604 } 2605 } 2606 } 2607} 2608