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