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