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