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