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