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