LocationManagerService.java revision 37425c3475877f2fdadb78f669ec57fecf82dca7
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.PendingIntent; 20import android.content.BroadcastReceiver; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.content.res.Resources; 29import android.database.ContentObserver; 30import android.location.Address; 31import android.location.Criteria; 32import android.location.GeocoderParams; 33import android.location.Geofence; 34import android.location.IGpsStatusListener; 35import android.location.IGpsStatusProvider; 36import android.location.ILocationListener; 37import android.location.ILocationManager; 38import android.location.INetInitiatedListener; 39import android.location.Location; 40import android.location.LocationManager; 41import android.location.LocationProvider; 42import android.location.LocationRequest; 43import android.os.Binder; 44import android.os.Bundle; 45import android.os.Handler; 46import android.os.IBinder; 47import android.os.Looper; 48import android.os.Message; 49import android.os.PowerManager; 50import android.os.Process; 51import android.os.RemoteException; 52import android.os.SystemClock; 53import android.os.UserHandle; 54import android.os.WorkSource; 55import android.provider.Settings; 56import android.util.Log; 57import android.util.Slog; 58 59import com.android.internal.content.PackageMonitor; 60import com.android.internal.location.ProviderProperties; 61import com.android.internal.location.ProviderRequest; 62import com.android.server.location.GeocoderProxy; 63import com.android.server.location.GeofenceManager; 64import com.android.server.location.GpsLocationProvider; 65import com.android.server.location.LocationBlacklist; 66import com.android.server.location.LocationFudger; 67import com.android.server.location.LocationProviderInterface; 68import com.android.server.location.LocationProviderProxy; 69import com.android.server.location.MockProvider; 70import com.android.server.location.PassiveProvider; 71 72import java.io.FileDescriptor; 73import java.io.PrintWriter; 74import java.util.ArrayList; 75import java.util.Arrays; 76import java.util.HashMap; 77import java.util.HashSet; 78import java.util.List; 79import java.util.Map; 80import java.util.Set; 81 82/** 83 * The service class that manages LocationProviders and issues location 84 * updates and alerts. 85 */ 86public class LocationManagerService extends ILocationManager.Stub implements Runnable { 87 private static final String TAG = "LocationManagerService"; 88 public static final boolean D = false; 89 90 private static final String WAKELOCK_KEY = TAG; 91 private static final String THREAD_NAME = TAG; 92 93 // Location resolution level: no location data whatsoever 94 private static final int RESOLUTION_LEVEL_NONE = 0; 95 // Location resolution level: coarse location data only 96 private static final int RESOLUTION_LEVEL_COARSE = 1; 97 // Location resolution level: fine location data 98 private static final int RESOLUTION_LEVEL_FINE = 2; 99 100 private static final String ACCESS_MOCK_LOCATION = 101 android.Manifest.permission.ACCESS_MOCK_LOCATION; 102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 104 private static final String INSTALL_LOCATION_PROVIDER = 105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER; 106 107 private static final String NETWORK_LOCATION_SERVICE_ACTION = 108 "com.android.location.service.v2.NetworkLocationProvider"; 109 private static final String FUSED_LOCATION_SERVICE_ACTION = 110 "com.android.location.service.FusedLocationProvider"; 111 112 private static final int MSG_LOCATION_CHANGED = 1; 113 114 // Location Providers may sometimes deliver location updates 115 // slightly faster that requested - provide grace period so 116 // we don't unnecessarily filter events that are otherwise on 117 // time 118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100; 119 120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest(); 121 122 private final Context mContext; 123 124 // used internally for synchronization 125 private final Object mLock = new Object(); 126 127 // --- fields below are final after init() --- 128 private LocationFudger mLocationFudger; 129 private GeofenceManager mGeofenceManager; 130 private PowerManager.WakeLock mWakeLock; 131 private PackageManager mPackageManager; 132 private GeocoderProxy mGeocodeProvider; 133 private IGpsStatusProvider mGpsStatusProvider; 134 private INetInitiatedListener mNetInitiatedListener; 135 private LocationWorkerHandler mLocationHandler; 136 private PassiveProvider mPassiveProvider; // track passive provider for special cases 137 private LocationBlacklist mBlacklist; 138 139 // --- fields below are protected by mWakeLock --- 140 private int mPendingBroadcasts; 141 142 // --- fields below are protected by mLock --- 143 // Set of providers that are explicitly enabled 144 private final Set<String> mEnabledProviders = new HashSet<String>(); 145 146 // Set of providers that are explicitly disabled 147 private final Set<String> mDisabledProviders = new HashSet<String>(); 148 149 // Mock (test) providers 150 private final HashMap<String, MockProvider> mMockProviders = 151 new HashMap<String, MockProvider>(); 152 153 // all receivers 154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 155 156 // currently installed providers (with mocks replacing real providers) 157 private final ArrayList<LocationProviderInterface> mProviders = 158 new ArrayList<LocationProviderInterface>(); 159 160 // real providers, saved here when mocked out 161 private final HashMap<String, LocationProviderInterface> mRealProviders = 162 new HashMap<String, LocationProviderInterface>(); 163 164 // mapping from provider name to provider 165 private final HashMap<String, LocationProviderInterface> mProvidersByName = 166 new HashMap<String, LocationProviderInterface>(); 167 168 // mapping from provider name to all its UpdateRecords 169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider = 170 new HashMap<String, ArrayList<UpdateRecord>>(); 171 172 // mapping from provider name to last known location 173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>(); 174 175 // all providers that operate over proxy, for authorizing incoming location 176 private final ArrayList<LocationProviderProxy> mProxyProviders = 177 new ArrayList<LocationProviderProxy>(); 178 179 // current active user on the device - other users are denied location data 180 private int mCurrentUserId = UserHandle.USER_OWNER; 181 182 public LocationManagerService(Context context) { 183 super(); 184 mContext = context; 185 186 if (D) Log.d(TAG, "Constructed"); 187 188 // most startup is deferred until systemReady() 189 } 190 191 public void systemReady() { 192 Thread thread = new Thread(null, this, THREAD_NAME); 193 thread.start(); 194 } 195 196 @Override 197 public void run() { 198 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 199 Looper.prepare(); 200 mLocationHandler = new LocationWorkerHandler(); 201 init(); 202 Looper.loop(); 203 } 204 205 private void init() { 206 if (D) Log.d(TAG, "init()"); 207 208 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 209 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 210 mPackageManager = mContext.getPackageManager(); 211 212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler); 213 mBlacklist.init(); 214 mLocationFudger = new LocationFudger(mContext, mLocationHandler); 215 216 synchronized (mLock) { 217 loadProvidersLocked(); 218 } 219 220 mGeofenceManager = new GeofenceManager(mContext, mBlacklist); 221 222 // listen for settings changes 223 mContext.getContentResolver().registerContentObserver( 224 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true, 225 new ContentObserver(mLocationHandler) { 226 @Override 227 public void onChange(boolean selfChange) { 228 synchronized (mLock) { 229 updateProvidersLocked(); 230 } 231 } 232 }, UserHandle.USER_ALL); 233 mPackageMonitor.register(mContext, Looper.myLooper(), true); 234 235 // listen for user change 236 IntentFilter intentFilter = new IntentFilter(); 237 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 238 239 mContext.registerReceiverAsUser(new BroadcastReceiver() { 240 @Override 241 public void onReceive(Context context, Intent intent) { 242 String action = intent.getAction(); 243 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 244 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 245 } 246 } 247 }, UserHandle.ALL, intentFilter, null, null); 248 249 updateProvidersLocked(); 250 } 251 252 private void loadProvidersLocked() { 253 // create a passive location provider, which is always enabled 254 PassiveProvider passiveProvider = new PassiveProvider(this); 255 addProviderLocked(passiveProvider); 256 mEnabledProviders.add(passiveProvider.getName()); 257 mPassiveProvider = passiveProvider; 258 259 if (GpsLocationProvider.isSupported()) { 260 // Create a gps location provider 261 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); 262 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 263 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 264 addProviderLocked(gpsProvider); 265 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); 266 } 267 268 /* 269 Load package name(s) containing location provider support. 270 These packages can contain services implementing location providers: 271 Geocoder Provider, Network Location Provider, and 272 Fused Location Provider. They will each be searched for 273 service components implementing these providers. 274 The location framework also has support for installation 275 of new location providers at run-time. The new package does not 276 have to be explicitly listed here, however it must have a signature 277 that matches the signature of at least one package on this list. 278 */ 279 Resources resources = mContext.getResources(); 280 ArrayList<String> providerPackageNames = new ArrayList<String>(); 281 String[] pkgs1 = resources.getStringArray( 282 com.android.internal.R.array.config_locationProviderPackageNames); 283 String[] pkgs2 = resources.getStringArray( 284 com.android.internal.R.array.config_overlay_locationProviderPackageNames); 285 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); 286 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2)); 287 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); 288 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2)); 289 290 // bind to network provider 291 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( 292 mContext, 293 LocationManager.NETWORK_PROVIDER, 294 NETWORK_LOCATION_SERVICE_ACTION, 295 providerPackageNames, mLocationHandler, mCurrentUserId); 296 if (networkProvider != null) { 297 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); 298 mProxyProviders.add(networkProvider); 299 addProviderLocked(networkProvider); 300 } else { 301 Slog.w(TAG, "no network location provider found"); 302 } 303 304 // bind to fused provider 305 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind( 306 mContext, 307 LocationManager.FUSED_PROVIDER, 308 FUSED_LOCATION_SERVICE_ACTION, 309 providerPackageNames, mLocationHandler, mCurrentUserId); 310 if (fusedLocationProvider != null) { 311 addProviderLocked(fusedLocationProvider); 312 mProxyProviders.add(fusedLocationProvider); 313 mEnabledProviders.add(fusedLocationProvider.getName()); 314 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider); 315 } else { 316 Slog.e(TAG, "no fused location provider found", 317 new IllegalStateException("Location service needs a fused location provider")); 318 } 319 320 // bind to geocoder provider 321 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames, 322 mCurrentUserId); 323 if (mGeocodeProvider == null) { 324 Slog.e(TAG, "no geocoder provider found"); 325 } 326 } 327 328 /** 329 * Called when the device's active user changes. 330 * @param userId the new active user's UserId 331 */ 332 private void switchUser(int userId) { 333 mBlacklist.switchUser(userId); 334 synchronized (mLock) { 335 mLastLocation.clear(); 336 for (LocationProviderInterface p : mProviders) { 337 updateProviderListenersLocked(p.getName(), false, mCurrentUserId); 338 p.switchUser(userId); 339 } 340 mCurrentUserId = userId; 341 updateProvidersLocked(); 342 } 343 } 344 345 /** 346 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 347 * location updates. 348 */ 349 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 350 final int mUid; // uid of receiver 351 final int mPid; // pid of receiver 352 final String mPackageName; // package name of receiver 353 final int mAllowedResolutionLevel; // resolution level allowed to receiver 354 355 final ILocationListener mListener; 356 final PendingIntent mPendingIntent; 357 final Object mKey; 358 359 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 360 361 int mPendingBroadcasts; 362 363 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, 364 String packageName) { 365 mListener = listener; 366 mPendingIntent = intent; 367 if (listener != null) { 368 mKey = listener.asBinder(); 369 } else { 370 mKey = intent; 371 } 372 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid); 373 mUid = uid; 374 mPid = pid; 375 mPackageName = packageName; 376 } 377 378 @Override 379 public boolean equals(Object otherObj) { 380 if (otherObj instanceof Receiver) { 381 return mKey.equals(((Receiver)otherObj).mKey); 382 } 383 return false; 384 } 385 386 @Override 387 public int hashCode() { 388 return mKey.hashCode(); 389 } 390 391 @Override 392 public String toString() { 393 StringBuilder s = new StringBuilder(); 394 s.append("Reciever["); 395 s.append(Integer.toHexString(System.identityHashCode(this))); 396 if (mListener != null) { 397 s.append(" listener"); 398 } else { 399 s.append(" intent"); 400 } 401 for (String p : mUpdateRecords.keySet()) { 402 s.append(" ").append(mUpdateRecords.get(p).toString()); 403 } 404 s.append("]"); 405 return s.toString(); 406 } 407 408 public boolean isListener() { 409 return mListener != null; 410 } 411 412 public boolean isPendingIntent() { 413 return mPendingIntent != null; 414 } 415 416 public ILocationListener getListener() { 417 if (mListener != null) { 418 return mListener; 419 } 420 throw new IllegalStateException("Request for non-existent listener"); 421 } 422 423 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 424 if (mListener != null) { 425 try { 426 synchronized (this) { 427 // synchronize to ensure incrementPendingBroadcastsLocked() 428 // is called before decrementPendingBroadcasts() 429 mListener.onStatusChanged(provider, status, extras); 430 // call this after broadcasting so we do not increment 431 // if we throw an exeption. 432 incrementPendingBroadcastsLocked(); 433 } 434 } catch (RemoteException e) { 435 return false; 436 } 437 } else { 438 Intent statusChanged = new Intent(); 439 statusChanged.putExtras(extras); 440 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 441 try { 442 synchronized (this) { 443 // synchronize to ensure incrementPendingBroadcastsLocked() 444 // is called before decrementPendingBroadcasts() 445 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, 446 getResolutionPermission(mAllowedResolutionLevel)); 447 // call this after broadcasting so we do not increment 448 // if we throw an exeption. 449 incrementPendingBroadcastsLocked(); 450 } 451 } catch (PendingIntent.CanceledException e) { 452 return false; 453 } 454 } 455 return true; 456 } 457 458 public boolean callLocationChangedLocked(Location location) { 459 if (mListener != null) { 460 try { 461 synchronized (this) { 462 // synchronize to ensure incrementPendingBroadcastsLocked() 463 // is called before decrementPendingBroadcasts() 464 mListener.onLocationChanged(location); 465 // call this after broadcasting so we do not increment 466 // if we throw an exeption. 467 incrementPendingBroadcastsLocked(); 468 } 469 } catch (RemoteException e) { 470 return false; 471 } 472 } else { 473 Intent locationChanged = new Intent(); 474 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 475 try { 476 synchronized (this) { 477 // synchronize to ensure incrementPendingBroadcastsLocked() 478 // is called before decrementPendingBroadcasts() 479 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, 480 getResolutionPermission(mAllowedResolutionLevel)); 481 // call this after broadcasting so we do not increment 482 // if we throw an exeption. 483 incrementPendingBroadcastsLocked(); 484 } 485 } catch (PendingIntent.CanceledException e) { 486 return false; 487 } 488 } 489 return true; 490 } 491 492 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 493 if (mListener != null) { 494 try { 495 synchronized (this) { 496 // synchronize to ensure incrementPendingBroadcastsLocked() 497 // is called before decrementPendingBroadcasts() 498 if (enabled) { 499 mListener.onProviderEnabled(provider); 500 } else { 501 mListener.onProviderDisabled(provider); 502 } 503 // call this after broadcasting so we do not increment 504 // if we throw an exeption. 505 incrementPendingBroadcastsLocked(); 506 } 507 } catch (RemoteException e) { 508 return false; 509 } 510 } else { 511 Intent providerIntent = new Intent(); 512 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 513 try { 514 synchronized (this) { 515 // synchronize to ensure incrementPendingBroadcastsLocked() 516 // is called before decrementPendingBroadcasts() 517 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, 518 getResolutionPermission(mAllowedResolutionLevel)); 519 // call this after broadcasting so we do not increment 520 // if we throw an exeption. 521 incrementPendingBroadcastsLocked(); 522 } 523 } catch (PendingIntent.CanceledException e) { 524 return false; 525 } 526 } 527 return true; 528 } 529 530 @Override 531 public void binderDied() { 532 if (D) Log.d(TAG, "Location listener died"); 533 534 synchronized (mLock) { 535 removeUpdatesLocked(this); 536 } 537 synchronized (this) { 538 if (mPendingBroadcasts > 0) { 539 LocationManagerService.this.decrementPendingBroadcasts(); 540 mPendingBroadcasts = 0; 541 } 542 } 543 } 544 545 @Override 546 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 547 int resultCode, String resultData, Bundle resultExtras) { 548 synchronized (this) { 549 decrementPendingBroadcastsLocked(); 550 } 551 } 552 553 // this must be called while synchronized by caller in a synchronized block 554 // containing the sending of the broadcaset 555 private void incrementPendingBroadcastsLocked() { 556 if (mPendingBroadcasts++ == 0) { 557 LocationManagerService.this.incrementPendingBroadcasts(); 558 } 559 } 560 561 private void decrementPendingBroadcastsLocked() { 562 if (--mPendingBroadcasts == 0) { 563 LocationManagerService.this.decrementPendingBroadcasts(); 564 } 565 } 566 } 567 568 @Override 569 public void locationCallbackFinished(ILocationListener listener) { 570 //Do not use getReceiver here as that will add the ILocationListener to 571 //the receiver list if it is not found. If it is not found then the 572 //LocationListener was removed when it had a pending broadcast and should 573 //not be added back. 574 IBinder binder = listener.asBinder(); 575 Receiver receiver = mReceivers.get(binder); 576 if (receiver != null) { 577 synchronized (receiver) { 578 // so wakelock calls will succeed 579 long identity = Binder.clearCallingIdentity(); 580 receiver.decrementPendingBroadcastsLocked(); 581 Binder.restoreCallingIdentity(identity); 582 } 583 } 584 } 585 586 private void addProviderLocked(LocationProviderInterface provider) { 587 mProviders.add(provider); 588 mProvidersByName.put(provider.getName(), provider); 589 } 590 591 private void removeProviderLocked(LocationProviderInterface provider) { 592 provider.disable(); 593 mProviders.remove(provider); 594 mProvidersByName.remove(provider.getName()); 595 } 596 597 598 private boolean isAllowedBySettingsLocked(String provider, int userId) { 599 if (userId != mCurrentUserId) { 600 return false; 601 } 602 if (mEnabledProviders.contains(provider)) { 603 return true; 604 } 605 if (mDisabledProviders.contains(provider)) { 606 return false; 607 } 608 // Use system settings 609 ContentResolver resolver = mContext.getContentResolver(); 610 611 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId); 612 } 613 614 /** 615 * Returns the permission string associated with the specified resolution level. 616 * 617 * @param resolutionLevel the resolution level 618 * @return the permission string 619 */ 620 private String getResolutionPermission(int resolutionLevel) { 621 switch (resolutionLevel) { 622 case RESOLUTION_LEVEL_FINE: 623 return android.Manifest.permission.ACCESS_FINE_LOCATION; 624 case RESOLUTION_LEVEL_COARSE: 625 return android.Manifest.permission.ACCESS_COARSE_LOCATION; 626 default: 627 return null; 628 } 629 } 630 631 /** 632 * Returns the resolution level allowed to the given PID/UID pair. 633 * 634 * @param pid the PID 635 * @param uid the UID 636 * @return resolution level allowed to the pid/uid pair 637 */ 638 private int getAllowedResolutionLevel(int pid, int uid) { 639 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, 640 pid, uid) == PackageManager.PERMISSION_GRANTED) { 641 return RESOLUTION_LEVEL_FINE; 642 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, 643 pid, uid) == PackageManager.PERMISSION_GRANTED) { 644 return RESOLUTION_LEVEL_COARSE; 645 } else { 646 return RESOLUTION_LEVEL_NONE; 647 } 648 } 649 650 /** 651 * Returns the resolution level allowed to the caller 652 * 653 * @return resolution level allowed to caller 654 */ 655 private int getCallerAllowedResolutionLevel() { 656 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid()); 657 } 658 659 /** 660 * Throw SecurityException if specified resolution level is insufficient to use geofences. 661 * 662 * @param allowedResolutionLevel resolution level allowed to caller 663 */ 664 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) { 665 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 666 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission"); 667 } 668 } 669 670 /** 671 * Return the minimum resolution level required to use the specified location provider. 672 * 673 * @param provider the name of the location provider 674 * @return minimum resolution level required for provider 675 */ 676 private int getMinimumResolutionLevelForProviderUse(String provider) { 677 if (LocationManager.GPS_PROVIDER.equals(provider) || 678 LocationManager.PASSIVE_PROVIDER.equals(provider)) { 679 // gps and passive providers require FINE permission 680 return RESOLUTION_LEVEL_FINE; 681 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) || 682 LocationManager.FUSED_PROVIDER.equals(provider)) { 683 // network and fused providers are ok with COARSE or FINE 684 return RESOLUTION_LEVEL_COARSE; 685 } else { 686 // mock providers 687 LocationProviderInterface lp = mMockProviders.get(provider); 688 if (lp != null) { 689 ProviderProperties properties = lp.getProperties(); 690 if (properties != null) { 691 if (properties.mRequiresSatellite) { 692 // provider requiring satellites require FINE permission 693 return RESOLUTION_LEVEL_FINE; 694 } else if (properties.mRequiresNetwork || properties.mRequiresCell) { 695 // provider requiring network and or cell require COARSE or FINE 696 return RESOLUTION_LEVEL_COARSE; 697 } 698 } 699 } 700 } 701 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE 702 } 703 704 /** 705 * Throw SecurityException if specified resolution level is insufficient to use the named 706 * location provider. 707 * 708 * @param allowedResolutionLevel resolution level allowed to caller 709 * @param providerName the name of the location provider 710 */ 711 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel, 712 String providerName) { 713 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName); 714 if (allowedResolutionLevel < requiredResolutionLevel) { 715 switch (requiredResolutionLevel) { 716 case RESOLUTION_LEVEL_FINE: 717 throw new SecurityException("\"" + providerName + "\" location provider " + 718 "requires ACCESS_FINE_LOCATION permission."); 719 case RESOLUTION_LEVEL_COARSE: 720 throw new SecurityException("\"" + providerName + "\" location provider " + 721 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); 722 default: 723 throw new SecurityException("Insufficient permission for \"" + providerName + 724 "\" location provider."); 725 } 726 } 727 } 728 729 /** 730 * Returns all providers by name, including passive, but excluding 731 * fused, also including ones that are not permitted to 732 * be accessed by the calling activity or are currently disabled. 733 */ 734 @Override 735 public List<String> getAllProviders() { 736 ArrayList<String> out; 737 synchronized (mLock) { 738 out = new ArrayList<String>(mProviders.size()); 739 for (LocationProviderInterface provider : mProviders) { 740 String name = provider.getName(); 741 if (LocationManager.FUSED_PROVIDER.equals(name)) { 742 continue; 743 } 744 out.add(name); 745 } 746 } 747 748 if (D) Log.d(TAG, "getAllProviders()=" + out); 749 return out; 750 } 751 752 /** 753 * Return all providers by name, that match criteria and are optionally 754 * enabled. 755 * Can return passive provider, but never returns fused provider. 756 */ 757 @Override 758 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 759 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 760 ArrayList<String> out; 761 int callingUserId = UserHandle.getCallingUserId(); 762 long identity = Binder.clearCallingIdentity(); 763 try { 764 synchronized (mLock) { 765 out = new ArrayList<String>(mProviders.size()); 766 for (LocationProviderInterface provider : mProviders) { 767 String name = provider.getName(); 768 if (LocationManager.FUSED_PROVIDER.equals(name)) { 769 continue; 770 } 771 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) { 772 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) { 773 continue; 774 } 775 if (criteria != null && !LocationProvider.propertiesMeetCriteria( 776 name, provider.getProperties(), criteria)) { 777 continue; 778 } 779 out.add(name); 780 } 781 } 782 } 783 } finally { 784 Binder.restoreCallingIdentity(identity); 785 } 786 787 if (D) Log.d(TAG, "getProviders()=" + out); 788 return out; 789 } 790 791 /** 792 * Return the name of the best provider given a Criteria object. 793 * This method has been deprecated from the public API, 794 * and the whole LocationProvider (including #meetsCriteria) 795 * has been deprecated as well. So this method now uses 796 * some simplified logic. 797 */ 798 @Override 799 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 800 String result = null; 801 802 List<String> providers = getProviders(criteria, enabledOnly); 803 if (!providers.isEmpty()) { 804 result = pickBest(providers); 805 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 806 return result; 807 } 808 providers = getProviders(null, enabledOnly); 809 if (!providers.isEmpty()) { 810 result = pickBest(providers); 811 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 812 return result; 813 } 814 815 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 816 return null; 817 } 818 819 private String pickBest(List<String> providers) { 820 if (providers.contains(LocationManager.GPS_PROVIDER)) { 821 return LocationManager.GPS_PROVIDER; 822 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) { 823 return LocationManager.NETWORK_PROVIDER; 824 } else { 825 return providers.get(0); 826 } 827 } 828 829 @Override 830 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 831 LocationProviderInterface p = mProvidersByName.get(provider); 832 if (p == null) { 833 throw new IllegalArgumentException("provider=" + provider); 834 } 835 836 boolean result = LocationProvider.propertiesMeetCriteria( 837 p.getName(), p.getProperties(), criteria); 838 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result); 839 return result; 840 } 841 842 private void updateProvidersLocked() { 843 boolean changesMade = false; 844 for (int i = mProviders.size() - 1; i >= 0; i--) { 845 LocationProviderInterface p = mProviders.get(i); 846 boolean isEnabled = p.isEnabled(); 847 String name = p.getName(); 848 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId); 849 if (isEnabled && !shouldBeEnabled) { 850 updateProviderListenersLocked(name, false, mCurrentUserId); 851 changesMade = true; 852 } else if (!isEnabled && shouldBeEnabled) { 853 updateProviderListenersLocked(name, true, mCurrentUserId); 854 changesMade = true; 855 } 856 } 857 if (changesMade) { 858 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION), 859 UserHandle.ALL); 860 } 861 } 862 863 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) { 864 int listeners = 0; 865 866 LocationProviderInterface p = mProvidersByName.get(provider); 867 if (p == null) return; 868 869 ArrayList<Receiver> deadReceivers = null; 870 871 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 872 if (records != null) { 873 final int N = records.size(); 874 for (int i = 0; i < N; i++) { 875 UpdateRecord record = records.get(i); 876 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) { 877 // Sends a notification message to the receiver 878 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 879 if (deadReceivers == null) { 880 deadReceivers = new ArrayList<Receiver>(); 881 } 882 deadReceivers.add(record.mReceiver); 883 } 884 listeners++; 885 } 886 } 887 } 888 889 if (deadReceivers != null) { 890 for (int i = deadReceivers.size() - 1; i >= 0; i--) { 891 removeUpdatesLocked(deadReceivers.get(i)); 892 } 893 } 894 895 if (enabled) { 896 p.enable(); 897 if (listeners > 0) { 898 applyRequirementsLocked(provider); 899 } 900 } else { 901 p.disable(); 902 } 903 } 904 905 private void applyRequirementsLocked(String provider) { 906 LocationProviderInterface p = mProvidersByName.get(provider); 907 if (p == null) return; 908 909 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 910 WorkSource worksource = new WorkSource(); 911 ProviderRequest providerRequest = new ProviderRequest(); 912 913 if (records != null) { 914 for (UpdateRecord record : records) { 915 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) { 916 LocationRequest locationRequest = record.mRequest; 917 providerRequest.locationRequests.add(locationRequest); 918 if (locationRequest.getInterval() < providerRequest.interval) { 919 providerRequest.reportLocation = true; 920 providerRequest.interval = locationRequest.getInterval(); 921 } 922 } 923 } 924 925 if (providerRequest.reportLocation) { 926 // calculate who to blame for power 927 // This is somewhat arbitrary. We pick a threshold interval 928 // that is slightly higher that the minimum interval, and 929 // spread the blame across all applications with a request 930 // under that threshold. 931 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2; 932 for (UpdateRecord record : records) { 933 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) { 934 LocationRequest locationRequest = record.mRequest; 935 if (locationRequest.getInterval() <= thresholdInterval) { 936 worksource.add(record.mReceiver.mUid); 937 } 938 } 939 } 940 } 941 } 942 943 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest); 944 p.setRequest(providerRequest, worksource); 945 } 946 947 private class UpdateRecord { 948 final String mProvider; 949 final LocationRequest mRequest; 950 final Receiver mReceiver; 951 Location mLastFixBroadcast; 952 long mLastStatusBroadcast; 953 954 /** 955 * Note: must be constructed with lock held. 956 */ 957 UpdateRecord(String provider, LocationRequest request, Receiver receiver) { 958 mProvider = provider; 959 mRequest = request; 960 mReceiver = receiver; 961 962 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 963 if (records == null) { 964 records = new ArrayList<UpdateRecord>(); 965 mRecordsByProvider.put(provider, records); 966 } 967 if (!records.contains(this)) { 968 records.add(this); 969 } 970 } 971 972 /** 973 * Method to be called when a record will no longer be used. Calling this multiple times 974 * must have the same effect as calling it once. 975 */ 976 void disposeLocked(boolean removeReceiver) { 977 // remove from mRecordsByProvider 978 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider); 979 if (globalRecords != null) { 980 globalRecords.remove(this); 981 } 982 983 if (!removeReceiver) return; // the caller will handle the rest 984 985 // remove from Receiver#mUpdateRecords 986 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords; 987 if (receiverRecords != null) { 988 receiverRecords.remove(this.mProvider); 989 990 // and also remove the Receiver if it has no more update records 991 if (removeReceiver && receiverRecords.size() == 0) { 992 removeUpdatesLocked(mReceiver); 993 } 994 } 995 } 996 997 @Override 998 public String toString() { 999 StringBuilder s = new StringBuilder(); 1000 s.append("UpdateRecord["); 1001 s.append(mProvider); 1002 s.append(' ').append(mReceiver.mPackageName).append('('); 1003 s.append(mReceiver.mUid).append(')'); 1004 s.append(' ').append(mRequest); 1005 s.append(']'); 1006 return s.toString(); 1007 } 1008 } 1009 1010 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) { 1011 IBinder binder = listener.asBinder(); 1012 Receiver receiver = mReceivers.get(binder); 1013 if (receiver == null) { 1014 receiver = new Receiver(listener, null, pid, uid, packageName); 1015 mReceivers.put(binder, receiver); 1016 1017 try { 1018 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1019 } catch (RemoteException e) { 1020 Slog.e(TAG, "linkToDeath failed:", e); 1021 return null; 1022 } 1023 } 1024 return receiver; 1025 } 1026 1027 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) { 1028 Receiver receiver = mReceivers.get(intent); 1029 if (receiver == null) { 1030 receiver = new Receiver(null, intent, pid, uid, packageName); 1031 mReceivers.put(intent, receiver); 1032 } 1033 return receiver; 1034 } 1035 1036 /** 1037 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution 1038 * and consistency requirements. 1039 * 1040 * @param request the LocationRequest from which to create a sanitized version 1041 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution 1042 * constraints 1043 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution 1044 * @return a version of request that meets the given resolution and consistency requirements 1045 * @hide 1046 */ 1047 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) { 1048 LocationRequest sanitizedRequest = new LocationRequest(request); 1049 if (resolutionLevel < RESOLUTION_LEVEL_FINE) { 1050 switch (sanitizedRequest.getQuality()) { 1051 case LocationRequest.ACCURACY_FINE: 1052 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK); 1053 break; 1054 case LocationRequest.POWER_HIGH: 1055 sanitizedRequest.setQuality(LocationRequest.POWER_LOW); 1056 break; 1057 } 1058 // throttle 1059 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1060 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 1061 } 1062 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 1063 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 1064 } 1065 } 1066 // make getFastestInterval() the minimum of interval and fastest interval 1067 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) { 1068 request.setFastestInterval(request.getInterval()); 1069 } 1070 return sanitizedRequest; 1071 } 1072 1073 private void checkPackageName(String packageName) { 1074 if (packageName == null) { 1075 throw new SecurityException("invalid package name: " + packageName); 1076 } 1077 int uid = Binder.getCallingUid(); 1078 String[] packages = mPackageManager.getPackagesForUid(uid); 1079 if (packages == null) { 1080 throw new SecurityException("invalid UID " + uid); 1081 } 1082 for (String pkg : packages) { 1083 if (packageName.equals(pkg)) return; 1084 } 1085 throw new SecurityException("invalid package name: " + packageName); 1086 } 1087 1088 private void checkPendingIntent(PendingIntent intent) { 1089 if (intent == null) { 1090 throw new IllegalArgumentException("invalid pending intent: " + intent); 1091 } 1092 } 1093 1094 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent, 1095 int pid, int uid, String packageName) { 1096 if (intent == null && listener == null) { 1097 throw new IllegalArgumentException("need eiter listener or intent"); 1098 } else if (intent != null && listener != null) { 1099 throw new IllegalArgumentException("cannot register both listener and intent"); 1100 } else if (intent != null) { 1101 checkPendingIntent(intent); 1102 return getReceiver(intent, pid, uid, packageName); 1103 } else { 1104 return getReceiver(listener, pid, uid, packageName); 1105 } 1106 } 1107 1108 @Override 1109 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 1110 PendingIntent intent, String packageName) { 1111 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1112 checkPackageName(packageName); 1113 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1114 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1115 request.getProvider()); 1116 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1117 1118 final int pid = Binder.getCallingPid(); 1119 final int uid = Binder.getCallingUid(); 1120 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); 1121 1122 // providers may use public location API's, need to clear identity 1123 long identity = Binder.clearCallingIdentity(); 1124 try { 1125 synchronized (mLock) { 1126 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); 1127 } 1128 } finally { 1129 Binder.restoreCallingIdentity(identity); 1130 } 1131 } 1132 1133 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 1134 int pid, int uid, String packageName) { 1135 // Figure out the provider. Either its explicitly request (legacy use cases), or 1136 // use the fused provider 1137 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1138 String name = request.getProvider(); 1139 if (name == null) { 1140 throw new IllegalArgumentException("provider name must not be null"); 1141 } 1142 LocationProviderInterface provider = mProvidersByName.get(name); 1143 if (provider == null) { 1144 throw new IllegalArgumentException("provider doesn't exisit: " + provider); 1145 } 1146 1147 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " + 1148 name + " " + request + " from " + packageName + "(" + uid + ")"); 1149 1150 UpdateRecord record = new UpdateRecord(name, request, receiver); 1151 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 1152 if (oldRecord != null) { 1153 oldRecord.disposeLocked(false); 1154 } 1155 1156 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid)); 1157 if (isProviderEnabled) { 1158 applyRequirementsLocked(name); 1159 } else { 1160 // Notify the listener that updates are currently disabled 1161 receiver.callProviderEnabledLocked(name, false); 1162 } 1163 } 1164 1165 @Override 1166 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1167 String packageName) { 1168 checkPackageName(packageName); 1169 1170 final int pid = Binder.getCallingPid(); 1171 final int uid = Binder.getCallingUid(); 1172 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); 1173 1174 // providers may use public location API's, need to clear identity 1175 long identity = Binder.clearCallingIdentity(); 1176 try { 1177 synchronized (mLock) { 1178 removeUpdatesLocked(receiver); 1179 } 1180 } finally { 1181 Binder.restoreCallingIdentity(identity); 1182 } 1183 } 1184 1185 private void removeUpdatesLocked(Receiver receiver) { 1186 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1187 1188 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1189 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1190 synchronized (receiver) { 1191 if (receiver.mPendingBroadcasts > 0) { 1192 decrementPendingBroadcasts(); 1193 receiver.mPendingBroadcasts = 0; 1194 } 1195 } 1196 } 1197 1198 // Record which providers were associated with this listener 1199 HashSet<String> providers = new HashSet<String>(); 1200 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1201 if (oldRecords != null) { 1202 // Call dispose() on the obsolete update records. 1203 for (UpdateRecord record : oldRecords.values()) { 1204 record.disposeLocked(false); 1205 } 1206 // Accumulate providers 1207 providers.addAll(oldRecords.keySet()); 1208 } 1209 1210 // update provider 1211 for (String provider : providers) { 1212 // If provider is already disabled, don't need to do anything 1213 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) { 1214 continue; 1215 } 1216 1217 applyRequirementsLocked(provider); 1218 } 1219 } 1220 1221 @Override 1222 public Location getLastLocation(LocationRequest request, String packageName) { 1223 if (D) Log.d(TAG, "getLastLocation: " + request); 1224 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1225 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1226 checkPackageName(packageName); 1227 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1228 request.getProvider()); 1229 // no need to sanitize this request, as only the provider name is used 1230 1231 long identity = Binder.clearCallingIdentity(); 1232 try { 1233 if (mBlacklist.isBlacklisted(packageName)) { 1234 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1235 packageName); 1236 return null; 1237 } 1238 1239 synchronized (mLock) { 1240 // Figure out the provider. Either its explicitly request (deprecated API's), 1241 // or use the fused provider 1242 String name = request.getProvider(); 1243 if (name == null) name = LocationManager.FUSED_PROVIDER; 1244 LocationProviderInterface provider = mProvidersByName.get(name); 1245 if (provider == null) return null; 1246 1247 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null; 1248 1249 Location location = mLastLocation.get(name); 1250 if (location == null) { 1251 return null; 1252 } 1253 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1254 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 1255 if (noGPSLocation != null) { 1256 return mLocationFudger.getOrCreate(noGPSLocation); 1257 } 1258 } else { 1259 return location; 1260 } 1261 } 1262 return null; 1263 } finally { 1264 Binder.restoreCallingIdentity(identity); 1265 } 1266 } 1267 1268 @Override 1269 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1270 String packageName) { 1271 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1272 int allowedResolutionLevel = getCallerAllowedResolutionLevel(); 1273 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel); 1274 checkPendingIntent(intent); 1275 checkPackageName(packageName); 1276 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, 1277 request.getProvider()); 1278 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); 1279 1280 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent); 1281 1282 // geo-fence manager uses the public location API, need to clear identity 1283 int uid = Binder.getCallingUid(); 1284 long identity = Binder.clearCallingIdentity(); 1285 try { 1286 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName); 1287 } finally { 1288 Binder.restoreCallingIdentity(identity); 1289 } 1290 } 1291 1292 @Override 1293 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1294 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel()); 1295 checkPendingIntent(intent); 1296 checkPackageName(packageName); 1297 1298 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1299 1300 // geo-fence manager uses the public location API, need to clear identity 1301 long identity = Binder.clearCallingIdentity(); 1302 try { 1303 mGeofenceManager.removeFence(geofence, intent); 1304 } finally { 1305 Binder.restoreCallingIdentity(identity); 1306 } 1307 } 1308 1309 1310 @Override 1311 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1312 if (mGpsStatusProvider == null) { 1313 return false; 1314 } 1315 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1316 LocationManager.GPS_PROVIDER); 1317 1318 try { 1319 mGpsStatusProvider.addGpsStatusListener(listener); 1320 } catch (RemoteException e) { 1321 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1322 return false; 1323 } 1324 return true; 1325 } 1326 1327 @Override 1328 public void removeGpsStatusListener(IGpsStatusListener listener) { 1329 synchronized (mLock) { 1330 try { 1331 mGpsStatusProvider.removeGpsStatusListener(listener); 1332 } catch (Exception e) { 1333 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1334 } 1335 } 1336 } 1337 1338 @Override 1339 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1340 if (provider == null) { 1341 // throw NullPointerException to remain compatible with previous implementation 1342 throw new NullPointerException(); 1343 } 1344 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1345 provider); 1346 1347 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1348 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1349 != PackageManager.PERMISSION_GRANTED)) { 1350 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1351 } 1352 1353 synchronized (mLock) { 1354 LocationProviderInterface p = mProvidersByName.get(provider); 1355 if (p == null) return false; 1356 1357 return p.sendExtraCommand(command, extras); 1358 } 1359 } 1360 1361 @Override 1362 public boolean sendNiResponse(int notifId, int userResponse) { 1363 if (Binder.getCallingUid() != Process.myUid()) { 1364 throw new SecurityException( 1365 "calling sendNiResponse from outside of the system is not allowed"); 1366 } 1367 try { 1368 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1369 } catch (RemoteException e) { 1370 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1371 return false; 1372 } 1373 } 1374 1375 /** 1376 * @return null if the provider does not exist 1377 * @throws SecurityException if the provider is not allowed to be 1378 * accessed by the caller 1379 */ 1380 @Override 1381 public ProviderProperties getProviderProperties(String provider) { 1382 if (mProvidersByName.get(provider) == null) { 1383 return null; 1384 } 1385 1386 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1387 provider); 1388 1389 LocationProviderInterface p; 1390 synchronized (mLock) { 1391 p = mProvidersByName.get(provider); 1392 } 1393 1394 if (p == null) return null; 1395 return p.getProperties(); 1396 } 1397 1398 @Override 1399 public boolean isProviderEnabled(String provider) { 1400 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), 1401 provider); 1402 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1403 1404 long identity = Binder.clearCallingIdentity(); 1405 try { 1406 synchronized (mLock) { 1407 LocationProviderInterface p = mProvidersByName.get(provider); 1408 if (p == null) return false; 1409 1410 return isAllowedBySettingsLocked(provider, mCurrentUserId); 1411 } 1412 } finally { 1413 Binder.restoreCallingIdentity(identity); 1414 } 1415 } 1416 1417 private void checkCallerIsProvider() { 1418 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1419 == PackageManager.PERMISSION_GRANTED) { 1420 return; 1421 } 1422 1423 // Previously we only used the INSTALL_LOCATION_PROVIDER 1424 // check. But that is system or signature 1425 // protection level which is not flexible enough for 1426 // providers installed oustide the system image. So 1427 // also allow providers with a UID matching the 1428 // currently bound package name 1429 1430 int uid = Binder.getCallingUid(); 1431 1432 if (mGeocodeProvider != null) { 1433 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return; 1434 } 1435 for (LocationProviderProxy proxy : mProxyProviders) { 1436 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return; 1437 } 1438 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1439 "or UID of a currently bound location provider"); 1440 } 1441 1442 private boolean doesPackageHaveUid(int uid, String packageName) { 1443 if (packageName == null) { 1444 return false; 1445 } 1446 try { 1447 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); 1448 if (appInfo.uid != uid) { 1449 return false; 1450 } 1451 } catch (NameNotFoundException e) { 1452 return false; 1453 } 1454 return true; 1455 } 1456 1457 @Override 1458 public void reportLocation(Location location, boolean passive) { 1459 checkCallerIsProvider(); 1460 1461 if (!location.isComplete()) { 1462 Log.w(TAG, "Dropping incomplete location: " + location); 1463 return; 1464 } 1465 1466 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 1467 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 1468 m.arg1 = (passive ? 1 : 0); 1469 mLocationHandler.sendMessageAtFrontOfQueue(m); 1470 } 1471 1472 1473 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1474 // Always broadcast the first update 1475 if (lastLoc == null) { 1476 return true; 1477 } 1478 1479 // Check whether sufficient time has passed 1480 long minTime = record.mRequest.getFastestInterval(); 1481 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L; 1482 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 1483 return false; 1484 } 1485 1486 // Check whether sufficient distance has been traveled 1487 double minDistance = record.mRequest.getSmallestDisplacement(); 1488 if (minDistance > 0.0) { 1489 if (loc.distanceTo(lastLoc) <= minDistance) { 1490 return false; 1491 } 1492 } 1493 1494 return true; 1495 } 1496 1497 private void handleLocationChangedLocked(Location location, boolean passive) { 1498 if (D) Log.d(TAG, "incoming location: " + location); 1499 1500 long now = SystemClock.elapsedRealtime(); 1501 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1502 1503 // Skip if the provider is unknown. 1504 LocationProviderInterface p = mProvidersByName.get(provider); 1505 if (p == null) return; 1506 1507 // Update last known locations 1508 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 1509 Location lastNoGPSLocation = null; 1510 Location lastLocation = mLastLocation.get(provider); 1511 if (lastLocation == null) { 1512 lastLocation = new Location(provider); 1513 mLastLocation.put(provider, lastLocation); 1514 } else { 1515 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); 1516 if (noGPSLocation == null && lastNoGPSLocation != null) { 1517 // New location has no no-GPS location: adopt last no-GPS location. This is set 1518 // directly into location because we do not want to notify COARSE clients. 1519 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); 1520 } 1521 } 1522 lastLocation.set(location); 1523 1524 // Skip if there are no UpdateRecords for this provider. 1525 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1526 if (records == null || records.size() == 0) return; 1527 1528 // Fetch coarse location 1529 Location coarseLocation = null; 1530 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) { 1531 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation); 1532 } 1533 1534 // Fetch latest status update time 1535 long newStatusUpdateTime = p.getStatusUpdateTime(); 1536 1537 // Get latest status 1538 Bundle extras = new Bundle(); 1539 int status = p.getStatus(extras); 1540 1541 ArrayList<Receiver> deadReceivers = null; 1542 ArrayList<UpdateRecord> deadUpdateRecords = null; 1543 1544 // Broadcast location or status to all listeners 1545 for (UpdateRecord r : records) { 1546 Receiver receiver = r.mReceiver; 1547 boolean receiverDead = false; 1548 1549 int receiverUserId = UserHandle.getUserId(receiver.mUid); 1550 if (receiverUserId != mCurrentUserId) { 1551 if (D) { 1552 Log.d(TAG, "skipping loc update for background user " + receiverUserId + 1553 " (current user: " + mCurrentUserId + ", app: " + 1554 receiver.mPackageName + ")"); 1555 } 1556 continue; 1557 } 1558 1559 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 1560 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 1561 receiver.mPackageName); 1562 continue; 1563 } 1564 1565 Location notifyLocation = null; 1566 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) { 1567 notifyLocation = coarseLocation; // use coarse location 1568 } else { 1569 notifyLocation = lastLocation; // use fine location 1570 } 1571 if (notifyLocation != null) { 1572 Location lastLoc = r.mLastFixBroadcast; 1573 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) { 1574 if (lastLoc == null) { 1575 lastLoc = new Location(notifyLocation); 1576 r.mLastFixBroadcast = lastLoc; 1577 } else { 1578 lastLoc.set(notifyLocation); 1579 } 1580 if (!receiver.callLocationChangedLocked(notifyLocation)) { 1581 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1582 receiverDead = true; 1583 } 1584 } 1585 } 1586 1587 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1588 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1589 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1590 1591 r.mLastStatusBroadcast = newStatusUpdateTime; 1592 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1593 receiverDead = true; 1594 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1595 } 1596 } 1597 1598 // track expired records 1599 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) { 1600 if (deadUpdateRecords == null) { 1601 deadUpdateRecords = new ArrayList<UpdateRecord>(); 1602 } 1603 deadUpdateRecords.add(r); 1604 } 1605 // track dead receivers 1606 if (receiverDead) { 1607 if (deadReceivers == null) { 1608 deadReceivers = new ArrayList<Receiver>(); 1609 } 1610 if (!deadReceivers.contains(receiver)) { 1611 deadReceivers.add(receiver); 1612 } 1613 } 1614 } 1615 1616 // remove dead records and receivers outside the loop 1617 if (deadReceivers != null) { 1618 for (Receiver receiver : deadReceivers) { 1619 removeUpdatesLocked(receiver); 1620 } 1621 } 1622 if (deadUpdateRecords != null) { 1623 for (UpdateRecord r : deadUpdateRecords) { 1624 r.disposeLocked(true); 1625 } 1626 } 1627 } 1628 1629 private class LocationWorkerHandler extends Handler { 1630 @Override 1631 public void handleMessage(Message msg) { 1632 switch (msg.what) { 1633 case MSG_LOCATION_CHANGED: 1634 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 1635 break; 1636 } 1637 } 1638 } 1639 1640 private void handleLocationChanged(Location location, boolean passive) { 1641 String provider = location.getProvider(); 1642 1643 if (!passive) { 1644 // notify passive provider of the new location 1645 mPassiveProvider.updateLocation(location); 1646 } 1647 1648 synchronized (mLock) { 1649 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) { 1650 handleLocationChangedLocked(location, passive); 1651 } 1652 } 1653 } 1654 1655 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1656 @Override 1657 public void onPackageDisappeared(String packageName, int reason) { 1658 // remove all receivers associated with this package name 1659 synchronized (mLock) { 1660 ArrayList<Receiver> deadReceivers = null; 1661 1662 for (Receiver receiver : mReceivers.values()) { 1663 if (receiver.mPackageName.equals(packageName)) { 1664 if (deadReceivers == null) { 1665 deadReceivers = new ArrayList<Receiver>(); 1666 } 1667 deadReceivers.add(receiver); 1668 } 1669 } 1670 1671 // perform removal outside of mReceivers loop 1672 if (deadReceivers != null) { 1673 for (Receiver receiver : deadReceivers) { 1674 removeUpdatesLocked(receiver); 1675 } 1676 } 1677 } 1678 } 1679 }; 1680 1681 // Wake locks 1682 1683 private void incrementPendingBroadcasts() { 1684 synchronized (mWakeLock) { 1685 if (mPendingBroadcasts++ == 0) { 1686 try { 1687 mWakeLock.acquire(); 1688 log("Acquired wakelock"); 1689 } catch (Exception e) { 1690 // This is to catch a runtime exception thrown when we try to release an 1691 // already released lock. 1692 Slog.e(TAG, "exception in acquireWakeLock()", e); 1693 } 1694 } 1695 } 1696 } 1697 1698 private void decrementPendingBroadcasts() { 1699 synchronized (mWakeLock) { 1700 if (--mPendingBroadcasts == 0) { 1701 try { 1702 // Release wake lock 1703 if (mWakeLock.isHeld()) { 1704 mWakeLock.release(); 1705 log("Released wakelock"); 1706 } else { 1707 log("Can't release wakelock again!"); 1708 } 1709 } catch (Exception e) { 1710 // This is to catch a runtime exception thrown when we try to release an 1711 // already released lock. 1712 Slog.e(TAG, "exception in releaseWakeLock()", e); 1713 } 1714 } 1715 } 1716 } 1717 1718 // Geocoder 1719 1720 @Override 1721 public boolean geocoderIsPresent() { 1722 return mGeocodeProvider != null; 1723 } 1724 1725 @Override 1726 public String getFromLocation(double latitude, double longitude, int maxResults, 1727 GeocoderParams params, List<Address> addrs) { 1728 if (mGeocodeProvider != null) { 1729 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1730 params, addrs); 1731 } 1732 return null; 1733 } 1734 1735 1736 @Override 1737 public String getFromLocationName(String locationName, 1738 double lowerLeftLatitude, double lowerLeftLongitude, 1739 double upperRightLatitude, double upperRightLongitude, int maxResults, 1740 GeocoderParams params, List<Address> addrs) { 1741 1742 if (mGeocodeProvider != null) { 1743 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1744 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1745 maxResults, params, addrs); 1746 } 1747 return null; 1748 } 1749 1750 // Mock Providers 1751 1752 private void checkMockPermissionsSafe() { 1753 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1754 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1755 if (!allowMocks) { 1756 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1757 } 1758 1759 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1760 PackageManager.PERMISSION_GRANTED) { 1761 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1762 } 1763 } 1764 1765 @Override 1766 public void addTestProvider(String name, ProviderProperties properties) { 1767 checkMockPermissionsSafe(); 1768 1769 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1770 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1771 } 1772 1773 long identity = Binder.clearCallingIdentity(); 1774 synchronized (mLock) { 1775 MockProvider provider = new MockProvider(name, this, properties); 1776 // remove the real provider if we are replacing GPS or network provider 1777 if (LocationManager.GPS_PROVIDER.equals(name) 1778 || LocationManager.NETWORK_PROVIDER.equals(name) 1779 || LocationManager.FUSED_PROVIDER.equals(name)) { 1780 LocationProviderInterface p = mProvidersByName.get(name); 1781 if (p != null) { 1782 removeProviderLocked(p); 1783 } 1784 } 1785 if (mProvidersByName.get(name) != null) { 1786 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1787 } 1788 addProviderLocked(provider); 1789 mMockProviders.put(name, provider); 1790 mLastLocation.put(name, null); 1791 updateProvidersLocked(); 1792 } 1793 Binder.restoreCallingIdentity(identity); 1794 } 1795 1796 @Override 1797 public void removeTestProvider(String provider) { 1798 checkMockPermissionsSafe(); 1799 synchronized (mLock) { 1800 MockProvider mockProvider = mMockProviders.get(provider); 1801 if (mockProvider == null) { 1802 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1803 } 1804 long identity = Binder.clearCallingIdentity(); 1805 removeProviderLocked(mProvidersByName.get(provider)); 1806 mMockProviders.remove(mockProvider); 1807 1808 // reinstate real provider if available 1809 LocationProviderInterface realProvider = mRealProviders.get(provider); 1810 if (realProvider != null) { 1811 addProviderLocked(realProvider); 1812 } 1813 mLastLocation.put(provider, null); 1814 updateProvidersLocked(); 1815 Binder.restoreCallingIdentity(identity); 1816 } 1817 } 1818 1819 @Override 1820 public void setTestProviderLocation(String provider, Location loc) { 1821 checkMockPermissionsSafe(); 1822 synchronized (mLock) { 1823 MockProvider mockProvider = mMockProviders.get(provider); 1824 if (mockProvider == null) { 1825 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1826 } 1827 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1828 long identity = Binder.clearCallingIdentity(); 1829 mockProvider.setLocation(loc); 1830 Binder.restoreCallingIdentity(identity); 1831 } 1832 } 1833 1834 @Override 1835 public void clearTestProviderLocation(String provider) { 1836 checkMockPermissionsSafe(); 1837 synchronized (mLock) { 1838 MockProvider mockProvider = mMockProviders.get(provider); 1839 if (mockProvider == null) { 1840 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1841 } 1842 mockProvider.clearLocation(); 1843 } 1844 } 1845 1846 @Override 1847 public void setTestProviderEnabled(String provider, boolean enabled) { 1848 checkMockPermissionsSafe(); 1849 synchronized (mLock) { 1850 MockProvider mockProvider = mMockProviders.get(provider); 1851 if (mockProvider == null) { 1852 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1853 } 1854 long identity = Binder.clearCallingIdentity(); 1855 if (enabled) { 1856 mockProvider.enable(); 1857 mEnabledProviders.add(provider); 1858 mDisabledProviders.remove(provider); 1859 } else { 1860 mockProvider.disable(); 1861 mEnabledProviders.remove(provider); 1862 mDisabledProviders.add(provider); 1863 } 1864 updateProvidersLocked(); 1865 Binder.restoreCallingIdentity(identity); 1866 } 1867 } 1868 1869 @Override 1870 public void clearTestProviderEnabled(String provider) { 1871 checkMockPermissionsSafe(); 1872 synchronized (mLock) { 1873 MockProvider mockProvider = mMockProviders.get(provider); 1874 if (mockProvider == null) { 1875 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1876 } 1877 long identity = Binder.clearCallingIdentity(); 1878 mEnabledProviders.remove(provider); 1879 mDisabledProviders.remove(provider); 1880 updateProvidersLocked(); 1881 Binder.restoreCallingIdentity(identity); 1882 } 1883 } 1884 1885 @Override 1886 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1887 checkMockPermissionsSafe(); 1888 synchronized (mLock) { 1889 MockProvider mockProvider = mMockProviders.get(provider); 1890 if (mockProvider == null) { 1891 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1892 } 1893 mockProvider.setStatus(status, extras, updateTime); 1894 } 1895 } 1896 1897 @Override 1898 public void clearTestProviderStatus(String provider) { 1899 checkMockPermissionsSafe(); 1900 synchronized (mLock) { 1901 MockProvider mockProvider = mMockProviders.get(provider); 1902 if (mockProvider == null) { 1903 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1904 } 1905 mockProvider.clearStatus(); 1906 } 1907 } 1908 1909 private void log(String log) { 1910 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1911 Slog.d(TAG, log); 1912 } 1913 } 1914 1915 @Override 1916 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1917 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1918 != PackageManager.PERMISSION_GRANTED) { 1919 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 1920 + Binder.getCallingPid() 1921 + ", uid=" + Binder.getCallingUid()); 1922 return; 1923 } 1924 1925 synchronized (mLock) { 1926 pw.println("Current Location Manager state:"); 1927 pw.println(" Location Listeners:"); 1928 for (Receiver receiver : mReceivers.values()) { 1929 pw.println(" " + receiver); 1930 } 1931 pw.println(" Records by Provider:"); 1932 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 1933 pw.println(" " + entry.getKey() + ":"); 1934 for (UpdateRecord record : entry.getValue()) { 1935 pw.println(" " + record); 1936 } 1937 } 1938 pw.println(" Last Known Locations:"); 1939 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 1940 String provider = entry.getKey(); 1941 Location location = entry.getValue(); 1942 pw.println(" " + provider + ": " + location); 1943 } 1944 1945 mGeofenceManager.dump(pw); 1946 1947 if (mEnabledProviders.size() > 0) { 1948 pw.println(" Enabled Providers:"); 1949 for (String i : mEnabledProviders) { 1950 pw.println(" " + i); 1951 } 1952 1953 } 1954 if (mDisabledProviders.size() > 0) { 1955 pw.println(" Disabled Providers:"); 1956 for (String i : mDisabledProviders) { 1957 pw.println(" " + i); 1958 } 1959 } 1960 pw.append(" "); 1961 mBlacklist.dump(pw); 1962 if (mMockProviders.size() > 0) { 1963 pw.println(" Mock Providers:"); 1964 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 1965 i.getValue().dump(pw, " "); 1966 } 1967 } 1968 1969 pw.append(" fudger: "); 1970 mLocationFudger.dump(fd, pw, args); 1971 1972 if (args.length > 0 && "short".equals(args[0])) { 1973 return; 1974 } 1975 for (LocationProviderInterface provider: mProviders) { 1976 pw.print(provider.getName() + " Internal State"); 1977 if (provider instanceof LocationProviderProxy) { 1978 LocationProviderProxy proxy = (LocationProviderProxy) provider; 1979 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 1980 } 1981 pw.println(":"); 1982 provider.dump(fd, pw, args); 1983 } 1984 } 1985 } 1986} 1987