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